From a93173b56ae0d732ec00c8acfe7c95b2f5db5dd2 Mon Sep 17 00:00:00 2001 From: Jordan Whited Date: Tue, 18 Jun 2024 14:06:00 -0700 Subject: [PATCH] cmd/xdpderper,derp/xdp: implement mode that drops STUN packets (#12527) This is useful during maintenance as a method for shedding home client load. Updates tailscale/corp#20689 Signed-off-by: Jordan Whited --- cmd/xdpderper/xdpderper.go | 22 ++++++++++++++++++- derp/xdp/bpf_bpfeb.go | 8 +++++-- derp/xdp/bpf_bpfeb.o | Bin 24120 -> 24368 bytes derp/xdp/bpf_bpfel.go | 8 +++++-- derp/xdp/bpf_bpfel.o | Bin 24288 -> 24536 bytes derp/xdp/xdp.c | 10 +++++++++ derp/xdp/xdp_default.go | 8 +++++++ derp/xdp/xdp_linux.go | 39 ++++++++++++++++++++++++++++----- derp/xdp/xdp_linux_test.go | 43 +++++++++++++++++++++++++++++++++++++ 9 files changed, 128 insertions(+), 10 deletions(-) diff --git a/cmd/xdpderper/xdpderper.go b/cmd/xdpderper/xdpderper.go index 8d52e9353..1af9c9d5a 100644 --- a/cmd/xdpderper/xdpderper.go +++ b/cmd/xdpderper/xdpderper.go @@ -5,6 +5,7 @@ package main import ( "flag" + "io" "log" "net/http" "os" @@ -57,7 +58,26 @@ func main() { log.Println("XDP STUN server started") mux := http.NewServeMux() - tsweb.Debugger(mux) + debug := tsweb.Debugger(mux) + debug.KVFunc("Drop STUN", func() any { + return server.GetDropSTUN() + }) + debug.Handle("drop-stun-on", "Drop STUN packets", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + err := server.SetDropSTUN(true) + if err != nil { + http.Error(w, err.Error(), 500) + } else { + io.WriteString(w, "STUN packets are now being dropped.") + } + })) + debug.Handle("drop-stun-off", "Handle STUN packets", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + err := server.SetDropSTUN(false) + if err != nil { + http.Error(w, err.Error(), 500) + } else { + io.WriteString(w, "STUN packets are now being handled.") + } + })) errCh := make(chan error, 1) go func() { err := http.ListenAndServe(*flagHTTP, mux) diff --git a/derp/xdp/bpf_bpfeb.go b/derp/xdp/bpf_bpfeb.go index 1883d52fe..e20228731 100644 --- a/derp/xdp/bpf_bpfeb.go +++ b/derp/xdp/bpf_bpfeb.go @@ -12,7 +12,10 @@ import ( "github.com/cilium/ebpf" ) -type bpfConfig struct{ DstPort uint16 } +type bpfConfig struct { + DstPort uint16 + DropStun uint16 +} type bpfCounterKeyAf uint32 @@ -46,7 +49,8 @@ const ( bpfCounterKeyProgEndCOUNTER_KEY_END_INVALID_IP_CSUM bpfCounterKeyProgEnd = 3 bpfCounterKeyProgEndCOUNTER_KEY_END_NOT_STUN_PORT bpfCounterKeyProgEnd = 4 bpfCounterKeyProgEndCOUNTER_KEY_END_INVALID_SW_ATTR_VAL bpfCounterKeyProgEnd = 5 - bpfCounterKeyProgEndCOUNTER_KEY_END_LEN bpfCounterKeyProgEnd = 6 + bpfCounterKeyProgEndCOUNTER_KEY_END_DROP_STUN bpfCounterKeyProgEnd = 6 + bpfCounterKeyProgEndCOUNTER_KEY_END_LEN bpfCounterKeyProgEnd = 7 ) type bpfCountersKey struct { diff --git a/derp/xdp/bpf_bpfeb.o b/derp/xdp/bpf_bpfeb.o index 06ff73fc1ff72d33b990dac3db5f64ef6255d183..64bde142dc482ea5a66e7270750f58f74964592c 100644 GIT binary patch delta 6766 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 EAAsh+?*IS* diff --git a/derp/xdp/bpf_bpfel.go b/derp/xdp/bpf_bpfel.go index 8cb7dec56..aab06b041 100644 --- a/derp/xdp/bpf_bpfel.go +++ b/derp/xdp/bpf_bpfel.go @@ -12,7 +12,10 @@ import ( "github.com/cilium/ebpf" ) -type bpfConfig struct{ DstPort uint16 } +type bpfConfig struct { + DstPort uint16 + DropStun uint16 +} type bpfCounterKeyAf uint32 @@ -46,7 +49,8 @@ const ( bpfCounterKeyProgEndCOUNTER_KEY_END_INVALID_IP_CSUM bpfCounterKeyProgEnd = 3 bpfCounterKeyProgEndCOUNTER_KEY_END_NOT_STUN_PORT bpfCounterKeyProgEnd = 4 bpfCounterKeyProgEndCOUNTER_KEY_END_INVALID_SW_ATTR_VAL bpfCounterKeyProgEnd = 5 - bpfCounterKeyProgEndCOUNTER_KEY_END_LEN bpfCounterKeyProgEnd = 6 + bpfCounterKeyProgEndCOUNTER_KEY_END_DROP_STUN bpfCounterKeyProgEnd = 6 + bpfCounterKeyProgEndCOUNTER_KEY_END_LEN bpfCounterKeyProgEnd = 7 ) type bpfCountersKey struct { diff --git a/derp/xdp/bpf_bpfel.o b/derp/xdp/bpf_bpfel.o index b4653efd91bf2ea899aad78f954e825b577d75c9..04b909ac7bba22a0ef46133ad101b6880416c2c4 100644 GIT binary patch delta 6876 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 diff --git a/derp/xdp/xdp.c b/derp/xdp/xdp.c index a72e67264..3ac6488a4 100644 --- a/derp/xdp/xdp.c +++ b/derp/xdp/xdp.c @@ -14,6 +14,10 @@ struct config { // the context of the data. cilium/ebpf uses native endian encoding for map // encoding even if we use big endian types here, e.g. __be16. __u16 dst_port; + // If drop_stun is set to a nonzero value all UDP packets destined to + // dst_port will be dropped. This is useful for shedding home client load + // during maintenance. + __u16 drop_stun; }; struct config *unused_config __attribute__((unused)); // required by bpf2go -type @@ -60,6 +64,7 @@ enum counter_key_prog_end { COUNTER_KEY_END_INVALID_IP_CSUM, COUNTER_KEY_END_NOT_STUN_PORT, COUNTER_KEY_END_INVALID_SW_ATTR_VAL, + COUNTER_KEY_END_DROP_STUN, COUNTER_KEY_END_LEN }; enum counter_key_prog_end *unused_counter_key_prog_end __attribute__((unused)); // required by bpf2go -type @@ -334,6 +339,11 @@ static __always_inline int handle_packet(struct xdp_md *ctx, struct packet_conte return XDP_PASS; } + if (c->drop_stun) { + pctx->prog_end = COUNTER_KEY_END_DROP_STUN; + return XDP_DROP; + } + if (validate_udp_csum) { __u16 cs; __u32 pseudo_sum; diff --git a/derp/xdp/xdp_default.go b/derp/xdp/xdp_default.go index 35fd659ca..99bc30d2c 100644 --- a/derp/xdp/xdp_default.go +++ b/derp/xdp/xdp_default.go @@ -26,3 +26,11 @@ func (s *STUNServer) Close() error { func (s *STUNServer) Describe(descCh chan<- *prometheus.Desc) {} func (s *STUNServer) Collect(metricCh chan<- prometheus.Metric) {} + +func (s *STUNServer) SetDropSTUN(v bool) error { + return errors.New("unimplemented on this GOOS") +} + +func (s *STUNServer) GetDropSTUN() bool { + return true +} diff --git a/derp/xdp/xdp_linux.go b/derp/xdp/xdp_linux.go index f2d47a372..aa6559842 100644 --- a/derp/xdp/xdp_linux.go +++ b/derp/xdp/xdp_linux.go @@ -22,9 +22,11 @@ import ( // the STUN protocol. It exports statistics for the XDP program via its // implementation of the prometheus.Collector interface. type STUNServer struct { - mu sync.Mutex - objs *bpfObjects - metrics *stunServerMetrics + mu sync.Mutex + objs *bpfObjects + metrics *stunServerMetrics + dstPort int + dropSTUN bool } //lint:ignore U1000 used in xdp_linux_test.go, which has a build tag @@ -68,12 +70,13 @@ func NewSTUNServer(config *STUNServerConfig, opts ...STUNServerOption) (*STUNSer server := &STUNServer{ objs: objs, metrics: newSTUNServerMetrics(), + dstPort: config.DstPort, } var key uint32 - xdpConfig := bpfConfig{ + xdpConfig := &bpfConfig{ DstPort: uint16(config.DstPort), } - err = objs.ConfigMap.Put(key, &xdpConfig) + err = objs.ConfigMap.Put(key, xdpConfig) if err != nil { return nil, fmt.Errorf("error loading config in eBPF map: %w", err) } @@ -181,6 +184,7 @@ var ( bpfCounterKeyProgEndCOUNTER_KEY_END_INVALID_IP_CSUM: "invalid_ip_csum", bpfCounterKeyProgEndCOUNTER_KEY_END_NOT_STUN_PORT: "not_stun_port", bpfCounterKeyProgEndCOUNTER_KEY_END_INVALID_SW_ATTR_VAL: "invalid_sw_attr_val", + bpfCounterKeyProgEndCOUNTER_KEY_END_DROP_STUN: "drop_stun", } packetCounterKeys = map[bpfCounterKeyPacketsBytesAction]bool{ @@ -262,6 +266,31 @@ func (s *STUNServer) Collect(metricCh chan<- prometheus.Metric) { s.metrics.registry.Collect(metricCh) } +func (s *STUNServer) SetDropSTUN(v bool) error { + s.mu.Lock() + defer s.mu.Unlock() + dropSTUN := 0 + if v { + dropSTUN = 1 + } + xdpConfig := &bpfConfig{ + DstPort: uint16(s.dstPort), + DropStun: uint16(dropSTUN), + } + var key uint32 + err := s.objs.ConfigMap.Put(key, xdpConfig) + if err == nil { + s.dropSTUN = v + } + return err +} + +func (s *STUNServer) GetDropSTUN() bool { + s.mu.Lock() + defer s.mu.Unlock() + return s.dropSTUN +} + func (s *STUNServer) updateMetrics() error { s.mu.Lock() defer s.mu.Unlock() diff --git a/derp/xdp/xdp_linux_test.go b/derp/xdp/xdp_linux_test.go index 1a59f9444..07f11eff6 100644 --- a/derp/xdp/xdp_linux_test.go +++ b/derp/xdp/xdp_linux_test.go @@ -440,11 +440,50 @@ func TestXDP(t *testing.T) { cases := []struct { name string + dropSTUN bool packetIn []byte wantCode xdpAction wantPacketOut []byte wantMetrics map[bpfCountersKey]uint64 }{ + { + name: "ipv4 STUN Binding Request Drop STUN", + dropSTUN: true, + packetIn: ipv4STUNBindingReqTX, + wantCode: xdpActionDrop, + wantPacketOut: ipv4STUNBindingReqTX, + wantMetrics: map[bpfCountersKey]uint64{ + { + Af: uint8(bpfCounterKeyAfCOUNTER_KEY_AF_IPV4), + Pba: uint8(bpfCounterKeyPacketsBytesActionCOUNTER_KEY_PACKETS_DROP_TOTAL), + ProgEnd: uint8(bpfCounterKeyProgEndCOUNTER_KEY_END_DROP_STUN), + }: 1, + { + Af: uint8(bpfCounterKeyAfCOUNTER_KEY_AF_IPV4), + Pba: uint8(bpfCounterKeyPacketsBytesActionCOUNTER_KEY_BYTES_DROP_TOTAL), + ProgEnd: uint8(bpfCounterKeyProgEndCOUNTER_KEY_END_DROP_STUN), + }: uint64(len(ipv4STUNBindingReqTX)), + }, + }, + { + name: "ipv6 STUN Binding Request Drop STUN", + dropSTUN: true, + packetIn: ipv6STUNBindingReqTX, + wantCode: xdpActionDrop, + wantPacketOut: ipv6STUNBindingReqTX, + wantMetrics: map[bpfCountersKey]uint64{ + { + Af: uint8(bpfCounterKeyAfCOUNTER_KEY_AF_IPV6), + Pba: uint8(bpfCounterKeyPacketsBytesActionCOUNTER_KEY_PACKETS_DROP_TOTAL), + ProgEnd: uint8(bpfCounterKeyProgEndCOUNTER_KEY_END_DROP_STUN), + }: 1, + { + Af: uint8(bpfCounterKeyAfCOUNTER_KEY_AF_IPV6), + Pba: uint8(bpfCounterKeyPacketsBytesActionCOUNTER_KEY_BYTES_DROP_TOTAL), + ProgEnd: uint8(bpfCounterKeyProgEndCOUNTER_KEY_END_DROP_STUN), + }: uint64(len(ipv6STUNBindingReqTX)), + }, + }, { name: "ipv4 STUN Binding Request TX", packetIn: ipv4STUNBindingReqTX, @@ -963,6 +1002,10 @@ func TestXDP(t *testing.T) { Data: c.packetIn, DataOut: make([]byte, 1514), } + err = server.SetDropSTUN(c.dropSTUN) + if err != nil { + t.Fatalf("error setting drop STUN: %v", err) + } got, err := server.objs.XdpProgFunc.Run(&opts) if err != nil { t.Fatalf("error running program: %v", err)