github.com/aergoio/aergo@v1.3.1/internal/network/address.go (about) 1 /* 2 * @file 3 * @copyright defined in aergo/LICENSE.txt 4 */ 5 6 package network 7 8 import ( 9 "errors" 10 "fmt" 11 "net" 12 "regexp" 13 ) 14 15 type AddressType int 16 17 // AddressType 18 const ( 19 AddressTypeError AddressType = iota 20 AddressTypeIP 21 AddressTypeFQDN 22 ) 23 24 var privateIPBlocks []*net.IPNet 25 26 func init() { 27 for _, cidr := range []string{ 28 "127.0.0.0/8", // IPv4 loopback 29 "10.0.0.0/8", // RFC1918 30 "172.16.0.0/12", // RFC1918 31 "192.168.0.0/16", // RFC1918 32 "::1/128", // IPv6 loopback 33 "fe80::/10", // IPv6 link-local 34 "fc00::/7", // IPv6 link-local 35 } { 36 _, block, _ := net.ParseCIDR(cidr) 37 privateIPBlocks = append(privateIPBlocks, block) 38 } 39 } 40 41 // IGetSingleIPAddress find and get ip address of given address string. 42 // It return first ip if DNS or /etc/hosts has multiple IPs, or return err if no ip is found or addrStr is malformed. 43 func GetSingleIPAddress(addrStr string) (net.IP, error) { 44 switch CheckAddressType(addrStr) { 45 case AddressTypeFQDN: 46 ips, err := ResolveHostDomain(addrStr) 47 if err != nil { 48 return nil, err 49 } 50 return ips[0], nil 51 case AddressTypeIP: 52 return net.ParseIP(addrStr), nil 53 default: 54 return nil, InvalidAddress 55 } 56 } 57 58 // ResolveHostDomain look for ip addresses for the domainName. it return ip addresses if found one or more, or return err if not found any ip address 59 func ResolveHostDomain(domainName string) ([]net.IP, error) { 60 addrs, err := net.LookupHost(domainName) 61 if err != nil { 62 return nil, fmt.Errorf("Could not get IPs: %v\n", err) 63 } else if len(addrs) == 0 { 64 return nil, errors.New("Could not get IPs: no ip found.") 65 } 66 ips := make([]net.IP, len(addrs)) 67 for i, addr := range addrs { 68 ips[i] = net.ParseIP(addr) 69 } 70 return ips, nil 71 } 72 73 const ( 74 DN = `^([a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62}){1}(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*[\._]?$` 75 IPv4 = `^((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])` 76 IPv6 = `^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$` 77 ) 78 79 var ( 80 DNPattern = regexp.MustCompile(DN) 81 82 InvalidAddress = fmt.Errorf("invalid address") 83 ) 84 85 func CheckAddressType(urlStr string) AddressType { 86 if ip := net.ParseIP(urlStr); ip != nil { 87 return AddressTypeIP 88 } else if DNPattern.MatchString(urlStr) { 89 return AddressTypeFQDN 90 } else { 91 return AddressTypeError 92 } 93 } 94 95 func CheckAddress(urlStr string) (string, error) { 96 if ip := net.ParseIP(urlStr); ip != nil { 97 return urlStr, nil 98 } else if DNPattern.MatchString(urlStr) { 99 return urlStr, nil 100 } else { 101 return "", InvalidAddress 102 } 103 } 104 105 func IsExternalAddr(addrStr string) bool { 106 switch CheckAddressType(addrStr) { 107 case AddressTypeIP: 108 parsed := net.ParseIP(addrStr) 109 return !isPrivateIP(parsed) 110 case AddressTypeFQDN: 111 return true 112 default: 113 return false 114 } 115 } 116 117 func isPrivateIP(ip net.IP) bool { 118 for _, block := range privateIPBlocks { 119 if block.Contains(ip) { 120 return true 121 } 122 } 123 return false 124 }