static __always_inline __u16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
__u32 len, __u8 proto,
__u32 csum)
{
__u64 s = csum;
s += (__u32)saddr;
s += (__u32)daddr; #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
s += proto + len; #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
s += (proto + len) << 8; #else #error Unknown endian #endif
s = (s & 0xffffffff) + (s >> 32);
s = (s & 0xffffffff) + (s >> 32);
return csum_fold((__u32)s);
}
static __always_inline __u16 csum_ipv6_magic(conststruct in6_addr *saddr, conststruct in6_addr *daddr,
__u32 len, __u8 proto, __u32 csum)
{
__u64 sum = csum; int i;
__pragma_loop_unroll for (i = 0; i < 4; i++)
sum += (__u32)saddr->in6_u.u6_addr32[i];
__pragma_loop_unroll for (i = 0; i < 4; i++)
sum += (__u32)daddr->in6_u.u6_addr32[i];
/* Don't combine additions to avoid 32-bit overflow. */
sum += bpf_htonl(len);
sum += bpf_htonl(proto);
sum = (sum & 0xffffffff) + (sum >> 32);
sum = (sum & 0xffffffff) + (sum >> 32);
/* Checksum is not yet verified, but both checksum failure and TCP *headerchecksreturnXDP_DROP,sotheorderdoesn'tmatter.
*/ if (hdr->tcp->fin || hdr->tcp->rst) return XDP_DROP;
/* Issue SYN cookies on allowed ports, drop SYN packets on blocked *ports.
*/ if (!check_port_allowed(bpf_ntohs(hdr->tcp->dest))) return XDP_DROP;
if (hdr->ipv4) { /* Check the IPv4 and TCP checksums before creating a SYNACK. */
value = bpf_csum_diff(0, 0, (void *)hdr->ipv4, hdr->ipv4->ihl * 4, 0); if (value < 0) return XDP_ABORTED; if (csum_fold(value) != 0) return XDP_DROP; /* Bad IPv4 checksum. */
value = bpf_csum_diff(0, 0, (void *)hdr->tcp, hdr->tcp_len, 0); if (value < 0) return XDP_ABORTED; if (csum_tcpudp_magic(hdr->ipv4->saddr, hdr->ipv4->daddr,
hdr->tcp_len, IPPROTO_TCP, value) != 0) return XDP_DROP; /* Bad TCP checksum. */
ip_len = sizeof(*hdr->ipv4);
value = bpf_tcp_raw_gen_syncookie_ipv4(hdr->ipv4, hdr->tcp,
hdr->tcp_len);
} elseif (hdr->ipv6) { /* Check the TCP checksum before creating a SYNACK. */
value = bpf_csum_diff(0, 0, (void *)hdr->tcp, hdr->tcp_len, 0); if (value < 0) return XDP_ABORTED; if (csum_ipv6_magic(&hdr->ipv6->saddr, &hdr->ipv6->daddr,
hdr->tcp_len, IPPROTO_TCP, value) != 0) return XDP_DROP; /* Bad TCP checksum. */
/* Check that there is enough space for a SYNACK. It also covers *thecheckthatthedestinationofthe__builtin_memmovebelow *doesn'toverflow.
*/ if (data + sizeof(*hdr->eth) + ip_len + TCP_MAXLEN > data_end) return XDP_ABORTED;
if (hdr->ipv4) { if (hdr->ipv4->ihl * 4 > sizeof(*hdr->ipv4)) { struct tcphdr *new_tcp_header;
/* Set the new packet size. */
old_pkt_size = data_end - data;
new_pkt_size = sizeof(*hdr->eth) + ip_len + hdr->tcp->doff * 4; if (xdp) { if (bpf_xdp_adjust_tail(ctx, new_pkt_size - old_pkt_size)) return XDP_ABORTED;
} else { if (bpf_skb_change_tail(ctx, new_pkt_size, 0)) return XDP_ABORTED;
}
values_inc_synacks();
return XDP_TX;
}
static __always_inline int syncookie_handle_ack(struct header_pointers *hdr)
{ int err;
if (hdr->tcp->rst) return XDP_DROP;
if (hdr->ipv4)
err = bpf_tcp_raw_check_syncookie_ipv4(hdr->ipv4, hdr->tcp); elseif (hdr->ipv6)
err = bpf_tcp_raw_check_syncookie_ipv6(hdr->ipv6, hdr->tcp); else return XDP_ABORTED; if (err) return XDP_DROP;
return XDP_PASS;
}
static __always_inline int syncookie_part1(void *ctx, void *data, void *data_end, struct header_pointers *hdr, bool xdp)
{ int ret;
ret = tcp_dissect(data, data_end, hdr); if (ret != XDP_TX) return ret;
ret = tcp_lookup(ctx, hdr, xdp); if (ret != XDP_TX) return ret;
/* Packet is TCP and doesn't belong to an established connection. */
if ((hdr->tcp->syn ^ hdr->tcp->ack) != 1) return XDP_DROP;
/* Grow the TCP header to TCP_MAXLEN to be able to pass any hdr->tcp_len *tobpf_tcp_raw_gen_syncookie_ipv{4,6}andpasstheverifier.
*/ if (xdp) { if (bpf_xdp_adjust_tail(ctx, TCP_MAXLEN - hdr->tcp_len)) return XDP_ABORTED;
} else { /* Without volatile the verifier throws this error: *R932-bitpointerarithmeticprohibited
*/ volatile u64 old_len = data_end - data;
if ((void *)hdr->tcp + TCP_MAXLEN > data_end) return XDP_ABORTED;
/* We run out of registers, tcp_len gets spilled to the stack, and the *verifierforgetsitsminandmaxvaluescheckedaboveintcp_dissect.
*/
hdr->tcp_len = hdr->tcp->doff * 4; if (hdr->tcp_len < sizeof(*hdr->tcp)) return XDP_ABORTED;
ret = syncookie_part1(skb, data, data_end, &hdr, false); if (ret != XDP_TX) return ret == XDP_PASS ? TC_ACT_OK : TC_ACT_SHOT;
data_end = (void *)(long)skb->data_end;
data = (void *)(long)skb->data;
ret = syncookie_part2(skb, data, data_end, &hdr, false); switch (ret) { case XDP_PASS: return TC_ACT_OK; case XDP_TX: return bpf_redirect(skb->ifindex, 0); default: return TC_ACT_SHOT;
}
}
char _license[] SEC("license") = "GPL";
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.14Bemerkung:
(vorverarbeitet am 2026-10-11)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.