interfaces_android.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package netmon
  4. import (
  5. "bytes"
  6. "log"
  7. "net/netip"
  8. "os/exec"
  9. "sync/atomic"
  10. "go4.org/mem"
  11. "golang.org/x/sys/unix"
  12. "tailscale.com/net/netaddr"
  13. "tailscale.com/syncs"
  14. "tailscale.com/util/lineiter"
  15. )
  16. var (
  17. lastKnownDefaultRouteIfName syncs.AtomicValue[string]
  18. )
  19. var procNetRoutePath = "/proc/net/route"
  20. // maxProcNetRouteRead is the max number of lines to read from
  21. // /proc/net/route looking for a default route.
  22. const maxProcNetRouteRead = 1000
  23. func init() {
  24. likelyHomeRouterIP = likelyHomeRouterIPAndroid
  25. }
  26. var procNetRouteErr atomic.Bool
  27. /*
  28. Parse 10.0.0.1 out of:
  29. $ cat /proc/net/route
  30. Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
  31. ens18 00000000 0100000A 0003 0 0 0 00000000 0 0 0
  32. ens18 0000000A 00000000 0001 0 0 0 0000FFFF 0 0 0
  33. */
  34. func likelyHomeRouterIPAndroid() (ret netip.Addr, myIP netip.Addr, ok bool) {
  35. if procNetRouteErr.Load() {
  36. // If we failed to read /proc/net/route previously, don't keep trying.
  37. return likelyHomeRouterIPHelper()
  38. }
  39. lineNum := 0
  40. var f []mem.RO
  41. for lr := range lineiter.File(procNetRoutePath) {
  42. line, err := lr.Value()
  43. if err != nil {
  44. procNetRouteErr.Store(true)
  45. return likelyHomeRouterIP()
  46. }
  47. lineNum++
  48. if lineNum == 1 {
  49. // Skip header line.
  50. continue
  51. }
  52. if lineNum > maxProcNetRouteRead {
  53. break
  54. }
  55. f = mem.AppendFields(f[:0], mem.B(line))
  56. if len(f) < 4 {
  57. continue
  58. }
  59. gwHex, flagsHex := f[2], f[3]
  60. flags, err := mem.ParseUint(flagsHex, 16, 16)
  61. if err != nil {
  62. continue // ignore error, skip line and keep going
  63. }
  64. if flags&(unix.RTF_UP|unix.RTF_GATEWAY) != unix.RTF_UP|unix.RTF_GATEWAY {
  65. continue
  66. }
  67. ipu32, err := mem.ParseUint(gwHex, 16, 32)
  68. if err != nil {
  69. continue // ignore error, skip line and keep going
  70. }
  71. ip := netaddr.IPv4(byte(ipu32), byte(ipu32>>8), byte(ipu32>>16), byte(ipu32>>24))
  72. if ip.IsPrivate() {
  73. ret = ip
  74. break
  75. }
  76. }
  77. if ret.IsValid() {
  78. // Try to get the local IP of the interface associated with
  79. // this route to short-circuit finding the IP associated with
  80. // this gateway. This isn't fatal if it fails.
  81. if len(f) > 0 && !disableLikelyHomeRouterIPSelf() {
  82. ForeachInterface(func(ni Interface, pfxs []netip.Prefix) {
  83. // Ensure this is the same interface
  84. if !f[0].EqualString(ni.Name) {
  85. return
  86. }
  87. // Find the first IPv4 address and use it.
  88. for _, pfx := range pfxs {
  89. if addr := pfx.Addr(); addr.Is4() {
  90. myIP = addr
  91. break
  92. }
  93. }
  94. })
  95. }
  96. return ret, myIP, true
  97. }
  98. if lineNum >= maxProcNetRouteRead {
  99. // If we went over our line limit without finding an answer, assume
  100. // we're a big fancy Linux router (or at least not a home system)
  101. // and set the error bit so we stop trying this in the future (and wasting CPU).
  102. // See https://github.com/tailscale/tailscale/issues/7621.
  103. //
  104. // Remember that "likelyHomeRouterIP" exists purely to find the port
  105. // mapping service (UPnP, PMP, PCP) often present on a home router. If we hit
  106. // the route (line) limit without finding an answer, we're unlikely to ever
  107. // find one in the future.
  108. procNetRouteErr.Store(true)
  109. }
  110. return netip.Addr{}, netip.Addr{}, false
  111. }
  112. // Android apps don't have permission to read /proc/net/route, at
  113. // least on Google devices and the Android emulator.
  114. func likelyHomeRouterIPHelper() (ret netip.Addr, _ netip.Addr, ok bool) {
  115. cmd := exec.Command("/system/bin/ip", "route", "show", "table", "0")
  116. out, err := cmd.StdoutPipe()
  117. if err != nil {
  118. return
  119. }
  120. if err := cmd.Start(); err != nil {
  121. log.Printf("interfaces: running /system/bin/ip: %v", err)
  122. return
  123. }
  124. // Search for line like "default via 10.0.2.2 dev radio0 table 1016 proto static mtu 1500 "
  125. for lr := range lineiter.Reader(out) {
  126. line, err := lr.Value()
  127. if err != nil {
  128. break
  129. }
  130. const pfx = "default via "
  131. if !mem.HasPrefix(mem.B(line), mem.S(pfx)) {
  132. continue
  133. }
  134. line = line[len(pfx):]
  135. sp := bytes.IndexByte(line, ' ')
  136. if sp == -1 {
  137. continue
  138. }
  139. ipb := line[:sp]
  140. if ip, err := netip.ParseAddr(string(ipb)); err == nil && ip.Is4() {
  141. ret = ip
  142. log.Printf("interfaces: found Android default route %v", ip)
  143. }
  144. }
  145. cmd.Process.Kill()
  146. cmd.Wait()
  147. return ret, netip.Addr{}, ret.IsValid()
  148. }
  149. // UpdateLastKnownDefaultRouteInterface is called by libtailscale in the Android app when
  150. // the connectivity manager detects a network path transition. If ifName is "", network has been lost.
  151. // After updating the interface, Android calls Monitor.InjectEvent(), triggering a link change.
  152. func UpdateLastKnownDefaultRouteInterface(ifName string) {
  153. if old := lastKnownDefaultRouteIfName.Swap(ifName); old != ifName {
  154. log.Printf("defaultroute: update from Android, ifName = %s (was %s)", ifName, old)
  155. }
  156. }
  157. func defaultRoute() (d DefaultRouteDetails, err error) {
  158. if ifName := lastKnownDefaultRouteIfName.Load(); ifName != "" {
  159. d.InterfaceName = ifName
  160. }
  161. return d, nil
  162. }