1// Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT.
2//go:generate bundle -o x_net_proxy.go golang.org/x/net/proxy
3
4// Package proxy provides support for a variety of protocols to proxy network
5// data.
6//
7
8package websocket
9
10import (
11	"errors"
12	"io"
13	"net"
14	"net/url"
15	"os"
16	"strconv"
17	"strings"
18	"sync"
19)
20
21type proxy_direct struct{}
22
23// Direct is a direct proxy: one that makes network connections directly.
24var proxy_Direct = proxy_direct{}
25
26func (proxy_direct) Dial(network, addr string) (net.Conn, error) {
27	return net.Dial(network, addr)
28}
29
30// A PerHost directs connections to a default Dialer unless the host name
31// requested matches one of a number of exceptions.
32type proxy_PerHost struct {
33	def, bypass proxy_Dialer
34
35	bypassNetworks []*net.IPNet
36	bypassIPs      []net.IP
37	bypassZones    []string
38	bypassHosts    []string
39}
40
41// NewPerHost returns a PerHost Dialer that directs connections to either
42// defaultDialer or bypass, depending on whether the connection matches one of
43// the configured rules.
44func proxy_NewPerHost(defaultDialer, bypass proxy_Dialer) *proxy_PerHost {
45	return &proxy_PerHost{
46		def:    defaultDialer,
47		bypass: bypass,
48	}
49}
50
51// Dial connects to the address addr on the given network through either
52// defaultDialer or bypass.
53func (p *proxy_PerHost) Dial(network, addr string) (c net.Conn, err error) {
54	host, _, err := net.SplitHostPort(addr)
55	if err != nil {
56		return nil, err
57	}
58
59	return p.dialerForRequest(host).Dial(network, addr)
60}
61
62func (p *proxy_PerHost) dialerForRequest(host string) proxy_Dialer {
63	if ip := net.ParseIP(host); ip != nil {
64		for _, net := range p.bypassNetworks {
65			if net.Contains(ip) {
66				return p.bypass
67			}
68		}
69		for _, bypassIP := range p.bypassIPs {
70			if bypassIP.Equal(ip) {
71				return p.bypass
72			}
73		}
74		return p.def
75	}
76
77	for _, zone := range p.bypassZones {
78		if strings.HasSuffix(host, zone) {
79			return p.bypass
80		}
81		if host == zone[1:] {
82			// For a zone ".example.com", we match "example.com"
83			// too.
84			return p.bypass
85		}
86	}
87	for _, bypassHost := range p.bypassHosts {
88		if bypassHost == host {
89			return p.bypass
90		}
91	}
92	return p.def
93}
94
95// AddFromString parses a string that contains comma-separated values
96// specifying hosts that should use the bypass proxy. Each value is either an
97// IP address, a CIDR range, a zone (*.example.com) or a host name
98// (localhost). A best effort is made to parse the string and errors are
99// ignored.
100func (p *proxy_PerHost) AddFromString(s string) {
101	hosts := strings.Split(s, ",")
102	for _, host := range hosts {
103		host = strings.TrimSpace(host)
104		if len(host) == 0 {
105			continue
106		}
107		if strings.Contains(host, "/") {
108			// We assume that it's a CIDR address like 127.0.0.0/8
109			if _, net, err := net.ParseCIDR(host); err == nil {
110				p.AddNetwork(net)
111			}
112			continue
113		}
114		if ip := net.ParseIP(host); ip != nil {
115			p.AddIP(ip)
116			continue
117		}
118		if strings.HasPrefix(host, "*.") {
119			p.AddZone(host[1:])
120			continue
121		}
122		p.AddHost(host)
123	}
124}
125
126// AddIP specifies an IP address that will use the bypass proxy. Note that
127// this will only take effect if a literal IP address is dialed. A connection
128// to a named host will never match an IP.
129func (p *proxy_PerHost) AddIP(ip net.IP) {
130	p.bypassIPs = append(p.bypassIPs, ip)
131}
132
133// AddNetwork specifies an IP range that will use the bypass proxy. Note that
134// this will only take effect if a literal IP address is dialed. A connection
135// to a named host will never match.
136func (p *proxy_PerHost) AddNetwork(net *net.IPNet) {
137	p.bypassNetworks = append(p.bypassNetworks, net)
138}
139
140// AddZone specifies a DNS suffix that will use the bypass proxy. A zone of
141// "example.com" matches "example.com" and all of its subdomains.
142func (p *proxy_PerHost) AddZone(zone string) {
143	if strings.HasSuffix(zone, ".") {
144		zone = zone[:len(zone)-1]
145	}
146	if !strings.HasPrefix(zone, ".") {
147		zone = "." + zone
148	}
149	p.bypassZones = append(p.bypassZones, zone)
150}
151
152// AddHost specifies a host name that will use the bypass proxy.
153func (p *proxy_PerHost) AddHost(host string) {
154	if strings.HasSuffix(host, ".") {
155		host = host[:len(host)-1]
156	}
157	p.bypassHosts = append(p.bypassHosts, host)
158}
159
160// A Dialer is a means to establish a connection.
161type proxy_Dialer interface {
162	// Dial connects to the given address via the proxy.
163	Dial(network, addr string) (c net.Conn, err error)
164}
165
166// Auth contains authentication parameters that specific Dialers may require.
167type proxy_Auth struct {
168	User, Password string
169}
170
171// FromEnvironment returns the dialer specified by the proxy related variables in
172// the environment.
173func proxy_FromEnvironment() proxy_Dialer {
174	allProxy := proxy_allProxyEnv.Get()
175	if len(allProxy) == 0 {
176		return proxy_Direct
177	}
178
179	proxyURL, err := url.Parse(allProxy)
180	if err != nil {
181		return proxy_Direct
182	}
183	proxy, err := proxy_FromURL(proxyURL, proxy_Direct)
184	if err != nil {
185		return proxy_Direct
186	}
187
188	noProxy := proxy_noProxyEnv.Get()
189	if len(noProxy) == 0 {
190		return proxy
191	}
192
193	perHost := proxy_NewPerHost(proxy, proxy_Direct)
194	perHost.AddFromString(noProxy)
195	return perHost
196}
197
198// proxySchemes is a map from URL schemes to a function that creates a Dialer
199// from a URL with such a scheme.
200var proxy_proxySchemes map[string]func(*url.URL, proxy_Dialer) (proxy_Dialer, error)
201
202// RegisterDialerType takes a URL scheme and a function to generate Dialers from
203// a URL with that scheme and a forwarding Dialer. Registered schemes are used
204// by FromURL.
205func proxy_RegisterDialerType(scheme string, f func(*url.URL, proxy_Dialer) (proxy_Dialer, error)) {
206	if proxy_proxySchemes == nil {
207		proxy_proxySchemes = make(map[string]func(*url.URL, proxy_Dialer) (proxy_Dialer, error))
208	}
209	proxy_proxySchemes[scheme] = f
210}
211
212// FromURL returns a Dialer given a URL specification and an underlying
213// Dialer for it to make network requests.
214func proxy_FromURL(u *url.URL, forward proxy_Dialer) (proxy_Dialer, error) {
215	var auth *proxy_Auth
216	if u.User != nil {
217		auth = new(proxy_Auth)
218		auth.User = u.User.Username()
219		if p, ok := u.User.Password(); ok {
220			auth.Password = p
221		}
222	}
223
224	switch u.Scheme {
225	case "socks5":
226		return proxy_SOCKS5("tcp", u.Host, auth, forward)
227	}
228
229	// If the scheme doesn't match any of the built-in schemes, see if it
230	// was registered by another package.
231	if proxy_proxySchemes != nil {
232		if f, ok := proxy_proxySchemes[u.Scheme]; ok {
233			return f(u, forward)
234		}
235	}
236
237	return nil, errors.New("proxy: unknown scheme: " + u.Scheme)
238}
239
240var (
241	proxy_allProxyEnv = &proxy_envOnce{
242		names: []string{"ALL_PROXY", "all_proxy"},
243	}
244	proxy_noProxyEnv = &proxy_envOnce{
245		names: []string{"NO_PROXY", "no_proxy"},
246	}
247)
248
249// envOnce looks up an environment variable (optionally by multiple
250// names) once. It mitigates expensive lookups on some platforms
251// (e.g. Windows).
252// (Borrowed from net/http/transport.go)
253type proxy_envOnce struct {
254	names []string
255	once  sync.Once
256	val   string
257}
258
259func (e *proxy_envOnce) Get() string {
260	e.once.Do(e.init)
261	return e.val
262}
263
264func (e *proxy_envOnce) init() {
265	for _, n := range e.names {
266		e.val = os.Getenv(n)
267		if e.val != "" {
268			return
269		}
270	}
271}
272
273// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address
274// with an optional username and password. See RFC 1928 and RFC 1929.
275func proxy_SOCKS5(network, addr string, auth *proxy_Auth, forward proxy_Dialer) (proxy_Dialer, error) {
276	s := &proxy_socks5{
277		network: network,
278		addr:    addr,
279		forward: forward,
280	}
281	if auth != nil {
282		s.user = auth.User
283		s.password = auth.Password
284	}
285
286	return s, nil
287}
288
289type proxy_socks5 struct {
290	user, password string
291	network, addr  string
292	forward        proxy_Dialer
293}
294
295const proxy_socks5Version = 5
296
297const (
298	proxy_socks5AuthNone     = 0
299	proxy_socks5AuthPassword = 2
300)
301
302const proxy_socks5Connect = 1
303
304const (
305	proxy_socks5IP4    = 1
306	proxy_socks5Domain = 3
307	proxy_socks5IP6    = 4
308)
309
310var proxy_socks5Errors = []string{
311	"",
312	"general failure",
313	"connection forbidden",
314	"network unreachable",
315	"host unreachable",
316	"connection refused",
317	"TTL expired",
318	"command not supported",
319	"address type not supported",
320}
321
322// Dial connects to the address addr on the given network via the SOCKS5 proxy.
323func (s *proxy_socks5) Dial(network, addr string) (net.Conn, error) {
324	switch network {
325	case "tcp", "tcp6", "tcp4":
326	default:
327		return nil, errors.New("proxy: no support for SOCKS5 proxy connections of type " + network)
328	}
329
330	conn, err := s.forward.Dial(s.network, s.addr)
331	if err != nil {
332		return nil, err
333	}
334	if err := s.connect(conn, addr); err != nil {
335		conn.Close()
336		return nil, err
337	}
338	return conn, nil
339}
340
341// connect takes an existing connection to a socks5 proxy server,
342// and commands the server to extend that connection to target,
343// which must be a canonical address with a host and port.
344func (s *proxy_socks5) connect(conn net.Conn, target string) error {
345	host, portStr, err := net.SplitHostPort(target)
346	if err != nil {
347		return err
348	}
349
350	port, err := strconv.Atoi(portStr)
351	if err != nil {
352		return errors.New("proxy: failed to parse port number: " + portStr)
353	}
354	if port < 1 || port > 0xffff {
355		return errors.New("proxy: port number out of range: " + portStr)
356	}
357
358	// the size here is just an estimate
359	buf := make([]byte, 0, 6+len(host))
360
361	buf = append(buf, proxy_socks5Version)
362	if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 {
363		buf = append(buf, 2 /* num auth methods */, proxy_socks5AuthNone, proxy_socks5AuthPassword)
364	} else {
365		buf = append(buf, 1 /* num auth methods */, proxy_socks5AuthNone)
366	}
367
368	if _, err := conn.Write(buf); err != nil {
369		return errors.New("proxy: failed to write greeting to SOCKS5 proxy at " + s.addr + ": " + err.Error())
370	}
371
372	if _, err := io.ReadFull(conn, buf[:2]); err != nil {
373		return errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error())
374	}
375	if buf[0] != 5 {
376		return errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0])))
377	}
378	if buf[1] == 0xff {
379		return errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication")
380	}
381
382	// See RFC 1929
383	if buf[1] == proxy_socks5AuthPassword {
384		buf = buf[:0]
385		buf = append(buf, 1 /* password protocol version */)
386		buf = append(buf, uint8(len(s.user)))
387		buf = append(buf, s.user...)
388		buf = append(buf, uint8(len(s.password)))
389		buf = append(buf, s.password...)
390
391		if _, err := conn.Write(buf); err != nil {
392			return errors.New("proxy: failed to write authentication request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
393		}
394
395		if _, err := io.ReadFull(conn, buf[:2]); err != nil {
396			return errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
397		}
398
399		if buf[1] != 0 {
400			return errors.New("proxy: SOCKS5 proxy at " + s.addr + " rejected username/password")
401		}
402	}
403
404	buf = buf[:0]
405	buf = append(buf, proxy_socks5Version, proxy_socks5Connect, 0 /* reserved */)
406
407	if ip := net.ParseIP(host); ip != nil {
408		if ip4 := ip.To4(); ip4 != nil {
409			buf = append(buf, proxy_socks5IP4)
410			ip = ip4
411		} else {
412			buf = append(buf, proxy_socks5IP6)
413		}
414		buf = append(buf, ip...)
415	} else {
416		if len(host) > 255 {
417			return errors.New("proxy: destination host name too long: " + host)
418		}
419		buf = append(buf, proxy_socks5Domain)
420		buf = append(buf, byte(len(host)))
421		buf = append(buf, host...)
422	}
423	buf = append(buf, byte(port>>8), byte(port))
424
425	if _, err := conn.Write(buf); err != nil {
426		return errors.New("proxy: failed to write connect request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
427	}
428
429	if _, err := io.ReadFull(conn, buf[:4]); err != nil {
430		return errors.New("proxy: failed to read connect reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
431	}
432
433	failure := "unknown error"
434	if int(buf[1]) < len(proxy_socks5Errors) {
435		failure = proxy_socks5Errors[buf[1]]
436	}
437
438	if len(failure) > 0 {
439		return errors.New("proxy: SOCKS5 proxy at " + s.addr + " failed to connect: " + failure)
440	}
441
442	bytesToDiscard := 0
443	switch buf[3] {
444	case proxy_socks5IP4:
445		bytesToDiscard = net.IPv4len
446	case proxy_socks5IP6:
447		bytesToDiscard = net.IPv6len
448	case proxy_socks5Domain:
449		_, err := io.ReadFull(conn, buf[:1])
450		if err != nil {
451			return errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error())
452		}
453		bytesToDiscard = int(buf[0])
454	default:
455		return errors.New("proxy: got unknown address type " + strconv.Itoa(int(buf[3])) + " from SOCKS5 proxy at " + s.addr)
456	}
457
458	if cap(buf) < bytesToDiscard {
459		buf = make([]byte, bytesToDiscard)
460	} else {
461		buf = buf[:bytesToDiscard]
462	}
463	if _, err := io.ReadFull(conn, buf); err != nil {
464		return errors.New("proxy: failed to read address from SOCKS5 proxy at " + s.addr + ": " + err.Error())
465	}
466
467	// Also need to discard the port number
468	if _, err := io.ReadFull(conn, buf[:2]); err != nil {
469		return errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error())
470	}
471
472	return nil
473}
474