github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gofrontend/libgo/go/exp/proxy/per_host.go (about) 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 6 7 import ( 8 "net" 9 "strings" 10 ) 11 12 // A PerHost directs connections to a default Dailer unless the hostname 13 // requested matches one of a number of exceptions. 14 type PerHost struct { 15 def, bypass Dialer 16 17 bypassNetworks []*net.IPNet 18 bypassIPs []net.IP 19 bypassZones []string 20 bypassHosts []string 21 } 22 23 // NewPerHost returns a PerHost Dialer that directs connections to either 24 // defaultDialer or bypass, depending on whether the connection matches one of 25 // the configured rules. 26 func NewPerHost(defaultDialer, bypass Dialer) *PerHost { 27 return &PerHost{ 28 def: defaultDialer, 29 bypass: bypass, 30 } 31 } 32 33 // Dial connects to the address addr on the network net through either 34 // defaultDialer or bypass. 35 func (p *PerHost) Dial(network, addr string) (c net.Conn, err error) { 36 host, _, err := net.SplitHostPort(addr) 37 if err != nil { 38 return nil, err 39 } 40 41 return p.dialerForRequest(host).Dial(network, addr) 42 } 43 44 func (p *PerHost) dialerForRequest(host string) Dialer { 45 if ip := net.ParseIP(host); ip != nil { 46 for _, net := range p.bypassNetworks { 47 if net.Contains(ip) { 48 return p.bypass 49 } 50 } 51 for _, bypassIP := range p.bypassIPs { 52 if bypassIP.Equal(ip) { 53 return p.bypass 54 } 55 } 56 return p.def 57 } 58 59 for _, zone := range p.bypassZones { 60 if strings.HasSuffix(host, zone) { 61 return p.bypass 62 } 63 if host == zone[1:] { 64 // For a zone "example.com", we match "example.com" 65 // too. 66 return p.bypass 67 } 68 } 69 for _, bypassHost := range p.bypassHosts { 70 if bypassHost == host { 71 return p.bypass 72 } 73 } 74 return p.def 75 } 76 77 // AddFromString parses a string that contains comma-separated values 78 // specifying hosts that should use the bypass proxy. Each value is either an 79 // IP address, a CIDR range, a zone (*.example.com) or a hostname 80 // (localhost). A best effort is made to parse the string and errors are 81 // ignored. 82 func (p *PerHost) AddFromString(s string) { 83 hosts := strings.Split(s, ",") 84 for _, host := range hosts { 85 host = strings.TrimSpace(host) 86 if len(host) == 0 { 87 continue 88 } 89 if strings.Contains(host, "/") { 90 // We assume that it's a CIDR address like 127.0.0.0/8 91 if _, net, err := net.ParseCIDR(host); err == nil { 92 p.AddNetwork(net) 93 } 94 continue 95 } 96 if ip := net.ParseIP(host); ip != nil { 97 p.AddIP(ip) 98 continue 99 } 100 if strings.HasPrefix(host, "*.") { 101 p.AddZone(host[1:]) 102 continue 103 } 104 p.AddHost(host) 105 } 106 } 107 108 // AddIP specifies an IP address that will use the bypass proxy. Note that 109 // this will only take effect if a literal IP address is dialed. A connection 110 // to a named host will never match an IP. 111 func (p *PerHost) AddIP(ip net.IP) { 112 p.bypassIPs = append(p.bypassIPs, ip) 113 } 114 115 // AddIP specifies an IP range that will use the bypass proxy. Note that this 116 // will only take effect if a literal IP address is dialed. A connection to a 117 // named host will never match. 118 func (p *PerHost) AddNetwork(net *net.IPNet) { 119 p.bypassNetworks = append(p.bypassNetworks, net) 120 } 121 122 // AddZone specifies a DNS suffix that will use the bypass proxy. A zone of 123 // "example.com" matches "example.com" and all of its subdomains. 124 func (p *PerHost) AddZone(zone string) { 125 if strings.HasSuffix(zone, ".") { 126 zone = zone[:len(zone)-1] 127 } 128 if !strings.HasPrefix(zone, ".") { 129 zone = "." + zone 130 } 131 p.bypassZones = append(p.bypassZones, zone) 132 } 133 134 // AddHost specifies a hostname that will use the bypass proxy. 135 func (p *PerHost) AddHost(host string) { 136 if strings.HasSuffix(host, ".") { 137 host = host[:len(host)-1] 138 } 139 p.bypassHosts = append(p.bypassHosts, host) 140 }