|
|
|
|
@ -228,55 +228,59 @@ func (h *Handler) serveDebugDERPRegion(w http.ResponseWriter, r *http.Request) { |
|
|
|
|
|
|
|
|
|
// Start by checking whether we can establish a HTTP connection
|
|
|
|
|
for _, derpNode := range reg.Nodes { |
|
|
|
|
connSuccess := checkConn(derpNode) |
|
|
|
|
if !derpNode.STUNOnly { |
|
|
|
|
connSuccess := checkConn(derpNode) |
|
|
|
|
|
|
|
|
|
// Verify that the /generate_204 endpoint works
|
|
|
|
|
captivePortalURL := fmt.Sprintf("http://%s/generate_204?t=%d", derpNode.HostName, time.Now().Unix()) |
|
|
|
|
req, err := http.NewRequest("GET", captivePortalURL, nil) |
|
|
|
|
if err != nil { |
|
|
|
|
st.Warnings = append(st.Warnings, fmt.Sprintf("Internal error creating request for captive portal check: %v", err)) |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
req.Header.Set("Cache-Control", "no-cache, no-store, must-revalidate, no-transform, max-age=0") |
|
|
|
|
resp, err := client.Do(req) |
|
|
|
|
if err != nil { |
|
|
|
|
st.Warnings = append(st.Warnings, fmt.Sprintf("Error making request to the captive portal check %q; is port 80 blocked?", captivePortalURL)) |
|
|
|
|
} else { |
|
|
|
|
resp.Body.Close() |
|
|
|
|
} |
|
|
|
|
// Verify that the /generate_204 endpoint works
|
|
|
|
|
captivePortalURL := fmt.Sprintf("http://%s/generate_204?t=%d", derpNode.HostName, time.Now().Unix()) |
|
|
|
|
req, err := http.NewRequest("GET", captivePortalURL, nil) |
|
|
|
|
if err != nil { |
|
|
|
|
st.Warnings = append(st.Warnings, fmt.Sprintf("Internal error creating request for captive portal check: %v", err)) |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
req.Header.Set("Cache-Control", "no-cache, no-store, must-revalidate, no-transform, max-age=0") |
|
|
|
|
resp, err := client.Do(req) |
|
|
|
|
if err != nil { |
|
|
|
|
st.Warnings = append(st.Warnings, fmt.Sprintf("Error making request to the captive portal check %q; is port 80 blocked?", captivePortalURL)) |
|
|
|
|
} else { |
|
|
|
|
resp.Body.Close() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if !connSuccess { |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
if !connSuccess { |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fakePrivKey := key.NewNode() |
|
|
|
|
|
|
|
|
|
// Next, repeatedly get the server key to see if the node is
|
|
|
|
|
// behind a load balancer (incorrectly).
|
|
|
|
|
serverPubKeys := make(map[key.NodePublic]bool) |
|
|
|
|
for i := range 5 { |
|
|
|
|
func() { |
|
|
|
|
rc := derphttp.NewRegionClient(fakePrivKey, h.logf, h.b.NetMon(), func() *tailcfg.DERPRegion { |
|
|
|
|
return &tailcfg.DERPRegion{ |
|
|
|
|
RegionID: reg.RegionID, |
|
|
|
|
RegionCode: reg.RegionCode, |
|
|
|
|
RegionName: reg.RegionName, |
|
|
|
|
Nodes: []*tailcfg.DERPNode{derpNode}, |
|
|
|
|
fakePrivKey := key.NewNode() |
|
|
|
|
|
|
|
|
|
// Next, repeatedly get the server key to see if the node is
|
|
|
|
|
// behind a load balancer (incorrectly).
|
|
|
|
|
serverPubKeys := make(map[key.NodePublic]bool) |
|
|
|
|
for i := range 5 { |
|
|
|
|
func() { |
|
|
|
|
rc := derphttp.NewRegionClient(fakePrivKey, h.logf, h.b.NetMon(), func() *tailcfg.DERPRegion { |
|
|
|
|
return &tailcfg.DERPRegion{ |
|
|
|
|
RegionID: reg.RegionID, |
|
|
|
|
RegionCode: reg.RegionCode, |
|
|
|
|
RegionName: reg.RegionName, |
|
|
|
|
Nodes: []*tailcfg.DERPNode{derpNode}, |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
if err := rc.Connect(ctx); err != nil { |
|
|
|
|
st.Errors = append(st.Errors, fmt.Sprintf("Error connecting to node %q @ try %d: %v", derpNode.HostName, i, err)) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
if err := rc.Connect(ctx); err != nil { |
|
|
|
|
st.Errors = append(st.Errors, fmt.Sprintf("Error connecting to node %q @ try %d: %v", derpNode.HostName, i, err)) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if len(serverPubKeys) == 0 { |
|
|
|
|
st.Info = append(st.Info, fmt.Sprintf("Successfully established a DERP connection with node %q", derpNode.HostName)) |
|
|
|
|
} |
|
|
|
|
serverPubKeys[rc.ServerPublicKey()] = true |
|
|
|
|
}() |
|
|
|
|
} |
|
|
|
|
if len(serverPubKeys) > 1 { |
|
|
|
|
st.Errors = append(st.Errors, fmt.Sprintf("Received multiple server public keys (%d); is the DERP server behind a load balancer?", len(serverPubKeys))) |
|
|
|
|
if len(serverPubKeys) == 0 { |
|
|
|
|
st.Info = append(st.Info, fmt.Sprintf("Successfully established a DERP connection with node %q", derpNode.HostName)) |
|
|
|
|
} |
|
|
|
|
serverPubKeys[rc.ServerPublicKey()] = true |
|
|
|
|
}() |
|
|
|
|
} |
|
|
|
|
if len(serverPubKeys) > 1 { |
|
|
|
|
st.Errors = append(st.Errors, fmt.Sprintf("Received multiple server public keys (%d); is the DERP server behind a load balancer?", len(serverPubKeys))) |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
st.Info = append(st.Info, fmt.Sprintf("Node %q is marked STUNOnly; skipped non-STUN checks", derpNode.HostName)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Send a STUN query to this node to verify whether or not it
|
|
|
|
|
|