netmon_darwin.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package netmon
  4. import (
  5. "fmt"
  6. "net/netip"
  7. "strings"
  8. "sync"
  9. "golang.org/x/net/route"
  10. "golang.org/x/sys/unix"
  11. "tailscale.com/net/netaddr"
  12. "tailscale.com/types/logger"
  13. )
  14. const debugRouteMessages = false
  15. // unspecifiedMessage is a minimal message implementation that should not
  16. // be ignored. In general, OS-specific implementations should use better
  17. // types and avoid this if they can.
  18. type unspecifiedMessage struct{}
  19. func (unspecifiedMessage) ignore() bool { return false }
  20. func newOSMon(logf logger.Logf, _ *Monitor) (osMon, error) {
  21. fd, err := unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, 0)
  22. if err != nil {
  23. return nil, err
  24. }
  25. return &darwinRouteMon{
  26. logf: logf,
  27. fd: fd,
  28. }, nil
  29. }
  30. type darwinRouteMon struct {
  31. logf logger.Logf
  32. fd int // AF_ROUTE socket
  33. buf [2 << 10]byte
  34. closeOnce sync.Once
  35. }
  36. func (m *darwinRouteMon) Close() error {
  37. var err error
  38. m.closeOnce.Do(func() {
  39. err = unix.Close(m.fd)
  40. })
  41. return err
  42. }
  43. func (m *darwinRouteMon) Receive() (message, error) {
  44. for {
  45. n, err := unix.Read(m.fd, m.buf[:])
  46. if err != nil {
  47. return nil, err
  48. }
  49. msgs, err := route.ParseRIB(route.RIBTypeRoute, m.buf[:n])
  50. if err != nil {
  51. if debugRouteMessages {
  52. m.logf("read %d bytes (% 02x), failed to parse RIB: %v", n, m.buf[:n], err)
  53. }
  54. return unspecifiedMessage{}, nil
  55. }
  56. if len(msgs) == 0 {
  57. if debugRouteMessages {
  58. m.logf("read %d bytes with no messages (% 02x)", n, m.buf[:n])
  59. }
  60. continue
  61. }
  62. nSkip := 0
  63. for _, msg := range msgs {
  64. if m.skipMessage(msg) {
  65. nSkip++
  66. }
  67. }
  68. if debugRouteMessages {
  69. m.logf("read %d bytes, %d messages (%d skipped)", n, len(msgs), nSkip)
  70. if nSkip < len(msgs) {
  71. m.logMessages(msgs)
  72. }
  73. }
  74. if nSkip == len(msgs) {
  75. continue
  76. }
  77. return unspecifiedMessage{}, nil
  78. }
  79. }
  80. func (m *darwinRouteMon) skipMessage(msg route.Message) bool {
  81. switch msg := msg.(type) {
  82. case *route.InterfaceMulticastAddrMessage:
  83. return true
  84. case *route.InterfaceAddrMessage:
  85. return m.skipInterfaceAddrMessage(msg)
  86. case *route.RouteMessage:
  87. return m.skipRouteMessage(msg)
  88. }
  89. return false
  90. }
  91. // addrType returns addrs[rtaxType], if that (the route address type) exists,
  92. // else it returns nil.
  93. //
  94. // The RTAX_* constants at https://github.com/apple/darwin-xnu/blob/main/bsd/net/route.h
  95. // for what each address index represents.
  96. func addrType(addrs []route.Addr, rtaxType int) route.Addr {
  97. if len(addrs) > rtaxType {
  98. return addrs[rtaxType]
  99. }
  100. return nil
  101. }
  102. func (m *darwinRouteMon) IsInterestingInterface(iface string) bool {
  103. baseName := strings.TrimRight(iface, "0123456789")
  104. switch baseName {
  105. // TODO(maisem): figure out what this list should actually be.
  106. case "llw", "awdl", "ipsec":
  107. return false
  108. }
  109. return true
  110. }
  111. func (m *darwinRouteMon) skipInterfaceAddrMessage(msg *route.InterfaceAddrMessage) bool {
  112. if la, ok := addrType(msg.Addrs, unix.RTAX_IFP).(*route.LinkAddr); ok {
  113. if !m.IsInterestingInterface(la.Name) {
  114. return true
  115. }
  116. }
  117. return false
  118. }
  119. func (m *darwinRouteMon) skipRouteMessage(msg *route.RouteMessage) bool {
  120. if ip := ipOfAddr(addrType(msg.Addrs, unix.RTAX_DST)); ip.IsLinkLocalUnicast() {
  121. // Skip those like:
  122. // dst = fe80::b476:66ff:fe30:c8f6%15
  123. return true
  124. }
  125. return false
  126. }
  127. func (m *darwinRouteMon) logMessages(msgs []route.Message) {
  128. for i, msg := range msgs {
  129. switch msg := msg.(type) {
  130. default:
  131. m.logf(" [%d] %T", i, msg)
  132. case *route.InterfaceAddrMessage:
  133. m.logf(" [%d] InterfaceAddrMessage: ver=%d, type=%v, flags=0x%x, idx=%v",
  134. i, msg.Version, msg.Type, msg.Flags, msg.Index)
  135. m.logAddrs(msg.Addrs)
  136. case *route.InterfaceMulticastAddrMessage:
  137. m.logf(" [%d] InterfaceMulticastAddrMessage: ver=%d, type=%v, flags=0x%x, idx=%v",
  138. i, msg.Version, msg.Type, msg.Flags, msg.Index)
  139. m.logAddrs(msg.Addrs)
  140. case *route.RouteMessage:
  141. m.logf(" [%d] RouteMessage: ver=%d, type=%v, flags=0x%x, idx=%v, id=%v, seq=%v, err=%v",
  142. i, msg.Version, msg.Type, msg.Flags, msg.Index, msg.ID, msg.Seq, msg.Err)
  143. m.logAddrs(msg.Addrs)
  144. }
  145. }
  146. }
  147. func (m *darwinRouteMon) logAddrs(addrs []route.Addr) {
  148. for i, a := range addrs {
  149. if a == nil {
  150. continue
  151. }
  152. m.logf(" %v = %v", rtaxName(i), fmtAddr(a))
  153. }
  154. }
  155. // ipOfAddr returns the route.Addr (possibly nil) as a netip.Addr
  156. // (possibly zero).
  157. func ipOfAddr(a route.Addr) netip.Addr {
  158. switch a := a.(type) {
  159. case *route.Inet4Addr:
  160. return netaddr.IPv4(a.IP[0], a.IP[1], a.IP[2], a.IP[3])
  161. case *route.Inet6Addr:
  162. ip := netip.AddrFrom16(a.IP)
  163. if a.ZoneID != 0 {
  164. ip = ip.WithZone(fmt.Sprint(a.ZoneID)) // TODO: look up net.InterfaceByIndex? but it might be changing?
  165. }
  166. return ip
  167. }
  168. return netip.Addr{}
  169. }
  170. func fmtAddr(a route.Addr) any {
  171. if a == nil {
  172. return nil
  173. }
  174. if ip := ipOfAddr(a); ip.IsValid() {
  175. return ip
  176. }
  177. switch a := a.(type) {
  178. case *route.LinkAddr:
  179. return fmt.Sprintf("[LinkAddr idx=%v name=%q addr=%x]", a.Index, a.Name, a.Addr)
  180. default:
  181. return fmt.Sprintf("%T: %+v", a, a)
  182. }
  183. }
  184. // See https://github.com/apple/darwin-xnu/blob/main/bsd/net/route.h
  185. func rtaxName(i int) string {
  186. switch i {
  187. case unix.RTAX_DST:
  188. return "dst"
  189. case unix.RTAX_GATEWAY:
  190. return "gateway"
  191. case unix.RTAX_NETMASK:
  192. return "netmask"
  193. case unix.RTAX_GENMASK:
  194. return "genmask"
  195. case unix.RTAX_IFP: // "interface name sockaddr present"
  196. return "IFP"
  197. case unix.RTAX_IFA: // "interface addr sockaddr present"
  198. return "IFA"
  199. case unix.RTAX_AUTHOR:
  200. return "author"
  201. case unix.RTAX_BRD:
  202. return "BRD"
  203. }
  204. return fmt.Sprint(i)
  205. }