Merge branch 'master' into EDGE-142
[platform/core/system/edge-orchestration.git] / vendor / github.com / miekg / dns / vendor / golang.org / x / net / internal / socks / socks.go
1 // Copyright 2018 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // Package socks provides a SOCKS version 5 client implementation.
6 //
7 // SOCKS protocol version 5 is defined in RFC 1928.
8 // Username/Password authentication for SOCKS version 5 is defined in
9 // RFC 1929.
10 package socks
11
12 import (
13         "context"
14         "errors"
15         "io"
16         "net"
17         "strconv"
18 )
19
20 // A Command represents a SOCKS command.
21 type Command int
22
23 func (cmd Command) String() string {
24         switch cmd {
25         case CmdConnect:
26                 return "socks connect"
27         case cmdBind:
28                 return "socks bind"
29         default:
30                 return "socks " + strconv.Itoa(int(cmd))
31         }
32 }
33
34 // An AuthMethod represents a SOCKS authentication method.
35 type AuthMethod int
36
37 // A Reply represents a SOCKS command reply code.
38 type Reply int
39
40 func (code Reply) String() string {
41         switch code {
42         case StatusSucceeded:
43                 return "succeeded"
44         case 0x01:
45                 return "general SOCKS server failure"
46         case 0x02:
47                 return "connection not allowed by ruleset"
48         case 0x03:
49                 return "network unreachable"
50         case 0x04:
51                 return "host unreachable"
52         case 0x05:
53                 return "connection refused"
54         case 0x06:
55                 return "TTL expired"
56         case 0x07:
57                 return "command not supported"
58         case 0x08:
59                 return "address type not supported"
60         default:
61                 return "unknown code: " + strconv.Itoa(int(code))
62         }
63 }
64
65 // Wire protocol constants.
66 const (
67         Version5 = 0x05
68
69         AddrTypeIPv4 = 0x01
70         AddrTypeFQDN = 0x03
71         AddrTypeIPv6 = 0x04
72
73         CmdConnect Command = 0x01 // establishes an active-open forward proxy connection
74         cmdBind    Command = 0x02 // establishes a passive-open forward proxy connection
75
76         AuthMethodNotRequired         AuthMethod = 0x00 // no authentication required
77         AuthMethodUsernamePassword    AuthMethod = 0x02 // use username/password
78         AuthMethodNoAcceptableMethods AuthMethod = 0xff // no acceptable authentication methods
79
80         StatusSucceeded Reply = 0x00
81 )
82
83 // An Addr represents a SOCKS-specific address.
84 // Either Name or IP is used exclusively.
85 type Addr struct {
86         Name string // fully-qualified domain name
87         IP   net.IP
88         Port int
89 }
90
91 func (a *Addr) Network() string { return "socks" }
92
93 func (a *Addr) String() string {
94         if a == nil {
95                 return "<nil>"
96         }
97         port := strconv.Itoa(a.Port)
98         if a.IP == nil {
99                 return net.JoinHostPort(a.Name, port)
100         }
101         return net.JoinHostPort(a.IP.String(), port)
102 }
103
104 // A Conn represents a forward proxy connection.
105 type Conn struct {
106         net.Conn
107
108         boundAddr net.Addr
109 }
110
111 // BoundAddr returns the address assigned by the proxy server for
112 // connecting to the command target address from the proxy server.
113 func (c *Conn) BoundAddr() net.Addr {
114         if c == nil {
115                 return nil
116         }
117         return c.boundAddr
118 }
119
120 // A Dialer holds SOCKS-specific options.
121 type Dialer struct {
122         cmd          Command // either CmdConnect or cmdBind
123         proxyNetwork string  // network between a proxy server and a client
124         proxyAddress string  // proxy server address
125
126         // ProxyDial specifies the optional dial function for
127         // establishing the transport connection.
128         ProxyDial func(context.Context, string, string) (net.Conn, error)
129
130         // AuthMethods specifies the list of request authention
131         // methods.
132         // If empty, SOCKS client requests only AuthMethodNotRequired.
133         AuthMethods []AuthMethod
134
135         // Authenticate specifies the optional authentication
136         // function. It must be non-nil when AuthMethods is not empty.
137         // It must return an error when the authentication is failed.
138         Authenticate func(context.Context, io.ReadWriter, AuthMethod) error
139 }
140
141 // DialContext connects to the provided address on the provided
142 // network.
143 //
144 // The returned error value may be a net.OpError. When the Op field of
145 // net.OpError contains "socks", the Source field contains a proxy
146 // server address and the Addr field contains a command target
147 // address.
148 //
149 // See func Dial of the net package of standard library for a
150 // description of the network and address parameters.
151 func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
152         if err := d.validateTarget(network, address); err != nil {
153                 proxy, dst, _ := d.pathAddrs(address)
154                 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
155         }
156         if ctx == nil {
157                 proxy, dst, _ := d.pathAddrs(address)
158                 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")}
159         }
160         var err error
161         var c net.Conn
162         if d.ProxyDial != nil {
163                 c, err = d.ProxyDial(ctx, d.proxyNetwork, d.proxyAddress)
164         } else {
165                 var dd net.Dialer
166                 c, err = dd.DialContext(ctx, d.proxyNetwork, d.proxyAddress)
167         }
168         if err != nil {
169                 proxy, dst, _ := d.pathAddrs(address)
170                 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
171         }
172         a, err := d.connect(ctx, c, address)
173         if err != nil {
174                 c.Close()
175                 proxy, dst, _ := d.pathAddrs(address)
176                 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
177         }
178         return &Conn{Conn: c, boundAddr: a}, nil
179 }
180
181 // DialWithConn initiates a connection from SOCKS server to the target
182 // network and address using the connection c that is already
183 // connected to the SOCKS server.
184 //
185 // It returns the connection's local address assigned by the SOCKS
186 // server.
187 func (d *Dialer) DialWithConn(ctx context.Context, c net.Conn, network, address string) (net.Addr, error) {
188         if err := d.validateTarget(network, address); err != nil {
189                 proxy, dst, _ := d.pathAddrs(address)
190                 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
191         }
192         if ctx == nil {
193                 proxy, dst, _ := d.pathAddrs(address)
194                 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")}
195         }
196         a, err := d.connect(ctx, c, address)
197         if err != nil {
198                 proxy, dst, _ := d.pathAddrs(address)
199                 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
200         }
201         return a, nil
202 }
203
204 // Dial connects to the provided address on the provided network.
205 //
206 // Unlike DialContext, it returns a raw transport connection instead
207 // of a forward proxy connection.
208 //
209 // Deprecated: Use DialContext or DialWithConn instead.
210 func (d *Dialer) Dial(network, address string) (net.Conn, error) {
211         if err := d.validateTarget(network, address); err != nil {
212                 proxy, dst, _ := d.pathAddrs(address)
213                 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
214         }
215         var err error
216         var c net.Conn
217         if d.ProxyDial != nil {
218                 c, err = d.ProxyDial(context.Background(), d.proxyNetwork, d.proxyAddress)
219         } else {
220                 c, err = net.Dial(d.proxyNetwork, d.proxyAddress)
221         }
222         if err != nil {
223                 proxy, dst, _ := d.pathAddrs(address)
224                 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
225         }
226         if _, err := d.DialWithConn(context.Background(), c, network, address); err != nil {
227                 c.Close()
228                 return nil, err
229         }
230         return c, nil
231 }
232
233 func (d *Dialer) validateTarget(network, address string) error {
234         switch network {
235         case "tcp", "tcp6", "tcp4":
236         default:
237                 return errors.New("network not implemented")
238         }
239         switch d.cmd {
240         case CmdConnect, cmdBind:
241         default:
242                 return errors.New("command not implemented")
243         }
244         return nil
245 }
246
247 func (d *Dialer) pathAddrs(address string) (proxy, dst net.Addr, err error) {
248         for i, s := range []string{d.proxyAddress, address} {
249                 host, port, err := splitHostPort(s)
250                 if err != nil {
251                         return nil, nil, err
252                 }
253                 a := &Addr{Port: port}
254                 a.IP = net.ParseIP(host)
255                 if a.IP == nil {
256                         a.Name = host
257                 }
258                 if i == 0 {
259                         proxy = a
260                 } else {
261                         dst = a
262                 }
263         }
264         return
265 }
266
267 // NewDialer returns a new Dialer that dials through the provided
268 // proxy server's network and address.
269 func NewDialer(network, address string) *Dialer {
270         return &Dialer{proxyNetwork: network, proxyAddress: address, cmd: CmdConnect}
271 }
272
273 const (
274         authUsernamePasswordVersion = 0x01
275         authStatusSucceeded         = 0x00
276 )
277
278 // UsernamePassword are the credentials for the username/password
279 // authentication method.
280 type UsernamePassword struct {
281         Username string
282         Password string
283 }
284
285 // Authenticate authenticates a pair of username and password with the
286 // proxy server.
287 func (up *UsernamePassword) Authenticate(ctx context.Context, rw io.ReadWriter, auth AuthMethod) error {
288         switch auth {
289         case AuthMethodNotRequired:
290                 return nil
291         case AuthMethodUsernamePassword:
292                 if len(up.Username) == 0 || len(up.Username) > 255 || len(up.Password) == 0 || len(up.Password) > 255 {
293                         return errors.New("invalid username/password")
294                 }
295                 b := []byte{authUsernamePasswordVersion}
296                 b = append(b, byte(len(up.Username)))
297                 b = append(b, up.Username...)
298                 b = append(b, byte(len(up.Password)))
299                 b = append(b, up.Password...)
300                 // TODO(mikio): handle IO deadlines and cancelation if
301                 // necessary
302                 if _, err := rw.Write(b); err != nil {
303                         return err
304                 }
305                 if _, err := io.ReadFull(rw, b[:2]); err != nil {
306                         return err
307                 }
308                 if b[0] != authUsernamePasswordVersion {
309                         return errors.New("invalid username/password version")
310                 }
311                 if b[1] != authStatusSucceeded {
312                         return errors.New("username/password authentication failed")
313                 }
314                 return nil
315         }
316         return errors.New("unsupported authentication method " + strconv.Itoa(int(auth)))
317 }