1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2018 Facebook
3 // Copyright (c) 2019 Cloudflare
8 #include <linux/pkt_cls.h>
9 #include <linux/if_ether.h>
12 #include <linux/ipv6.h>
13 #include <sys/socket.h>
14 #include <linux/tcp.h>
16 #include <bpf/bpf_helpers.h>
17 #include <bpf/bpf_endian.h>
19 struct bpf_map_def
SEC("maps") results
= {
20 .type
= BPF_MAP_TYPE_ARRAY
,
21 .key_size
= sizeof(__u32
),
22 .value_size
= sizeof(__u32
),
26 static __always_inline __s64
gen_syncookie(void *data_end
, struct bpf_sock
*sk
,
27 void *iph
, __u32 ip_size
,
30 __u32 thlen
= tcph
->doff
* 4;
32 if (tcph
->syn
&& !tcph
->ack
) {
33 // packet should only have an MSS option
37 if ((void *)tcph
+ thlen
> data_end
)
40 return bpf_tcp_gen_syncookie(sk
, iph
, ip_size
, tcph
, thlen
);
45 static __always_inline
void check_syncookie(void *ctx
, void *data
,
48 struct bpf_sock_tuple tup
;
52 struct ipv6hdr
*ipv6h
;
61 if (ethh
+ 1 > data_end
)
64 switch (bpf_ntohs(ethh
->h_proto
)) {
66 ipv4h
= data
+ sizeof(struct ethhdr
);
67 if (ipv4h
+ 1 > data_end
)
73 tcph
= data
+ sizeof(struct ethhdr
) + sizeof(struct iphdr
);
74 if (tcph
+ 1 > data_end
)
77 tup
.ipv4
.saddr
= ipv4h
->saddr
;
78 tup
.ipv4
.daddr
= ipv4h
->daddr
;
79 tup
.ipv4
.sport
= tcph
->source
;
80 tup
.ipv4
.dport
= tcph
->dest
;
82 sk
= bpf_skc_lookup_tcp(ctx
, &tup
, sizeof(tup
.ipv4
),
83 BPF_F_CURRENT_NETNS
, 0);
87 if (sk
->state
!= BPF_TCP_LISTEN
)
90 seq_mss
= gen_syncookie(data_end
, sk
, ipv4h
, sizeof(*ipv4h
),
93 ret
= bpf_tcp_check_syncookie(sk
, ipv4h
, sizeof(*ipv4h
),
98 ipv6h
= data
+ sizeof(struct ethhdr
);
99 if (ipv6h
+ 1 > data_end
)
102 if (ipv6h
->nexthdr
!= IPPROTO_TCP
)
105 tcph
= data
+ sizeof(struct ethhdr
) + sizeof(struct ipv6hdr
);
106 if (tcph
+ 1 > data_end
)
109 memcpy(tup
.ipv6
.saddr
, &ipv6h
->saddr
, sizeof(tup
.ipv6
.saddr
));
110 memcpy(tup
.ipv6
.daddr
, &ipv6h
->daddr
, sizeof(tup
.ipv6
.daddr
));
111 tup
.ipv6
.sport
= tcph
->source
;
112 tup
.ipv6
.dport
= tcph
->dest
;
114 sk
= bpf_skc_lookup_tcp(ctx
, &tup
, sizeof(tup
.ipv6
),
115 BPF_F_CURRENT_NETNS
, 0);
119 if (sk
->state
!= BPF_TCP_LISTEN
)
122 seq_mss
= gen_syncookie(data_end
, sk
, ipv6h
, sizeof(*ipv6h
),
125 ret
= bpf_tcp_check_syncookie(sk
, ipv6h
, sizeof(*ipv6h
),
126 tcph
, sizeof(*tcph
));
134 __u32 cookie
= (__u32
)seq_mss
;
135 __u32 mss
= seq_mss
>> 32;
137 bpf_map_update_elem(&results
, &key_gen
, &cookie
, 0);
138 bpf_map_update_elem(&results
, &key_mss
, &mss
, 0);
142 __u32 cookie
= bpf_ntohl(tcph
->ack_seq
) - 1;
144 bpf_map_update_elem(&results
, &key
, &cookie
, 0);
151 SEC("clsact/check_syncookie")
152 int check_syncookie_clsact(struct __sk_buff
*skb
)
154 check_syncookie(skb
, (void *)(long)skb
->data
,
155 (void *)(long)skb
->data_end
);
159 SEC("xdp/check_syncookie")
160 int check_syncookie_xdp(struct xdp_md
*ctx
)
162 check_syncookie(ctx
, (void *)(long)ctx
->data
,
163 (void *)(long)ctx
->data_end
);
167 char _license
[] SEC("license") = "GPL";