linux/tools/testing/selftests/bpf/progs/test_btf_skc_cls_ingress.c
<<
>>
Prefs
   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("classifier/ingress")
 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";
 175