github.com/volts-dev/volts@v0.0.0-20240120094013-5e9c65924106/internal/addr/addr.go (about)

     1  package addr
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  )
     7  
     8  var (
     9  	privateBlocks []*net.IPNet
    10  )
    11  
    12  func init() {
    13  	for _, b := range []string{"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "100.64.0.0/10", "fd00::/8"} {
    14  		if _, block, err := net.ParseCIDR(b); err == nil {
    15  			privateBlocks = append(privateBlocks, block)
    16  		}
    17  	}
    18  }
    19  
    20  // AppendPrivateBlocks append private network blocks
    21  func AppendPrivateBlocks(bs ...string) {
    22  	for _, b := range bs {
    23  		if _, block, err := net.ParseCIDR(b); err == nil {
    24  			privateBlocks = append(privateBlocks, block)
    25  		}
    26  	}
    27  }
    28  
    29  func isPrivateIP(ipAddr string) bool {
    30  	ip := net.ParseIP(ipAddr)
    31  	for _, priv := range privateBlocks {
    32  		if priv.Contains(ip) {
    33  			return true
    34  		}
    35  	}
    36  	return false
    37  }
    38  
    39  // IsLocal tells us whether an ip is local
    40  func IsLocal(addr string) bool {
    41  	// extract the host
    42  	host, _, err := net.SplitHostPort(addr)
    43  	if err == nil {
    44  		addr = host
    45  	}
    46  
    47  	// check if its localhost
    48  	if addr == "localhost" {
    49  		return true
    50  	}
    51  
    52  	// check against all local ips
    53  	for _, ip := range IPs() {
    54  		if addr == ip {
    55  			return true
    56  		}
    57  	}
    58  
    59  	return false
    60  }
    61  
    62  // Extract returns a real ip
    63  func Extract(addr string) (string, error) {
    64  	// if addr specified then its returned
    65  	if len(addr) > 0 && (addr != "0.0.0.0" && addr != "[::]" && addr != "::") {
    66  		return addr, nil
    67  	}
    68  
    69  	ifaces, err := net.Interfaces()
    70  	if err != nil {
    71  		return "", fmt.Errorf("Failed to get interfaces! Err: %v", err)
    72  	}
    73  
    74  	//nolint:prealloc
    75  	var addrs []net.Addr
    76  	var loAddrs []net.Addr
    77  	for _, iface := range ifaces {
    78  		ifaceAddrs, err := iface.Addrs()
    79  		if err != nil {
    80  			// ignore error, interface can disappear from system
    81  			continue
    82  		}
    83  		if iface.Flags&net.FlagLoopback != 0 {
    84  			loAddrs = append(loAddrs, ifaceAddrs...)
    85  			continue
    86  		}
    87  		addrs = append(addrs, ifaceAddrs...)
    88  	}
    89  	addrs = append(addrs, loAddrs...)
    90  
    91  	var ipAddr string
    92  	var publicIP string
    93  
    94  	for _, rawAddr := range addrs {
    95  		var ip net.IP
    96  		switch addr := rawAddr.(type) {
    97  		case *net.IPAddr:
    98  			ip = addr.IP
    99  		case *net.IPNet:
   100  			ip = addr.IP
   101  		default:
   102  			continue
   103  		}
   104  
   105  		if !isPrivateIP(ip.String()) {
   106  			publicIP = ip.String()
   107  			continue
   108  		}
   109  
   110  		ipAddr = ip.String()
   111  		break
   112  	}
   113  
   114  	// return private ip
   115  	if len(ipAddr) > 0 {
   116  		a := net.ParseIP(ipAddr)
   117  		if a == nil {
   118  			return "", fmt.Errorf("ip addr %s is invalid", ipAddr)
   119  		}
   120  		return a.String(), nil
   121  	}
   122  
   123  	// return public or virtual ip
   124  	if len(publicIP) > 0 {
   125  		a := net.ParseIP(publicIP)
   126  		if a == nil {
   127  			return "", fmt.Errorf("ip addr %s is invalid", publicIP)
   128  		}
   129  		return a.String(), nil
   130  	}
   131  
   132  	return "", fmt.Errorf("No IP address found, and explicit IP not provided")
   133  }
   134  
   135  // IPs returns all known ips
   136  func IPs() []string {
   137  	ifaces, err := net.Interfaces()
   138  	if err != nil {
   139  		return nil
   140  	}
   141  
   142  	var ipAddrs []string
   143  
   144  	for _, i := range ifaces {
   145  		addrs, err := i.Addrs()
   146  		if err != nil {
   147  			continue
   148  		}
   149  
   150  		for _, addr := range addrs {
   151  			var ip net.IP
   152  			switch v := addr.(type) {
   153  			case *net.IPNet:
   154  				ip = v.IP
   155  			case *net.IPAddr:
   156  				ip = v.IP
   157  			}
   158  
   159  			if ip == nil {
   160  				continue
   161  			}
   162  
   163  			// dont skip ipv6 addrs
   164  			/*
   165  				ip = ip.To4()
   166  				if ip == nil {
   167  					continue
   168  				}
   169  			*/
   170  
   171  			ipAddrs = append(ipAddrs, ip.String())
   172  		}
   173  	}
   174  
   175  	return ipAddrs
   176  }