magicsock, interfaces: move some code from magicsock to interfaces

pull/122/head
Brad Fitzpatrick 5 years ago
parent af7a01d6f0
commit bc7bc43fb8

@ -45,8 +45,9 @@ func HaveIPv6GlobalAddress() (bool, error) {
if err != nil { if err != nil {
return false, err return false, err
} }
for _, iface := range ifs { for i := range ifs {
if isLoopbackInterfaceName(iface.Name) { iface := &ifs[i]
if !isUp(iface) || isLoopback(iface) {
continue continue
} }
addrs, err := iface.Addrs() addrs, err := iface.Addrs()
@ -67,10 +68,6 @@ func HaveIPv6GlobalAddress() (bool, error) {
return false, nil return false, nil
} }
func isLoopbackInterfaceName(s string) bool {
return strings.HasPrefix(s, "lo")
}
// maybeTailscaleInterfaceName reports whether s is an interface // maybeTailscaleInterfaceName reports whether s is an interface
// name that might be used by Tailscale. // name that might be used by Tailscale.
func maybeTailscaleInterfaceName(s string) bool { func maybeTailscaleInterfaceName(s string) bool {
@ -86,6 +83,60 @@ func IsTailscaleIP(ip net.IP) bool {
return cgNAT.Contains(ip) return cgNAT.Contains(ip)
} }
func isUp(nif *net.Interface) bool { return nif.Flags&net.FlagUp != 0 }
func isLoopback(nif *net.Interface) bool { return nif.Flags&net.FlagLoopback != 0 }
// LocalAddresses returns the machine's IP addresses, separated by
// whether they're loopback addresses.
func LocalAddresses() (regular, loopback []string, err error) {
// TODO(crawshaw): don't serve interface addresses that we are routing
ifaces, err := net.Interfaces()
if err != nil {
return nil, nil, err
}
for i := range ifaces {
iface := &ifaces[i]
if !isUp(iface) {
// Down interfaces don't count
continue
}
ifcIsLoopback := isLoopback(iface)
addrs, err := iface.Addrs()
if err != nil {
return nil, nil, err
}
for _, a := range addrs {
switch v := a.(type) {
case *net.IPNet:
// TODO(crawshaw): IPv6 support.
// Easy to do here, but we need good endpoint ordering logic.
ip := v.IP.To4()
if ip == nil {
continue
}
// TODO(apenwarr): don't special case cgNAT.
// In the general wireguard case, it might
// very well be something we can route to
// directly, because both nodes are
// behind the same CGNAT router.
if cgNAT.Contains(ip) {
continue
}
if linkLocalIPv4.Contains(ip) {
continue
}
if ip.IsLoopback() || ifcIsLoopback {
loopback = append(loopback, ip.String())
} else {
regular = append(regular, ip.String())
}
}
}
}
return regular, loopback, nil
}
var cgNAT = func() *net.IPNet { var cgNAT = func() *net.IPNet {
_, ipNet, err := net.ParseCIDR("100.64.0.0/10") _, ipNet, err := net.ParseCIDR("100.64.0.0/10")
if err != nil { if err != nil {
@ -93,3 +144,11 @@ var cgNAT = func() *net.IPNet {
} }
return ipNet return ipNet
}() }()
var linkLocalIPv4 = func() *net.IPNet {
_, ipNet, err := net.ParseCIDR("169.254.0.0/16")
if err != nil {
panic(err)
}
return ipNet
}()

@ -27,6 +27,7 @@ import (
"golang.org/x/time/rate" "golang.org/x/time/rate"
"tailscale.com/derp" "tailscale.com/derp"
"tailscale.com/derp/derphttp" "tailscale.com/derp/derphttp"
"tailscale.com/interfaces"
"tailscale.com/stun" "tailscale.com/stun"
"tailscale.com/stunner" "tailscale.com/stunner"
"tailscale.com/types/key" "tailscale.com/types/key"
@ -242,21 +243,21 @@ func (c *Conn) determineEndpoints(ctx context.Context) ([]string, error) {
c.ignoreSTUNPackets() c.ignoreSTUNPackets()
if localAddr := c.pconn.LocalAddr(); localAddr.IP.IsUnspecified() { if localAddr := c.pconn.LocalAddr(); localAddr.IP.IsUnspecified() {
localPort := fmt.Sprintf("%d", localAddr.Port) ips, loopback, err := interfaces.LocalAddresses()
loopbacks, err := localAddresses(localPort, func(s string) {
addAddr(s, "localAddresses")
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
if len(eps) == 0 { reason := "localAddresses"
if len(ips) == 0 {
// Only include loopback addresses if we have no // Only include loopback addresses if we have no
// interfaces at all to use as endpoints. This allows // interfaces at all to use as endpoints. This allows
// for localhost testing when you're on a plane and // for localhost testing when you're on a plane and
// offline, for example. // offline, for example.
for _, s := range loopbacks { ips = loopback
addAddr(s, "loopback") reason = "loopback"
} }
for _, ipStr := range ips {
addAddr(net.JoinHostPort(ipStr, fmt.Sprint(localAddr.Port)), reason)
} }
} else { } else {
// Our local endpoint is bound to a particular address. // Our local endpoint is bound to a particular address.
@ -289,73 +290,6 @@ func stringsEqual(x, y []string) bool {
return true return true
} }
func localAddresses(localPort string, addAddr func(s string)) ([]string, error) {
var loopback []string
// TODO(crawshaw): don't serve interface addresses that we are routing
ifaces, err := net.Interfaces()
if err != nil {
return nil, err
}
for _, i := range ifaces {
if (i.Flags & net.FlagUp) == 0 {
// Down interfaces don't count
continue
}
ifcIsLoopback := (i.Flags & net.FlagLoopback) != 0
addrs, err := i.Addrs()
if err != nil {
return nil, err
}
for _, a := range addrs {
switch v := a.(type) {
case *net.IPNet:
// TODO(crawshaw): IPv6 support.
// Easy to do here, but we need good endpoint ordering logic.
ip := v.IP.To4()
if ip == nil {
continue
}
// TODO(apenwarr): don't special case cgNAT.
// In the general wireguard case, it might
// very well be something we can route to
// directly, because both nodes are
// behind the same CGNAT router.
if cgNAT.Contains(ip) {
continue
}
if linkLocalIPv4.Contains(ip) {
continue
}
ep := net.JoinHostPort(ip.String(), localPort)
if ip.IsLoopback() || ifcIsLoopback {
loopback = append(loopback, ep)
continue
}
addAddr(ep)
}
}
}
return loopback, nil
}
var cgNAT = func() *net.IPNet {
_, ipNet, err := net.ParseCIDR("100.64.0.0/10")
if err != nil {
panic(err)
}
return ipNet
}()
var linkLocalIPv4 = func() *net.IPNet {
_, ipNet, err := net.ParseCIDR("169.254.0.0/16")
if err != nil {
panic(err)
}
return ipNet
}()
func (c *Conn) LocalPort() uint16 { func (c *Conn) LocalPort() uint16 {
laddr := c.pconn.LocalAddr() laddr := c.pconn.LocalAddr()
return uint16(laddr.Port) return uint16(laddr.Port)

Loading…
Cancel
Save