// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
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
}