@ -15,6 +15,7 @@ import (
"strings"
"inet.af/netaddr"
"tailscale.com/hostinfo"
"tailscale.com/net/tsaddr"
"tailscale.com/net/tshttpproxy"
)
@ -81,13 +82,16 @@ func isProblematicInterface(nif *net.Interface) bool {
}
// LocalAddresses returns the machine's IP addresses, separated by
// whether they're loopback addresses.
// whether they're loopback addresses. If there are no regular addresses
// it will return any IPv4 linklocal or IPv6 unique local addresses because we
// know of environments where these are used with NAT to provide connectivity.
func LocalAddresses ( ) ( regular , loopback [ ] netaddr . IP , err error ) {
// TODO(crawshaw): don't serve interface addresses that we are routing
ifaces , err := net . Interfaces ( )
if err != nil {
return nil , nil , err
}
var regular4 , regular6 , linklocal4 , ula6 [ ] netaddr . IP
for i := range ifaces {
iface := & ifaces [ i ]
if ! isUp ( iface ) || isProblematicInterface ( iface ) {
@ -117,17 +121,44 @@ func LocalAddresses() (regular, loopback []netaddr.IP, err error) {
if tsaddr . IsTailscaleIP ( ip ) {
continue
}
if ip . IsLinkLocalUnicast ( ) {
continue
}
if ip . IsLoopback ( ) || ifcIsLoopback {
loopback = append ( loopback , ip )
} else if ip . IsLinkLocalUnicast ( ) {
if ip . Is4 ( ) {
linklocal4 = append ( linklocal4 , ip )
}
// We know of no cases where the IPv6 fe80:: addresses
// are used to provide WAN connectivity. It is also very
// common for users to have no IPv6 WAN connectivity,
// but their OS supports IPv6 so they have an fe80::
// address. We don't want to report all of those
// IPv6 LL to Control.
} else if ip . Is6 ( ) && tsaddr . IsULA ( ip ) {
// Google Cloud Run uses NAT with IPv6 Unique
// Local Addresses to provide IPv6 connectivity.
ula6 = append ( ula6 , ip )
} else {
if ip . Is4 ( ) {
regular4 = append ( regular4 , ip )
} else {
regular = append ( regular , ip )
regular6 = append ( regular6 , ip )
}
}
}
}
}
if len ( regular4 ) == 0 && len ( regular6 ) == 0 {
// if we have no usable IP addresses then be willing to accept
// addresses we otherwise wouldn't, like:
// + 169.254.x.x (AWS Lambda uses NAT with these)
// + IPv6 ULA (Google Cloud Run uses these with address translation)
if hostinfo . GetEnvType ( ) == hostinfo . AWSLambda {
regular4 = linklocal4
}
regular6 = ula6
}
regular = append ( regular4 , regular6 ... )
sortIPs ( regular )
sortIPs ( loopback )
return regular , loopback , nil
@ -407,11 +438,11 @@ func GetState() (*State, error) {
return
}
for _ , pfx := range pfxs {
if pfx . IP ( ) . IsLoopback ( ) || pfx . IP ( ) . IsLinkLocalUnicast ( ) {
if pfx . IP ( ) . IsLoopback ( ) {
continue
}
s . HaveV6 = s . HaveV6 || isUsableV6 ( pfx . IP ( ) )
s . HaveV4 = s . HaveV4 || pfx . IP ( ) . Is4 ( )
s . HaveV4 = s . HaveV4 || isUsableV4 ( pfx . IP ( ) )
}
} ) ; err != nil {
return nil , err
@ -503,6 +534,24 @@ func isPrivateIP(ip netaddr.IP) bool {
return private1 . Contains ( ip ) || private2 . Contains ( ip ) || private3 . Contains ( ip )
}
// isUsableV4 reports whether ip is a usable IPv4 address which could
// conceivably be used to get Internet connectivity. Globally routable and
// private IPv4 addresses are always Usable, and link local 169.254.x.x
// addresses are in some environments.
func isUsableV4 ( ip netaddr . IP ) bool {
if ! ip . Is4 ( ) || ip . IsLoopback ( ) {
return false
}
if ip . IsLinkLocalUnicast ( ) {
return hostinfo . GetEnvType ( ) == hostinfo . AWSLambda
}
return true
}
// isUsableV6 reports whether ip is a usable IPv6 address which could
// conceivably be used to get Internet connectivity. Globally routable
// IPv6 addresses are always Usable, and Unique Local Addresses
// (fc00::/7) are in some environments used with address translation.
func isUsableV6 ( ip netaddr . IP ) bool {
return v6Global1 . Contains ( ip ) ||
( tsaddr . IsULA ( ip ) && ! tsaddr . TailscaleULARange ( ) . Contains ( ip ) )