interfaces_bsd.go 4.1 KB

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