@ -161,10 +161,11 @@ type State struct {
InterfaceUp map [ string ] bool
InterfaceUp map [ string ] bool
// HaveV6Global is whether this machine has an IPv6 global address
// HaveV6Global is whether this machine has an IPv6 global address
// on some interface.
// on some non-Tailscale interface that's up .
HaveV6Global bool
HaveV6Global bool
// HaveV4 is whether the machine has some non-localhost IPv4 address.
// HaveV4 is whether the machine has some non-localhost,
// non-link-local IPv4 address on a non-Tailscale interface that's up.
HaveV4 bool
HaveV4 bool
// IsExpensive is whether the current network interface is
// IsExpensive is whether the current network interface is
@ -174,6 +175,8 @@ type State struct {
// DefaultRouteInterface is the interface name for the machine's default route.
// DefaultRouteInterface is the interface name for the machine's default route.
// It is not yet populated on all OSes.
// It is not yet populated on all OSes.
// Its exact value should not be assumed to be a map key for
// the Interface maps above; it's only used for debugging.
DefaultRouteInterface string
DefaultRouteInterface string
// HTTPProxy is the HTTP proxy to use.
// HTTPProxy is the HTTP proxy to use.
@ -244,20 +247,29 @@ func (s *State) Equal(s2 *State) bool {
func ( s * State ) HasPAC ( ) bool { return s != nil && s . PAC != "" }
func ( s * State ) HasPAC ( ) bool { return s != nil && s . PAC != "" }
// AnyInterfaceUp reports whether any interface seems like it has Internet access.
func ( s * State ) AnyInterfaceUp ( ) bool {
return s != nil && ( s . HaveV4 || s . HaveV6Global )
}
// RemoveTailscaleInterfaces modifes s to remove any interfaces that
// RemoveTailscaleInterfaces modifes s to remove any interfaces that
// are owned by this process. (TODO: make this true; currently it
// are owned by this process. (TODO: make this true; currently it
// makes the Linux-only assumption that the interface is named
// makes the Linux-only assumption that the interface is named
// /^tailscale/)
// /^tailscale/)
func ( s * State ) RemoveTailscaleInterfaces ( ) {
func ( s * State ) RemoveTailscaleInterfaces ( ) {
for name := range s . InterfaceIPs {
for name := range s . InterfaceIPs {
if name == "Tailscale" || // as it is on Windows
if isTailscaleInterfaceName ( name ) {
strings . HasPrefix ( name , "tailscale" ) { // TODO: use --tun flag value, etc; see TODO in method doc
delete ( s . InterfaceIPs , name )
delete ( s . InterfaceIPs , name )
delete ( s . InterfaceUp , name )
delete ( s . InterfaceUp , name )
}
}
}
}
}
}
func isTailscaleInterfaceName ( name string ) bool {
return name == "Tailscale" || // as it is on Windows
strings . HasPrefix ( name , "tailscale" ) // TODO: use --tun flag value, etc; see TODO in method doc
}
// getPAC, if non-nil, returns the current PAC file URL.
// getPAC, if non-nil, returns the current PAC file URL.
var getPAC func ( ) string
var getPAC func ( ) string
@ -270,15 +282,19 @@ func GetState() (*State, error) {
InterfaceUp : make ( map [ string ] bool ) ,
InterfaceUp : make ( map [ string ] bool ) ,
}
}
if err := ForeachInterfaceAddress ( func ( ni Interface , ip netaddr . IP ) {
if err := ForeachInterfaceAddress ( func ( ni Interface , ip netaddr . IP ) {
ifUp := ni . IsUp ( )
s . InterfaceIPs [ ni . Name ] = append ( s . InterfaceIPs [ ni . Name ] , ip )
s . InterfaceIPs [ ni . Name ] = append ( s . InterfaceIPs [ ni . Name ] , ip )
s . InterfaceUp [ ni . Name ] = ni . IsUp ( )
s . InterfaceUp [ ni . Name ] = ifUp
if ifUp && ! ip . IsLoopback ( ) && ! ip . IsLinkLocalUnicast ( ) && ! isTailscaleInterfaceName ( ni . Name ) {
s . HaveV6Global = s . HaveV6Global || isGlobalV6 ( ip )
s . HaveV6Global = s . HaveV6Global || isGlobalV6 ( ip )
s . HaveV4 = s . HaveV4 || ( ip . Is4 ( ) && ! ip . IsLoopback ( ) )
s . HaveV4 = s . HaveV4 || ip . Is4 ( )
}
} ) ; err != nil {
} ) ; err != nil {
return nil , err
return nil , err
}
}
s . DefaultRouteInterface , _ = DefaultRouteInterface ( )
s . DefaultRouteInterface , _ = DefaultRouteInterface ( )
if s . AnyInterfaceUp ( ) {
req , err := http . NewRequest ( "GET" , LoginEndpointForProxyDetermination , nil )
req , err := http . NewRequest ( "GET" , LoginEndpointForProxyDetermination , nil )
if err != nil {
if err != nil {
return nil , err
return nil , err
@ -289,6 +305,7 @@ func GetState() (*State, error) {
if getPAC != nil {
if getPAC != nil {
s . PAC = getPAC ( )
s . PAC = getPAC ( )
}
}
}
return s , nil
return s , nil
}
}