fea: merge http and socks5 proxy.

This commit is contained in:
Daniel Ding
2025-03-14 14:18:56 +08:00
parent 45481a6956
commit 32afec64a4
9 changed files with 265 additions and 114 deletions

View File

@@ -78,11 +78,9 @@ builder:
# tar xvf libreswan_4.10.orig.tar.gz # tar xvf libreswan_4.10.orig.tar.gz
# cd libreswan-4.10 && make deb # cd libreswan-4.10 && make deb
docker-bin: ## binary by Docker docker-bin: ## binary by Docker
docker exec openlan_builder bash -c "cd /opt/openlan && make linux-bin" docker exec openlan_builder bash -c "cd /opt/openlan && make linux-bin"
docker-test: ## test by Docker docker-test: ## test by Docker
docker exec openlan_builder bash -c "cd /opt/openlan && make test" docker exec openlan_builder bash -c "cd /opt/openlan && make test"
@@ -92,6 +90,9 @@ docker-darwin: ## binary for MacOS by Docker
docker-windows: ## binary for Windows by Docker docker-windows: ## binary for Windows by Docker
docker exec openlan_builder bash -c "cd /opt/openlan && make windows-gzip" docker exec openlan_builder bash -c "cd /opt/openlan && make windows-gzip"
docker-ceci: ## binary for ceci by Docker
docker exec openlan_builder bash -c "cd /opt/openlan && make ceci"
docker-rhel: docker-bin ## build image for redhat docker-rhel: docker-bin ## build image for redhat
cp -rf $(SD)/docker/centos $(BD) cp -rf $(SD)/docker/centos $(BD)
cd $(BD) && \ cd $(BD) && \
@@ -118,13 +119,19 @@ docker-compose: ## create a compose files
echo "$ cd /tmp/openlan.c" && \ echo "$ cd /tmp/openlan.c" && \
echo "$ docker-compose up -d" echo "$ docker-compose up -d"
linux: env ## build linux binary ceci: linux-ceci darwin-ceci windows-ceci ## build all platform ceci
linux: env linux-ceci linux-proxy ## build linux binary
go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan ./cmd/main.go go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan ./cmd/main.go
go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-proxy ./cmd/proxy
go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-ceci ./cmd/ceci
go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-point ./cmd/point go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-point ./cmd/point
go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-switch ./cmd/switch go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-switch ./cmd/switch
linux-ceci:
go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-ceci ./cmd/ceci
linux-proxy:
go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-proxy ./cmd/proxy
linux-gzip: install ## build linux packages linux-gzip: install ## build linux packages
@rm -rf $(LIN_DIR).tar.gz @rm -rf $(LIN_DIR).tar.gz
tar -cf $(LIN_DIR).tar $(LIN_DIR) && mv $(LIN_DIR).tar $(BD) tar -cf $(LIN_DIR).tar $(LIN_DIR) && mv $(LIN_DIR).tar $(BD)
@@ -152,8 +159,12 @@ install: env linux ## install packages
@echo "Installed to $(LIN_DIR)" @echo "Installed to $(LIN_DIR)"
## cross build for windows ## cross build for windows
windows: ## build windows binary windows: env windows-ceci windows-proxy ## build windows binary
windows-proxy:
GOOS=windows GOARCH=amd64 go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-proxy.exe ./cmd/proxy GOOS=windows GOARCH=amd64 go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-proxy.exe ./cmd/proxy
windows-ceci:
GOOS=windows GOARCH=amd64 go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-ceci.exe ./cmd/ceci GOOS=windows GOARCH=amd64 go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-ceci.exe ./cmd/ceci
windows-gzip: env windows ## build windows packages windows-gzip: env windows ## build windows packages
@@ -166,12 +177,16 @@ windows-gzip: env windows ## build windows packages
## cross build for osx ## cross build for osx
osx: darwin osx: darwin
darwin: env ## build darwin binary darwin: env darwin-ceci darwin-proxy ## build darwin binary
GOOS=darwin GOARCH=amd64 go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-proxy.dar ./cmd/proxy
GOOS=darwin GOARCH=arm64 go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-proxy.arm64.dar ./cmd/proxy darwin-ceci:
GOOS=darwin GOARCH=amd64 go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-ceci.dar ./cmd/ceci GOOS=darwin GOARCH=amd64 go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-ceci.dar ./cmd/ceci
GOOS=darwin GOARCH=arm64 go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-ceci.arm64.dar ./cmd/ceci GOOS=darwin GOARCH=arm64 go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-ceci.arm64.dar ./cmd/ceci
darwin-proxy:
GOOS=darwin GOARCH=amd64 go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-proxy.dar ./cmd/proxy
GOOS=darwin GOARCH=arm64 go build -mod=vendor -ldflags "$(LDFLAGS)" -o $(BD)/openlan-proxy.arm64.dar ./cmd/proxy
darwin-gzip: env darwin ## build darwin packages darwin-gzip: env darwin ## build darwin packages
@rm -rf $(MAC_DIR) && mkdir -p $(MAC_DIR) @rm -rf $(MAC_DIR) && mkdir -p $(MAC_DIR)
@cp -rf $(SD)/dist/rootfs/etc/openlan/proxy.json.local $(MAC_DIR)/proxy.json @cp -rf $(SD)/dist/rootfs/etc/openlan/proxy.json.local $(MAC_DIR)/proxy.json

91
cmd/api/v5/ceci.go Executable file
View File

@@ -0,0 +1,91 @@
package v5
import (
"github.com/luscis/openlan/cmd/api"
"github.com/luscis/openlan/pkg/schema"
"github.com/urfave/cli/v2"
)
type Ceci struct {
Cmd
}
func (u Ceci) Url(prefix, name string) string {
return prefix + "/api/interface/" + name + "/ceci"
}
func (u Ceci) Tmpl() string {
return `# total {{ len . }}
{{ps -16 "Name"}} {{ps -8 "Configure"}}
{{- range . }}
{{ps -16 .Name}} {{pi .Configure}}
{{- end }}
`
}
func (u Ceci) List(c *cli.Context) error {
url := u.Url(c.String("url"), "")
clt := u.NewHttp(c.String("token"))
var items []schema.Ceci
if err := clt.GetJSON(url, &items); err != nil {
return err
}
return u.Out(items, c.String("format"), u.Tmpl())
}
func (u Ceci) Add(c *cli.Context) error {
name := c.String("name")
rate := &schema.Ceci{
Name: name,
}
url := u.Url(c.String("url"), name)
clt := u.NewHttp(c.String("token"))
if err := clt.PostJSON(url, rate, nil); err != nil {
return err
}
return nil
}
func (u Ceci) Remove(c *cli.Context) error {
name := c.String("name")
url := u.Url(c.String("url"), name)
clt := u.NewHttp(c.String("token"))
if err := clt.DeleteJSON(url, nil, nil); err != nil {
return err
}
return nil
}
func (u Ceci) Commands(app *api.App) {
app.Command(&cli.Command{
Name: "ceci",
Usage: "Ceci proxy",
Subcommands: []*cli.Command{
{
Name: "list",
Usage: "Display all ceci proxy",
Aliases: []string{"ls"},
Action: u.List,
},
{
Name: "add",
Usage: "Add a ceci proxy",
Flags: []cli.Flag{
&cli.StringFlag{Name: "name", Required: true},
&cli.StringFlag{Name: "file", Required: true},
},
Action: u.Add,
},
{
Name: "remove",
Usage: "Remove a ceci proxy",
Aliases: []string{"rm"},
Flags: []cli.Flag{
&cli.StringFlag{Name: "name", Required: true},
},
Action: u.Remove,
},
},
})
}

View File

@@ -40,4 +40,5 @@ func Commands(app *api.App) {
Log{}.Commands(app) Log{}.Commands(app)
ZTrust{}.Commands(app) ZTrust{}.Commands(app)
Rate{}.Commands(app) Rate{}.Commands(app)
Ceci{}.Commands(app)
} }

View File

@@ -0,0 +1,12 @@
listen: 127.0.0.1:1080
socks:
listen: 127.0.0.1:1081
cacert: ca.crt
backends:
- protocol: ssl
server: <s1>:18000
socks:
server: <s2:18001>
match:
- a.b.com

View File

@@ -2,8 +2,10 @@ package config
import ( import (
"flag" "flag"
"fmt"
"os" "os"
"path" "path"
"regexp"
"github.com/luscis/openlan/pkg/libol" "github.com/luscis/openlan/pkg/libol"
) )
@@ -18,11 +20,69 @@ type ShadowProxy struct {
Protocol string `json:"protocol,omitempty"` Protocol string `json:"protocol,omitempty"`
} }
type ForwardSocks struct {
Server string `json:"server,omitempty"`
}
type HttpForward struct {
Protocol string `json:"protocol,omitempty" yaml:"protocol,omitempty"`
Server string `json:"server,omitempty" yaml:"server,omitempty"`
Insecure bool `json:"insecure,omitempty" yaml:"insecure,omitempty"`
Match []string `json:"match,omitempty" yaml:"match,omitempty"`
Secret string `json:"secret,omitempty" yaml:"secret,omitempty"`
Socks ForwardSocks `json:"socks,omitempty" yaml:"socks,omitempty"`
}
func (f *HttpForward) SocksAddr() string {
if f.Socks.Server != "" {
return f.Socks.Server
}
return f.Server
}
type HttpBackends []*HttpForward
func (h HttpBackends) isMatch(value string, rules []string) bool {
if len(rules) == 0 {
return true
}
for _, rule := range rules {
pattern := fmt.Sprintf(`(^|\.)%s(:\d+)?$`, regexp.QuoteMeta(rule))
re := regexp.MustCompile(pattern)
if re.MatchString(value) {
return true
}
}
return false
}
func (h HttpBackends) FindBackend(host string) *HttpForward {
for _, via := range h {
if via == nil {
continue
}
if via.Server == "" && via.Socks.Server == "" {
continue
}
if h.isMatch(host, via.Match) {
return via
}
}
return nil
}
type FindBackend interface {
FindBackend(host string) *HttpForward
}
type SocksProxy struct { type SocksProxy struct {
Conf string `json:"-" yaml:"-"` Conf string `json:"-" yaml:"-"`
Listen string `json:"listen,omitempty" yaml:"listen,omitempty"` Listen string `json:"listen,omitempty" yaml:"listen,omitempty"`
Auth *Password `json:"auth,omitempty" yaml:"auth,omitempty"` Auth *Password `json:"auth,omitempty" yaml:"auth,omitempty"`
Backends []*HttpForward `json:"backends,omitempty" yaml:"backends,omitempty"` Backends HttpBackends `json:"backends,omitempty" yaml:"backends,omitempty"`
} }
func (s *SocksProxy) Initialize() error { func (s *SocksProxy) Initialize() error {
@@ -41,12 +101,8 @@ func (s *SocksProxy) Load() error {
return libol.UnmarshalLoad(s, s.Conf) return libol.UnmarshalLoad(s, s.Conf)
} }
type HttpForward struct { type HttpSocks struct {
Protocol string `json:"protocol,omitempty" yaml:"protocol,omitempty"` Listen string `json:"listen,omitempty"`
Server string `json:"server,omitempty" yaml:"server,omitempty"`
Insecure bool `json:"insecure,omitempty" yaml:"insecure,omitempty"`
Match []string `json:"match,omitempty" yaml:"match,omitempty"`
Secret string `json:"secret,omitempty" yaml:"secret,omitempty"`
} }
type HttpProxy struct { type HttpProxy struct {
@@ -57,8 +113,9 @@ type HttpProxy struct {
Cert *Cert `json:"cert,omitempty" yaml:"cert,omitempty"` Cert *Cert `json:"cert,omitempty" yaml:"cert,omitempty"`
Password string `json:"password,omitempty" yaml:"password,omitempty"` Password string `json:"password,omitempty" yaml:"password,omitempty"`
CaCert string `json:"cacert,omitempty" yaml:"cacert,omitempty"` CaCert string `json:"cacert,omitempty" yaml:"cacert,omitempty"`
Forward *HttpForward `json:"forward,omitempty" yaml:"forward,omitempty"` Backends HttpBackends `json:"backends,omitempty" yaml:"backends,omitempty"`
Backends []*HttpForward `json:"backends,omitempty" yaml:"backends,omitempty"` Socks *HttpSocks `json:"socks,omitempty" yaml:"socks,omitempty"`
SocksProxy *SocksProxy `json:"-" yaml:"-"`
} }
func (h *HttpProxy) Initialize() error { func (h *HttpProxy) Initialize() error {
@@ -93,6 +150,11 @@ func (h *HttpProxy) Correct() {
h.CaCert = "ca.crt" h.CaCert = "ca.crt"
} }
h.CaCert = path.Join(h.ConfDir, h.CaCert) h.CaCert = path.Join(h.ConfDir, h.CaCert)
if h.Socks != nil {
h.SocksProxy = &SocksProxy{
Listen: h.Socks.Listen,
}
}
} }
func (h *HttpProxy) FindMatch(domain string, to *HttpForward) int { func (h *HttpProxy) FindMatch(domain string, to *HttpForward) int {
@@ -105,9 +167,6 @@ func (h *HttpProxy) FindMatch(domain string, to *HttpForward) int {
} }
func (h *HttpProxy) FindBackend(remote string) *HttpForward { func (h *HttpProxy) FindBackend(remote string) *HttpForward {
if remote == "" || remote == "null" {
return h.Forward
}
for _, to := range h.Backends { for _, to := range h.Backends {
if to.Server == remote { if to.Server == remote {
return to return to

View File

@@ -13,7 +13,6 @@ import (
"net/http" "net/http"
"net/http/httputil" "net/http/httputil"
"os" "os"
"regexp"
"sort" "sort"
"strings" "strings"
"sync" "sync"
@@ -57,6 +56,7 @@ type HttpProxy struct {
startat time.Time startat time.Time
requests map[string]*HttpRecord requests map[string]*HttpRecord
lock sync.RWMutex lock sync.RWMutex
socks *SocksProxy
} }
var ( var (
@@ -134,7 +134,10 @@ func NewHttpProxy(cfg *co.HttpProxy, px Proxyer) *HttpProxy {
if auth != nil && auth.Username != "" { if auth != nil && auth.Username != "" {
h.pass[auth.Username] = auth.Password h.pass[auth.Username] = auth.Password
} }
if cfg.SocksProxy != nil {
h.socks = NewSocksProxy(cfg.SocksProxy)
h.socks.server.SetBackends(h)
}
h.loadUrl() h.loadUrl()
h.loadPass() h.loadPass()
@@ -271,7 +274,7 @@ func (t *HttpProxy) toTunnel(w http.ResponseWriter, conn net.Conn, update func(b
} }
func (t *HttpProxy) openConn(protocol, remote string, insecure bool) (net.Conn, error) { func (t *HttpProxy) openConn(protocol, remote string, insecure bool) (net.Conn, error) {
if protocol == "https" { if protocol == "https" || protocol == "tls" {
conf := &tls.Config{ conf := &tls.Config{
InsecureSkipVerify: insecure, InsecureSkipVerify: insecure,
} }
@@ -294,6 +297,12 @@ func (t *HttpProxy) openConn(protocol, remote string, insecure bool) (net.Conn,
return net.DialTimeout("tcp", remote, 10*time.Second) return net.DialTimeout("tcp", remote, 10*time.Second)
} }
func (h *HttpProxy) FindBackend(host string) *co.HttpForward {
h.lock.RLock()
defer h.lock.RUnlock()
return h.cfg.Backends.FindBackend(host)
}
func (t *HttpProxy) cloneRequest(r *http.Request, secret string) ([]byte, error) { func (t *HttpProxy) cloneRequest(r *http.Request, secret string) ([]byte, error) {
var err error var err error
var b bytes.Buffer var b bytes.Buffer
@@ -344,36 +353,6 @@ func (t *HttpProxy) cloneRequest(r *http.Request, secret string) ([]byte, error)
return b.Bytes(), nil return b.Bytes(), nil
} }
func (t *HttpProxy) isMatch(value string, rules []string) bool {
if len(rules) == 0 {
return true
}
for _, rule := range rules {
pattern := fmt.Sprintf(`(^|\.)%s(:\d+)?$`, regexp.QuoteMeta(rule))
re := regexp.MustCompile(pattern)
if re.MatchString(value) {
return true
}
}
return false
}
func (t *HttpProxy) findForward(r *http.Request) *co.HttpForward {
t.lock.RLock()
defer t.lock.RUnlock()
via := t.cfg.Forward
if via != nil && t.isMatch(r.URL.Host, via.Match) {
return via
}
for _, via := range t.cfg.Backends {
if via != nil && t.isMatch(r.URL.Host, via.Match) {
return via
}
}
return nil
}
func (t *HttpProxy) doRecord(r *http.Request, bytes int64) { func (t *HttpProxy) doRecord(r *http.Request, bytes int64) {
t.lock.Lock() t.lock.Lock()
defer t.lock.Unlock() defer t.lock.Unlock()
@@ -401,7 +380,7 @@ func (t *HttpProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
} }
t.doRecord(r, 0) t.doRecord(r, 0)
via := t.findForward(r) via := t.FindBackend(r.URL.Host)
if via != nil { if via != nil {
t.out.Info("HttpProxy.ServeHTTP %s %s -> %s via %s", r.Method, r.RemoteAddr, r.URL.Host, via.Server) t.out.Info("HttpProxy.ServeHTTP %s %s -> %s via %s", r.Method, r.RemoteAddr, r.URL.Host, via.Server)
conn, err := t.openConn(via.Protocol, via.Server, via.Insecure) conn, err := t.openConn(via.Protocol, via.Server, via.Insecure)
@@ -450,6 +429,11 @@ func (t *HttpProxy) Start() {
if t.server == nil || t.cfg == nil { if t.server == nil || t.cfg == nil {
return return
} }
if t.socks != nil {
t.socks.Start()
}
crt := t.cfg.Cert crt := t.cfg.Cert
if crt == nil || crt.KeyFile == "" { if crt == nil || crt.KeyFile == "" {
t.out.Info("HttpProxy.start http://%s", t.server.Addr) t.out.Info("HttpProxy.start http://%s", t.server.Addr)

View File

@@ -50,7 +50,7 @@ func (s *SocksProxy) Start() {
return return
} }
addr := s.cfg.Listen addr := s.cfg.Listen
s.out.Info("SocksProxy.Start: %s", s.cfg.Listen) s.out.Info("SocksProxy.Start: socks5://%s", s.cfg.Listen)
promise := &libol.Promise{ promise := &libol.Promise{
First: time.Second * 2, First: time.Second * 2,

6
pkg/schema/ceci.go Normal file
View File

@@ -0,0 +1,6 @@
package schema
type Ceci struct {
Name string `json:"name"`
Config interface{} `json:"config"`
}

View File

@@ -6,7 +6,6 @@ import (
"fmt" "fmt"
"io" "io"
"net" "net"
"regexp"
"time" "time"
co "github.com/luscis/openlan/pkg/config" co "github.com/luscis/openlan/pkg/config"
@@ -54,7 +53,7 @@ type Config struct {
Dial func(ctx context.Context, network, addr string) (net.Conn, error) Dial func(ctx context.Context, network, addr string) (net.Conn, error)
// Backends forwarding socks request // Backends forwarding socks request
Backends []*co.HttpForward Backends co.FindBackend
} }
// Server is reponsible for accepting connections and handling // Server is reponsible for accepting connections and handling
@@ -121,7 +120,6 @@ func (s *Server) Serve(l net.Listener) error {
} }
go s.ServeConn(conn) go s.ServeConn(conn)
} }
return nil
} }
// ServeConn is used to serve a single connection. // ServeConn is used to serve a single connection.
@@ -132,14 +130,14 @@ func (s *Server) ServeConn(conn net.Conn) error {
// Read the version byte // Read the version byte
version := []byte{0} version := []byte{0}
if _, err := bufConn.Read(version); err != nil { if _, err := bufConn.Read(version); err != nil {
s.config.Logger.Error("socks: Failed to get version byte: %v", err) s.config.Logger.Error("Socks.ServeConn Failed to get version byte: %v", err)
return err return err
} }
// Ensure we are compatible // Ensure we are compatible
if version[0] != socks5Version { if version[0] != socks5Version {
err := fmt.Errorf("Unsupported SOCKS version: %v", version) err := fmt.Errorf("Unsupported SOCKS version: %v", version)
s.config.Logger.Error("socks: %v", err) s.config.Logger.Error("Socks.ServeConn %v", err)
return err return err
} }
@@ -147,7 +145,7 @@ func (s *Server) ServeConn(conn net.Conn) error {
authContext, err := s.authenticate(conn, bufConn) authContext, err := s.authenticate(conn, bufConn)
if err != nil { if err != nil {
err = fmt.Errorf("Failed to authenticate: %v", err) err = fmt.Errorf("Failed to authenticate: %v", err)
s.config.Logger.Error("socks: %v", err) s.config.Logger.Error("Socks.ServeConn %v", err)
return err return err
} }
@@ -166,20 +164,22 @@ func (s *Server) ServeConn(conn net.Conn) error {
} }
dstAddr := request.DestAddr dstAddr := request.DestAddr
via := s.findForward(dstAddr.Address()) if s.config.Backends != nil {
via := s.config.Backends.FindBackend(dstAddr.Address())
if via != nil { if via != nil {
if err := s.toForward(request, conn, via); err != nil { if err := s.toForward(request, conn, via); err != nil {
s.config.Logger.Error("socks.forward: %v", err) s.config.Logger.Error("Socks.ServeConn: %v", err)
return err return err
} }
return nil return nil
} }
}
s.config.Logger.Info("socks.ServeConn: %s", dstAddr.Address()) s.config.Logger.Info("Socks.ServeConn CONNECT %s", dstAddr.Address())
//Process the client request //Process the client request
if err := s.handleRequest(request, conn); err != nil { if err := s.handleRequest(request, conn); err != nil {
err = fmt.Errorf("Failed to handle request: %v", err) err = fmt.Errorf("Failed to handle request: %v", err)
s.config.Logger.Error("socks: %v", err) s.config.Logger.Error("Socks.ServeConn %v", err)
} }
return nil return nil
@@ -205,34 +205,13 @@ func (s *Server) openConn(remote string) (net.Conn, error) {
return net.DialTimeout("tcp", remote, 10*time.Second) return net.DialTimeout("tcp", remote, 10*time.Second)
} }
func (s *Server) isMatch(value string, rules []string) bool {
if len(rules) == 0 {
return true
}
for _, rule := range rules {
pattern := fmt.Sprintf(`(^|\.)%s(:\d+)?$`, regexp.QuoteMeta(rule))
re := regexp.MustCompile(pattern)
if re.MatchString(value) {
return true
}
}
return false
}
func (s *Server) findForward(host string) *co.HttpForward {
for _, via := range s.config.Backends {
if via != nil && s.isMatch(host, via.Match) {
return via
}
}
return nil
}
func (s *Server) toForward(req *Request, local net.Conn, via *co.HttpForward) error { func (s *Server) toForward(req *Request, local net.Conn, via *co.HttpForward) error {
dstAddr := req.DestAddr dstAddr := req.DestAddr
s.config.Logger.Info("socks.toForward: %s via %s", dstAddr.Address(), via.Server) proxy := via.SocksAddr()
target, err := s.openConn(via.Server) s.config.Logger.Info("Socks.ServeConn CONNECT %s via %s", dstAddr.Address(), proxy)
target, err := s.openConn(proxy)
if err != nil { if err != nil {
sendReply(local, networkUnreachable, nil) sendReply(local, networkUnreachable, nil)
return err return err
@@ -270,3 +249,7 @@ func (s *Server) toForward(req *Request, local net.Conn, via *co.HttpForward) er
s.toTunnel(local, target) s.toTunnel(local, target)
return nil return nil
} }
func (s *Server) SetBackends(find co.FindBackend) {
s.config.Backends = find
}