cmd/tailscaled: add debug -portmap mode
"io"
"io/ioutil"
"log"
+ "net"
"net/http"
"net/http/httptrace"
"net/url"
"tailscale.com/derp/derphttp"
"tailscale.com/ipn"
"tailscale.com/net/interfaces"
+ "tailscale.com/net/portmapper"
"tailscale.com/net/tshttpproxy"
"tailscale.com/tailcfg"
"tailscale.com/types/key"
+ "tailscale.com/types/logger"
"tailscale.com/wgengine/monitor"
)
monitor bool
getURL string
derpCheck string
+ portmap bool
}
var debugModeFunc = debugMode // so it can be addressable
func debugMode(args []string) error {
fs := flag.NewFlagSet("debug", flag.ExitOnError)
fs.BoolVar(&debugArgs.monitor, "monitor", false, "If true, run link monitor forever. Precludes all other options.")
+ fs.BoolVar(&debugArgs.portmap, "portmap", false, "If true, run portmap debugging. Precludes all other options.")
fs.StringVar(&debugArgs.getURL, "get-url", "", "If non-empty, fetch provided URL.")
fs.StringVar(&debugArgs.derpCheck, "derp", "", "if non-empty, test a DERP ping via named region code")
if err := fs.Parse(args); err != nil {
@@ -55,6 +60,9 @@ func debugMode(args []string) error {
if debugArgs.monitor {
return runMonitor(ctx)
}
+ if debugArgs.portmap {
+ return debugPortmap(ctx)
+ }
if debugArgs.getURL != "" {
return getURL(ctx, debugArgs.getURL)
}
@@ -191,3 +199,63 @@ func checkDerp(ctx context.Context, derpRegion string) error {
log.Printf("ok")
return err
}
+
+func debugPortmap(ctx context.Context) error {
+ ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
+ defer cancel()
+
+ done := make(chan bool, 1)
+
+ var c *portmapper.Client
+ logf := log.Printf
+ c = portmapper.NewClient(logger.WithPrefix(logf, "portmapper: "), func() {
+ logf("portmapping changed.")
+ logf("have mapping: %v", c.HaveMapping())
+
+ if ext, ok := c.GetCachedMappingOrStartCreatingOne(); ok {
+ logf("cb: mapping: %v", ext)
+ select {
+ case done <- true:
+ default:
+ }
+ return
+ }
+ logf("cb: no mapping")
+ })
+ linkMon, err := monitor.New(logger.WithPrefix(logf, "monitor: "))
+ if err != nil {
+ return err
+ }
+ c.SetGatewayLookupFunc(linkMon.GatewayAndSelfIP)
+
+ res, err := c.Probe(ctx)
+ if err != nil {
+ return fmt.Errorf("Probe: %v", err)
+ }
+ logf("Probe: %+v", res)
+
+ if !res.PCP && !res.PMP && !res.UPnP {
+ logf("no portmapping services available")
+ return nil
+ }
+
+ uc, err := net.ListenPacket("udp", "0.0.0.0:0")
+ if err != nil {
+ return err
+ }
+ defer uc.Close()
+ c.SetLocalPort(uint16(uc.LocalAddr().(*net.UDPAddr).Port))
+
+ if ext, ok := c.GetCachedMappingOrStartCreatingOne(); ok {
+ logf("mapping: %v", ext)
+ } else {
+ logf("no mapping")
+ }
+
+ select {
+ case <-done:
+ return nil
+ case <-ctx.Done():
+ return ctx.Err()
+ }
+}
