소스 검색

derp/xdp: fix handling of zero value UDP checksums (#12510)

validate_udp_checksum was previously indeterminate (not zero) at
declaration, and IPv4 zero value UDP checksum packets were being passed
to the kernel.

Updates tailscale/corp#20689

Signed-off-by: Jordan Whited <[email protected]>
Jordan Whited 1 년 전
부모
커밋
315f3d5df1
4개의 변경된 파일49개의 추가작업 그리고 1개의 파일을 삭제
  1. BIN
      derp/xdp/bpf_bpfeb.o
  2. BIN
      derp/xdp/bpf_bpfel.o
  3. 1 1
      derp/xdp/xdp.c
  4. 48 0
      derp/xdp/xdp_linux_test.go

BIN
derp/xdp/bpf_bpfeb.o


BIN
derp/xdp/bpf_bpfel.o


+ 1 - 1
derp/xdp/xdp.c

@@ -244,7 +244,7 @@ static __always_inline int handle_packet(struct xdp_md *ctx, struct packet_conte
 	struct ipv6hdr *ip6;
 	struct udphdr *udp;
 
-	int validate_udp_csum;
+	int validate_udp_csum = 0;
 	if (eth->h_proto == bpf_htons(ETH_P_IP)) {
 		pctx->af = COUNTER_KEY_AF_IPV4;
 		ip = (void *)(eth + 1);

+ 48 - 0
derp/xdp/xdp_linux_test.go

@@ -426,6 +426,18 @@ func TestXDP(t *testing.T) {
 		},
 	})
 
+	ipv4STUNBindingReqUDPZeroCsumTx := getIPv4STUNBindingReq(&ipv4Mutations{
+		udpHeaderFn: func(udpH header.UDP) {
+			udpH.SetChecksum(0)
+		},
+	})
+
+	ipv6STUNBindingReqUDPZeroCsumPass := getIPv6STUNBindingReq(&ipv6Mutations{
+		udpHeaderFn: func(udpH header.UDP) {
+			udpH.SetChecksum(0)
+		},
+	})
+
 	cases := []struct {
 		name          string
 		packetIn      []byte
@@ -865,6 +877,42 @@ func TestXDP(t *testing.T) {
 				}: uint64(len(ipv6STUNBindingReqSTUNFirstAttrPass)),
 			},
 		},
+		{
+			name:          "ipv4 UDP zero csum TX",
+			packetIn:      ipv4STUNBindingReqUDPZeroCsumTx,
+			wantCode:      xdpActionTX,
+			wantPacketOut: getIPv4STUNBindingResp(),
+			wantMetrics: map[bpfCountersKey]uint64{
+				{
+					Af:      uint8(bpfCounterKeyAfCOUNTER_KEY_AF_IPV4),
+					Pba:     uint8(bpfCounterKeyPacketsBytesActionCOUNTER_KEY_PACKETS_TX_TOTAL),
+					ProgEnd: uint8(bpfCounterKeyProgEndCOUNTER_KEY_END_UNSPECIFIED),
+				}: 1,
+				{
+					Af:      uint8(bpfCounterKeyAfCOUNTER_KEY_AF_IPV4),
+					Pba:     uint8(bpfCounterKeyPacketsBytesActionCOUNTER_KEY_BYTES_TX_TOTAL),
+					ProgEnd: uint8(bpfCounterKeyProgEndCOUNTER_KEY_END_UNSPECIFIED),
+				}: uint64(len(getIPv4STUNBindingResp())),
+			},
+		},
+		{
+			name:          "ipv6 UDP zero csum PASS",
+			packetIn:      ipv6STUNBindingReqUDPZeroCsumPass,
+			wantCode:      xdpActionPass,
+			wantPacketOut: ipv6STUNBindingReqUDPZeroCsumPass,
+			wantMetrics: map[bpfCountersKey]uint64{
+				{
+					Af:      uint8(bpfCounterKeyAfCOUNTER_KEY_AF_IPV6),
+					Pba:     uint8(bpfCounterKeyPacketsBytesActionCOUNTER_KEY_PACKETS_PASS_TOTAL),
+					ProgEnd: uint8(bpfCounterKeyProgEndCOUNTER_KEY_END_INVALID_UDP_CSUM),
+				}: 1,
+				{
+					Af:      uint8(bpfCounterKeyAfCOUNTER_KEY_AF_IPV6),
+					Pba:     uint8(bpfCounterKeyPacketsBytesActionCOUNTER_KEY_BYTES_PASS_TOTAL),
+					ProgEnd: uint8(bpfCounterKeyProgEndCOUNTER_KEY_END_INVALID_UDP_CSUM),
+				}: uint64(len(ipv6STUNBindingReqUDPZeroCsumPass)),
+			},
+		},
 	}
 
 	server, err := NewSTUNServer(&STUNServerConfig{DeviceName: "fake", DstPort: defaultSTUNPort},