interfaces_linux.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. // Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package interfaces
  5. import (
  6. "bufio"
  7. "bytes"
  8. "errors"
  9. "fmt"
  10. "io"
  11. "log"
  12. "os"
  13. "os/exec"
  14. "runtime"
  15. "strings"
  16. "go4.org/mem"
  17. "inet.af/netaddr"
  18. "tailscale.com/syncs"
  19. "tailscale.com/util/lineread"
  20. )
  21. func init() {
  22. likelyHomeRouterIP = likelyHomeRouterIPLinux
  23. }
  24. var procNetRouteErr syncs.AtomicBool
  25. /*
  26. Parse 10.0.0.1 out of:
  27. $ cat /proc/net/route
  28. Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
  29. ens18 00000000 0100000A 0003 0 0 0 00000000 0 0 0
  30. ens18 0000000A 00000000 0001 0 0 0 0000FFFF 0 0 0
  31. */
  32. func likelyHomeRouterIPLinux() (ret netaddr.IP, ok bool) {
  33. if procNetRouteErr.Get() {
  34. // If we failed to read /proc/net/route previously, don't keep trying.
  35. // But if we're on Android, go into the Android path.
  36. if runtime.GOOS == "android" {
  37. return likelyHomeRouterIPAndroid()
  38. }
  39. return ret, false
  40. }
  41. lineNum := 0
  42. var f []mem.RO
  43. err := lineread.File("/proc/net/route", func(line []byte) error {
  44. lineNum++
  45. if lineNum == 1 {
  46. // Skip header line.
  47. return nil
  48. }
  49. f = mem.AppendFields(f[:0], mem.B(line))
  50. if len(f) < 4 {
  51. return nil
  52. }
  53. gwHex, flagsHex := f[2], f[3]
  54. flags, err := mem.ParseUint(flagsHex, 16, 16)
  55. if err != nil {
  56. return nil // ignore error, skip line and keep going
  57. }
  58. const RTF_UP = 0x0001
  59. const RTF_GATEWAY = 0x0002
  60. if flags&(RTF_UP|RTF_GATEWAY) != RTF_UP|RTF_GATEWAY {
  61. return nil
  62. }
  63. ipu32, err := mem.ParseUint(gwHex, 16, 32)
  64. if err != nil {
  65. return nil // ignore error, skip line and keep going
  66. }
  67. ip := netaddr.IPv4(byte(ipu32), byte(ipu32>>8), byte(ipu32>>16), byte(ipu32>>24))
  68. if isPrivateIP(ip) {
  69. ret = ip
  70. }
  71. return nil
  72. })
  73. if err != nil {
  74. procNetRouteErr.Set(true)
  75. if runtime.GOOS == "android" {
  76. return likelyHomeRouterIPAndroid()
  77. }
  78. log.Printf("interfaces: failed to read /proc/net/route: %v", err)
  79. }
  80. return ret, !ret.IsZero()
  81. }
  82. // Android apps don't have permission to read /proc/net/route, at
  83. // least on Google devices and the Android emulator.
  84. func likelyHomeRouterIPAndroid() (ret netaddr.IP, ok bool) {
  85. cmd := exec.Command("/system/bin/ip", "route", "show", "table", "0")
  86. out, err := cmd.StdoutPipe()
  87. if err != nil {
  88. return
  89. }
  90. if err := cmd.Start(); err != nil {
  91. log.Printf("interfaces: running /system/bin/ip: %v", err)
  92. return
  93. }
  94. // Search for line like "default via 10.0.2.2 dev radio0 table 1016 proto static mtu 1500 "
  95. lineread.Reader(out, func(line []byte) error {
  96. const pfx = "default via "
  97. if !mem.HasPrefix(mem.B(line), mem.S(pfx)) {
  98. return nil
  99. }
  100. line = line[len(pfx):]
  101. sp := bytes.IndexByte(line, ' ')
  102. if sp == -1 {
  103. return nil
  104. }
  105. ipb := line[:sp]
  106. if ip, err := netaddr.ParseIP(string(ipb)); err == nil && ip.Is4() {
  107. ret = ip
  108. log.Printf("interfaces: found Android default route %v", ip)
  109. }
  110. return nil
  111. })
  112. cmd.Process.Kill()
  113. cmd.Wait()
  114. return ret, !ret.IsZero()
  115. }
  116. // DefaultRouteInterface returns the name of the network interface that owns
  117. // the default route, not including any tailscale interfaces.
  118. func DefaultRouteInterface() (string, error) {
  119. v, err := defaultRouteInterfaceProcNet()
  120. if err == nil {
  121. return v, nil
  122. }
  123. if runtime.GOOS == "android" {
  124. return defaultRouteInterfaceAndroidIPRoute()
  125. }
  126. return v, err
  127. }
  128. var zeroRouteBytes = []byte("00000000")
  129. var procNetRoutePath = "/proc/net/route"
  130. func defaultRouteInterfaceProcNetInternal(bufsize int) (string, error) {
  131. f, err := os.Open(procNetRoutePath)
  132. if err != nil {
  133. return "", err
  134. }
  135. defer f.Close()
  136. br := bufio.NewReaderSize(f, bufsize)
  137. for {
  138. line, err := br.ReadSlice('\n')
  139. if err == io.EOF {
  140. return "", fmt.Errorf("no default routes found: %w", err)
  141. }
  142. if err != nil {
  143. return "", err
  144. }
  145. if !bytes.Contains(line, zeroRouteBytes) {
  146. continue
  147. }
  148. fields := strings.Fields(string(line))
  149. ifc := fields[0]
  150. ip := fields[1]
  151. netmask := fields[7]
  152. if strings.HasPrefix(ifc, "tailscale") ||
  153. strings.HasPrefix(ifc, "wg") {
  154. continue
  155. }
  156. if ip == "00000000" && netmask == "00000000" {
  157. // default route
  158. return ifc, nil // interface name
  159. }
  160. }
  161. }
  162. // returns string interface name and an error.
  163. // io.EOF: full route table processed, no default route found.
  164. // other io error: something went wrong reading the route file.
  165. func defaultRouteInterfaceProcNet() (string, error) {
  166. rc, err := defaultRouteInterfaceProcNetInternal(128)
  167. if rc == "" && (errors.Is(err, io.EOF) || err == nil) {
  168. // https://github.com/google/gvisor/issues/5732
  169. // On a regular Linux kernel you can read the first 128 bytes of /proc/net/route,
  170. // then come back later to read the next 128 bytes and so on.
  171. //
  172. // In Google Cloud Run, where /proc/net/route comes from gVisor, you have to
  173. // read it all at once. If you read only the first few bytes then the second
  174. // read returns 0 bytes no matter how much originally appeared to be in the file.
  175. //
  176. // At the time of this writing (Mar 2021) Google Cloud Run has eth0 and eth1
  177. // with a 384 byte /proc/net/route. We allocate a large buffer to ensure we'll
  178. // read it all in one call.
  179. return defaultRouteInterfaceProcNetInternal(4096)
  180. }
  181. return rc, err
  182. }
  183. // defaultRouteInterfaceAndroidIPRoute tries to find the machine's default route interface name
  184. // by parsing the "ip route" command output. We use this on Android where /proc/net/route
  185. // can be missing entries or have locked-down permissions.
  186. // See also comments in https://github.com/tailscale/tailscale/pull/666.
  187. func defaultRouteInterfaceAndroidIPRoute() (ifname string, err error) {
  188. cmd := exec.Command("/system/bin/ip", "route", "show", "table", "0")
  189. out, err := cmd.StdoutPipe()
  190. if err != nil {
  191. return "", err
  192. }
  193. if err := cmd.Start(); err != nil {
  194. log.Printf("interfaces: running /system/bin/ip: %v", err)
  195. return "", err
  196. }
  197. // Search for line like "default via 10.0.2.2 dev radio0 table 1016 proto static mtu 1500 "
  198. lineread.Reader(out, func(line []byte) error {
  199. const pfx = "default via "
  200. if !mem.HasPrefix(mem.B(line), mem.S(pfx)) {
  201. return nil
  202. }
  203. ff := strings.Fields(string(line))
  204. for i, v := range ff {
  205. if i > 0 && ff[i-1] == "dev" && ifname == "" {
  206. ifname = v
  207. }
  208. }
  209. return nil
  210. })
  211. cmd.Process.Kill()
  212. cmd.Wait()
  213. if ifname == "" {
  214. return "", errors.New("no default routes found")
  215. }
  216. return ifname, nil
  217. }