github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/net/http/socks_bundle.go (about) 1 // Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT. 2 //go:generate bundle -o socks_bundle.go -prefix socks golang.org/x/net/internal/socks 3 4 // Package socks provides a SOCKS version 5 client implementation. 5 // 6 // SOCKS protocol version 5 is defined in RFC 1928. 7 // Username/Password authentication for SOCKS version 5 is defined in 8 // RFC 1929. 9 // 10 11 package http 12 13 import ( 14 "context" 15 "errors" 16 "io" 17 "net" 18 "strconv" 19 "time" 20 ) 21 22 var ( 23 socksnoDeadline = time.Time{} 24 socksaLongTimeAgo = time.Unix(1, 0) 25 ) 26 27 func (d *socksDialer) connect(ctx context.Context, c net.Conn, address string) (_ net.Addr, ctxErr error) { 28 host, port, err := sockssplitHostPort(address) 29 if err != nil { 30 return nil, err 31 } 32 if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() { 33 c.SetDeadline(deadline) 34 defer c.SetDeadline(socksnoDeadline) 35 } 36 if ctx != context.Background() { 37 errCh := make(chan error, 1) 38 done := make(chan struct{}) 39 defer func() { 40 close(done) 41 if ctxErr == nil { 42 ctxErr = <-errCh 43 } 44 }() 45 go func() { 46 select { 47 case <-ctx.Done(): 48 c.SetDeadline(socksaLongTimeAgo) 49 errCh <- ctx.Err() 50 case <-done: 51 errCh <- nil 52 } 53 }() 54 } 55 56 b := make([]byte, 0, 6+len(host)) // the size here is just an estimate 57 b = append(b, socksVersion5) 58 if len(d.AuthMethods) == 0 || d.Authenticate == nil { 59 b = append(b, 1, byte(socksAuthMethodNotRequired)) 60 } else { 61 ams := d.AuthMethods 62 if len(ams) > 255 { 63 return nil, errors.New("too many authentication methods") 64 } 65 b = append(b, byte(len(ams))) 66 for _, am := range ams { 67 b = append(b, byte(am)) 68 } 69 } 70 if _, ctxErr = c.Write(b); ctxErr != nil { 71 return 72 } 73 74 if _, ctxErr = io.ReadFull(c, b[:2]); ctxErr != nil { 75 return 76 } 77 if b[0] != socksVersion5 { 78 return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0]))) 79 } 80 am := socksAuthMethod(b[1]) 81 if am == socksAuthMethodNoAcceptableMethods { 82 return nil, errors.New("no acceptable authentication methods") 83 } 84 if d.Authenticate != nil { 85 if ctxErr = d.Authenticate(ctx, c, am); ctxErr != nil { 86 return 87 } 88 } 89 90 b = b[:0] 91 b = append(b, socksVersion5, byte(d.cmd), 0) 92 if ip := net.ParseIP(host); ip != nil { 93 if ip4 := ip.To4(); ip4 != nil { 94 b = append(b, socksAddrTypeIPv4) 95 b = append(b, ip4...) 96 } else if ip6 := ip.To16(); ip6 != nil { 97 b = append(b, socksAddrTypeIPv6) 98 b = append(b, ip6...) 99 } else { 100 return nil, errors.New("unknown address type") 101 } 102 } else { 103 if len(host) > 255 { 104 return nil, errors.New("FQDN too long") 105 } 106 b = append(b, socksAddrTypeFQDN) 107 b = append(b, byte(len(host))) 108 b = append(b, host...) 109 } 110 b = append(b, byte(port>>8), byte(port)) 111 if _, ctxErr = c.Write(b); ctxErr != nil { 112 return 113 } 114 115 if _, ctxErr = io.ReadFull(c, b[:4]); ctxErr != nil { 116 return 117 } 118 if b[0] != socksVersion5 { 119 return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0]))) 120 } 121 if cmdErr := socksReply(b[1]); cmdErr != socksStatusSucceeded { 122 return nil, errors.New("unknown error " + cmdErr.String()) 123 } 124 if b[2] != 0 { 125 return nil, errors.New("non-zero reserved field") 126 } 127 l := 2 128 var a socksAddr 129 switch b[3] { 130 case socksAddrTypeIPv4: 131 l += net.IPv4len 132 a.IP = make(net.IP, net.IPv4len) 133 case socksAddrTypeIPv6: 134 l += net.IPv6len 135 a.IP = make(net.IP, net.IPv6len) 136 case socksAddrTypeFQDN: 137 if _, err := io.ReadFull(c, b[:1]); err != nil { 138 return nil, err 139 } 140 l += int(b[0]) 141 default: 142 return nil, errors.New("unknown address type " + strconv.Itoa(int(b[3]))) 143 } 144 if cap(b) < l { 145 b = make([]byte, l) 146 } else { 147 b = b[:l] 148 } 149 if _, ctxErr = io.ReadFull(c, b); ctxErr != nil { 150 return 151 } 152 if a.IP != nil { 153 copy(a.IP, b) 154 } else { 155 a.Name = string(b[:len(b)-2]) 156 } 157 a.Port = int(b[len(b)-2])<<8 | int(b[len(b)-1]) 158 return &a, nil 159 } 160 161 func sockssplitHostPort(address string) (string, int, error) { 162 host, port, err := net.SplitHostPort(address) 163 if err != nil { 164 return "", 0, err 165 } 166 portnum, err := strconv.Atoi(port) 167 if err != nil { 168 return "", 0, err 169 } 170 if 1 > portnum || portnum > 0xffff { 171 return "", 0, errors.New("port number out of range " + port) 172 } 173 return host, portnum, nil 174 } 175 176 // A Command represents a SOCKS command. 177 type socksCommand int 178 179 func (cmd socksCommand) String() string { 180 switch cmd { 181 case socksCmdConnect: 182 return "socks connect" 183 case sockscmdBind: 184 return "socks bind" 185 default: 186 return "socks " + strconv.Itoa(int(cmd)) 187 } 188 } 189 190 // An AuthMethod represents a SOCKS authentication method. 191 type socksAuthMethod int 192 193 // A Reply represents a SOCKS command reply code. 194 type socksReply int 195 196 func (code socksReply) String() string { 197 switch code { 198 case socksStatusSucceeded: 199 return "succeeded" 200 case 0x01: 201 return "general SOCKS server failure" 202 case 0x02: 203 return "connection not allowed by ruleset" 204 case 0x03: 205 return "network unreachable" 206 case 0x04: 207 return "host unreachable" 208 case 0x05: 209 return "connection refused" 210 case 0x06: 211 return "TTL expired" 212 case 0x07: 213 return "command not supported" 214 case 0x08: 215 return "address type not supported" 216 default: 217 return "unknown code: " + strconv.Itoa(int(code)) 218 } 219 } 220 221 // Wire protocol constants. 222 const ( 223 socksVersion5 = 0x05 224 225 socksAddrTypeIPv4 = 0x01 226 socksAddrTypeFQDN = 0x03 227 socksAddrTypeIPv6 = 0x04 228 229 socksCmdConnect socksCommand = 0x01 // establishes an active-open forward proxy connection 230 sockscmdBind socksCommand = 0x02 // establishes a passive-open forward proxy connection 231 232 socksAuthMethodNotRequired socksAuthMethod = 0x00 // no authentication required 233 socksAuthMethodUsernamePassword socksAuthMethod = 0x02 // use username/password 234 socksAuthMethodNoAcceptableMethods socksAuthMethod = 0xff // no acceptable authentication methods 235 236 socksStatusSucceeded socksReply = 0x00 237 ) 238 239 // An Addr represents a SOCKS-specific address. 240 // Either Name or IP is used exclusively. 241 type socksAddr struct { 242 Name string // fully-qualified domain name 243 IP net.IP 244 Port int 245 } 246 247 func (a *socksAddr) Network() string { return "socks" } 248 249 func (a *socksAddr) String() string { 250 if a == nil { 251 return "<nil>" 252 } 253 port := strconv.Itoa(a.Port) 254 if a.IP == nil { 255 return net.JoinHostPort(a.Name, port) 256 } 257 return net.JoinHostPort(a.IP.String(), port) 258 } 259 260 // A Conn represents a forward proxy connection. 261 type socksConn struct { 262 net.Conn 263 264 boundAddr net.Addr 265 } 266 267 // BoundAddr returns the address assigned by the proxy server for 268 // connecting to the command target address from the proxy server. 269 func (c *socksConn) BoundAddr() net.Addr { 270 if c == nil { 271 return nil 272 } 273 return c.boundAddr 274 } 275 276 // A Dialer holds SOCKS-specific options. 277 type socksDialer struct { 278 cmd socksCommand // either CmdConnect or cmdBind 279 proxyNetwork string // network between a proxy server and a client 280 proxyAddress string // proxy server address 281 282 // ProxyDial specifies the optional dial function for 283 // establishing the transport connection. 284 ProxyDial func(context.Context, string, string) (net.Conn, error) 285 286 // AuthMethods specifies the list of request authentication 287 // methods. 288 // If empty, SOCKS client requests only AuthMethodNotRequired. 289 AuthMethods []socksAuthMethod 290 291 // Authenticate specifies the optional authentication 292 // function. It must be non-nil when AuthMethods is not empty. 293 // It must return an error when the authentication is failed. 294 Authenticate func(context.Context, io.ReadWriter, socksAuthMethod) error 295 } 296 297 // DialContext connects to the provided address on the provided 298 // network. 299 // 300 // The returned error value may be a net.OpError. When the Op field of 301 // net.OpError contains "socks", the Source field contains a proxy 302 // server address and the Addr field contains a command target 303 // address. 304 // 305 // See func Dial of the net package of standard library for a 306 // description of the network and address parameters. 307 func (d *socksDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { 308 if err := d.validateTarget(network, address); err != nil { 309 proxy, dst, _ := d.pathAddrs(address) 310 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} 311 } 312 if ctx == nil { 313 proxy, dst, _ := d.pathAddrs(address) 314 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")} 315 } 316 var err error 317 var c net.Conn 318 if d.ProxyDial != nil { 319 c, err = d.ProxyDial(ctx, d.proxyNetwork, d.proxyAddress) 320 } else { 321 var dd net.Dialer 322 c, err = dd.DialContext(ctx, d.proxyNetwork, d.proxyAddress) 323 } 324 if err != nil { 325 proxy, dst, _ := d.pathAddrs(address) 326 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} 327 } 328 a, err := d.connect(ctx, c, address) 329 if err != nil { 330 c.Close() 331 proxy, dst, _ := d.pathAddrs(address) 332 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} 333 } 334 return &socksConn{Conn: c, boundAddr: a}, nil 335 } 336 337 // DialWithConn initiates a connection from SOCKS server to the target 338 // network and address using the connection c that is already 339 // connected to the SOCKS server. 340 // 341 // It returns the connection's local address assigned by the SOCKS 342 // server. 343 func (d *socksDialer) DialWithConn(ctx context.Context, c net.Conn, network, address string) (net.Addr, error) { 344 if err := d.validateTarget(network, address); err != nil { 345 proxy, dst, _ := d.pathAddrs(address) 346 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} 347 } 348 if ctx == nil { 349 proxy, dst, _ := d.pathAddrs(address) 350 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")} 351 } 352 a, err := d.connect(ctx, c, address) 353 if err != nil { 354 proxy, dst, _ := d.pathAddrs(address) 355 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} 356 } 357 return a, nil 358 } 359 360 // Dial connects to the provided address on the provided network. 361 // 362 // Unlike DialContext, it returns a raw transport connection instead 363 // of a forward proxy connection. 364 // 365 // Deprecated: Use DialContext or DialWithConn instead. 366 func (d *socksDialer) Dial(network, address string) (net.Conn, error) { 367 if err := d.validateTarget(network, address); err != nil { 368 proxy, dst, _ := d.pathAddrs(address) 369 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} 370 } 371 var err error 372 var c net.Conn 373 if d.ProxyDial != nil { 374 c, err = d.ProxyDial(context.Background(), d.proxyNetwork, d.proxyAddress) 375 } else { 376 c, err = net.Dial(d.proxyNetwork, d.proxyAddress) 377 } 378 if err != nil { 379 proxy, dst, _ := d.pathAddrs(address) 380 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} 381 } 382 if _, err := d.DialWithConn(context.Background(), c, network, address); err != nil { 383 c.Close() 384 return nil, err 385 } 386 return c, nil 387 } 388 389 func (d *socksDialer) validateTarget(network, address string) error { 390 switch network { 391 case "tcp", "tcp6", "tcp4": 392 default: 393 return errors.New("network not implemented") 394 } 395 switch d.cmd { 396 case socksCmdConnect, sockscmdBind: 397 default: 398 return errors.New("command not implemented") 399 } 400 return nil 401 } 402 403 func (d *socksDialer) pathAddrs(address string) (proxy, dst net.Addr, err error) { 404 for i, s := range []string{d.proxyAddress, address} { 405 host, port, err := sockssplitHostPort(s) 406 if err != nil { 407 return nil, nil, err 408 } 409 a := &socksAddr{Port: port} 410 a.IP = net.ParseIP(host) 411 if a.IP == nil { 412 a.Name = host 413 } 414 if i == 0 { 415 proxy = a 416 } else { 417 dst = a 418 } 419 } 420 return 421 } 422 423 // NewDialer returns a new Dialer that dials through the provided 424 // proxy server's network and address. 425 func socksNewDialer(network, address string) *socksDialer { 426 return &socksDialer{proxyNetwork: network, proxyAddress: address, cmd: socksCmdConnect} 427 } 428 429 const ( 430 socksauthUsernamePasswordVersion = 0x01 431 socksauthStatusSucceeded = 0x00 432 ) 433 434 // UsernamePassword are the credentials for the username/password 435 // authentication method. 436 type socksUsernamePassword struct { 437 Username string 438 Password string 439 } 440 441 // Authenticate authenticates a pair of username and password with the 442 // proxy server. 443 func (up *socksUsernamePassword) Authenticate(ctx context.Context, rw io.ReadWriter, auth socksAuthMethod) error { 444 switch auth { 445 case socksAuthMethodNotRequired: 446 return nil 447 case socksAuthMethodUsernamePassword: 448 if len(up.Username) == 0 || len(up.Username) > 255 || len(up.Password) > 255 { 449 return errors.New("invalid username/password") 450 } 451 b := []byte{socksauthUsernamePasswordVersion} 452 b = append(b, byte(len(up.Username))) 453 b = append(b, up.Username...) 454 b = append(b, byte(len(up.Password))) 455 b = append(b, up.Password...) 456 // TODO(mikio): handle IO deadlines and cancelation if 457 // necessary 458 if _, err := rw.Write(b); err != nil { 459 return err 460 } 461 if _, err := io.ReadFull(rw, b[:2]); err != nil { 462 return err 463 } 464 if b[0] != socksauthUsernamePasswordVersion { 465 return errors.New("invalid username/password version") 466 } 467 if b[1] != socksauthStatusSucceeded { 468 return errors.New("username/password authentication failed") 469 } 470 return nil 471 } 472 return errors.New("unsupported authentication method " + strconv.Itoa(int(auth))) 473 }