test_btf_skc_cls_ingress.c (3461B)
1// SPDX-License-Identifier: GPL-2.0 2/* Copyright (c) 2020 Facebook */ 3 4#include <string.h> 5#include <errno.h> 6#include <netinet/in.h> 7#include <linux/stddef.h> 8#include <linux/bpf.h> 9#include <linux/ipv6.h> 10#include <linux/tcp.h> 11#include <linux/if_ether.h> 12#include <linux/pkt_cls.h> 13 14#include <bpf/bpf_helpers.h> 15#include <bpf/bpf_endian.h> 16#include "bpf_tcp_helpers.h" 17 18struct sockaddr_in6 srv_sa6 = {}; 19__u16 listen_tp_sport = 0; 20__u16 req_sk_sport = 0; 21__u32 recv_cookie = 0; 22__u32 gen_cookie = 0; 23__u32 linum = 0; 24 25#define LOG() ({ if (!linum) linum = __LINE__; }) 26 27static void test_syncookie_helper(struct ipv6hdr *ip6h, struct tcphdr *th, 28 struct tcp_sock *tp, 29 struct __sk_buff *skb) 30{ 31 if (th->syn) { 32 __s64 mss_cookie; 33 void *data_end; 34 35 data_end = (void *)(long)(skb->data_end); 36 37 if (th->doff * 4 != 40) { 38 LOG(); 39 return; 40 } 41 42 if ((void *)th + 40 > data_end) { 43 LOG(); 44 return; 45 } 46 47 mss_cookie = bpf_tcp_gen_syncookie(tp, ip6h, sizeof(*ip6h), 48 th, 40); 49 if (mss_cookie < 0) { 50 if (mss_cookie != -ENOENT) 51 LOG(); 52 } else { 53 gen_cookie = (__u32)mss_cookie; 54 } 55 } else if (gen_cookie) { 56 /* It was in cookie mode */ 57 int ret = bpf_tcp_check_syncookie(tp, ip6h, sizeof(*ip6h), 58 th, sizeof(*th)); 59 60 if (ret < 0) { 61 if (ret != -ENOENT) 62 LOG(); 63 } else { 64 recv_cookie = bpf_ntohl(th->ack_seq) - 1; 65 } 66 } 67} 68 69static int handle_ip6_tcp(struct ipv6hdr *ip6h, struct __sk_buff *skb) 70{ 71 struct bpf_sock_tuple *tuple; 72 struct bpf_sock *bpf_skc; 73 unsigned int tuple_len; 74 struct tcphdr *th; 75 void *data_end; 76 77 data_end = (void *)(long)(skb->data_end); 78 79 th = (struct tcphdr *)(ip6h + 1); 80 if (th + 1 > data_end) 81 return TC_ACT_OK; 82 83 /* Is it the testing traffic? */ 84 if (th->dest != srv_sa6.sin6_port) 85 return TC_ACT_OK; 86 87 tuple_len = sizeof(tuple->ipv6); 88 tuple = (struct bpf_sock_tuple *)&ip6h->saddr; 89 if ((void *)tuple + tuple_len > data_end) { 90 LOG(); 91 return TC_ACT_OK; 92 } 93 94 bpf_skc = bpf_skc_lookup_tcp(skb, tuple, tuple_len, 95 BPF_F_CURRENT_NETNS, 0); 96 if (!bpf_skc) { 97 LOG(); 98 return TC_ACT_OK; 99 } 100 101 if (bpf_skc->state == BPF_TCP_NEW_SYN_RECV) { 102 struct request_sock *req_sk; 103 104 req_sk = (struct request_sock *)bpf_skc_to_tcp_request_sock(bpf_skc); 105 if (!req_sk) { 106 LOG(); 107 goto release; 108 } 109 110 if (bpf_sk_assign(skb, req_sk, 0)) { 111 LOG(); 112 goto release; 113 } 114 115 req_sk_sport = req_sk->__req_common.skc_num; 116 117 bpf_sk_release(req_sk); 118 return TC_ACT_OK; 119 } else if (bpf_skc->state == BPF_TCP_LISTEN) { 120 struct tcp_sock *tp; 121 122 tp = bpf_skc_to_tcp_sock(bpf_skc); 123 if (!tp) { 124 LOG(); 125 goto release; 126 } 127 128 if (bpf_sk_assign(skb, tp, 0)) { 129 LOG(); 130 goto release; 131 } 132 133 listen_tp_sport = tp->inet_conn.icsk_inet.sk.__sk_common.skc_num; 134 135 test_syncookie_helper(ip6h, th, tp, skb); 136 bpf_sk_release(tp); 137 return TC_ACT_OK; 138 } 139 140 if (bpf_sk_assign(skb, bpf_skc, 0)) 141 LOG(); 142 143release: 144 bpf_sk_release(bpf_skc); 145 return TC_ACT_OK; 146} 147 148SEC("tc") 149int cls_ingress(struct __sk_buff *skb) 150{ 151 struct ipv6hdr *ip6h; 152 struct ethhdr *eth; 153 void *data_end; 154 155 data_end = (void *)(long)(skb->data_end); 156 157 eth = (struct ethhdr *)(long)(skb->data); 158 if (eth + 1 > data_end) 159 return TC_ACT_OK; 160 161 if (eth->h_proto != bpf_htons(ETH_P_IPV6)) 162 return TC_ACT_OK; 163 164 ip6h = (struct ipv6hdr *)(eth + 1); 165 if (ip6h + 1 > data_end) 166 return TC_ACT_OK; 167 168 if (ip6h->nexthdr == IPPROTO_TCP) 169 return handle_ip6_tcp(ip6h, skb); 170 171 return TC_ACT_OK; 172} 173 174char _license[] SEC("license") = "GPL";