fix(xdp): two RST-challenge bugs found by live kernel testing
Found on real kernel 5.15 (netns+veth, challenge enabled): 1. truncated IP: after bpf_xdp_adjust_tail the IPv4 tot_len / IPv6 payload_len still claimed the original SYN size — peer silently dropped the malformed SYN-ACK, challenge never seen 2. endianness: marker/bad_ack written as raw host-order halfwords into network-order tcpw[] — client echoed swap16halves(bad_ack) in its RST.seq, verification always failed (CHAL_FAILED == CHAL_SENT) Post-fix e2e: SYN -> bad-ACK SYN-ACK (XDP_TX) -> client RST -> verified -> retry connects transparently; counters SENT=1 VERIFIED=1 FAILED=0
This commit is contained in:
parent
564613b82d
commit
d6bcae54c8
1 changed files with 12 additions and 4 deletions
|
|
@ -96,8 +96,14 @@ static __always_inline void chal_build_synack(struct xdp_md *ctx,
|
||||||
ipw[8] = s0;
|
ipw[8] = s0;
|
||||||
ipw[9] = s1;
|
ipw[9] = s1;
|
||||||
((__u8 *)ipw)[8] = 64; // TTL
|
((__u8 *)ipw)[8] = 64; // TTL
|
||||||
|
// tot_len must match the trimmed frame: 20 (IP) + 20 (TCP).
|
||||||
|
// Without this the peer sees "truncated IP" and drops the challenge.
|
||||||
|
ipw[1] = bpf_htons(sizeof(struct iphdr) + sizeof(struct tcphdr));
|
||||||
ipw[5] = 0; // checksum placeholder
|
ipw[5] = 0; // checksum placeholder
|
||||||
ipw[5] = chal_csum_fold(chal_sum10(ipw));
|
ipw[5] = chal_csum_fold(chal_sum10(ipw));
|
||||||
|
} else {
|
||||||
|
((struct ipv6hdr *)l3)->payload_len =
|
||||||
|
bpf_htons(sizeof(struct tcphdr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TCP header: swap ports, inject secret-derived seq/ack, SYN|ACK
|
// TCP header: swap ports, inject secret-derived seq/ack, SYN|ACK
|
||||||
|
|
@ -105,10 +111,12 @@ static __always_inline void chal_build_synack(struct xdp_md *ctx,
|
||||||
__u16 ndport = tcpw[0]; // new dest = old source
|
__u16 ndport = tcpw[0]; // new dest = old source
|
||||||
tcpw[0] = nsport;
|
tcpw[0] = nsport;
|
||||||
tcpw[1] = ndport;
|
tcpw[1] = ndport;
|
||||||
tcpw[2] = (__u16)(marker >> 16);
|
// seq/ack are written per-halfword with htons: tcpw is a view over
|
||||||
tcpw[3] = (__u16)marker;
|
// network-order memory, raw host-order stores would swap halfword bytes.
|
||||||
tcpw[4] = (__u16)(bad_ack >> 16);
|
tcpw[2] = bpf_htons((__u16)(marker >> 16));
|
||||||
tcpw[5] = (__u16)bad_ack;
|
tcpw[3] = bpf_htons((__u16)(marker & 0xFFFF));
|
||||||
|
tcpw[4] = bpf_htons((__u16)(bad_ack >> 16));
|
||||||
|
tcpw[5] = bpf_htons((__u16)(bad_ack & 0xFFFF));
|
||||||
tcpw[6] = bpf_htons(0x5012); // doff=5, flags SYN|ACK
|
tcpw[6] = bpf_htons(0x5012); // doff=5, flags SYN|ACK
|
||||||
tcpw[7] = bpf_htons(0xFFFF); // window
|
tcpw[7] = bpf_htons(0xFFFF); // window
|
||||||
tcpw[8] = 0; // checksum placeholder
|
tcpw[8] = 0; // checksum placeholder
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue