// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package ipaddr import ( "fmt" "net" ) // GetPrivateIPv4 returns the list of private network IPv4 addresses on // all active interfaces. func GetPrivateIPv4() ([]*net.IPAddr, error) { addresses, err := activeInterfaceAddresses() if err != nil { return nil, fmt.Errorf("Failed to get interface addresses: %v", err) } var addrs []*net.IPAddr for _, rawAddr := range addresses { var ip net.IP switch addr := rawAddr.(type) { case *net.IPAddr: ip = addr.IP case *net.IPNet: ip = addr.IP default: continue } if ip.To4() == nil { continue } if !isPrivate(ip) { continue } addrs = append(addrs, &net.IPAddr{IP: ip}) } return addrs, nil } // GetPublicIPv6 returns the list of all public IPv6 addresses // on all active interfaces. func GetPublicIPv6() ([]*net.IPAddr, error) { addresses, err := net.InterfaceAddrs() if err != nil { return nil, fmt.Errorf("Failed to get interface addresses: %v", err) } var addrs []*net.IPAddr for _, rawAddr := range addresses { var ip net.IP switch addr := rawAddr.(type) { case *net.IPAddr: ip = addr.IP case *net.IPNet: ip = addr.IP default: continue } if ip.To4() != nil { continue } if isPrivate(ip) { continue } addrs = append(addrs, &net.IPAddr{IP: ip}) } return addrs, nil } // privateBlocks contains non-forwardable address blocks which are used // for private networks. RFC 6890 provides an overview of special // address blocks. var privateBlocks = []*net.IPNet{ parseCIDR("10.0.0.0/8"), // RFC 1918 IPv4 private network address parseCIDR("100.64.0.0/10"), // RFC 6598 IPv4 shared address space parseCIDR("127.0.0.0/8"), // RFC 1122 IPv4 loopback address parseCIDR("169.254.0.0/16"), // RFC 3927 IPv4 link local address parseCIDR("172.16.0.0/12"), // RFC 1918 IPv4 private network address parseCIDR("192.0.0.0/24"), // RFC 6890 IPv4 IANA address parseCIDR("192.0.2.0/24"), // RFC 5737 IPv4 documentation address parseCIDR("192.168.0.0/16"), // RFC 1918 IPv4 private network address parseCIDR("::1/128"), // RFC 1884 IPv6 loopback address parseCIDR("fe80::/10"), // RFC 4291 IPv6 link local addresses parseCIDR("fc00::/7"), // RFC 4193 IPv6 unique local addresses parseCIDR("fec0::/10"), // RFC 1884 IPv6 site-local addresses parseCIDR("2001:db8::/32"), // RFC 3849 IPv6 documentation address } func parseCIDR(s string) *net.IPNet { _, block, err := net.ParseCIDR(s) if err != nil { panic(fmt.Sprintf("Bad CIDR %s: %s", s, err)) } return block } func isPrivate(ip net.IP) bool { for _, priv := range privateBlocks { if priv.Contains(ip) { return true } } return false } // Returns addresses from interfaces that is up func activeInterfaceAddresses() ([]net.Addr, error) { var upAddrs []net.Addr var loAddrs []net.Addr interfaces, err := net.Interfaces() if err != nil { return nil, fmt.Errorf("Failed to get interfaces: %v", err) } for _, iface := range interfaces { // Require interface to be up if iface.Flags&net.FlagUp == 0 { continue } addresses, err := iface.Addrs() if err != nil { return nil, fmt.Errorf("Failed to get interface addresses: %v", err) } if iface.Flags&net.FlagLoopback != 0 { loAddrs = append(loAddrs, addresses...) continue } upAddrs = append(upAddrs, addresses...) } if len(upAddrs) == 0 { return loAddrs, nil } return upAddrs, nil }