mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-29 04:55:31 +00:00
ipn/localapi: also verify STUN queries work in 'debug derp'
Updates #6526 Signed-off-by: Andrew Dunham <andrew@du.nham.ca> Change-Id: I274b7ed53ee0be3fb94fdb00cafe06a1d676e1cf
This commit is contained in:
parent
f844791e15
commit
3ede3aafe4
@ -4,17 +4,24 @@
|
||||
package localapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"tailscale.com/derp/derphttp"
|
||||
"tailscale.com/ipn/ipnstate"
|
||||
"tailscale.com/net/netaddr"
|
||||
"tailscale.com/net/netns"
|
||||
"tailscale.com/net/stun"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/key"
|
||||
"tailscale.com/types/nettype"
|
||||
)
|
||||
|
||||
func (h *Handler) serveDebugDERPRegion(w http.ResponseWriter, r *http.Request) {
|
||||
@ -132,6 +139,92 @@ func (h *Handler) serveDebugDERPRegion(w http.ResponseWriter, r *http.Request) {
|
||||
return hasIPv4 || hasIPv6
|
||||
}
|
||||
|
||||
checkSTUN4 := func(derpNode *tailcfg.DERPNode) {
|
||||
u4, err := nettype.MakePacketListenerWithNetIP(netns.Listener(h.logf)).ListenPacket(ctx, "udp4", ":0")
|
||||
if err != nil {
|
||||
st.Errors = append(st.Errors, fmt.Sprintf("Error creating IPv4 STUN listener: %v", err))
|
||||
return
|
||||
}
|
||||
defer u4.Close()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
var addr netip.Addr
|
||||
if derpNode.IPv4 != "" {
|
||||
addr, err = netip.ParseAddr(derpNode.IPv4)
|
||||
if err != nil {
|
||||
// Error printed elsewhere
|
||||
return
|
||||
}
|
||||
} else {
|
||||
addrs, err := net.DefaultResolver.LookupNetIP(ctx, "ip4", derpNode.HostName)
|
||||
if err != nil {
|
||||
st.Errors = append(st.Errors, fmt.Sprintf("Error resolving node %q IPv4 addresses: %v", derpNode.HostName, err))
|
||||
return
|
||||
}
|
||||
addr = addrs[0]
|
||||
}
|
||||
|
||||
addrPort := netip.AddrPortFrom(addr, uint16(firstNonzero(derpNode.STUNPort, 3478)))
|
||||
|
||||
txID := stun.NewTxID()
|
||||
req := stun.Request(txID)
|
||||
|
||||
done := make(chan struct{})
|
||||
defer close(done)
|
||||
|
||||
go func() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case <-done:
|
||||
}
|
||||
u4.Close()
|
||||
}()
|
||||
|
||||
gotResponse := make(chan netip.AddrPort, 1)
|
||||
go func() {
|
||||
defer u4.Close()
|
||||
|
||||
var buf [64 << 10]byte
|
||||
for {
|
||||
n, addr, err := u4.ReadFromUDPAddrPort(buf[:])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
pkt := buf[:n]
|
||||
if !stun.Is(pkt) {
|
||||
continue
|
||||
}
|
||||
ap := netaddr.Unmap(addr)
|
||||
if !ap.IsValid() {
|
||||
continue
|
||||
}
|
||||
tx, addrPort, err := stun.ParseResponse(pkt)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if tx == txID {
|
||||
gotResponse <- addrPort
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
_, err = u4.WriteToUDPAddrPort(req, addrPort)
|
||||
if err != nil {
|
||||
st.Errors = append(st.Errors, fmt.Sprintf("Error sending IPv4 STUN packet to %v (%q): %v", addrPort, derpNode.HostName, err))
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case resp := <-gotResponse:
|
||||
st.Info = append(st.Info, fmt.Sprintf("Node %q returned IPv4 STUN response: %v", derpNode.HostName, resp))
|
||||
case <-ctx.Done():
|
||||
st.Warnings = append(st.Warnings, fmt.Sprintf("Node %q did not return a IPv4 STUN response", derpNode.HostName))
|
||||
}
|
||||
}
|
||||
|
||||
// Start by checking whether we can establish a HTTP connection
|
||||
for _, derpNode := range reg.Nodes {
|
||||
connSuccess := checkConn(derpNode)
|
||||
@ -178,6 +271,10 @@ func() {
|
||||
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)))
|
||||
}
|
||||
|
||||
// Send a STUN query to this node to verify whether or not it
|
||||
// correctly returns an IP address.
|
||||
checkSTUN4(derpNode)
|
||||
}
|
||||
|
||||
// TODO(bradfitz): finish:
|
||||
@ -191,7 +288,6 @@ func() {
|
||||
// protocol to say how many peers it's meshed with. Should match count
|
||||
// in DERPRegion. Or maybe even list all their server pub keys that it's peered
|
||||
// with.
|
||||
// * try STUN queries
|
||||
// * If their certificate is bad, either expired or just wrongly
|
||||
// issued in the first place, tell them specifically that the
|
||||
// cert is bad not just that the connection failed.
|
||||
|
Loading…
Reference in New Issue
Block a user