-
Notifications
You must be signed in to change notification settings - Fork 107
/
socks4.go
71 lines (66 loc) · 1.8 KB
/
socks4.go
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
package socks
import (
"errors"
"net"
"time"
)
func (cfg *config) dialSocks4(targetAddr string) (_ net.Conn, err error) {
socksType := cfg.Proto
proxy := cfg.Host
// dial TCP
conn, err := net.DialTimeout("tcp", proxy, cfg.Timeout)
if err != nil {
return nil, err
}
defer func() {
if err != nil {
conn.Close()
}
}()
// connection request
host, port, err := splitHostPort(targetAddr)
if err != nil {
return nil, err
}
ip := net.IPv4(0, 0, 0, 1).To4()
if socksType == SOCKS4 {
ip, err = lookupIPv4(host)
if err != nil {
return nil, err
}
}
req := []byte{
4, // version number
1, // command CONNECT
byte(port >> 8), // higher byte of destination port
byte(port), // lower byte of destination port (big endian)
ip[0], ip[1], ip[2], ip[3], // special invalid IP address to indicate the host name is provided
0, // user id is empty, anonymous proxy only
}
if socksType == SOCKS4A {
req = append(req, []byte(host+"\x00")...)
}
resp, err := cfg.sendReceive(conn, req)
if err != nil {
return nil, err
} else if len(resp) != 8 {
return nil, errors.New("server does not respond properly")
}
switch resp[1] {
case 90:
// request granted
case 91:
return nil, errors.New("socks connection request rejected or failed")
case 92:
return nil, errors.New("socks connection request rejected because SOCKS server cannot connect to identd on the client")
case 93:
return nil, errors.New("socks connection request rejected because the client program and identd report different user-ids")
default:
return nil, errors.New("socks connection request failed, unknown error")
}
// clear the deadline before returning
if err := conn.SetDeadline(time.Time{}); err != nil {
return nil, err
}
return conn, nil
}