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  }