Просмотр исходного кода

net/interfaces: add FreeBSD default route lookup (portmapping, etc)

Updates #4101 (probably fixes)

Change-Id: I2b75ee3ced276fb7b211f17c382621cf1ef882fa
Signed-off-by: Brad Fitzpatrick <[email protected]>
Brad Fitzpatrick 4 лет назад
Родитель
Сommit
61cdcf4082
2 измененных файлов с 138 добавлено и 2 удалено
  1. 136 0
      net/interfaces/interfaces_bsd.go
  2. 2 2
      net/interfaces/interfaces_defaultrouteif_todo.go

+ 136 - 0
net/interfaces/interfaces_bsd.go

@@ -0,0 +1,136 @@
+// Copyright (c) 2022 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.
+
+// This might work on other BSDs, but only tested on FreeBSD.
+// Originally a fork of interfaces_darwin.go with slightly different flags.
+
+//go:build freebsd
+// +build freebsd
+
+package interfaces
+
+import (
+	"errors"
+	"fmt"
+	"log"
+	"net"
+	"syscall"
+
+	"golang.org/x/net/route"
+	"golang.org/x/sys/unix"
+	"inet.af/netaddr"
+)
+
+func defaultRoute() (d DefaultRouteDetails, err error) {
+	idx, err := DefaultRouteInterfaceIndex()
+	if err != nil {
+		return d, err
+	}
+	iface, err := net.InterfaceByIndex(idx)
+	if err != nil {
+		return d, err
+	}
+	d.InterfaceName = iface.Name
+	d.InterfaceIndex = idx
+	return d, nil
+}
+
+// fetchRoutingTable calls route.FetchRIB, fetching NET_RT_DUMP.
+func fetchRoutingTable() (rib []byte, err error) {
+	return route.FetchRIB(syscall.AF_UNSPEC, unix.NET_RT_DUMP, 0)
+}
+
+func DefaultRouteInterfaceIndex() (int, error) {
+	// $ netstat -nr
+	// Routing tables
+	// Internet:
+	// Destination        Gateway            Flags        Netif Expire
+	// default            10.0.0.1           UGSc           en0         <-- want this one
+	// default            10.0.0.1           UGScI          en1
+
+	// From man netstat:
+	// U       RTF_UP           Route usable
+	// G       RTF_GATEWAY      Destination requires forwarding by intermediary
+	// S       RTF_STATIC       Manually added
+	// c       RTF_PRCLONING    Protocol-specified generate new routes on use
+	// I       RTF_IFSCOPE      Route is associated with an interface scope
+
+	rib, err := fetchRoutingTable()
+	if err != nil {
+		return 0, fmt.Errorf("route.FetchRIB: %w", err)
+	}
+	msgs, err := route.ParseRIB(unix.NET_RT_IFLIST, rib)
+	if err != nil {
+		return 0, fmt.Errorf("route.ParseRIB: %w", err)
+	}
+	indexSeen := map[int]int{} // index => count
+	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
+		}
+		indexSeen[rm.Index]++
+	}
+	if len(indexSeen) == 0 {
+		return 0, errors.New("no gateway index found")
+	}
+	if len(indexSeen) == 1 {
+		for idx := range indexSeen {
+			return idx, nil
+		}
+	}
+	return 0, fmt.Errorf("ambiguous gateway interfaces found: %v", indexSeen)
+}
+
+func init() {
+	likelyHomeRouterIP = likelyHomeRouterIPBSDFetchRIB
+}
+
+func likelyHomeRouterIPBSDFetchRIB() (ret netaddr.IP, ok bool) {
+	rib, err := fetchRoutingTable()
+	if err != nil {
+		log.Printf("routerIP/FetchRIB: %v", err)
+		return ret, false
+	}
+	msgs, err := route.ParseRIB(unix.NET_RT_IFLIST, 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_IFSCOPE = 0x1000000
+		if rm.Flags&unix.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
+}

+ 2 - 2
net/interfaces/interfaces_defaultrouteif_todo.go

@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build !linux && !windows && !darwin
-// +build !linux,!windows,!darwin
+//go:build !linux && !windows && !darwin && !freebsd
+// +build !linux,!windows,!darwin,!freebsd
 
 package interfaces