interfaces_linux.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. //go:build !android
  4. package netmon
  5. import (
  6. "bufio"
  7. "bytes"
  8. "errors"
  9. "fmt"
  10. "io"
  11. "log"
  12. "net"
  13. "net/netip"
  14. "os"
  15. "strings"
  16. "sync/atomic"
  17. "github.com/jsimonetti/rtnetlink"
  18. "github.com/mdlayher/netlink"
  19. "go4.org/mem"
  20. "golang.org/x/sys/unix"
  21. "tailscale.com/feature/buildfeatures"
  22. "tailscale.com/net/netaddr"
  23. "tailscale.com/util/lineiter"
  24. )
  25. func init() {
  26. likelyHomeRouterIP = likelyHomeRouterIPLinux
  27. }
  28. var procNetRouteErr atomic.Bool
  29. /*
  30. Parse 10.0.0.1 out of:
  31. $ cat /proc/net/route
  32. Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
  33. ens18 00000000 0100000A 0003 0 0 0 00000000 0 0 0
  34. ens18 0000000A 00000000 0001 0 0 0 0000FFFF 0 0 0
  35. */
  36. func likelyHomeRouterIPLinux() (ret netip.Addr, myIP netip.Addr, ok bool) {
  37. if !buildfeatures.HasPortMapper {
  38. return
  39. }
  40. if procNetRouteErr.Load() {
  41. // If we failed to read /proc/net/route previously, don't keep trying.
  42. return ret, myIP, false
  43. }
  44. lineNum := 0
  45. var f []mem.RO
  46. for lr := range lineiter.File(procNetRoutePath) {
  47. line, err := lr.Value()
  48. if err != nil {
  49. procNetRouteErr.Store(true)
  50. log.Printf("interfaces: failed to read /proc/net/route: %v", err)
  51. return ret, myIP, false
  52. }
  53. lineNum++
  54. if lineNum == 1 {
  55. // Skip header line.
  56. continue
  57. }
  58. if lineNum > maxProcNetRouteRead {
  59. break
  60. }
  61. f = mem.AppendFields(f[:0], mem.B(line))
  62. if len(f) < 4 {
  63. continue
  64. }
  65. gwHex, flagsHex := f[2], f[3]
  66. flags, err := mem.ParseUint(flagsHex, 16, 16)
  67. if err != nil {
  68. continue // ignore error, skip line and keep going
  69. }
  70. if flags&(unix.RTF_UP|unix.RTF_GATEWAY) != unix.RTF_UP|unix.RTF_GATEWAY {
  71. continue
  72. }
  73. ipu32, err := mem.ParseUint(gwHex, 16, 32)
  74. if err != nil {
  75. continue // ignore error, skip line and keep going
  76. }
  77. ip := netaddr.IPv4(byte(ipu32), byte(ipu32>>8), byte(ipu32>>16), byte(ipu32>>24))
  78. if ip.IsPrivate() {
  79. ret = ip
  80. break
  81. }
  82. }
  83. if ret.IsValid() {
  84. // Try to get the local IP of the interface associated with
  85. // this route to short-circuit finding the IP associated with
  86. // this gateway. This isn't fatal if it fails.
  87. if len(f) > 0 && !disableLikelyHomeRouterIPSelf() {
  88. ForeachInterface(func(ni Interface, pfxs []netip.Prefix) {
  89. // Ensure this is the same interface
  90. if !f[0].EqualString(ni.Name) {
  91. return
  92. }
  93. // Find the first IPv4 address and use it.
  94. for _, pfx := range pfxs {
  95. if addr := pfx.Addr(); addr.Is4() {
  96. myIP = addr
  97. break
  98. }
  99. }
  100. })
  101. }
  102. return ret, myIP, true
  103. }
  104. if lineNum >= maxProcNetRouteRead {
  105. // If we went over our line limit without finding an answer, assume
  106. // we're a big fancy Linux router (or at least not a home system)
  107. // and set the error bit so we stop trying this in the future (and wasting CPU).
  108. // See https://github.com/tailscale/tailscale/issues/7621.
  109. //
  110. // Remember that "likelyHomeRouterIP" exists purely to find the port
  111. // mapping service (UPnP, PMP, PCP) often present on a home router. If we hit
  112. // the route (line) limit without finding an answer, we're unlikely to ever
  113. // find one in the future.
  114. procNetRouteErr.Store(true)
  115. }
  116. return netip.Addr{}, netip.Addr{}, false
  117. }
  118. func defaultRoute() (d DefaultRouteDetails, err error) {
  119. v, err := defaultRouteInterfaceProcNet()
  120. if err == nil {
  121. d.InterfaceName = v
  122. return d, nil
  123. }
  124. // Issue 4038: the default route (such as on Unifi UDM Pro)
  125. // might be in a non-default table, so it won't show up in
  126. // /proc/net/route. Use netlink to find the default route.
  127. //
  128. // TODO(bradfitz): this allocates a fair bit. We should track
  129. // this in net/interfaces/monitor instead and have
  130. // interfaces.GetState take a netmon.Monitor or similar so the
  131. // routing table can be cached and the monitor's existing
  132. // subscription to route changes can update the cached state,
  133. // rather than querying the whole thing every time like
  134. // defaultRouteFromNetlink does.
  135. //
  136. // Then we should just always try to use the cached route
  137. // table from netlink every time, and only use /proc/net/route
  138. // as a fallback for weird environments where netlink might be
  139. // banned but /proc/net/route is emulated (e.g. stuff like
  140. // Cloud Run?).
  141. return defaultRouteFromNetlink()
  142. }
  143. func defaultRouteFromNetlink() (d DefaultRouteDetails, err error) {
  144. c, err := rtnetlink.Dial(&netlink.Config{Strict: true})
  145. if err != nil {
  146. return d, fmt.Errorf("defaultRouteFromNetlink: Dial: %w", err)
  147. }
  148. defer c.Close()
  149. rms, err := c.Route.List()
  150. if err != nil {
  151. return d, fmt.Errorf("defaultRouteFromNetlink: List: %w", err)
  152. }
  153. for _, rm := range rms {
  154. if rm.Attributes.Gateway == nil {
  155. // A default route has a gateway. If it doesn't, skip it.
  156. continue
  157. }
  158. if rm.Attributes.Dst != nil {
  159. // A default route has a nil destination to mean anything
  160. // so ignore any route for a specific destination.
  161. // TODO(bradfitz): better heuristic?
  162. // empirically this seems like enough.
  163. continue
  164. }
  165. // TODO(bradfitz): care about address family, if
  166. // callers ever start caring about v4-vs-v6 default
  167. // route differences.
  168. idx := int(rm.Attributes.OutIface)
  169. if idx == 0 {
  170. continue
  171. }
  172. if iface, err := net.InterfaceByIndex(idx); err == nil {
  173. d.InterfaceName = iface.Name
  174. d.InterfaceIndex = idx
  175. return d, nil
  176. }
  177. }
  178. return d, errNoDefaultRoute
  179. }
  180. var zeroRouteBytes = []byte("00000000")
  181. var procNetRoutePath = "/proc/net/route"
  182. // maxProcNetRouteRead is the max number of lines to read from
  183. // /proc/net/route looking for a default route.
  184. const maxProcNetRouteRead = 1000
  185. var errNoDefaultRoute = errors.New("no default route found")
  186. func defaultRouteInterfaceProcNetInternal(bufsize int) (string, error) {
  187. f, err := os.Open(procNetRoutePath)
  188. if err != nil {
  189. return "", err
  190. }
  191. defer f.Close()
  192. br := bufio.NewReaderSize(f, bufsize)
  193. lineNum := 0
  194. for {
  195. lineNum++
  196. line, err := br.ReadSlice('\n')
  197. if err == io.EOF || lineNum > maxProcNetRouteRead {
  198. return "", errNoDefaultRoute
  199. }
  200. if err != nil {
  201. return "", err
  202. }
  203. if !bytes.Contains(line, zeroRouteBytes) {
  204. continue
  205. }
  206. fields := strings.Fields(string(line))
  207. ifc := fields[0]
  208. ip := fields[1]
  209. netmask := fields[7]
  210. if strings.HasPrefix(ifc, "tailscale") ||
  211. strings.HasPrefix(ifc, "wg") {
  212. continue
  213. }
  214. if ip == "00000000" && netmask == "00000000" {
  215. // default route
  216. return ifc, nil // interface name
  217. }
  218. }
  219. }
  220. // returns string interface name and an error.
  221. // io.EOF: full route table processed, no default route found.
  222. // other io error: something went wrong reading the route file.
  223. func defaultRouteInterfaceProcNet() (string, error) {
  224. rc, err := defaultRouteInterfaceProcNetInternal(128)
  225. if rc == "" && (errors.Is(err, io.EOF) || err == nil) {
  226. // https://github.com/google/gvisor/issues/5732
  227. // On a regular Linux kernel you can read the first 128 bytes of /proc/net/route,
  228. // then come back later to read the next 128 bytes and so on.
  229. //
  230. // In Google Cloud Run, where /proc/net/route comes from gVisor, you have to
  231. // read it all at once. If you read only the first few bytes then the second
  232. // read returns 0 bytes no matter how much originally appeared to be in the file.
  233. //
  234. // At the time of this writing (Mar 2021) Google Cloud Run has eth0 and eth1
  235. // with a 384 byte /proc/net/route. We allocate a large buffer to ensure we'll
  236. // read it all in one call.
  237. return defaultRouteInterfaceProcNetInternal(4096)
  238. }
  239. return rc, err
  240. }