2014-01-23 22:16:44 +00:00
|
|
|
package socks5
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"io"
|
2015-09-07 00:19:34 +00:00
|
|
|
"log"
|
2014-01-23 22:16:44 +00:00
|
|
|
"net"
|
2015-09-07 00:19:34 +00:00
|
|
|
"os"
|
2014-01-23 22:16:44 +00:00
|
|
|
"testing"
|
|
|
|
"time"
|
2020-04-20 11:56:35 +00:00
|
|
|
|
|
|
|
"golang.org/x/net/proxy"
|
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")
|
|
|
|
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)
|
|
|
|
}
|
2020-04-22 02:32:03 +00:00
|
|
|
_, _ = conn.Write([]byte("pong"))
|
2014-01-23 22:16:44 +00:00
|
|
|
}()
|
|
|
|
lAddr := l.Addr().(*net.TCPAddr)
|
|
|
|
|
|
|
|
// Create a socks server
|
2020-04-20 08:19:51 +00:00
|
|
|
cator := UserPassAuthenticator{
|
|
|
|
Credentials: StaticCredentials{"foo": "bar"},
|
2014-01-23 22:16:44 +00:00
|
|
|
}
|
2020-04-20 13:17:38 +00:00
|
|
|
serv := New(
|
|
|
|
WithAuthMethods([]Authenticator{cator}),
|
|
|
|
WithLogger(NewLogger(log.New(os.Stdout, "socks5: ", log.LstdFlags))),
|
|
|
|
)
|
2014-01-23 22:16:44 +00:00
|
|
|
|
|
|
|
// 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
|
2020-04-20 08:19:51 +00:00
|
|
|
req := new(bytes.Buffer)
|
2020-04-21 06:03:20 +00:00
|
|
|
req.Write([]byte{VersionSocks5, 2, MethodNoAuth, MethodUserPassAuth})
|
|
|
|
req.Write([]byte{UserPassAuthVersion, 3, 'f', 'o', 'o', 3, 'b', 'a', 'r'})
|
2020-04-20 08:19:51 +00:00
|
|
|
reqHead := Header{
|
2020-04-21 06:03:20 +00:00
|
|
|
Version: VersionSocks5,
|
|
|
|
Command: CommandConnect,
|
2020-04-20 08:19:51 +00:00
|
|
|
Reserved: 0,
|
|
|
|
Address: AddrSpec{
|
|
|
|
"",
|
|
|
|
net.ParseIP("127.0.0.1"),
|
|
|
|
lAddr.Port,
|
|
|
|
},
|
2020-04-21 06:03:20 +00:00
|
|
|
addrType: 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())
|
|
|
|
|
|
|
|
// Verify response
|
|
|
|
expected := []byte{
|
2020-04-21 06:03:20 +00:00
|
|
|
VersionSocks5, MethodUserPassAuth, // use user password auth
|
|
|
|
UserPassAuthVersion, AuthSuccess, // response auth success
|
2014-01-23 22:16:44 +00:00
|
|
|
}
|
2020-04-20 08:19:51 +00:00
|
|
|
rspHead := Header{
|
2020-04-21 06:03:20 +00:00
|
|
|
Version: VersionSocks5,
|
2020-04-22 02:32:03 +00:00
|
|
|
Command: RepSuccess,
|
2020-04-20 08:19:51 +00:00
|
|
|
Reserved: 0,
|
|
|
|
Address: AddrSpec{
|
|
|
|
"",
|
|
|
|
net.ParseIP("127.0.0.1"),
|
|
|
|
0, // Ignore the port
|
|
|
|
},
|
2020-04-21 06:03:20 +00:00
|
|
|
addrType: 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))
|
2020-04-22 02:32:03 +00:00
|
|
|
_ = conn.SetDeadline(time.Now().Add(time.Second))
|
2020-04-20 08:19:51 +00:00
|
|
|
if _, err := io.ReadFull(conn, out); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Logf("proxy bind port: %d", buildPort(out[12], out[13]))
|
|
|
|
|
|
|
|
// Ignore the port
|
|
|
|
out[12] = 0
|
|
|
|
out[13] = 0
|
|
|
|
|
|
|
|
if !bytes.Equal(out, expected) {
|
|
|
|
t.Fatalf("bad: %v", out)
|
|
|
|
}
|
|
|
|
}
|
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: 12398,
|
|
|
|
}
|
2020-04-20 09:09:16 +00:00
|
|
|
l, err := net.ListenUDP("udp", lAddr)
|
2020-04-20 08:19:51 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
defer l.Close()
|
|
|
|
go func() {
|
|
|
|
buf := make([]byte, 2048)
|
|
|
|
for {
|
|
|
|
n, remote, err := l.ReadFrom(buf)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2020-04-23 15:40:00 +00:00
|
|
|
|
2020-04-20 08:19:51 +00:00
|
|
|
if !bytes.Equal(buf[:n], []byte("ping")) {
|
|
|
|
t.Fatalf("bad: %v", buf)
|
|
|
|
}
|
2020-04-22 02:32:03 +00:00
|
|
|
_, _ = l.WriteTo([]byte("pong"), remote)
|
2020-04-20 08:19:51 +00:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
// Create a socks server
|
|
|
|
cator := UserPassAuthenticator{Credentials: StaticCredentials{"foo": "bar"}}
|
2020-04-20 13:17:38 +00:00
|
|
|
serv := New(
|
|
|
|
WithAuthMethods([]Authenticator{cator}),
|
|
|
|
WithLogger(NewLogger(log.New(os.Stdout, "socks5: ", log.LstdFlags))),
|
|
|
|
)
|
2020-04-20 08:19:51 +00:00
|
|
|
// Start listening
|
|
|
|
go func() {
|
|
|
|
if err := serv.ListenAndServe("tcp", "127.0.0.1:12355"); 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:12355")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Connect, auth and connec to local
|
|
|
|
req := new(bytes.Buffer)
|
2020-04-21 06:03:20 +00:00
|
|
|
req.Write([]byte{VersionSocks5, 2, MethodNoAuth, MethodUserPassAuth})
|
|
|
|
req.Write([]byte{UserPassAuthVersion, 3, 'f', 'o', 'o', 3, 'b', 'a', 'r'})
|
2020-04-20 08:19:51 +00:00
|
|
|
reqHead := Header{
|
2020-04-21 06:03:20 +00:00
|
|
|
Version: VersionSocks5,
|
|
|
|
Command: CommandAssociate,
|
2020-04-20 08:19:51 +00:00
|
|
|
Reserved: 0,
|
|
|
|
Address: AddrSpec{
|
|
|
|
"",
|
|
|
|
locIP,
|
|
|
|
lAddr.Port,
|
|
|
|
},
|
2020-04-21 06:03:20 +00:00
|
|
|
addrType: ATYPIPv4,
|
2020-04-20 08:19:51 +00:00
|
|
|
}
|
|
|
|
req.Write(reqHead.Bytes())
|
|
|
|
// Send all the bytes
|
|
|
|
conn.Write(req.Bytes())
|
|
|
|
|
|
|
|
// Verify response
|
|
|
|
expected := []byte{
|
2020-04-21 06:03:20 +00:00
|
|
|
VersionSocks5, MethodUserPassAuth, // use user password auth
|
|
|
|
UserPassAuthVersion, AuthSuccess, // response auth success
|
2020-04-20 08:19:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
out := make([]byte, len(expected))
|
2020-04-22 02:32:03 +00:00
|
|
|
_ = conn.SetDeadline(time.Now().Add(time.Second))
|
2020-04-20 08:19:51 +00:00
|
|
|
if _, err := io.ReadFull(conn, out); err != nil {
|
2014-01-23 22:16:44 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !bytes.Equal(out, expected) {
|
|
|
|
t.Fatalf("bad: %v", out)
|
|
|
|
}
|
2020-04-20 08:19:51 +00:00
|
|
|
|
2020-08-05 02:34:29 +00:00
|
|
|
rspHead, err := ParseHeader(conn)
|
2020-04-20 09:09:16 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("bad response header: %v", err)
|
|
|
|
}
|
2020-04-22 02:32:03 +00:00
|
|
|
if rspHead.Version != VersionSocks5 && rspHead.Command != RepSuccess {
|
2020-04-20 09:09:16 +00:00
|
|
|
t.Fatalf("parse success but bad header: %v", rspHead)
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Logf("proxy bind listen port: %d", rspHead.Address.Port)
|
|
|
|
|
|
|
|
udpConn, err := net.DialUDP("udp", nil, &net.UDPAddr{
|
|
|
|
IP: locIP,
|
|
|
|
Port: rspHead.Address.Port,
|
2020-04-20 08:19:51 +00:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("bad dial: %v", err)
|
|
|
|
}
|
|
|
|
// Send a ping
|
2020-04-22 02:32:03 +00:00
|
|
|
_, _ = udpConn.Write(append([]byte{0, 0, 0, ATYPIPv4, 0, 0, 0, 0, 0, 0}, []byte("ping")...))
|
2020-04-20 08:19:51 +00:00
|
|
|
response := make([]byte, 1024)
|
|
|
|
n, _, err := udpConn.ReadFrom(response)
|
2020-04-22 02:32:03 +00:00
|
|
|
if err != nil || !bytes.Equal(response[n-4:n], []byte("pong")) {
|
2020-04-20 08:19:51 +00:00
|
|
|
t.Fatalf("bad udp read: %v", string(response[:n]))
|
|
|
|
}
|
|
|
|
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")
|
|
|
|
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
|
|
|
|
cator := UserPassAuthenticator{Credentials: StaticCredentials{"foo": "bar"}}
|
2020-04-20 13:17:38 +00:00
|
|
|
serv := New(
|
|
|
|
WithAuthMethods([]Authenticator{cator}),
|
|
|
|
WithLogger(NewLogger(log.New(os.Stdout, "socks5: ", log.LstdFlags))),
|
|
|
|
)
|
2020-04-20 11:56:35 +00:00
|
|
|
|
|
|
|
// Start listening
|
|
|
|
go func() {
|
|
|
|
if err := serv.ListenAndServe("tcp", "127.0.0.1:12395"); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
|
|
|
|
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-04-20 11:56:35 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Connect, auth and connect to local
|
|
|
|
conn, err := dial.Dial("tcp", lAddr.String())
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send a ping
|
2020-04-22 02:32:03 +00:00
|
|
|
_, _ = conn.Write([]byte("ping"))
|
2020-04-20 11:56:35 +00:00
|
|
|
|
|
|
|
out := make([]byte, 4)
|
2020-04-22 02:32:03 +00:00
|
|
|
_ = conn.SetDeadline(time.Now().Add(time.Second))
|
2020-04-20 11:56:35 +00:00
|
|
|
if _, err := io.ReadFull(conn, out); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !bytes.Equal(out, []byte("pong")) {
|
|
|
|
t.Fatalf("bad: %v", out)
|
|
|
|
}
|
|
|
|
}
|