1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2020 Facebook */
6 #include <netinet/in.h>
7 #include <linux/stddef.h>
9 #include <linux/ipv6.h>
10 #include <linux/tcp.h>
11 #include <linux/if_ether.h>
12 #include <linux/pkt_cls.h>
14 #include <bpf/bpf_helpers.h>
15 #include <bpf/bpf_endian.h>
16 #include "bpf_tcp_helpers.h"
18 struct sockaddr_in6 srv_sa6
= {};
19 __u16 listen_tp_sport
= 0;
20 __u16 req_sk_sport
= 0;
21 __u32 recv_cookie
= 0;
25 #define LOG() ({ if (!linum) linum = __LINE__; })
27 static void test_syncookie_helper(struct ipv6hdr
*ip6h
, struct tcphdr
*th
,
29 struct __sk_buff
*skb
)
35 data_end
= (void *)(long)(skb
->data_end
);
37 if (th
->doff
* 4 != 40) {
42 if ((void *)th
+ 40 > data_end
) {
47 mss_cookie
= bpf_tcp_gen_syncookie(tp
, ip6h
, sizeof(*ip6h
),
50 if (mss_cookie
!= -ENOENT
)
53 gen_cookie
= (__u32
)mss_cookie
;
55 } else if (gen_cookie
) {
56 /* It was in cookie mode */
57 int ret
= bpf_tcp_check_syncookie(tp
, ip6h
, sizeof(*ip6h
),
64 recv_cookie
= bpf_ntohl(th
->ack_seq
) - 1;
69 static int handle_ip6_tcp(struct ipv6hdr
*ip6h
, struct __sk_buff
*skb
)
71 struct bpf_sock_tuple
*tuple
;
72 struct bpf_sock
*bpf_skc
;
73 unsigned int tuple_len
;
77 data_end
= (void *)(long)(skb
->data_end
);
79 th
= (struct tcphdr
*)(ip6h
+ 1);
80 if (th
+ 1 > data_end
)
83 /* Is it the testing traffic? */
84 if (th
->dest
!= srv_sa6
.sin6_port
)
87 tuple_len
= sizeof(tuple
->ipv6
);
88 tuple
= (struct bpf_sock_tuple
*)&ip6h
->saddr
;
89 if ((void *)tuple
+ tuple_len
> data_end
) {
94 bpf_skc
= bpf_skc_lookup_tcp(skb
, tuple
, tuple_len
,
95 BPF_F_CURRENT_NETNS
, 0);
101 if (bpf_skc
->state
== BPF_TCP_NEW_SYN_RECV
) {
102 struct request_sock
*req_sk
;
104 req_sk
= (struct request_sock
*)bpf_skc_to_tcp_request_sock(bpf_skc
);
110 if (bpf_sk_assign(skb
, req_sk
, 0)) {
115 req_sk_sport
= req_sk
->__req_common
.skc_num
;
117 bpf_sk_release(req_sk
);
119 } else if (bpf_skc
->state
== BPF_TCP_LISTEN
) {
122 tp
= bpf_skc_to_tcp_sock(bpf_skc
);
128 if (bpf_sk_assign(skb
, tp
, 0)) {
133 listen_tp_sport
= tp
->inet_conn
.icsk_inet
.sk
.__sk_common
.skc_num
;
135 test_syncookie_helper(ip6h
, th
, tp
, skb
);
140 if (bpf_sk_assign(skb
, bpf_skc
, 0))
144 bpf_sk_release(bpf_skc
);
148 SEC("classifier/ingress")
149 int cls_ingress(struct __sk_buff
*skb
)
151 struct ipv6hdr
*ip6h
;
155 data_end
= (void *)(long)(skb
->data_end
);
157 eth
= (struct ethhdr
*)(long)(skb
->data
);
158 if (eth
+ 1 > data_end
)
161 if (eth
->h_proto
!= bpf_htons(ETH_P_IPV6
))
164 ip6h
= (struct ipv6hdr
*)(eth
+ 1);
165 if (ip6h
+ 1 > data_end
)
168 if (ip6h
->nexthdr
== IPPROTO_TCP
)
169 return handle_ip6_tcp(ip6h
, skb
);
174 char _license
[] SEC("license") = "GPL";