x_net_proxy.go (12907B)
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 8 package websocket 9 10 import ( 11 "errors" 12 "io" 13 "net" 14 "net/url" 15 "os" 16 "strconv" 17 "strings" 18 "sync" 19 ) 20 21 type proxy_direct struct{} 22 23 // Direct is a direct proxy: one that makes network connections directly. 24 var proxy_Direct = proxy_direct{} 25 26 func (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. 32 type 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. 44 func 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. 53 func (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 62 func (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. 100 func (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. 129 func (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. 136 func (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. 142 func (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. 153 func (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. 161 type 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. 167 type proxy_Auth struct { 168 User, Password string 169 } 170 171 // FromEnvironment returns the dialer specified by the proxy related variables in 172 // the environment. 173 func 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. 200 var 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. 205 func 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. 214 func 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 240 var ( 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) 253 type proxy_envOnce struct { 254 names []string 255 once sync.Once 256 val string 257 } 258 259 func (e *proxy_envOnce) Get() string { 260 e.once.Do(e.init) 261 return e.val 262 } 263 264 func (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. 275 func 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 289 type proxy_socks5 struct { 290 user, password string 291 network, addr string 292 forward proxy_Dialer 293 } 294 295 const proxy_socks5Version = 5 296 297 const ( 298 proxy_socks5AuthNone = 0 299 proxy_socks5AuthPassword = 2 300 ) 301 302 const proxy_socks5Connect = 1 303 304 const ( 305 proxy_socks5IP4 = 1 306 proxy_socks5Domain = 3 307 proxy_socks5IP6 = 4 308 ) 309 310 var 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. 323 func (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. 344 func (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 }