support proxying to real DERPs, for testing

Change-Id: I27da972ed6c37188b2de17e3d9287410eace73e4
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2024-07-27 16:34:06 -07:00
parent 3ebc3495e7
commit 95da5023fc

View File

@@ -4,6 +4,7 @@ import (
"bufio" "bufio"
"context" "context"
"encoding/binary" "encoding/binary"
"encoding/json"
"errors" "errors"
"flag" "flag"
"fmt" "fmt"
@@ -11,6 +12,7 @@ import (
"log" "log"
"net" "net"
"net/netip" "net/netip"
"os/exec"
"strconv" "strconv"
"sync" "sync"
@@ -30,6 +32,7 @@ import (
"gvisor.dev/gvisor/pkg/waiter" "gvisor.dev/gvisor/pkg/waiter"
"tailscale.com/net/stun" "tailscale.com/net/stun"
"tailscale.com/syncs" "tailscale.com/syncs"
"tailscale.com/tailcfg"
"tailscale.com/util/set" "tailscale.com/util/set"
) )
@@ -53,6 +56,10 @@ func main() {
log.Fatalf("newServer: %v", err) log.Fatalf("newServer: %v", err)
} }
if err := s.populateDERPMapIPs(); err != nil {
log.Printf("warning: ignoring failure to populate DERP map: %v", err)
}
// Hard-coded world shape for me. // Hard-coded world shape for me.
net1 := &network{ net1 := &network{
s: s, s: s,
@@ -78,6 +85,25 @@ func main() {
} }
} }
func (s *Server) populateDERPMapIPs() error {
out, err := exec.Command("tailscale", "debug", "derp-map").Output()
if err != nil {
return fmt.Errorf("tailscale debug derp-map: %v", err)
}
var dm tailcfg.DERPMap
if err := json.Unmarshal(out, &dm); err != nil {
return fmt.Errorf("unmarshal DERPMap: %v", err)
}
for _, r := range dm.Regions {
for _, n := range r.Nodes {
if n.IPv4 != "" {
s.derpIPs.Add(netip.MustParseAddr(n.IPv4))
}
}
}
return nil
}
func (s *Server) registerNetwork(n *network) error { func (s *Server) registerNetwork(n *network) error {
if n == nil { if n == nil {
return errors.New("nil network") return errors.New("nil network")
@@ -293,8 +319,14 @@ func (n *network) acceptTCP(r *tcp.ForwarderRequest) {
return return
} }
if destIP == fakeControlplaneIP { var targetDial string
c, err := net.Dial("tcp", "controlplane.tailscale.com:"+strconv.Itoa(int(reqDetails.LocalPort))) if n.s.derpIPs.Contains(destIP) {
targetDial = destIP.String() + ":" + strconv.Itoa(int(reqDetails.LocalPort))
} else if destIP == fakeControlplaneIP {
targetDial = "controlplane.tailscale.com:" + strconv.Itoa(int(reqDetails.LocalPort))
}
if targetDial != "" {
c, err := net.Dial("tcp", targetDial)
if err != nil { if err != nil {
r.Complete(true) r.Complete(true)
log.Printf("Dial controlplane: %v", err) log.Printf("Dial controlplane: %v", err)
@@ -394,6 +426,8 @@ type Server struct {
shutdownCtx context.Context shutdownCtx context.Context
shutdownCancel context.CancelFunc shutdownCancel context.CancelFunc
derpIPs set.Set[netip.Addr]
nodes map[MAC]*node nodes map[MAC]*node
networks set.Set[*network] networks set.Set[*network]
networkByWAN map[netip.Addr]*network networkByWAN map[netip.Addr]*network
@@ -404,9 +438,12 @@ func newServer() (*Server, error) {
s := &Server{ s := &Server{
shutdownCtx: ctx, shutdownCtx: ctx,
shutdownCancel: cancel, shutdownCancel: cancel,
nodes: map[MAC]*node{},
networkByWAN: map[netip.Addr]*network{}, derpIPs: set.Of[netip.Addr](),
networks: set.Set[*network]{},
nodes: map[MAC]*node{},
networkByWAN: map[netip.Addr]*network{},
networks: set.Of[*network](),
} }
return s, nil return s, nil
} }
@@ -684,7 +721,7 @@ func (n *network) HandleEthernetIPv4PacketForRouter(ep EthernetPacket) {
return return
} }
if toForward && shouldInterceptTCP(packet) { if toForward && n.s.shouldInterceptTCP(packet) {
ipp := packet.Layer(layers.LayerTypeIPv4).(*layers.IPv4) ipp := packet.Layer(layers.LayerTypeIPv4).(*layers.IPv4)
pktCopy := make([]byte, 0, len(ipp.Contents)+len(ipp.Payload)) pktCopy := make([]byte, 0, len(ipp.Contents)+len(ipp.Payload))
pktCopy = append(pktCopy, ipp.Contents...) pktCopy = append(pktCopy, ipp.Contents...)
@@ -830,7 +867,7 @@ func isMDNSQuery(pkt gopacket.Packet) bool {
return ok && udp.SrcPort == 5353 && udp.DstPort == 5353 return ok && udp.SrcPort == 5353 && udp.DstPort == 5353
} }
func shouldInterceptTCP(pkt gopacket.Packet) bool { func (s *Server) shouldInterceptTCP(pkt gopacket.Packet) bool {
tcp, ok := pkt.Layer(layers.LayerTypeTCP).(*layers.TCP) tcp, ok := pkt.Layer(layers.LayerTypeTCP).(*layers.TCP)
if !ok { if !ok {
return false return false
@@ -842,9 +879,9 @@ func shouldInterceptTCP(pkt gopacket.Packet) bool {
if tcp.DstPort == 123 { if tcp.DstPort == 123 {
return true return true
} }
dstIP, _ := netip.AddrFromSlice(ipv4.DstIP.To4())
if tcp.DstPort == 80 || tcp.DstPort == 443 { if tcp.DstPort == 80 || tcp.DstPort == 443 {
dstIP, _ := netip.AddrFromSlice(ipv4.DstIP.To4()) if dstIP == fakeControlplaneIP || s.derpIPs.Contains(dstIP) {
if dstIP == fakeControlplaneIP {
return true return true
} }
} }