1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
|
package socks
import (
"errors"
"net"
)
func (cfg *config) dialSocks5(targetAddr string) (_ net.Conn, err error) {
proxy := cfg.Host
// dial TCP
conn, err := net.Dial("tcp", proxy)
if err != nil {
return nil, err
}
defer func() {
if err != nil {
conn.Close()
}
}()
var req requestBuilder
version := byte(5) // socks version 5
method := byte(0) // method 0: no authentication (only anonymous access supported for now)
if cfg.Auth != nil {
method = 2 // method 2: username/password
}
// version identifier/method selection request
req.add(
version, // socks version
1, // number of methods
method,
)
resp, err := cfg.sendReceive(conn, req.Bytes())
if err != nil {
return nil, err
} else if len(resp) != 2 {
return nil, errors.New("server does not respond properly")
} else if resp[0] != 5 {
return nil, errors.New("server does not support Socks 5")
} else if resp[1] != method {
return nil, errors.New("socks method negotiation failed")
}
if cfg.Auth != nil {
version := byte(1) // user/password version 1
req.Reset()
req.add(
version, // user/password version
byte(len(cfg.Auth.Username)), // length of username
)
req.add([]byte(cfg.Auth.Username)...)
req.add(byte(len(cfg.Auth.Password)))
req.add([]byte(cfg.Auth.Password)...)
resp, err := cfg.sendReceive(conn, req.Bytes())
if err != nil {
return nil, err
} else if len(resp) != 2 {
return nil, errors.New("server does not respond properly")
} else if resp[0] != version {
return nil, errors.New("server does not support user/password version 1")
} else if resp[1] != 0 { // not success
return nil, errors.New("user/password login failed")
}
}
// detail request
host, port, err := splitHostPort(targetAddr)
if err != nil {
return nil, err
}
req.Reset()
req.add(
5, // version number
1, // connect command
0, // reserved, must be zero
3, // address type, 3 means domain name
byte(len(host)), // address length
)
req.add([]byte(host)...)
req.add(
byte(port>>8), // higher byte of destination port
byte(port), // lower byte of destination port (big endian)
)
resp, err = cfg.sendReceive(conn, req.Bytes())
if err != nil {
return
} else if len(resp) != 10 {
return nil, errors.New("server does not respond properly")
} else if resp[1] != 0 {
return nil, errors.New("can't complete SOCKS5 connection")
}
return conn, nil
}
|