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  }