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 }