debug.go 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  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. //go:build go1.18
  5. // +build go1.18
  6. package main
  7. import (
  8. "context"
  9. "crypto/tls"
  10. "encoding/json"
  11. "errors"
  12. "flag"
  13. "fmt"
  14. "io"
  15. "io/ioutil"
  16. "log"
  17. "net"
  18. "net/http"
  19. "net/http/httptrace"
  20. "net/url"
  21. "os"
  22. "strings"
  23. "time"
  24. "inet.af/netaddr"
  25. "tailscale.com/derp/derphttp"
  26. "tailscale.com/envknob"
  27. "tailscale.com/ipn"
  28. "tailscale.com/net/interfaces"
  29. "tailscale.com/net/portmapper"
  30. "tailscale.com/net/tshttpproxy"
  31. "tailscale.com/tailcfg"
  32. "tailscale.com/types/key"
  33. "tailscale.com/types/logger"
  34. "tailscale.com/wgengine/monitor"
  35. )
  36. var debugArgs struct {
  37. ifconfig bool // print network state once and exit
  38. monitor bool
  39. getURL string
  40. derpCheck string
  41. portmap bool
  42. }
  43. var debugModeFunc = debugMode // so it can be addressable
  44. func debugMode(args []string) error {
  45. fs := flag.NewFlagSet("debug", flag.ExitOnError)
  46. fs.BoolVar(&debugArgs.ifconfig, "ifconfig", false, "If true, print network interface state")
  47. fs.BoolVar(&debugArgs.monitor, "monitor", false, "If true, run link monitor forever. Precludes all other options.")
  48. fs.BoolVar(&debugArgs.portmap, "portmap", false, "If true, run portmap debugging. Precludes all other options.")
  49. fs.StringVar(&debugArgs.getURL, "get-url", "", "If non-empty, fetch provided URL.")
  50. fs.StringVar(&debugArgs.derpCheck, "derp", "", "if non-empty, test a DERP ping via named region code")
  51. if err := fs.Parse(args); err != nil {
  52. return err
  53. }
  54. if len(fs.Args()) > 0 {
  55. return errors.New("unknown non-flag debug subcommand arguments")
  56. }
  57. ctx := context.Background()
  58. if debugArgs.derpCheck != "" {
  59. return checkDerp(ctx, debugArgs.derpCheck)
  60. }
  61. if debugArgs.ifconfig {
  62. return runMonitor(ctx, false)
  63. }
  64. if debugArgs.monitor {
  65. return runMonitor(ctx, true)
  66. }
  67. if debugArgs.portmap {
  68. return debugPortmap(ctx)
  69. }
  70. if debugArgs.getURL != "" {
  71. return getURL(ctx, debugArgs.getURL)
  72. }
  73. return errors.New("only --monitor is available at the moment")
  74. }
  75. func runMonitor(ctx context.Context, loop bool) error {
  76. dump := func(st *interfaces.State) {
  77. j, _ := json.MarshalIndent(st, "", " ")
  78. os.Stderr.Write(j)
  79. }
  80. mon, err := monitor.New(log.Printf)
  81. if err != nil {
  82. return err
  83. }
  84. mon.RegisterChangeCallback(func(changed bool, st *interfaces.State) {
  85. if !changed {
  86. log.Printf("Link monitor fired; no change")
  87. return
  88. }
  89. log.Printf("Link monitor fired. New state:")
  90. dump(st)
  91. })
  92. if loop {
  93. log.Printf("Starting link change monitor; initial state:")
  94. }
  95. dump(mon.InterfaceState())
  96. if !loop {
  97. return nil
  98. }
  99. mon.Start()
  100. log.Printf("Started link change monitor; waiting...")
  101. select {}
  102. }
  103. func getURL(ctx context.Context, urlStr string) error {
  104. if urlStr == "login" {
  105. urlStr = "https://login.tailscale.com"
  106. }
  107. log.SetOutput(os.Stdout)
  108. ctx = httptrace.WithClientTrace(ctx, &httptrace.ClientTrace{
  109. GetConn: func(hostPort string) { log.Printf("GetConn(%q)", hostPort) },
  110. GotConn: func(info httptrace.GotConnInfo) { log.Printf("GotConn: %+v", info) },
  111. DNSStart: func(info httptrace.DNSStartInfo) { log.Printf("DNSStart: %+v", info) },
  112. DNSDone: func(info httptrace.DNSDoneInfo) { log.Printf("DNSDoneInfo: %+v", info) },
  113. TLSHandshakeStart: func() { log.Printf("TLSHandshakeStart") },
  114. TLSHandshakeDone: func(cs tls.ConnectionState, err error) { log.Printf("TLSHandshakeDone: %+v, %v", cs, err) },
  115. WroteRequest: func(info httptrace.WroteRequestInfo) { log.Printf("WroteRequest: %+v", info) },
  116. })
  117. req, err := http.NewRequestWithContext(ctx, "GET", urlStr, nil)
  118. if err != nil {
  119. return fmt.Errorf("http.NewRequestWithContext: %v", err)
  120. }
  121. proxyURL, err := tshttpproxy.ProxyFromEnvironment(req)
  122. if err != nil {
  123. return fmt.Errorf("tshttpproxy.ProxyFromEnvironment: %v", err)
  124. }
  125. log.Printf("proxy: %v", proxyURL)
  126. tr := &http.Transport{
  127. Proxy: func(*http.Request) (*url.URL, error) { return proxyURL, nil },
  128. ProxyConnectHeader: http.Header{},
  129. DisableKeepAlives: true,
  130. }
  131. if proxyURL != nil {
  132. auth, err := tshttpproxy.GetAuthHeader(proxyURL)
  133. if err == nil && auth != "" {
  134. tr.ProxyConnectHeader.Set("Proxy-Authorization", auth)
  135. }
  136. log.Printf("tshttpproxy.GetAuthHeader(%v) got: auth of %d bytes, err=%v", proxyURL, len(auth), err)
  137. const truncLen = 20
  138. if len(auth) > truncLen {
  139. auth = fmt.Sprintf("%s...(%d total bytes)", auth[:truncLen], len(auth))
  140. }
  141. if auth != "" {
  142. // We used log.Printf above (for timestamps).
  143. // Use fmt.Printf here instead just to appease
  144. // a security scanner, despite log.Printf only
  145. // going to stdout.
  146. fmt.Printf("... Proxy-Authorization = %q\n", auth)
  147. }
  148. }
  149. res, err := tr.RoundTrip(req)
  150. if err != nil {
  151. return fmt.Errorf("Transport.RoundTrip: %v", err)
  152. }
  153. defer res.Body.Close()
  154. return res.Write(os.Stdout)
  155. }
  156. func checkDerp(ctx context.Context, derpRegion string) error {
  157. req, err := http.NewRequestWithContext(ctx, "GET", ipn.DefaultControlURL+"/derpmap/default", nil)
  158. if err != nil {
  159. return fmt.Errorf("create derp map request: %w", err)
  160. }
  161. res, err := http.DefaultClient.Do(req)
  162. if err != nil {
  163. return fmt.Errorf("fetch derp map failed: %w", err)
  164. }
  165. defer res.Body.Close()
  166. b, err := ioutil.ReadAll(io.LimitReader(res.Body, 1<<20))
  167. if err != nil {
  168. return fmt.Errorf("fetch derp map failed: %w", err)
  169. }
  170. if res.StatusCode != 200 {
  171. return fmt.Errorf("fetch derp map: %v: %s", res.Status, b)
  172. }
  173. var dmap tailcfg.DERPMap
  174. if err = json.Unmarshal(b, &dmap); err != nil {
  175. return fmt.Errorf("fetch DERP map: %w", err)
  176. }
  177. getRegion := func() *tailcfg.DERPRegion {
  178. for _, r := range dmap.Regions {
  179. if r.RegionCode == derpRegion {
  180. return r
  181. }
  182. }
  183. for _, r := range dmap.Regions {
  184. log.Printf("Known region: %q", r.RegionCode)
  185. }
  186. log.Fatalf("unknown region %q", derpRegion)
  187. panic("unreachable")
  188. }
  189. priv1 := key.NewNode()
  190. priv2 := key.NewNode()
  191. c1 := derphttp.NewRegionClient(priv1, log.Printf, getRegion)
  192. c2 := derphttp.NewRegionClient(priv2, log.Printf, getRegion)
  193. c2.NotePreferred(true) // just to open it
  194. m, err := c2.Recv()
  195. log.Printf("c2 got %T, %v", m, err)
  196. t0 := time.Now()
  197. if err := c1.Send(priv2.Public(), []byte("hello")); err != nil {
  198. return err
  199. }
  200. fmt.Println(time.Since(t0))
  201. m, err = c2.Recv()
  202. log.Printf("c2 got %T, %v", m, err)
  203. if err != nil {
  204. return err
  205. }
  206. log.Printf("ok")
  207. return err
  208. }
  209. func debugPortmap(ctx context.Context) error {
  210. ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
  211. defer cancel()
  212. portmapper.VerboseLogs = true
  213. switch envknob.String("TS_DEBUG_PORTMAP_TYPE") {
  214. case "":
  215. case "pmp":
  216. portmapper.DisablePCP = true
  217. portmapper.DisableUPnP = true
  218. case "pcp":
  219. portmapper.DisablePMP = true
  220. portmapper.DisableUPnP = true
  221. case "upnp":
  222. portmapper.DisablePCP = true
  223. portmapper.DisablePMP = true
  224. default:
  225. log.Fatalf("TS_DEBUG_PORTMAP_TYPE must be one of pmp,pcp,upnp")
  226. }
  227. done := make(chan bool, 1)
  228. var c *portmapper.Client
  229. logf := log.Printf
  230. c = portmapper.NewClient(logger.WithPrefix(logf, "portmapper: "), func() {
  231. logf("portmapping changed.")
  232. logf("have mapping: %v", c.HaveMapping())
  233. if ext, ok := c.GetCachedMappingOrStartCreatingOne(); ok {
  234. logf("cb: mapping: %v", ext)
  235. select {
  236. case done <- true:
  237. default:
  238. }
  239. return
  240. }
  241. logf("cb: no mapping")
  242. })
  243. linkMon, err := monitor.New(logger.WithPrefix(logf, "monitor: "))
  244. if err != nil {
  245. return err
  246. }
  247. gatewayAndSelfIP := func() (gw, self netaddr.IP, ok bool) {
  248. if v := os.Getenv("TS_DEBUG_GW_SELF"); strings.Contains(v, "/") {
  249. i := strings.Index(v, "/")
  250. gw = netaddr.MustParseIP(v[:i])
  251. self = netaddr.MustParseIP(v[i+1:])
  252. return gw, self, true
  253. }
  254. return linkMon.GatewayAndSelfIP()
  255. }
  256. c.SetGatewayLookupFunc(gatewayAndSelfIP)
  257. gw, selfIP, ok := gatewayAndSelfIP()
  258. if !ok {
  259. logf("no gateway or self IP; %v", linkMon.InterfaceState())
  260. return nil
  261. }
  262. logf("gw=%v; self=%v", gw, selfIP)
  263. uc, err := net.ListenPacket("udp", "0.0.0.0:0")
  264. if err != nil {
  265. return err
  266. }
  267. defer uc.Close()
  268. c.SetLocalPort(uint16(uc.LocalAddr().(*net.UDPAddr).Port))
  269. res, err := c.Probe(ctx)
  270. if err != nil {
  271. return fmt.Errorf("Probe: %v", err)
  272. }
  273. logf("Probe: %+v", res)
  274. if !res.PCP && !res.PMP && !res.UPnP {
  275. logf("no portmapping services available")
  276. return nil
  277. }
  278. if ext, ok := c.GetCachedMappingOrStartCreatingOne(); ok {
  279. logf("mapping: %v", ext)
  280. } else {
  281. logf("no mapping")
  282. }
  283. select {
  284. case <-done:
  285. return nil
  286. case <-ctx.Done():
  287. return ctx.Err()
  288. }
  289. }