summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--net/interfaces/interfaces_darwin.go110
-rw-r--r--net/interfaces/interfaces_darwin_cgo.go126
-rw-r--r--net/interfaces/interfaces_darwin_cgo_test.go20
-rw-r--r--net/interfaces/interfaces_darwin_nocgo.go11
-rw-r--r--net/interfaces/interfaces_darwin_test.go86
5 files changed, 133 insertions, 220 deletions
diff --git a/net/interfaces/interfaces_darwin.go b/net/interfaces/interfaces_darwin.go
index 9d0f0526f..72173e122 100644
--- a/net/interfaces/interfaces_darwin.go
+++ b/net/interfaces/interfaces_darwin.go
@@ -7,76 +7,15 @@ package interfaces
import (
"errors"
"fmt"
+ "log"
"net"
- "os/exec"
"syscall"
- "go4.org/mem"
"golang.org/x/net/route"
+ "golang.org/x/sys/unix"
"inet.af/netaddr"
- "tailscale.com/util/lineread"
- "tailscale.com/version"
)
-/*
-Parse out 10.0.0.1 from:
-
-$ netstat -r -n -f inet
-Routing tables
-
-Internet:
-Destination Gateway Flags Netif Expire
-default 10.0.0.1 UGSc en0
-default link#14 UCSI utun2
-10/16 link#4 UCS en0 !
-10.0.0.1/32 link#4 UCS en0 !
-...
-
-*/
-func likelyHomeRouterIPDarwinExec() (ret netaddr.IP, ok bool) {
- if version.IsMobile() {
- // Don't try to do subprocesses on iOS. Ends up with log spam like:
- // kernel: "Sandbox: IPNExtension(86580) deny(1) process-fork"
- // This is why we have likelyHomeRouterIPDarwinSyscall.
- return ret, false
- }
- cmd := exec.Command("/usr/sbin/netstat", "-r", "-n", "-f", "inet")
- stdout, err := cmd.StdoutPipe()
- if err != nil {
- return
- }
- if err := cmd.Start(); err != nil {
- return
- }
- defer cmd.Wait()
-
- var f []mem.RO
- lineread.Reader(stdout, func(lineb []byte) error {
- line := mem.B(lineb)
- if !mem.Contains(line, mem.S("default")) {
- return nil
- }
- f = mem.AppendFields(f[:0], line)
- if len(f) < 3 || !f[0].EqualString("default") {
- return nil
- }
- ipm, flagsm := f[1], f[2]
- if !mem.Contains(flagsm, mem.S("G")) {
- return nil
- }
- ip, err := netaddr.ParseIP(string(mem.Append(nil, ipm)))
- if err == nil && isPrivateIP(ip) {
- ret = ip
- // We've found what we're looking for.
- return errStopReadingNetstatTable
- }
- return nil
- })
- return ret, !ret.IsZero()
-}
-
-var errStopReadingNetstatTable = errors.New("found private gateway")
-
func DefaultRouteInterface() (string, error) {
idx, err := DefaultRouteInterfaceIndex()
if err != nil {
@@ -138,3 +77,48 @@ func DefaultRouteInterfaceIndex() (int, error) {
}
return 0, fmt.Errorf("ambiguous gateway interfaces found: %v", indexSeen)
}
+
+func init() {
+ likelyHomeRouterIP = likelyHomeRouterIPDarwinFetchRIB
+}
+
+func likelyHomeRouterIPDarwinFetchRIB() (ret netaddr.IP, ok bool) {
+ rib, err := route.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_DUMP2, 0)
+ if err != nil {
+ log.Printf("routerIP/FetchRIB: %v", err)
+ return ret, false
+ }
+ msgs, err := route.ParseRIB(syscall.NET_RT_IFLIST2, rib)
+ if err != nil {
+ log.Printf("routerIP/ParseRIB: %v", err)
+ return ret, false
+ }
+ for _, m := range msgs {
+ rm, ok := m.(*route.RouteMessage)
+ if !ok {
+ continue
+ }
+ const RTF_GATEWAY = 0x2
+ const RTF_IFSCOPE = 0x1000000
+ if rm.Flags&RTF_GATEWAY == 0 {
+ continue
+ }
+ if rm.Flags&RTF_IFSCOPE != 0 {
+ continue
+ }
+ if len(rm.Addrs) > unix.RTAX_GATEWAY {
+ dst4, ok := rm.Addrs[unix.RTAX_DST].(*route.Inet4Addr)
+ if !ok || dst4.IP != ([4]byte{0, 0, 0, 0}) {
+ // Expect 0.0.0.0 as DST field.
+ continue
+ }
+ gw, ok := rm.Addrs[unix.RTAX_GATEWAY].(*route.Inet4Addr)
+ if !ok {
+ continue
+ }
+ return netaddr.IPv4(gw.IP[0], gw.IP[1], gw.IP[2], gw.IP[3]), true
+ }
+ }
+
+ return ret, false
+}
diff --git a/net/interfaces/interfaces_darwin_cgo.go b/net/interfaces/interfaces_darwin_cgo.go
deleted file mode 100644
index 91f245ca9..000000000
--- a/net/interfaces/interfaces_darwin_cgo.go
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build darwin,cgo
-
-package interfaces
-
-/*
-#import "route.h"
-#import <netinet/in.h>
-#import <sys/sysctl.h>
-#import <stdlib.h>
-#import <stdio.h>
-
-// privateGatewayIPFromRoute returns the private gateway ip address from rtm, if it exists.
-// Otherwise, it returns 0.
-uint32_t privateGatewayIPFromRoute(struct rt_msghdr2 *rtm)
-{
- // sockaddrs are after the message header
- struct sockaddr* dst_sa = (struct sockaddr *)(rtm + 1);
-
- if((rtm->rtm_addrs & (RTA_DST|RTA_GATEWAY)) != (RTA_DST|RTA_GATEWAY))
- return 0; // missing dst or gateway addr
- if (dst_sa->sa_family != AF_INET)
- return 0; // dst not IPv4
- if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
- return 0; // gateway flag not set
-
- struct sockaddr_in* dst_si = (struct sockaddr_in *)dst_sa;
- if (dst_si->sin_addr.s_addr != INADDR_ANY)
- return 0; // not default route
-
- #define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
-
- struct sockaddr* gateway_sa = (struct sockaddr *)((char *)dst_sa + ROUNDUP(dst_sa->sa_len));
- if (gateway_sa->sa_family != AF_INET)
- return 0; // gateway not IPv4
-
- struct sockaddr_in* gateway_si= (struct sockaddr_in *)gateway_sa;
- uint32_t ip;
- ip = gateway_si->sin_addr.s_addr;
-
- unsigned char a, b;
- a = (ip >> 0) & 0xff;
- b = (ip >> 8) & 0xff;
-
- // Check whether ip is private, that is, whether it is
- // in one of 10.0.0.0/8, 172.16.0.0/12, or 192.168.0.0/16.
- if (a == 10)
- return ip; // matches 10.0.0.0/8
- if (a == 172 && (b >> 4) == 1)
- return ip; // matches 172.16.0.0/12
- if (a == 192 && b == 168)
- return ip; // matches 192.168.0.0/16
-
- // Not a private IP.
- return 0;
-}
-
-// privateGatewayIP returns the private gateway IP address, if it exists.
-// If no private gateway IP address was found, it returns 0.
-// On an error, it returns an error code in (0, 255].
-// Any private gateway IP address is > 255.
-uint32_t privateGatewayIP()
-{
- size_t needed;
- int mib[6];
- char *buf;
-
- mib[0] = CTL_NET;
- mib[1] = PF_ROUTE;
- mib[2] = 0;
- mib[3] = 0;
- mib[4] = NET_RT_DUMP2;
- mib[5] = 0;
-
- if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
- return 1; // route dump size estimation failed
- if ((buf = malloc(needed)) == 0)
- return 2; // malloc failed
- if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
- free(buf);
- return 3; // route dump failed
- }
-
- // Loop over all routes.
- char *next, *lim;
- lim = buf + needed;
- struct rt_msghdr2 *rtm;
- for (next = buf; next < lim; next += rtm->rtm_msglen) {
- rtm = (struct rt_msghdr2 *)next;
- uint32_t ip;
- ip = privateGatewayIPFromRoute(rtm);
- if (ip) {
- free(buf);
- return ip;
- }
- }
- free(buf);
- return 0; // no gateway found
-}
-*/
-import "C"
-
-import (
- "encoding/binary"
- "log"
-
- "inet.af/netaddr"
-)
-
-func init() {
- likelyHomeRouterIP = likelyHomeRouterIPDarwinSyscall
-}
-
-func likelyHomeRouterIPDarwinSyscall() (ret netaddr.IP, ok bool) {
- ip := C.privateGatewayIP()
- if ip < 255 {
- log.Printf("likelyHomeRouterIPDarwinSyscall: error code %v", ip)
- return netaddr.IP{}, false
- }
- var q [4]byte
- binary.LittleEndian.PutUint32(q[:], uint32(ip))
- return netaddr.IPv4(q[0], q[1], q[2], q[3]), true
-}
diff --git a/net/interfaces/interfaces_darwin_cgo_test.go b/net/interfaces/interfaces_darwin_cgo_test.go
deleted file mode 100644
index 094732f27..000000000
--- a/net/interfaces/interfaces_darwin_cgo_test.go
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build cgo,darwin
-
-package interfaces
-
-import "testing"
-
-func TestLikelyHomeRouterIPSyscallExec(t *testing.T) {
- syscallIP, syscallOK := likelyHomeRouterIPDarwinSyscall()
- netstatIP, netstatOK := likelyHomeRouterIPDarwinExec()
- if syscallOK != netstatOK || syscallIP != netstatIP {
- t.Errorf("syscall() = %v, %v, netstat = %v, %v",
- syscallIP, syscallOK,
- netstatIP, netstatOK,
- )
- }
-}
diff --git a/net/interfaces/interfaces_darwin_nocgo.go b/net/interfaces/interfaces_darwin_nocgo.go
deleted file mode 100644
index da1db44e0..000000000
--- a/net/interfaces/interfaces_darwin_nocgo.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build darwin,!cgo
-
-package interfaces
-
-func init() {
- likelyHomeRouterIP = likelyHomeRouterIPDarwinExec
-}
diff --git a/net/interfaces/interfaces_darwin_test.go b/net/interfaces/interfaces_darwin_test.go
new file mode 100644
index 000000000..310a8266f
--- /dev/null
+++ b/net/interfaces/interfaces_darwin_test.go
@@ -0,0 +1,86 @@
+// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package interfaces
+
+import (
+ "errors"
+ "os/exec"
+ "testing"
+
+ "go4.org/mem"
+ "inet.af/netaddr"
+ "tailscale.com/util/lineread"
+ "tailscale.com/version"
+)
+
+func TestLikelyHomeRouterIPSyscallExec(t *testing.T) {
+ syscallIP, syscallOK := likelyHomeRouterIPDarwinFetchRIB()
+ netstatIP, netstatOK := likelyHomeRouterIPDarwinExec()
+ if syscallOK != netstatOK || syscallIP != netstatIP {
+ t.Errorf("syscall() = %v, %v, netstat = %v, %v",
+ syscallIP, syscallOK,
+ netstatIP, netstatOK,
+ )
+ }
+}
+
+/*
+Parse out 10.0.0.1 from:
+
+$ netstat -r -n -f inet
+Routing tables
+
+Internet:
+Destination Gateway Flags Netif Expire
+default 10.0.0.1 UGSc en0
+default link#14 UCSI utun2
+10/16 link#4 UCS en0 !
+10.0.0.1/32 link#4 UCS en0 !
+...
+
+*/
+func likelyHomeRouterIPDarwinExec() (ret netaddr.IP, ok bool) {
+ if version.IsMobile() {
+ // Don't try to do subprocesses on iOS. Ends up with log spam like:
+ // kernel: "Sandbox: IPNExtension(86580) deny(1) process-fork"
+ // This is why we have likelyHomeRouterIPDarwinSyscall.
+ return ret, false
+ }
+ cmd := exec.Command("/usr/sbin/netstat", "-r", "-n", "-f", "inet")
+ stdout, err := cmd.StdoutPipe()
+ if err != nil {
+ return
+ }
+ if err := cmd.Start(); err != nil {
+ return
+ }
+ defer cmd.Wait()
+
+ var f []mem.RO
+ lineread.Reader(stdout, func(lineb []byte) error {
+ line := mem.B(lineb)
+ if !mem.Contains(line, mem.S("default")) {
+ return nil
+ }
+ f = mem.AppendFields(f[:0], line)
+ if len(f) < 3 || !f[0].EqualString("default") {
+ return nil
+ }
+ ipm, flagsm := f[1], f[2]
+ if !mem.Contains(flagsm, mem.S("G")) {
+ return nil
+ }
+ ip, err := netaddr.ParseIP(string(mem.Append(nil, ipm)))
+ if err == nil && isPrivateIP(ip) {
+ ret = ip
+ // We've found what we're looking for.
+ return errStopReadingNetstatTable
+ }
+ return nil
+ })
+ return ret, !ret.IsZero()
+}
+
+var errStopReadingNetstatTable = errors.New("found private gateway")