* remove redundant code * check invalid ip address first * remove redundant code * cleanup Co-authored-by: 刘海洋 <haiyang@snqu.com>
		
			
				
	
	
		
			151 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			151 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package addr
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"net"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	privateBlocks []*net.IPNet
 | |
| )
 | |
| 
 | |
| func init() {
 | |
| 	blocks := []string{
 | |
| 		"10.0.0.0/8",
 | |
| 		"172.16.0.0/12",
 | |
| 		"192.168.0.0/16",
 | |
| 		"100.64.0.0/10",
 | |
| 		"fd00::/8",
 | |
| 	}
 | |
| 	AppendPrivateBlocks(blocks...)
 | |
| }
 | |
| 
 | |
| // AppendPrivateBlocks append private network blocks
 | |
| func AppendPrivateBlocks(bs ...string) {
 | |
| 	for _, b := range bs {
 | |
| 		if _, block, err := net.ParseCIDR(b); err == nil {
 | |
| 			privateBlocks = append(privateBlocks, block)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func isPrivateIP(ipAddr string) bool {
 | |
| 	ip := net.ParseIP(ipAddr)
 | |
| 	if ip == nil {
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	for _, blocks := range privateBlocks {
 | |
| 		if blocks.Contains(ip) {
 | |
| 			return true
 | |
| 		}
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| func addrToIP(addr net.Addr) net.IP {
 | |
| 	switch v := addr.(type) {
 | |
| 	case *net.IPAddr:
 | |
| 		return v.IP
 | |
| 	case *net.IPNet:
 | |
| 		return v.IP
 | |
| 	default:
 | |
| 		return nil
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func localIPs() []string {
 | |
| 	ifaces, err := net.Interfaces()
 | |
| 	if err != nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	var ipAddrs []string
 | |
| 
 | |
| 	for _, iface := range ifaces {
 | |
| 		addrs, err := iface.Addrs()
 | |
| 		if err != nil {
 | |
| 			continue // ignore error
 | |
| 		}
 | |
| 
 | |
| 		for _, addr := range addrs {
 | |
| 			if ip := addrToIP(addr); ip != nil {
 | |
| 				ipAddrs = append(ipAddrs, ip.String())
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return ipAddrs
 | |
| }
 | |
| 
 | |
| // IsLocal tells us whether an ip is local
 | |
| func IsLocal(addr string) bool {
 | |
| 	// extract the host
 | |
| 	host, _, err := net.SplitHostPort(addr)
 | |
| 	if err == nil {
 | |
| 		addr = host
 | |
| 	}
 | |
| 
 | |
| 	// check if its localhost
 | |
| 	if addr == "localhost" {
 | |
| 		return true
 | |
| 	}
 | |
| 
 | |
| 	// check against all local ips
 | |
| 	for _, ip := range localIPs() {
 | |
| 		if addr == ip {
 | |
| 			return true
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| // Extract returns a real ip
 | |
| func Extract(addr string) (string, error) {
 | |
| 	// if addr specified then its returned
 | |
| 	if len(addr) > 0 {
 | |
| 		if addr != "0.0.0.0" && addr != "[::]" && addr != "::" {
 | |
| 			return addr, nil
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	var privateAddrs []string
 | |
| 	var publicAddrs []string
 | |
| 	var loopbackAddrs []string
 | |
| 
 | |
| 	for _, ipAddr := range localIPs() {
 | |
| 		ip := net.ParseIP(ipAddr)
 | |
| 		if ip == nil {
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		if ip.IsUnspecified() {
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		if ip.IsLoopback() {
 | |
| 			loopbackAddrs = append(loopbackAddrs, ipAddr)
 | |
| 		} else if isPrivateIP(ipAddr) {
 | |
| 			privateAddrs = append(privateAddrs, ipAddr)
 | |
| 		} else {
 | |
| 			publicAddrs = append(publicAddrs, ipAddr)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if len(privateAddrs) > 0 {
 | |
| 		return privateAddrs[0], nil
 | |
| 	} else if len(publicAddrs) > 0 {
 | |
| 		return publicAddrs[0], nil
 | |
| 	} else if len(loopbackAddrs) > 0 {
 | |
| 		return loopbackAddrs[0], nil
 | |
| 	}
 | |
| 
 | |
| 	return "", fmt.Errorf("No IP address found, and explicit IP not provided")
 | |
| }
 | |
| 
 | |
| // IPs returns all known ips
 | |
| func IPs() []string {
 | |
| 	return localIPs()
 | |
| }
 |