From 70b76392ca5707afff11b96bfc28d4565a19f09f Mon Sep 17 00:00:00 2001 From: Daniel Ding Date: Thu, 2 Jan 2025 13:09:08 +0800 Subject: [PATCH] fea: go-socks in self. --- go.mod | 1 - go.sum | 2 - pkg/proxy/socks.go | 2 +- .../armon/go-socks5 => pkg/socks5}/LICENSE | 0 .../armon/go-socks5 => pkg/socks5}/README.md | 0 .../armon/go-socks5 => pkg/socks5}/auth.go | 0 pkg/socks5/auth_test.go | 119 ++++++++++++ .../go-socks5 => pkg/socks5}/credentials.go | 0 pkg/socks5/credentials_test.go | 24 +++ .../armon/go-socks5 => pkg/socks5}/request.go | 0 pkg/socks5/request_test.go | 169 ++++++++++++++++++ .../go-socks5 => pkg/socks5}/resolver.go | 0 pkg/socks5/resolver_test.go | 21 +++ .../armon/go-socks5 => pkg/socks5}/ruleset.go | 0 pkg/socks5/ruleset_test.go | 24 +++ .../armon/go-socks5 => pkg/socks5}/socks5.go | 0 pkg/socks5/socks5_test.go | 110 ++++++++++++ vendor/github.com/armon/go-socks5/.gitignore | 22 --- vendor/github.com/armon/go-socks5/.travis.yml | 4 - vendor/modules.txt | 3 - 20 files changed, 468 insertions(+), 33 deletions(-) rename {vendor/github.com/armon/go-socks5 => pkg/socks5}/LICENSE (100%) rename {vendor/github.com/armon/go-socks5 => pkg/socks5}/README.md (100%) rename {vendor/github.com/armon/go-socks5 => pkg/socks5}/auth.go (100%) create mode 100644 pkg/socks5/auth_test.go rename {vendor/github.com/armon/go-socks5 => pkg/socks5}/credentials.go (100%) create mode 100644 pkg/socks5/credentials_test.go rename {vendor/github.com/armon/go-socks5 => pkg/socks5}/request.go (100%) create mode 100644 pkg/socks5/request_test.go rename {vendor/github.com/armon/go-socks5 => pkg/socks5}/resolver.go (100%) create mode 100644 pkg/socks5/resolver_test.go rename {vendor/github.com/armon/go-socks5 => pkg/socks5}/ruleset.go (100%) create mode 100644 pkg/socks5/ruleset_test.go rename {vendor/github.com/armon/go-socks5 => pkg/socks5}/socks5.go (100%) create mode 100644 pkg/socks5/socks5_test.go delete mode 100644 vendor/github.com/armon/go-socks5/.gitignore delete mode 100644 vendor/github.com/armon/go-socks5/.travis.yml diff --git a/go.mod b/go.mod index 7d81e15..1ea8c31 100755 --- a/go.mod +++ b/go.mod @@ -14,7 +14,6 @@ exclude github.com/sirupsen/logrus v1.8.1 require ( github.com/Sirupsen/logrus v0.0.0-00010101000000-000000000000 // indirect - github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 github.com/chzyer/logex v1.2.0 // indirect github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e github.com/chzyer/test v0.0.0-20210722231415-061457976a23 // indirect diff --git a/go.sum b/go.sum index 88e7a08..a363c55 100644 --- a/go.sum +++ b/go.sum @@ -8,8 +8,6 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= diff --git a/pkg/proxy/socks.go b/pkg/proxy/socks.go index 2bd49b1..d77f4b9 100755 --- a/pkg/proxy/socks.go +++ b/pkg/proxy/socks.go @@ -3,9 +3,9 @@ package proxy import ( "time" - "github.com/armon/go-socks5" "github.com/luscis/openlan/pkg/config" "github.com/luscis/openlan/pkg/libol" + "github.com/luscis/openlan/pkg/socks5" ) type SocksProxy struct { diff --git a/vendor/github.com/armon/go-socks5/LICENSE b/pkg/socks5/LICENSE similarity index 100% rename from vendor/github.com/armon/go-socks5/LICENSE rename to pkg/socks5/LICENSE diff --git a/vendor/github.com/armon/go-socks5/README.md b/pkg/socks5/README.md similarity index 100% rename from vendor/github.com/armon/go-socks5/README.md rename to pkg/socks5/README.md diff --git a/vendor/github.com/armon/go-socks5/auth.go b/pkg/socks5/auth.go similarity index 100% rename from vendor/github.com/armon/go-socks5/auth.go rename to pkg/socks5/auth.go diff --git a/pkg/socks5/auth_test.go b/pkg/socks5/auth_test.go new file mode 100644 index 0000000..f782f4a --- /dev/null +++ b/pkg/socks5/auth_test.go @@ -0,0 +1,119 @@ +package socks5 + +import ( + "bytes" + "testing" +) + +func TestNoAuth(t *testing.T) { + req := bytes.NewBuffer(nil) + req.Write([]byte{1, NoAuth}) + var resp bytes.Buffer + + s, _ := New(&Config{}) + ctx, err := s.authenticate(&resp, req) + if err != nil { + t.Fatalf("err: %v", err) + } + + if ctx.Method != NoAuth { + t.Fatal("Invalid Context Method") + } + + out := resp.Bytes() + if !bytes.Equal(out, []byte{socks5Version, NoAuth}) { + t.Fatalf("bad: %v", out) + } +} + +func TestPasswordAuth_Valid(t *testing.T) { + req := bytes.NewBuffer(nil) + req.Write([]byte{2, NoAuth, UserPassAuth}) + req.Write([]byte{1, 3, 'f', 'o', 'o', 3, 'b', 'a', 'r'}) + var resp bytes.Buffer + + cred := StaticCredentials{ + "foo": "bar", + } + + cator := UserPassAuthenticator{Credentials: cred} + + s, _ := New(&Config{AuthMethods: []Authenticator{cator}}) + + ctx, err := s.authenticate(&resp, req) + if err != nil { + t.Fatalf("err: %v", err) + } + + if ctx.Method != UserPassAuth { + t.Fatal("Invalid Context Method") + } + + val, ok := ctx.Payload["Username"] + if !ok { + t.Fatal("Missing key Username in auth context's payload") + } + + if val != "foo" { + t.Fatal("Invalid Username in auth context's payload") + } + + out := resp.Bytes() + if !bytes.Equal(out, []byte{socks5Version, UserPassAuth, 1, authSuccess}) { + t.Fatalf("bad: %v", out) + } +} + +func TestPasswordAuth_Invalid(t *testing.T) { + req := bytes.NewBuffer(nil) + req.Write([]byte{2, NoAuth, UserPassAuth}) + req.Write([]byte{1, 3, 'f', 'o', 'o', 3, 'b', 'a', 'z'}) + var resp bytes.Buffer + + cred := StaticCredentials{ + "foo": "bar", + } + cator := UserPassAuthenticator{Credentials: cred} + s, _ := New(&Config{AuthMethods: []Authenticator{cator}}) + + ctx, err := s.authenticate(&resp, req) + if err != UserAuthFailed { + t.Fatalf("err: %v", err) + } + + if ctx != nil { + t.Fatal("Invalid Context Method") + } + + out := resp.Bytes() + if !bytes.Equal(out, []byte{socks5Version, UserPassAuth, 1, authFailure}) { + t.Fatalf("bad: %v", out) + } +} + +func TestNoSupportedAuth(t *testing.T) { + req := bytes.NewBuffer(nil) + req.Write([]byte{1, NoAuth}) + var resp bytes.Buffer + + cred := StaticCredentials{ + "foo": "bar", + } + cator := UserPassAuthenticator{Credentials: cred} + + s, _ := New(&Config{AuthMethods: []Authenticator{cator}}) + + ctx, err := s.authenticate(&resp, req) + if err != NoSupportedAuth { + t.Fatalf("err: %v", err) + } + + if ctx != nil { + t.Fatal("Invalid Context Method") + } + + out := resp.Bytes() + if !bytes.Equal(out, []byte{socks5Version, noAcceptable}) { + t.Fatalf("bad: %v", out) + } +} diff --git a/vendor/github.com/armon/go-socks5/credentials.go b/pkg/socks5/credentials.go similarity index 100% rename from vendor/github.com/armon/go-socks5/credentials.go rename to pkg/socks5/credentials.go diff --git a/pkg/socks5/credentials_test.go b/pkg/socks5/credentials_test.go new file mode 100644 index 0000000..e14256b --- /dev/null +++ b/pkg/socks5/credentials_test.go @@ -0,0 +1,24 @@ +package socks5 + +import ( + "testing" +) + +func TestStaticCredentials(t *testing.T) { + creds := StaticCredentials{ + "foo": "bar", + "baz": "", + } + + if !creds.Valid("foo", "bar") { + t.Fatalf("expect valid") + } + + if !creds.Valid("baz", "") { + t.Fatalf("expect valid") + } + + if creds.Valid("foo", "") { + t.Fatalf("expect invalid") + } +} diff --git a/vendor/github.com/armon/go-socks5/request.go b/pkg/socks5/request.go similarity index 100% rename from vendor/github.com/armon/go-socks5/request.go rename to pkg/socks5/request.go diff --git a/pkg/socks5/request_test.go b/pkg/socks5/request_test.go new file mode 100644 index 0000000..5465113 --- /dev/null +++ b/pkg/socks5/request_test.go @@ -0,0 +1,169 @@ +package socks5 + +import ( + "bytes" + "encoding/binary" + "io" + "log" + "net" + "os" + "strings" + "testing" +) + +type MockConn struct { + buf bytes.Buffer +} + +func (m *MockConn) Write(b []byte) (int, error) { + return m.buf.Write(b) +} + +func (m *MockConn) RemoteAddr() net.Addr { + return &net.TCPAddr{IP: []byte{127, 0, 0, 1}, Port: 65432} +} + +func TestRequest_Connect(t *testing.T) { + // Create a local listener + l, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatalf("err: %v", err) + } + go func() { + conn, err := l.Accept() + if err != nil { + t.Fatalf("err: %v", err) + } + defer conn.Close() + + buf := make([]byte, 4) + if _, err := io.ReadAtLeast(conn, buf, 4); err != nil { + t.Fatalf("err: %v", err) + } + + if !bytes.Equal(buf, []byte("ping")) { + t.Fatalf("bad: %v", buf) + } + conn.Write([]byte("pong")) + }() + lAddr := l.Addr().(*net.TCPAddr) + + // Make server + s := &Server{config: &Config{ + Rules: PermitAll(), + Resolver: DNSResolver{}, + Logger: log.New(os.Stdout, "", log.LstdFlags), + }} + + // Create the connect request + buf := bytes.NewBuffer(nil) + buf.Write([]byte{5, 1, 0, 1, 127, 0, 0, 1}) + + port := []byte{0, 0} + binary.BigEndian.PutUint16(port, uint16(lAddr.Port)) + buf.Write(port) + + // Send a ping + buf.Write([]byte("ping")) + + // Handle the request + resp := &MockConn{} + req, err := NewRequest(buf) + if err != nil { + t.Fatalf("err: %v", err) + } + + if err := s.handleRequest(req, resp); err != nil { + t.Fatalf("err: %v", err) + } + + // Verify response + out := resp.buf.Bytes() + expected := []byte{ + 5, + 0, + 0, + 1, + 127, 0, 0, 1, + 0, 0, + 'p', 'o', 'n', 'g', + } + + // Ignore the port for both + out[8] = 0 + out[9] = 0 + + if !bytes.Equal(out, expected) { + t.Fatalf("bad: %v %v", out, expected) + } +} + +func TestRequest_Connect_RuleFail(t *testing.T) { + // Create a local listener + l, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatalf("err: %v", err) + } + go func() { + conn, err := l.Accept() + if err != nil { + t.Fatalf("err: %v", err) + } + defer conn.Close() + + buf := make([]byte, 4) + if _, err := io.ReadAtLeast(conn, buf, 4); err != nil { + t.Fatalf("err: %v", err) + } + + if !bytes.Equal(buf, []byte("ping")) { + t.Fatalf("bad: %v", buf) + } + conn.Write([]byte("pong")) + }() + lAddr := l.Addr().(*net.TCPAddr) + + // Make server + s := &Server{config: &Config{ + Rules: PermitNone(), + Resolver: DNSResolver{}, + Logger: log.New(os.Stdout, "", log.LstdFlags), + }} + + // Create the connect request + buf := bytes.NewBuffer(nil) + buf.Write([]byte{5, 1, 0, 1, 127, 0, 0, 1}) + + port := []byte{0, 0} + binary.BigEndian.PutUint16(port, uint16(lAddr.Port)) + buf.Write(port) + + // Send a ping + buf.Write([]byte("ping")) + + // Handle the request + resp := &MockConn{} + req, err := NewRequest(buf) + if err != nil { + t.Fatalf("err: %v", err) + } + + if err := s.handleRequest(req, resp); !strings.Contains(err.Error(), "blocked by rules") { + t.Fatalf("err: %v", err) + } + + // Verify response + out := resp.buf.Bytes() + expected := []byte{ + 5, + 2, + 0, + 1, + 0, 0, 0, 0, + 0, 0, + } + + if !bytes.Equal(out, expected) { + t.Fatalf("bad: %v %v", out, expected) + } +} diff --git a/vendor/github.com/armon/go-socks5/resolver.go b/pkg/socks5/resolver.go similarity index 100% rename from vendor/github.com/armon/go-socks5/resolver.go rename to pkg/socks5/resolver.go diff --git a/pkg/socks5/resolver_test.go b/pkg/socks5/resolver_test.go new file mode 100644 index 0000000..16d56ee --- /dev/null +++ b/pkg/socks5/resolver_test.go @@ -0,0 +1,21 @@ +package socks5 + +import ( + "testing" + + "golang.org/x/net/context" +) + +func TestDNSResolver(t *testing.T) { + d := DNSResolver{} + ctx := context.Background() + + _, addr, err := d.Resolve(ctx, "localhost") + if err != nil { + t.Fatalf("err: %v", err) + } + + if !addr.IsLoopback() { + t.Fatalf("expected loopback") + } +} diff --git a/vendor/github.com/armon/go-socks5/ruleset.go b/pkg/socks5/ruleset.go similarity index 100% rename from vendor/github.com/armon/go-socks5/ruleset.go rename to pkg/socks5/ruleset.go diff --git a/pkg/socks5/ruleset_test.go b/pkg/socks5/ruleset_test.go new file mode 100644 index 0000000..b93f4a8 --- /dev/null +++ b/pkg/socks5/ruleset_test.go @@ -0,0 +1,24 @@ +package socks5 + +import ( + "testing" + + "golang.org/x/net/context" +) + +func TestPermitCommand(t *testing.T) { + ctx := context.Background() + r := &PermitCommand{true, false, false} + + if _, ok := r.Allow(ctx, &Request{Command: ConnectCommand}); !ok { + t.Fatalf("expect connect") + } + + if _, ok := r.Allow(ctx, &Request{Command: BindCommand}); ok { + t.Fatalf("do not expect bind") + } + + if _, ok := r.Allow(ctx, &Request{Command: AssociateCommand}); ok { + t.Fatalf("do not expect associate") + } +} diff --git a/vendor/github.com/armon/go-socks5/socks5.go b/pkg/socks5/socks5.go similarity index 100% rename from vendor/github.com/armon/go-socks5/socks5.go rename to pkg/socks5/socks5.go diff --git a/pkg/socks5/socks5_test.go b/pkg/socks5/socks5_test.go new file mode 100644 index 0000000..8cfbee0 --- /dev/null +++ b/pkg/socks5/socks5_test.go @@ -0,0 +1,110 @@ +package socks5 + +import ( + "bytes" + "encoding/binary" + "io" + "log" + "net" + "os" + "testing" + "time" +) + +func TestSOCKS5_Connect(t *testing.T) { + // Create a local listener + l, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatalf("err: %v", err) + } + go func() { + conn, err := l.Accept() + if err != nil { + t.Fatalf("err: %v", err) + } + defer conn.Close() + + buf := make([]byte, 4) + if _, err := io.ReadAtLeast(conn, buf, 4); err != nil { + t.Fatalf("err: %v", err) + } + + if !bytes.Equal(buf, []byte("ping")) { + t.Fatalf("bad: %v", buf) + } + conn.Write([]byte("pong")) + }() + lAddr := l.Addr().(*net.TCPAddr) + + // Create a socks server + creds := StaticCredentials{ + "foo": "bar", + } + cator := UserPassAuthenticator{Credentials: creds} + conf := &Config{ + AuthMethods: []Authenticator{cator}, + Logger: log.New(os.Stdout, "", log.LstdFlags), + } + serv, err := New(conf) + if err != nil { + t.Fatalf("err: %v", err) + } + + // Start listening + go func() { + if err := serv.ListenAndServe("tcp", "127.0.0.1:12365"); err != nil { + t.Fatalf("err: %v", err) + } + }() + time.Sleep(10 * time.Millisecond) + + // Get a local conn + conn, err := net.Dial("tcp", "127.0.0.1:12365") + if err != nil { + t.Fatalf("err: %v", err) + } + + // Connect, auth and connec to local + req := bytes.NewBuffer(nil) + req.Write([]byte{5}) + req.Write([]byte{2, NoAuth, UserPassAuth}) + req.Write([]byte{1, 3, 'f', 'o', 'o', 3, 'b', 'a', 'r'}) + req.Write([]byte{5, 1, 0, 1, 127, 0, 0, 1}) + + port := []byte{0, 0} + binary.BigEndian.PutUint16(port, uint16(lAddr.Port)) + req.Write(port) + + // Send a ping + req.Write([]byte("ping")) + + // Send all the bytes + conn.Write(req.Bytes()) + + // Verify response + expected := []byte{ + socks5Version, UserPassAuth, + 1, authSuccess, + 5, + 0, + 0, + 1, + 127, 0, 0, 1, + 0, 0, + 'p', 'o', 'n', 'g', + } + out := make([]byte, len(expected)) + + conn.SetDeadline(time.Now().Add(time.Second)) + if _, err := io.ReadAtLeast(conn, out, len(out)); err != nil { + t.Fatalf("err: %v", err) + } + + // Ignore the port + out[12] = 0 + out[13] = 0 + + if !bytes.Equal(out, expected) { + t.Fatalf("bad: %v", out) + } +} diff --git a/vendor/github.com/armon/go-socks5/.gitignore b/vendor/github.com/armon/go-socks5/.gitignore deleted file mode 100644 index 0026861..0000000 --- a/vendor/github.com/armon/go-socks5/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe diff --git a/vendor/github.com/armon/go-socks5/.travis.yml b/vendor/github.com/armon/go-socks5/.travis.yml deleted file mode 100644 index 8d61700..0000000 --- a/vendor/github.com/armon/go-socks5/.travis.yml +++ /dev/null @@ -1,4 +0,0 @@ -language: go -go: - - 1.1 - - tip diff --git a/vendor/modules.txt b/vendor/modules.txt index 22dfa84..8832f78 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,9 +1,6 @@ # github.com/Sirupsen/logrus v0.0.0-00010101000000-000000000000 => github.com/sirupsen/logrus v1.8.1 ## explicit github.com/Sirupsen/logrus -# github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 -## explicit -github.com/armon/go-socks5 # github.com/beorn7/perks v1.0.1 github.com/beorn7/perks/quantile # github.com/cenkalti/backoff/v4 v4.1.1