Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright (c) 2020 Facebook */
0003 
0004 #include <string.h>
0005 #include <errno.h>
0006 #include <netinet/in.h>
0007 #include <linux/stddef.h>
0008 #include <linux/bpf.h>
0009 #include <linux/ipv6.h>
0010 #include <linux/tcp.h>
0011 #include <linux/if_ether.h>
0012 #include <linux/pkt_cls.h>
0013 
0014 #include <bpf/bpf_helpers.h>
0015 #include <bpf/bpf_endian.h>
0016 #include "bpf_tcp_helpers.h"
0017 
0018 struct sockaddr_in6 srv_sa6 = {};
0019 __u16 listen_tp_sport = 0;
0020 __u16 req_sk_sport = 0;
0021 __u32 recv_cookie = 0;
0022 __u32 gen_cookie = 0;
0023 __u32 linum = 0;
0024 
0025 #define LOG() ({ if (!linum) linum = __LINE__; })
0026 
0027 static void test_syncookie_helper(struct ipv6hdr *ip6h, struct tcphdr *th,
0028                   struct tcp_sock *tp,
0029                   struct __sk_buff *skb)
0030 {
0031     if (th->syn) {
0032         __s64 mss_cookie;
0033         void *data_end;
0034 
0035         data_end = (void *)(long)(skb->data_end);
0036 
0037         if (th->doff * 4 != 40) {
0038             LOG();
0039             return;
0040         }
0041 
0042         if ((void *)th + 40 > data_end) {
0043             LOG();
0044             return;
0045         }
0046 
0047         mss_cookie = bpf_tcp_gen_syncookie(tp, ip6h, sizeof(*ip6h),
0048                            th, 40);
0049         if (mss_cookie < 0) {
0050             if (mss_cookie != -ENOENT)
0051                 LOG();
0052         } else {
0053             gen_cookie = (__u32)mss_cookie;
0054         }
0055     } else if (gen_cookie) {
0056         /* It was in cookie mode */
0057         int ret = bpf_tcp_check_syncookie(tp, ip6h, sizeof(*ip6h),
0058                           th, sizeof(*th));
0059 
0060         if (ret < 0) {
0061             if (ret != -ENOENT)
0062                 LOG();
0063         } else {
0064             recv_cookie = bpf_ntohl(th->ack_seq) - 1;
0065         }
0066     }
0067 }
0068 
0069 static int handle_ip6_tcp(struct ipv6hdr *ip6h, struct __sk_buff *skb)
0070 {
0071     struct bpf_sock_tuple *tuple;
0072     struct bpf_sock *bpf_skc;
0073     unsigned int tuple_len;
0074     struct tcphdr *th;
0075     void *data_end;
0076 
0077     data_end = (void *)(long)(skb->data_end);
0078 
0079     th = (struct tcphdr *)(ip6h + 1);
0080     if (th + 1 > data_end)
0081         return TC_ACT_OK;
0082 
0083     /* Is it the testing traffic? */
0084     if (th->dest != srv_sa6.sin6_port)
0085         return TC_ACT_OK;
0086 
0087     tuple_len = sizeof(tuple->ipv6);
0088     tuple = (struct bpf_sock_tuple *)&ip6h->saddr;
0089     if ((void *)tuple + tuple_len > data_end) {
0090         LOG();
0091         return TC_ACT_OK;
0092     }
0093 
0094     bpf_skc = bpf_skc_lookup_tcp(skb, tuple, tuple_len,
0095                      BPF_F_CURRENT_NETNS, 0);
0096     if (!bpf_skc) {
0097         LOG();
0098         return TC_ACT_OK;
0099     }
0100 
0101     if (bpf_skc->state == BPF_TCP_NEW_SYN_RECV) {
0102         struct request_sock *req_sk;
0103 
0104         req_sk = (struct request_sock *)bpf_skc_to_tcp_request_sock(bpf_skc);
0105         if (!req_sk) {
0106             LOG();
0107             goto release;
0108         }
0109 
0110         if (bpf_sk_assign(skb, req_sk, 0)) {
0111             LOG();
0112             goto release;
0113         }
0114 
0115         req_sk_sport = req_sk->__req_common.skc_num;
0116 
0117         bpf_sk_release(req_sk);
0118         return TC_ACT_OK;
0119     } else if (bpf_skc->state == BPF_TCP_LISTEN) {
0120         struct tcp_sock *tp;
0121 
0122         tp = bpf_skc_to_tcp_sock(bpf_skc);
0123         if (!tp) {
0124             LOG();
0125             goto release;
0126         }
0127 
0128         if (bpf_sk_assign(skb, tp, 0)) {
0129             LOG();
0130             goto release;
0131         }
0132 
0133         listen_tp_sport = tp->inet_conn.icsk_inet.sk.__sk_common.skc_num;
0134 
0135         test_syncookie_helper(ip6h, th, tp, skb);
0136         bpf_sk_release(tp);
0137         return TC_ACT_OK;
0138     }
0139 
0140     if (bpf_sk_assign(skb, bpf_skc, 0))
0141         LOG();
0142 
0143 release:
0144     bpf_sk_release(bpf_skc);
0145     return TC_ACT_OK;
0146 }
0147 
0148 SEC("tc")
0149 int cls_ingress(struct __sk_buff *skb)
0150 {
0151     struct ipv6hdr *ip6h;
0152     struct ethhdr *eth;
0153     void *data_end;
0154 
0155     data_end = (void *)(long)(skb->data_end);
0156 
0157     eth = (struct ethhdr *)(long)(skb->data);
0158     if (eth + 1 > data_end)
0159         return TC_ACT_OK;
0160 
0161     if (eth->h_proto != bpf_htons(ETH_P_IPV6))
0162         return TC_ACT_OK;
0163 
0164     ip6h = (struct ipv6hdr *)(eth + 1);
0165     if (ip6h + 1 > data_end)
0166         return TC_ACT_OK;
0167 
0168     if (ip6h->nexthdr == IPPROTO_TCP)
0169         return handle_ip6_tcp(ip6h, skb);
0170 
0171     return TC_ACT_OK;
0172 }
0173 
0174 char _license[] SEC("license") = "GPL";