1// Copyright 2011 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 proxy provides support for a variety of protocols to proxy network 6// data. 7package proxy // import "golang.org/x/net/proxy" 8 9import ( 10 "errors" 11 "net" 12 "net/url" 13 "os" 14 "sync" 15) 16 17// A Dialer is a means to establish a connection. 18// Custom dialers should also implement ContextDialer. 19type Dialer interface { 20 // Dial connects to the given address via the proxy. 21 Dial(network, addr string) (c net.Conn, err error) 22} 23 24// Auth contains authentication parameters that specific Dialers may require. 25type Auth struct { 26 User, Password string 27} 28 29// FromEnvironment returns the dialer specified by the proxy-related 30// variables in the environment and makes underlying connections 31// directly. 32func FromEnvironment() Dialer { 33 return FromEnvironmentUsing(Direct) 34} 35 36// FromEnvironmentUsing returns the dialer specify by the proxy-related 37// variables in the environment and makes underlying connections 38// using the provided forwarding Dialer (for instance, a *net.Dialer 39// with desired configuration). 40func FromEnvironmentUsing(forward Dialer) Dialer { 41 allProxy := allProxyEnv.Get() 42 if len(allProxy) == 0 { 43 return forward 44 } 45 46 proxyURL, err := url.Parse(allProxy) 47 if err != nil { 48 return forward 49 } 50 proxy, err := FromURL(proxyURL, forward) 51 if err != nil { 52 return forward 53 } 54 55 noProxy := noProxyEnv.Get() 56 if len(noProxy) == 0 { 57 return proxy 58 } 59 60 perHost := NewPerHost(proxy, forward) 61 perHost.AddFromString(noProxy) 62 return perHost 63} 64 65// proxySchemes is a map from URL schemes to a function that creates a Dialer 66// from a URL with such a scheme. 67var proxySchemes map[string]func(*url.URL, Dialer) (Dialer, error) 68 69// RegisterDialerType takes a URL scheme and a function to generate Dialers from 70// a URL with that scheme and a forwarding Dialer. Registered schemes are used 71// by FromURL. 72func RegisterDialerType(scheme string, f func(*url.URL, Dialer) (Dialer, error)) { 73 if proxySchemes == nil { 74 proxySchemes = make(map[string]func(*url.URL, Dialer) (Dialer, error)) 75 } 76 proxySchemes[scheme] = f 77} 78 79// FromURL returns a Dialer given a URL specification and an underlying 80// Dialer for it to make network requests. 81func FromURL(u *url.URL, forward Dialer) (Dialer, error) { 82 var auth *Auth 83 if u.User != nil { 84 auth = new(Auth) 85 auth.User = u.User.Username() 86 if p, ok := u.User.Password(); ok { 87 auth.Password = p 88 } 89 } 90 91 switch u.Scheme { 92 case "socks5", "socks5h": 93 addr := u.Hostname() 94 port := u.Port() 95 if port == "" { 96 port = "1080" 97 } 98 return SOCKS5("tcp", net.JoinHostPort(addr, port), auth, forward) 99 } 100 101 // If the scheme doesn't match any of the built-in schemes, see if it 102 // was registered by another package. 103 if proxySchemes != nil { 104 if f, ok := proxySchemes[u.Scheme]; ok { 105 return f(u, forward) 106 } 107 } 108 109 return nil, errors.New("proxy: unknown scheme: " + u.Scheme) 110} 111 112var ( 113 allProxyEnv = &envOnce{ 114 names: []string{"ALL_PROXY", "all_proxy"}, 115 } 116 noProxyEnv = &envOnce{ 117 names: []string{"NO_PROXY", "no_proxy"}, 118 } 119) 120 121// envOnce looks up an environment variable (optionally by multiple 122// names) once. It mitigates expensive lookups on some platforms 123// (e.g. Windows). 124// (Borrowed from net/http/transport.go) 125type envOnce struct { 126 names []string 127 once sync.Once 128 val string 129} 130 131func (e *envOnce) Get() string { 132 e.once.Do(e.init) 133 return e.val 134} 135 136func (e *envOnce) init() { 137 for _, n := range e.names { 138 e.val = os.Getenv(n) 139 if e.val != "" { 140 return 141 } 142 } 143} 144 145// reset is used by tests 146func (e *envOnce) reset() { 147 e.once = sync.Once{} 148 e.val = "" 149} 150