Repository: gojue/ecapture
File: kern/tc.h (C/C++)

Code before:

    return true;
}

// filter_pcap_ebpf_l2 is a stub to inject pcap-filter.
static __noinline bool filter_pcap_ebpf_l2(void *_skb, void *__skb,
                                           void *___skb, void *data,
                                           void* data_end) {
    return data != data_end && _skb == __skb && __skb == ___skb;
}

static __always_inline bool filter_pcap_l2(struct __sk_buff *skb, void *data,
                                           void *data_end) {
    return filter_pcap_ebpf_l2((void *) skb, (void *) skb, (void *) skb, data,
                               data_end);
}

///////////////////// ebpf functions //////////////////////
static __always_inline int capture_packets(struct __sk_buff *skb, bool is_ingress) {
    // packet data
    unsigned char *data_start = (void *)(long)skb->data;
    unsigned char *data_end = (void *)(long)skb->data_end;

    // packet length check
    if (data_start + sizeof(struct ethhdr) > data_end || 
        data_start + sizeof(struct ethhdr) + sizeof(struct iphdr) > data_end) 
    {
        return TC_ACT_OK;
    }

    // filter L2/L3/L4 packet, include arp
#ifndef KERNEL_LESS_5_2
    if (!filter_pcap_l2(skb, data_start, data_end))
        return TC_ACT_OK;
#endif

    struct net_id_t conn_id = {0};
    struct net_ctx_t *net_ctx = NULL;
    // Ethernet headers
    struct ethhdr *eth = (struct ethhdr *)data_start;
    if (eth->h_proto == bpf_htons(ETH_P_IPV6)) {
        // IPv6 packect
        uint32_t l4_hdr_off = sizeof(struct ethhdr) + sizeof(struct ipv6hdr);
        if (!skb_revalidate_data(skb, &data_start, &data_end, l4_hdr_off)) {
            return TC_ACT_OK;
        }

        struct ipv6hdr *iph = (struct ipv6hdr *)(data_start + sizeof(struct ethhdr));
        if (iph->nexthdr != IPPROTO_TCP && iph->nexthdr != IPPROTO_UDP) {
            return TC_ACT_OK;
        }

Review comment (suggestion):
`data_start + sizeof(struct ethhdr) > data_end` is unnecessary here. `data_start + sizeof(struct ethhdr) + sizeof(struct iphdr) > data_end` is enough. As we filter ethernet layer info alongside IP layer info at most time.

Code after:

    return true;
}

// filter_pcap_ebpf_l2 is a stub to inject pcap-filter.
static __noinline bool filter_pcap_ebpf_l2(void *_skb, void *__skb,
                                           void *___skb, void *data,
                                           void* data_end) {
    return data != data_end && _skb == __skb && __skb == ___skb;
}

static __always_inline bool filter_pcap_l2(struct __sk_buff *skb, void *data,
                                           void *data_end) {
    return filter_pcap_ebpf_l2((void *) skb, (void *) skb, (void *) skb, data,
                               data_end);
}

///////////////////// ebpf functions //////////////////////
static __always_inline int capture_packets(struct __sk_buff *skb, bool is_ingress) {
    // packet data
    unsigned char *data_start = (void *)(long)skb->data;
    unsigned char *data_end = (void *)(long)skb->data_end;

    // packet length check
    if (data_start + sizeof(struct ethhdr) + sizeof(struct iphdr) > data_end) 
    {
        return TC_ACT_OK;
    }

    // filter L2/L3/L4 packet, include arp
#ifndef KERNEL_LESS_5_2
    if (!filter_pcap_l2(skb, data_start, data_end))
        return TC_ACT_OK;
#endif

    struct net_id_t conn_id = {0};
    struct net_ctx_t *net_ctx = NULL;
    // Ethernet headers
    struct ethhdr *eth = (struct ethhdr *)data_start;
    if (eth->h_proto == bpf_htons(ETH_P_IPV6)) {
        // IPv6 packect
        uint32_t l4_hdr_off = sizeof(struct ethhdr) + sizeof(struct ipv6hdr);
        if (!skb_revalidate_data(skb, &data_start, &data_end, l4_hdr_off)) {
            return TC_ACT_OK;
        }

        struct ipv6hdr *iph = (struct ipv6hdr *)(data_start + sizeof(struct ethhdr));
        if (iph->nexthdr != IPPROTO_TCP && iph->nexthdr != IPPROTO_UDP) {
            return TC_ACT_OK;
        }