You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							177 lines
						
					
					
						
							4.2 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							177 lines
						
					
					
						
							4.2 KiB
						
					
					
				| package net2 | |
| 
 | |
| import ( | |
| 	"fmt" | |
| 	"log" | |
| 	"net" | |
| 	"os" | |
| 	"strings" | |
| 	"sync" | |
| ) | |
| 
 | |
| var myHostname string | |
| var myHostnameOnce sync.Once | |
| 
 | |
| // Like os.Hostname but caches first successful result, making it cheap to call it | |
| // over and over. | |
| // It will also crash whole process if fetching Hostname fails! | |
| func MyHostname() string { | |
| 	myHostnameOnce.Do(func() { | |
| 		var err error | |
| 		myHostname, err = os.Hostname() | |
| 		if err != nil { | |
| 			log.Fatal(err) | |
| 		} | |
| 	}) | |
| 	return myHostname | |
| } | |
| 
 | |
| var myIp4 *net.IPAddr | |
| var myIp4Once sync.Once | |
| 
 | |
| // Resolves `MyHostname()` to an Ip4 address. Caches first successful result, making it | |
| // cheap to call it over and over. | |
| // It will also crash whole process if resolving the IP fails! | |
| func MyIp4() *net.IPAddr { | |
| 	myIp4Once.Do(func() { | |
| 		var err error | |
| 		myIp4, err = net.ResolveIPAddr("ip4", MyHostname()) | |
| 		if err != nil { | |
| 			log.Fatal(err) | |
| 		} | |
| 	}) | |
| 	return myIp4 | |
| } | |
| 
 | |
| var myIp6 *net.IPAddr | |
| var myIp6Once sync.Once | |
| 
 | |
| // Resolves `MyHostname()` to an Ip6 address. Caches first successful result, making it | |
| // cheap to call it over and over. | |
| // It will also crash whole process if resolving the IP fails! | |
| func MyIp6() *net.IPAddr { | |
| 	myIp6Once.Do(func() { | |
| 		var err error | |
| 		myIp6, err = net.ResolveIPAddr("ip6", MyHostname()) | |
| 		if err != nil { | |
| 			log.Fatal(err) | |
| 		} | |
| 	}) | |
| 	return myIp6 | |
| } | |
| 
 | |
| // This returns the list of local ip addresses which other hosts can connect | |
| // to (NOTE: Loopback ip is ignored). | |
| // Also resolves Hostname to an address and adds it to the list too, so | |
| // IPs from /etc/hosts can work too. | |
| func GetLocalIPs() ([]*net.IP, error) { | |
| 	hostname, err := os.Hostname() | |
| 	if err != nil { | |
| 		return nil, fmt.Errorf("Failed to lookup hostname: %v", err) | |
| 	} | |
| 	// Resolves IP Address from Hostname, this way overrides in /etc/hosts | |
| 	// can work too for IP resolution. | |
| 	ipInfo, err := net.ResolveIPAddr("ip4", hostname) | |
| 	if err != nil { | |
| 		return nil, fmt.Errorf("Failed to resolve ip: %v", err) | |
| 	} | |
| 	ips := []*net.IP{&ipInfo.IP} | |
| 
 | |
| 	// TODO(zviad): Is rest of the code really necessary? | |
| 	addrs, err := net.InterfaceAddrs() | |
| 	if err != nil { | |
| 		return nil, fmt.Errorf("Failed to get interface addresses: %v", err) | |
| 	} | |
| 	for _, addr := range addrs { | |
| 		ipnet, ok := addr.(*net.IPNet) | |
| 		if !ok { | |
| 			continue | |
| 		} | |
| 
 | |
| 		if ipnet.IP.IsLoopback() { | |
| 			continue | |
| 		} | |
| 
 | |
| 		ips = append(ips, &ipnet.IP) | |
| 	} | |
| 	return ips, nil | |
| } | |
| 
 | |
| var localhostIPNets []*net.IPNet | |
| 
 | |
| func init() { | |
| 	for _, mask := range []string{"127.0.0.1/8", "::1/128"} { | |
| 		_, ipnet, err := net.ParseCIDR(mask) | |
| 		if err != nil { | |
| 			panic(err) | |
| 		} | |
| 		localhostIPNets = append(localhostIPNets, ipnet) | |
| 	} | |
| } | |
| 
 | |
| func IsLocalhostIp(ipStr string) bool { | |
| 	ip := net.ParseIP(ipStr) | |
| 	if ip == nil { | |
| 		return false | |
| 	} | |
| 	for _, ipnet := range localhostIPNets { | |
| 		if ipnet.Contains(ip) { | |
| 			return true | |
| 		} | |
| 	} | |
| 	return false | |
| } | |
| 
 | |
| // Given a host string, return true if the host is an ip (v4/v6) localhost. | |
| func IsLocalhost(host string) bool { | |
| 	return IsLocalhostIp(host) || | |
| 		host == "localhost" || | |
| 		host == "ip6-localhost" || | |
| 		host == "ipv6-localhost" | |
| } | |
| 
 | |
| // Resolves hostnames in addresses to actual IP4 addresses. Skips all invalid addresses | |
| // and all addresses that can't be resolved. | |
| // `addrs` are assumed to be of form: ["<hostname>:<port>", ...] | |
| // Returns an error in addition to resolved addresses if not all resolutions succeed. | |
| func ResolveIP4s(addrs []string) ([]string, error) { | |
| 	resolvedAddrs := make([]string, 0, len(addrs)) | |
| 	var lastErr error | |
| 
 | |
| 	for _, server := range addrs { | |
| 		hostPort := strings.Split(server, ":") | |
| 		if len(hostPort) != 2 { | |
| 			lastErr = fmt.Errorf("Skipping invalid address: %s", server) | |
| 			continue | |
| 		} | |
| 
 | |
| 		ip, err := net.ResolveIPAddr("ip4", hostPort[0]) | |
| 		if err != nil { | |
| 			lastErr = err | |
| 			continue | |
| 		} | |
| 		resolvedAddrs = append(resolvedAddrs, ip.IP.String()+":"+hostPort[1]) | |
| 	} | |
| 	return resolvedAddrs, lastErr | |
| } | |
| 
 | |
| func LookupValidAddrs() (map[string]bool, error) { | |
| 	hostName, err := os.Hostname() | |
| 	if err != nil { | |
| 		return nil, err | |
| 	} | |
| 	addrs, err := net.LookupHost(hostName) | |
| 	if err != nil { | |
| 		return nil, err | |
| 	} | |
| 	validAddrs := make(map[string]bool) | |
| 	validAddrs[hostName] = true | |
| 	for _, addr := range addrs { | |
| 		validAddrs[addr] = true | |
| 	} | |
| 	// Special case localhost/127.0.0.1 so that this works on devVMs. It should | |
| 	// have no affect in production. | |
| 	validAddrs["127.0.0.1"] = true | |
| 	validAddrs["localhost"] = true | |
| 	return validAddrs, nil | |
| }
 |