interfaces_bsd.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. // Common code for FreeBSD and Darwin. This might also work on other
  4. // BSD systems (e.g. OpenBSD) but has not been tested.
  5. //go:build darwin || freebsd
  6. package interfaces
  7. import (
  8. "errors"
  9. "fmt"
  10. "log"
  11. "net"
  12. "net/netip"
  13. "syscall"
  14. "golang.org/x/net/route"
  15. "golang.org/x/sys/unix"
  16. "tailscale.com/net/netaddr"
  17. )
  18. func defaultRoute() (d DefaultRouteDetails, err error) {
  19. idx, err := DefaultRouteInterfaceIndex()
  20. if err != nil {
  21. return d, err
  22. }
  23. iface, err := net.InterfaceByIndex(idx)
  24. if err != nil {
  25. return d, err
  26. }
  27. d.InterfaceName = iface.Name
  28. d.InterfaceIndex = idx
  29. return d, nil
  30. }
  31. // ErrNoGatewayIndexFound is returned by DefaultRouteInterfaceIndex when no
  32. // default route is found.
  33. var ErrNoGatewayIndexFound = errors.New("no gateway index found")
  34. // DefaultRouteInterfaceIndex returns the index of the network interface that
  35. // owns the default route. It returns the first IPv4 or IPv6 default route it
  36. // finds (it does not prefer one or the other).
  37. func DefaultRouteInterfaceIndex() (int, error) {
  38. // $ netstat -nr
  39. // Routing tables
  40. // Internet:
  41. // Destination Gateway Flags Netif Expire
  42. // default 10.0.0.1 UGSc en0 <-- want this one
  43. // default 10.0.0.1 UGScI en1
  44. // From man netstat:
  45. // U RTF_UP Route usable
  46. // G RTF_GATEWAY Destination requires forwarding by intermediary
  47. // S RTF_STATIC Manually added
  48. // c RTF_PRCLONING Protocol-specified generate new routes on use
  49. // I RTF_IFSCOPE Route is associated with an interface scope
  50. rib, err := fetchRoutingTable()
  51. if err != nil {
  52. return 0, fmt.Errorf("route.FetchRIB: %w", err)
  53. }
  54. msgs, err := parseRoutingTable(rib)
  55. if err != nil {
  56. return 0, fmt.Errorf("route.ParseRIB: %w", err)
  57. }
  58. for _, m := range msgs {
  59. rm, ok := m.(*route.RouteMessage)
  60. if !ok {
  61. continue
  62. }
  63. if isDefaultGateway(rm) {
  64. if delegatedIndex, err := getDelegatedInterface(rm.Index); err == nil && delegatedIndex != 0 {
  65. return delegatedIndex, nil
  66. } else if err != nil {
  67. log.Printf("interfaces_bsd: could not get delegated interface: %v", err)
  68. }
  69. return rm.Index, nil
  70. }
  71. }
  72. return 0, ErrNoGatewayIndexFound
  73. }
  74. func init() {
  75. likelyHomeRouterIP = likelyHomeRouterIPBSDFetchRIB
  76. }
  77. func likelyHomeRouterIPBSDFetchRIB() (ret netip.Addr, ok bool) {
  78. rib, err := fetchRoutingTable()
  79. if err != nil {
  80. log.Printf("routerIP/FetchRIB: %v", err)
  81. return ret, false
  82. }
  83. msgs, err := parseRoutingTable(rib)
  84. if err != nil {
  85. log.Printf("routerIP/ParseRIB: %v", err)
  86. return ret, false
  87. }
  88. for _, m := range msgs {
  89. rm, ok := m.(*route.RouteMessage)
  90. if !ok {
  91. continue
  92. }
  93. if !isDefaultGateway(rm) {
  94. continue
  95. }
  96. gw, ok := rm.Addrs[unix.RTAX_GATEWAY].(*route.Inet4Addr)
  97. if !ok {
  98. continue
  99. }
  100. return netaddr.IPv4(gw.IP[0], gw.IP[1], gw.IP[2], gw.IP[3]), true
  101. }
  102. return ret, false
  103. }
  104. var v4default = [4]byte{0, 0, 0, 0}
  105. var v6default = [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
  106. func isDefaultGateway(rm *route.RouteMessage) bool {
  107. if rm.Flags&unix.RTF_GATEWAY == 0 {
  108. return false
  109. }
  110. // Defined locally because FreeBSD does not have unix.RTF_IFSCOPE.
  111. const RTF_IFSCOPE = 0x1000000
  112. if rm.Flags&RTF_IFSCOPE != 0 {
  113. return false
  114. }
  115. // Addrs is [RTAX_DST, RTAX_GATEWAY, RTAX_NETMASK, ...]
  116. if len(rm.Addrs) <= unix.RTAX_NETMASK {
  117. return false
  118. }
  119. dst := rm.Addrs[unix.RTAX_DST]
  120. netmask := rm.Addrs[unix.RTAX_NETMASK]
  121. if dst == nil || netmask == nil {
  122. return false
  123. }
  124. if dst.Family() == syscall.AF_INET && netmask.Family() == syscall.AF_INET {
  125. dstAddr, dstOk := dst.(*route.Inet4Addr)
  126. nmAddr, nmOk := netmask.(*route.Inet4Addr)
  127. if dstOk && nmOk && dstAddr.IP == v4default && nmAddr.IP == v4default {
  128. return true
  129. }
  130. }
  131. if dst.Family() == syscall.AF_INET6 && netmask.Family() == syscall.AF_INET6 {
  132. dstAddr, dstOk := dst.(*route.Inet6Addr)
  133. nmAddr, nmOk := netmask.(*route.Inet6Addr)
  134. if dstOk && nmOk && dstAddr.IP == v6default && nmAddr.IP == v6default {
  135. return true
  136. }
  137. }
  138. return false
  139. }