go-socks5/server_test.go

321 lines
8.8 KiB
Go
Raw Normal View History

2014-01-23 22:16:44 +00:00
package socks5
import (
"bytes"
2020-08-05 06:40:07 +00:00
"errors"
2014-01-23 22:16:44 +00:00
"io"
"log"
2014-01-23 22:16:44 +00:00
"net"
"os"
2014-01-23 22:16:44 +00:00
"testing"
"time"
2020-04-20 11:56:35 +00:00
2020-08-05 06:40:07 +00:00
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
2020-04-20 11:56:35 +00:00
"golang.org/x/net/proxy"
2020-08-05 05:17:05 +00:00
2022-10-17 01:36:23 +00:00
"git.tcp.direct/kayos/go-socks5/statute"
2014-01-23 22:16:44 +00:00
)
func TestSOCKS5_Connect(t *testing.T) {
// Create a local listener
l, err := net.Listen("tcp", "127.0.0.1:0")
2020-08-05 09:32:37 +00:00
require.NoError(t, err)
2014-01-23 22:16:44 +00:00
go func() {
conn, err := l.Accept()
2020-08-05 09:32:37 +00:00
require.NoError(t, err)
2014-01-23 22:16:44 +00:00
defer conn.Close()
buf := make([]byte, 4)
2020-08-05 09:32:37 +00:00
_, err = io.ReadAtLeast(conn, buf, 4)
require.NoError(t, err)
assert.Equal(t, []byte("ping"), buf)
conn.Write([]byte("pong")) // nolint: errcheck
2014-01-23 22:16:44 +00:00
}()
lAddr := l.Addr().(*net.TCPAddr)
// Create a socks server with UserPass auth.
2020-08-05 09:32:37 +00:00
cator := UserPassAuthenticator{StaticCredentials{"foo": "bar"}}
srv := NewServer(
2020-04-20 13:17:38 +00:00
WithAuthMethods([]Authenticator{cator}),
WithLogger(NewLogger(log.New(os.Stdout, "socks5: ", log.LstdFlags))),
)
2014-01-23 22:16:44 +00:00
// Start listening
go func() {
2020-08-05 09:32:37 +00:00
err := srv.ListenAndServe("tcp", "127.0.0.1:12365")
require.NoError(t, err)
2014-01-23 22:16:44 +00:00
}()
time.Sleep(10 * time.Millisecond)
// Get a local conn
conn, err := net.Dial("tcp", "127.0.0.1:12365")
2020-08-05 09:32:37 +00:00
require.NoError(t, err)
2014-01-23 22:16:44 +00:00
// Connect, auth and connec to local
req := bytes.NewBuffer(
[]byte{
statute.VersionSocks5, 2, statute.MethodNoAuth, statute.MethodUserPassAuth, // methods
statute.UserPassAuthVersion, 3, 'f', 'o', 'o', 3, 'b', 'a', 'r', // userpass auth
})
2020-08-05 10:10:50 +00:00
reqHead := statute.Request{
2020-08-05 05:17:05 +00:00
Version: statute.VersionSocks5,
Command: statute.CommandConnect,
2020-04-20 08:19:51 +00:00
Reserved: 0,
DstAddr: statute.AddrSpec{
FQDN: "",
IP: net.ParseIP("127.0.0.1"),
Port: lAddr.Port,
AddrType: statute.ATYPIPv4,
2020-04-20 08:19:51 +00:00
},
}
req.Write(reqHead.Bytes())
2014-01-23 22:16:44 +00:00
// Send a ping
req.Write([]byte("ping"))
// Send all the bytes
conn.Write(req.Bytes()) // nolint: errcheck
2014-01-23 22:16:44 +00:00
// Verify response
expected := []byte{
statute.VersionSocks5, statute.MethodUserPassAuth, // response use UserPass auth
2020-08-05 05:17:05 +00:00
statute.UserPassAuthVersion, statute.AuthSuccess, // response auth success
2014-01-23 22:16:44 +00:00
}
2020-08-05 10:10:50 +00:00
rspHead := statute.Request{
2020-08-05 05:17:05 +00:00
Version: statute.VersionSocks5,
Command: statute.RepSuccess,
2020-04-20 08:19:51 +00:00
Reserved: 0,
DstAddr: statute.AddrSpec{
FQDN: "",
IP: net.ParseIP("127.0.0.1"),
Port: 0,
AddrType: statute.ATYPIPv4,
2020-04-20 08:19:51 +00:00
},
}
expected = append(expected, rspHead.Bytes()...)
expected = append(expected, []byte("pong")...)
2014-01-23 22:16:44 +00:00
out := make([]byte, len(expected))
conn.SetDeadline(time.Now().Add(time.Second)) // nolint: errcheck
2020-08-05 09:32:37 +00:00
_, err = io.ReadFull(conn, out)
conn.SetDeadline(time.Time{}) // nolint: errcheck
2020-08-05 09:32:37 +00:00
require.NoError(t, err)
2020-04-20 08:19:51 +00:00
// Ignore the port
out[12] = 0
out[13] = 0
2020-08-05 09:32:37 +00:00
assert.Equal(t, expected, out)
2020-04-20 08:19:51 +00:00
}
2014-01-23 22:16:44 +00:00
2020-04-20 08:19:51 +00:00
func TestSOCKS5_Associate(t *testing.T) {
locIP := net.ParseIP("127.0.0.1")
// Create a local listener
lAddr := &net.UDPAddr{IP: locIP, Port: 12399}
2020-04-20 09:09:16 +00:00
l, err := net.ListenUDP("udp", lAddr)
2020-08-05 09:32:37 +00:00
require.NoError(t, err)
2020-04-20 08:19:51 +00:00
defer l.Close()
2020-08-05 09:32:37 +00:00
2020-04-20 08:19:51 +00:00
go func() {
buf := make([]byte, 2048)
for {
n, remote, err := l.ReadFrom(buf)
if err != nil {
return
}
2020-08-05 09:32:37 +00:00
require.Equal(t, []byte("ping"), buf[:n])
2020-04-23 15:40:00 +00:00
2020-08-05 09:32:37 +00:00
l.WriteTo([]byte("pong"), remote) // nolint: errcheck
2020-04-20 08:19:51 +00:00
}
}()
// Create a socks server
2020-08-05 09:32:37 +00:00
cator := UserPassAuthenticator{StaticCredentials{"foo": "bar"}}
2020-08-06 03:11:30 +00:00
proxySrv := NewServer(
2020-04-20 13:17:38 +00:00
WithAuthMethods([]Authenticator{cator}),
WithLogger(NewLogger(log.New(os.Stdout, "socks5: ", log.LstdFlags))),
)
2020-04-20 08:19:51 +00:00
// Start listening
go func() {
2020-08-06 03:11:30 +00:00
err := proxySrv.ListenAndServe("tcp", "127.0.0.1:12355")
2020-08-05 09:32:37 +00:00
require.NoError(t, err)
2020-04-20 08:19:51 +00:00
}()
time.Sleep(10 * time.Millisecond)
// Get a local conn
conn, err := net.Dial("tcp", "127.0.0.1:12355")
2020-08-05 09:32:37 +00:00
require.NoError(t, err)
2020-04-20 08:19:51 +00:00
// Connect, auth and connec to local
2020-08-06 03:11:30 +00:00
req := bytes.NewBuffer(
[]byte{
statute.VersionSocks5, 2, statute.MethodNoAuth, statute.MethodUserPassAuth,
statute.UserPassAuthVersion, 3, 'f', 'o', 'o', 3, 'b', 'a', 'r',
})
2020-08-05 10:10:50 +00:00
reqHead := statute.Request{
2020-08-05 05:17:05 +00:00
Version: statute.VersionSocks5,
Command: statute.CommandAssociate,
2020-04-20 08:19:51 +00:00
Reserved: 0,
DstAddr: statute.AddrSpec{
FQDN: "",
IP: locIP,
Port: lAddr.Port,
AddrType: statute.ATYPIPv4,
2020-04-20 08:19:51 +00:00
},
}
req.Write(reqHead.Bytes())
// Send all the bytes
2020-08-05 09:32:37 +00:00
conn.Write(req.Bytes()) // nolint: errcheck
2020-04-20 08:19:51 +00:00
// Verify response
expected := []byte{
2020-08-05 05:17:05 +00:00
statute.VersionSocks5, statute.MethodUserPassAuth, // use user password auth
statute.UserPassAuthVersion, statute.AuthSuccess, // response auth success
2020-04-20 08:19:51 +00:00
}
out := make([]byte, len(expected))
conn.SetDeadline(time.Now().Add(time.Second)) // nolint: errcheck
2020-08-05 09:32:37 +00:00
_, err = io.ReadFull(conn, out)
conn.SetDeadline(time.Time{}) // nolint: errcheck
2020-08-05 09:32:37 +00:00
require.NoError(t, err)
require.Equal(t, expected, out)
2020-04-20 08:19:51 +00:00
2020-08-06 03:11:30 +00:00
rspHead, err := statute.ParseReply(conn)
2020-08-05 09:32:37 +00:00
require.NoError(t, err)
require.Equal(t, statute.VersionSocks5, rspHead.Version)
2020-08-06 03:11:30 +00:00
require.Equal(t, statute.RepSuccess, rspHead.Response)
2020-04-20 09:09:16 +00:00
// t.Logf("proxy bind listen port: %d", rspHead.BndAddr.Port)
2020-04-20 09:09:16 +00:00
udpConn, err := net.DialUDP("udp", nil, &net.UDPAddr{
IP: locIP,
Port: rspHead.BndAddr.Port,
2020-04-20 08:19:51 +00:00
})
2020-08-05 09:32:37 +00:00
require.NoError(t, err)
2020-04-20 08:19:51 +00:00
// Send a ping
2020-08-05 09:32:37 +00:00
udpConn.Write(append([]byte{0, 0, 0, statute.ATYPIPv4, 0, 0, 0, 0, 0, 0}, []byte("ping")...)) // nolint: errcheck
2020-04-20 08:19:51 +00:00
response := make([]byte, 1024)
n, _, err := udpConn.ReadFrom(response)
2020-08-06 03:11:30 +00:00
require.NoError(t, err)
assert.Equal(t, []byte("pong"), response[n-4:n])
2020-04-20 08:19:51 +00:00
time.Sleep(time.Second * 1)
2014-01-23 22:16:44 +00:00
}
2020-04-20 11:56:35 +00:00
func Test_SocksWithProxy(t *testing.T) {
// Create a local listener
l, err := net.Listen("tcp", "127.0.0.1:0")
2020-08-05 09:32:37 +00:00
require.NoError(t, err)
2020-04-20 11:56:35 +00:00
go func() {
conn, err := l.Accept()
2020-08-05 09:32:37 +00:00
require.NoError(t, err)
2020-04-20 11:56:35 +00:00
defer conn.Close()
buf := make([]byte, 4)
2020-08-05 09:32:37 +00:00
_, err = io.ReadAtLeast(conn, buf, 4)
require.NoError(t, err)
require.Equal(t, []byte("ping"), buf)
2020-04-20 11:56:35 +00:00
conn.Write([]byte("pong")) // nolint: errcheck
2020-04-20 11:56:35 +00:00
}()
lAddr := l.Addr().(*net.TCPAddr)
// Create a socks server with UserPass auth.
2020-08-05 09:32:37 +00:00
cator := UserPassAuthenticator{StaticCredentials{"foo": "bar"}}
serv := NewServer(
2020-04-20 13:17:38 +00:00
WithAuthMethods([]Authenticator{cator}),
WithLogger(NewLogger(log.New(os.Stdout, "socks5: ", log.LstdFlags))),
)
2020-08-05 09:32:37 +00:00
// Start socks server
2020-04-20 11:56:35 +00:00
go func() {
2020-08-05 09:32:37 +00:00
err := serv.ListenAndServe("tcp", "127.0.0.1:12395")
require.NoError(t, err)
2020-04-20 11:56:35 +00:00
}()
time.Sleep(10 * time.Millisecond)
2020-08-05 09:32:37 +00:00
// client
2020-04-21 14:28:34 +00:00
dial, err := proxy.SOCKS5("tcp", "127.0.0.1:12395", &proxy.Auth{User: "foo", Password: "bar"}, proxy.Direct)
2020-08-05 09:32:37 +00:00
require.NoError(t, err)
2020-04-20 11:56:35 +00:00
// Connect, auth and connect to local
conn, err := dial.Dial("tcp", lAddr.String())
2020-08-05 09:32:37 +00:00
require.NoError(t, err)
2020-04-20 11:56:35 +00:00
// Send a ping
2020-08-05 09:32:37 +00:00
conn.Write([]byte("ping")) // nolint: errcheck
2020-04-20 11:56:35 +00:00
out := make([]byte, 4)
conn.SetDeadline(time.Now().Add(time.Second)) // nolint: errcheck
2020-08-05 09:32:37 +00:00
_, err = io.ReadFull(conn, out)
conn.SetDeadline(time.Time{}) // nolint: errcheck
2020-08-05 09:32:37 +00:00
require.NoError(t, err)
require.Equal(t, []byte("pong"), out)
2020-04-20 11:56:35 +00:00
}
2020-08-05 06:40:07 +00:00
/***************************** auth *******************************/
2020-08-05 06:40:07 +00:00
func TestNoAuth_Server(t *testing.T) {
req := bytes.NewBuffer(nil)
rsp := new(bytes.Buffer)
2020-08-06 08:29:38 +00:00
s := NewServer(WithAuthMethods([]Authenticator{&NoAuthAuthenticator{}}))
2020-08-05 06:40:07 +00:00
ctx, err := s.authenticate(rsp, req, "", []byte{statute.MethodNoAuth})
require.NoError(t, err)
assert.Equal(t, statute.MethodNoAuth, ctx.Method)
assert.Equal(t, []byte{statute.VersionSocks5, statute.MethodNoAuth}, rsp.Bytes())
}
func TestPasswordAuth_Valid_Server(t *testing.T) {
req := bytes.NewBuffer([]byte{1, 3, 'f', 'o', 'o', 3, 'b', 'a', 'r'})
rsp := new(bytes.Buffer)
cator := UserPassAuthenticator{
2020-08-05 09:32:37 +00:00
StaticCredentials{"foo": "bar"},
2020-08-05 06:40:07 +00:00
}
2020-08-05 09:32:37 +00:00
s := NewServer(WithAuthMethods([]Authenticator{cator}))
2020-08-05 06:40:07 +00:00
ctx, err := s.authenticate(rsp, req, "", []byte{statute.MethodUserPassAuth})
require.NoError(t, err)
assert.Equal(t, statute.MethodUserPassAuth, ctx.Method)
val, ok := ctx.Payload["username"]
require.True(t, ok)
require.Equal(t, "foo", val)
val, ok = ctx.Payload["password"]
require.True(t, ok)
require.Equal(t, "bar", val)
assert.Equal(t, []byte{statute.VersionSocks5, statute.MethodUserPassAuth, 1, statute.AuthSuccess}, rsp.Bytes())
}
func TestPasswordAuth_Invalid_Server(t *testing.T) {
req := bytes.NewBuffer([]byte{1, 3, 'f', 'o', 'o', 3, 'b', 'a', 'z'})
rsp := new(bytes.Buffer)
cator := UserPassAuthenticator{
2020-08-05 09:32:37 +00:00
StaticCredentials{"foo": "bar"},
2020-08-05 06:40:07 +00:00
}
2020-08-05 09:32:37 +00:00
s := NewServer(WithAuthMethods([]Authenticator{cator}))
2020-08-05 06:40:07 +00:00
ctx, err := s.authenticate(rsp, req, "", []byte{statute.MethodNoAuth, statute.MethodUserPassAuth})
require.True(t, errors.Is(err, statute.ErrUserAuthFailed))
require.Nil(t, ctx)
assert.Equal(t, []byte{statute.VersionSocks5, statute.MethodUserPassAuth, 1, statute.AuthFailure}, rsp.Bytes())
}
func TestNoSupportedAuth_Server(t *testing.T) {
req := bytes.NewBuffer(nil)
rsp := new(bytes.Buffer)
cator := UserPassAuthenticator{
2020-08-05 09:32:37 +00:00
StaticCredentials{"foo": "bar"},
2020-08-05 06:40:07 +00:00
}
2020-08-05 09:32:37 +00:00
s := NewServer(WithAuthMethods([]Authenticator{cator}))
2020-08-05 06:40:07 +00:00
ctx, err := s.authenticate(rsp, req, "", []byte{statute.MethodNoAuth})
require.True(t, errors.Is(err, statute.ErrNoSupportedAuth))
require.Nil(t, ctx)
assert.Equal(t, []byte{statute.VersionSocks5, statute.MethodNoAcceptable}, rsp.Bytes())
}