github.com/Cloud-Foundations/Dominator@v0.3.4/lib/net/proxy/socks.go (about) 1 package proxy 2 3 import ( 4 "errors" 5 "io" 6 "net" 7 "strconv" 8 ) 9 10 var ( 11 errorNoIPs = errors.New("no IP addresses") 12 errorNoIPv4s = errors.New("no IPv4 addresses") 13 errorNotIPv4 = errors.New("not an IPv4 address") 14 errorShortRead = errors.New("short read") 15 errorShortWrite = errors.New("short write") 16 errorUnsupportedTransport = errors.New("unsupported transport") 17 18 errorRequestRejected = errors.New("request rejected") 19 errorNoIdentd = errors.New("no client identd") 20 errorUserIdNotConfirmed = errors.New("user ID not confirmed") 21 errorUnknownResponseCode = errors.New("unknown response code") 22 ) 23 24 type socksDialer struct { 25 dialer *net.Dialer 26 proxyAddress string 27 proxyDNS bool 28 udpSupported bool 29 } 30 31 func (d *socksDialer) Dial(network, address string) (net.Conn, error) { 32 switch network { 33 case "tcp": 34 return d.dialTCP(address) 35 case "udp": 36 } 37 return nil, errorUnsupportedTransport 38 } 39 40 func (d *socksDialer) dialTCP(address string) (net.Conn, error) { 41 host, portStr, err := net.SplitHostPort(address) 42 if err != nil { 43 return nil, err 44 } 45 port, err := strconv.ParseUint(portStr, 10, 16) 46 if err != nil { 47 return nil, err 48 } 49 var request []byte 50 if ip := net.ParseIP(host); ip != nil { 51 if request, err = makeSocks4IpRequest(ip, uint16(port)); err != nil { 52 return nil, err 53 } 54 } else if d.proxyDNS { 55 if request, err = makeSocks4aRequest(host, uint16(port)); err != nil { 56 return nil, err 57 } 58 } else { 59 if request, err = makeSocks4Request(host, uint16(port)); err != nil { 60 return nil, err 61 } 62 } 63 if conn, err := d.dialer.Dial("tcp", d.proxyAddress); err != nil { 64 return nil, err 65 } else { 66 if nWritten, err := conn.Write(request); err != nil { 67 conn.Close() 68 return nil, err 69 } else if nWritten < len(request) { 70 conn.Close() 71 return nil, errorShortWrite 72 } 73 if err := readSocks4Response(conn); err != nil { 74 conn.Close() 75 return nil, err 76 } 77 return conn, nil 78 } 79 } 80 81 func makeSocks4aRequest(host string, port uint16) ([]byte, error) { 82 request := make([]byte, 10+len(host)) 83 request[0] = 0x04 84 request[1] = 0x01 85 request[2] = byte(port >> 8) 86 request[3] = byte(port & 0xff) 87 request[7] = 0xff 88 copy(request[9:], host) 89 return request, nil 90 } 91 92 func makeSocks4IpRequest(ip net.IP, port uint16) ([]byte, error) { 93 if ip = ip.To4(); ip == nil { 94 return nil, errorNoIPv4s 95 } 96 request := make([]byte, 9) 97 request[0] = 0x04 98 request[1] = 0x01 99 request[2] = byte(port >> 8) 100 request[3] = byte(port & 0xff) 101 request[4] = ip[0] 102 request[5] = ip[1] 103 request[6] = ip[2] 104 request[7] = ip[3] 105 return request, nil 106 } 107 108 func makeSocks4Request(host string, port uint16) ([]byte, error) { 109 ips, err := net.LookupIP(host) 110 if err != nil { 111 return nil, err 112 } 113 if len(ips) < 1 { 114 return nil, errorNoIPs 115 } 116 var ip4 net.IP 117 for _, ip := range ips { 118 if ip4 = ip.To4(); ip4 != nil { 119 break 120 } 121 } 122 if len(ip4) != 4 { 123 return nil, errorNoIPv4s 124 } 125 return makeSocks4IpRequest(ip4, port) 126 } 127 128 func readSocks4Response(reader io.Reader) error { 129 response := make([]byte, 8) 130 if nRead, err := reader.Read(response); err != nil { 131 return err 132 } else if nRead < len(response) { 133 return errorShortRead 134 } else { 135 switch response[1] { 136 case 0x5a: 137 return nil 138 case 0x5b: 139 return errorRequestRejected 140 case 0x5c: 141 return errorNoIdentd 142 case 0x5d: 143 return errorUserIdNotConfirmed 144 default: 145 return errorUnknownResponseCode 146 } 147 } 148 }