1 // Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT.
2 //go:generate bundle -o socks_bundle.go -dst net/http -prefix socks -underscore golang.org/x/net/internal/socks
4 // Package socks provides a SOCKS version 5 client implementation.
6 // SOCKS protocol version 5 is defined in RFC 1928.
7 // Username/Password authentication for SOCKS version 5 is defined in
23 socksnoDeadline
= time
.Time
{}
24 socksaLongTimeAgo
= time
.Unix(1, 0)
27 func (d
*socksDialer
) connect(ctx context
.Context
, c net
.Conn
, address
string) (_ net
.Addr
, ctxErr error
) {
28 host
, port
, err
:= sockssplitHostPort(address
)
32 if deadline
, ok
:= ctx
.Deadline(); ok
&& !deadline
.IsZero() {
33 c
.SetDeadline(deadline
)
34 defer c
.SetDeadline(socksnoDeadline
)
36 if ctx
!= context
.Background() {
37 errCh
:= make(chan error
, 1)
38 done
:= make(chan struct{})
48 c
.SetDeadline(socksaLongTimeAgo
)
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
))
63 return nil, errors
.New("too many authentication methods")
65 b
= append(b
, byte(len(ams
)))
66 for _
, am
:= range ams
{
67 b
= append(b
, byte(am
))
70 if _
, ctxErr
= c
.Write(b
); ctxErr
!= nil {
74 if _
, ctxErr
= io
.ReadFull(c
, b
[:2]); ctxErr
!= nil {
77 if b
[0] != socksVersion5
{
78 return nil, errors
.New("unexpected protocol version " + strconv
.Itoa(int(b
[0])))
80 am
:= socksAuthMethod(b
[1])
81 if am
== socksAuthMethodNoAcceptableMethods
{
82 return nil, errors
.New("no acceptable authentication methods")
84 if d
.Authenticate
!= nil {
85 if ctxErr
= d
.Authenticate(ctx
, c
, am
); ctxErr
!= nil {
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
)
96 } else if ip6
:= ip
.To16(); ip6
!= nil {
97 b
= append(b
, socksAddrTypeIPv6
)
100 return nil, errors
.New("unknown address type")
104 return nil, errors
.New("FQDN too long")
106 b
= append(b
, socksAddrTypeFQDN
)
107 b
= append(b
, byte(len(host
)))
108 b
= append(b
, host
...)
110 b
= append(b
, byte(port
>>8), byte(port
))
111 if _
, ctxErr
= c
.Write(b
); ctxErr
!= nil {
115 if _
, ctxErr
= io
.ReadFull(c
, b
[:4]); ctxErr
!= nil {
118 if b
[0] != socksVersion5
{
119 return nil, errors
.New("unexpected protocol version " + strconv
.Itoa(int(b
[0])))
121 if cmdErr
:= socksReply(b
[1]); cmdErr
!= socksStatusSucceeded
{
122 return nil, errors
.New("unknown error " + cmdErr
.String())
125 return nil, errors
.New("non-zero reserved field")
130 case socksAddrTypeIPv4
:
132 a
.IP
= make(net
.IP
, net
.IPv4len
)
133 case socksAddrTypeIPv6
:
135 a
.IP
= make(net
.IP
, net
.IPv6len
)
136 case socksAddrTypeFQDN
:
137 if _
, err
:= io
.ReadFull(c
, b
[:1]); err
!= nil {
142 return nil, errors
.New("unknown address type " + strconv
.Itoa(int(b
[3])))
149 if _
, ctxErr
= io
.ReadFull(c
, b
); ctxErr
!= nil {
155 a
.Name
= string(b
[:len(b
)-2])
157 a
.Port
= int(b
[len(b
)-2])<<8 |
int(b
[len(b
)-1])
161 func sockssplitHostPort(address
string) (string, int, error
) {
162 host
, port
, err
:= net
.SplitHostPort(address
)
166 portnum
, err
:= strconv
.Atoi(port
)
170 if 1 > portnum || portnum
> 0xffff {
171 return "", 0, errors
.New("port number out of range " + port
)
173 return host
, portnum
, nil
176 // A Command represents a SOCKS command.
177 type socksCommand
int
179 func (cmd socksCommand
) String() string {
181 case socksCmdConnect
:
182 return "socks connect"
186 return "socks " + strconv
.Itoa(int(cmd
))
190 // An AuthMethod represents a SOCKS authentication method.
191 type socksAuthMethod
int
193 // A Reply represents a SOCKS command reply code.
196 func (code socksReply
) String() string {
198 case socksStatusSucceeded
:
201 return "general SOCKS server failure"
203 return "connection not allowed by ruleset"
205 return "network unreachable"
207 return "host unreachable"
209 return "connection refused"
213 return "command not supported"
215 return "address type not supported"
217 return "unknown code: " + strconv
.Itoa(int(code
))
221 // Wire protocol constants.
225 socksAddrTypeIPv4
= 0x01
226 socksAddrTypeFQDN
= 0x03
227 socksAddrTypeIPv6
= 0x04
229 socksCmdConnect socksCommand
= 0x01 // establishes an active-open forward proxy connection
230 sockscmdBind socksCommand
= 0x02 // establishes a passive-open forward proxy connection
232 socksAuthMethodNotRequired socksAuthMethod
= 0x00 // no authentication required
233 socksAuthMethodUsernamePassword socksAuthMethod
= 0x02 // use username/password
234 socksAuthMethodNoAcceptableMethods socksAuthMethod
= 0xff // no acceptable authentication methods
236 socksStatusSucceeded socksReply
= 0x00
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
247 func (a
*socksAddr
) Network() string { return "socks" }
249 func (a
*socksAddr
) String() string {
253 port
:= strconv
.Itoa(a
.Port
)
255 return net
.JoinHostPort(a
.Name
, port
)
257 return net
.JoinHostPort(a
.IP
.String(), port
)
260 // A Conn represents a forward proxy connection.
261 type socksConn
struct {
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
{
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
282 // ProxyDial specifies the optional dial function for
283 // establishing the transport connection.
284 ProxyDial
func(context
.Context
, string, string) (net
.Conn
, error
)
286 // AuthMethods specifies the list of request authention
288 // If empty, SOCKS client requests only AuthMethodNotRequired.
289 AuthMethods
[]socksAuthMethod
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
297 // DialContext connects to the provided address on the provided
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
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
}
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")}
318 if d
.ProxyDial
!= nil {
319 c
, err
= d
.ProxyDial(ctx
, d
.proxyNetwork
, d
.proxyAddress
)
322 c
, err
= dd
.DialContext(ctx
, d
.proxyNetwork
, d
.proxyAddress
)
325 proxy
, dst
, _
:= d
.pathAddrs(address
)
326 return nil, &net
.OpError
{Op
: d
.cmd
.String(), Net
: network
, Source
: proxy
, Addr
: dst
, Err
: err
}
328 a
, err
:= d
.connect(ctx
, c
, address
)
331 proxy
, dst
, _
:= d
.pathAddrs(address
)
332 return nil, &net
.OpError
{Op
: d
.cmd
.String(), Net
: network
, Source
: proxy
, Addr
: dst
, Err
: err
}
334 return &socksConn
{Conn
: c
, boundAddr
: a
}, nil
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.
341 // It returns the connection's local address assigned by the SOCKS
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
}
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")}
352 a
, err
:= d
.connect(ctx
, c
, address
)
354 proxy
, dst
, _
:= d
.pathAddrs(address
)
355 return nil, &net
.OpError
{Op
: d
.cmd
.String(), Net
: network
, Source
: proxy
, Addr
: dst
, Err
: err
}
360 // Dial connects to the provided address on the provided network.
362 // Unlike DialContext, it returns a raw transport connection instead
363 // of a forward proxy connection.
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
}
373 if d
.ProxyDial
!= nil {
374 c
, err
= d
.ProxyDial(context
.Background(), d
.proxyNetwork
, d
.proxyAddress
)
376 c
, err
= net
.Dial(d
.proxyNetwork
, d
.proxyAddress
)
379 proxy
, dst
, _
:= d
.pathAddrs(address
)
380 return nil, &net
.OpError
{Op
: d
.cmd
.String(), Net
: network
, Source
: proxy
, Addr
: dst
, Err
: err
}
382 if _
, err
:= d
.DialWithConn(context
.Background(), c
, network
, address
); err
!= nil {
388 func (d
*socksDialer
) validateTarget(network
, address
string) error
{
390 case "tcp", "tcp6", "tcp4":
392 return errors
.New("network not implemented")
395 case socksCmdConnect
, sockscmdBind
:
397 return errors
.New("command not implemented")
402 func (d
*socksDialer
) pathAddrs(address
string) (proxy
, dst net
.Addr
, err error
) {
403 for i
, s
:= range []string{d
.proxyAddress
, address
} {
404 host
, port
, err
:= sockssplitHostPort(s
)
408 a
:= &socksAddr
{Port
: port
}
409 a
.IP
= net
.ParseIP(host
)
422 // NewDialer returns a new Dialer that dials through the provided
423 // proxy server's network and address.
424 func socksNewDialer(network
, address
string) *socksDialer
{
425 return &socksDialer
{proxyNetwork
: network
, proxyAddress
: address
, cmd
: socksCmdConnect
}
429 socksauthUsernamePasswordVersion
= 0x01
430 socksauthStatusSucceeded
= 0x00
433 // UsernamePassword are the credentials for the username/password
434 // authentication method.
435 type socksUsernamePassword
struct {
440 // Authenticate authenticates a pair of username and password with the
442 func (up
*socksUsernamePassword
) Authenticate(ctx context
.Context
, rw io
.ReadWriter
, auth socksAuthMethod
) error
{
444 case socksAuthMethodNotRequired
:
446 case socksAuthMethodUsernamePassword
:
447 if len(up
.Username
) == 0 ||
len(up
.Username
) > 255 ||
len(up
.Password
) == 0 ||
len(up
.Password
) > 255 {
448 return errors
.New("invalid username/password")
450 b
:= []byte{socksauthUsernamePasswordVersion
}
451 b
= append(b
, byte(len(up
.Username
)))
452 b
= append(b
, up
.Username
...)
453 b
= append(b
, byte(len(up
.Password
)))
454 b
= append(b
, up
.Password
...)
455 // TODO(mikio): handle IO deadlines and cancelation if
457 if _
, err
:= rw
.Write(b
); err
!= nil {
460 if _
, err
:= io
.ReadFull(rw
, b
[:2]); err
!= nil {
463 if b
[0] != socksauthUsernamePasswordVersion
{
464 return errors
.New("invalid username/password version")
466 if b
[1] != socksauthStatusSucceeded
{
467 return errors
.New("username/password authentication failed")
471 return errors
.New("unsupported authentication method " + strconv
.Itoa(int(auth
)))