165d472fbSAlexei Starovoitov /* Copyright (c) 2016 Facebook
265d472fbSAlexei Starovoitov *
365d472fbSAlexei Starovoitov * This program is free software; you can redistribute it and/or
465d472fbSAlexei Starovoitov * modify it under the terms of version 2 of the GNU General Public
565d472fbSAlexei Starovoitov * License as published by the Free Software Foundation.
665d472fbSAlexei Starovoitov */
796a8eb1eSDaniel Borkmann #define KBUILD_MODNAME "foo"
865d472fbSAlexei Starovoitov #include <linux/if_ether.h>
94d5d33a0STaeung Song #include <linux/if_vlan.h>
1065d472fbSAlexei Starovoitov #include <linux/ip.h>
1165d472fbSAlexei Starovoitov #include <linux/ipv6.h>
1265d472fbSAlexei Starovoitov #include <linux/in.h>
1365d472fbSAlexei Starovoitov #include <linux/tcp.h>
1465d472fbSAlexei Starovoitov #include <linux/udp.h>
1565d472fbSAlexei Starovoitov #include <uapi/linux/bpf.h>
1665d472fbSAlexei Starovoitov #include <net/ip.h>
17*7cf245a3SToke Høiland-Jørgensen #include <bpf/bpf_helpers.h>
1865d472fbSAlexei Starovoitov
1965d472fbSAlexei Starovoitov #define DEFAULT_PKTGEN_UDP_PORT 9
2065d472fbSAlexei Starovoitov #define DEBUG 0
2165d472fbSAlexei Starovoitov
tcp(void * data,uint64_t tp_off,void * data_end)2265d472fbSAlexei Starovoitov static int tcp(void *data, uint64_t tp_off, void *data_end)
2365d472fbSAlexei Starovoitov {
2465d472fbSAlexei Starovoitov struct tcphdr *tcp = data + tp_off;
2565d472fbSAlexei Starovoitov
2665d472fbSAlexei Starovoitov if (tcp + 1 > data_end)
2765d472fbSAlexei Starovoitov return 0;
2865d472fbSAlexei Starovoitov if (tcp->dest == htons(80) || tcp->source == htons(80))
2965d472fbSAlexei Starovoitov return TC_ACT_SHOT;
3065d472fbSAlexei Starovoitov return 0;
3165d472fbSAlexei Starovoitov }
3265d472fbSAlexei Starovoitov
udp(void * data,uint64_t tp_off,void * data_end)3365d472fbSAlexei Starovoitov static int udp(void *data, uint64_t tp_off, void *data_end)
3465d472fbSAlexei Starovoitov {
3565d472fbSAlexei Starovoitov struct udphdr *udp = data + tp_off;
3665d472fbSAlexei Starovoitov
3765d472fbSAlexei Starovoitov if (udp + 1 > data_end)
3865d472fbSAlexei Starovoitov return 0;
3965d472fbSAlexei Starovoitov if (udp->dest == htons(DEFAULT_PKTGEN_UDP_PORT) ||
4065d472fbSAlexei Starovoitov udp->source == htons(DEFAULT_PKTGEN_UDP_PORT)) {
4165d472fbSAlexei Starovoitov if (DEBUG) {
4265d472fbSAlexei Starovoitov char fmt[] = "udp port 9 indeed\n";
4365d472fbSAlexei Starovoitov
4465d472fbSAlexei Starovoitov bpf_trace_printk(fmt, sizeof(fmt));
4565d472fbSAlexei Starovoitov }
4665d472fbSAlexei Starovoitov return TC_ACT_SHOT;
4765d472fbSAlexei Starovoitov }
4865d472fbSAlexei Starovoitov return 0;
4965d472fbSAlexei Starovoitov }
5065d472fbSAlexei Starovoitov
parse_ipv4(void * data,uint64_t nh_off,void * data_end)5165d472fbSAlexei Starovoitov static int parse_ipv4(void *data, uint64_t nh_off, void *data_end)
5265d472fbSAlexei Starovoitov {
5365d472fbSAlexei Starovoitov struct iphdr *iph;
5465d472fbSAlexei Starovoitov uint64_t ihl_len;
5565d472fbSAlexei Starovoitov
5665d472fbSAlexei Starovoitov iph = data + nh_off;
5765d472fbSAlexei Starovoitov if (iph + 1 > data_end)
5865d472fbSAlexei Starovoitov return 0;
5965d472fbSAlexei Starovoitov
6065d472fbSAlexei Starovoitov if (ip_is_fragment(iph))
6165d472fbSAlexei Starovoitov return 0;
6265d472fbSAlexei Starovoitov ihl_len = iph->ihl * 4;
6365d472fbSAlexei Starovoitov
6465d472fbSAlexei Starovoitov if (iph->protocol == IPPROTO_IPIP) {
6565d472fbSAlexei Starovoitov iph = data + nh_off + ihl_len;
6665d472fbSAlexei Starovoitov if (iph + 1 > data_end)
6765d472fbSAlexei Starovoitov return 0;
6865d472fbSAlexei Starovoitov ihl_len += iph->ihl * 4;
6965d472fbSAlexei Starovoitov }
7065d472fbSAlexei Starovoitov
7165d472fbSAlexei Starovoitov if (iph->protocol == IPPROTO_TCP)
7265d472fbSAlexei Starovoitov return tcp(data, nh_off + ihl_len, data_end);
7365d472fbSAlexei Starovoitov else if (iph->protocol == IPPROTO_UDP)
7465d472fbSAlexei Starovoitov return udp(data, nh_off + ihl_len, data_end);
7565d472fbSAlexei Starovoitov return 0;
7665d472fbSAlexei Starovoitov }
7765d472fbSAlexei Starovoitov
parse_ipv6(void * data,uint64_t nh_off,void * data_end)7865d472fbSAlexei Starovoitov static int parse_ipv6(void *data, uint64_t nh_off, void *data_end)
7965d472fbSAlexei Starovoitov {
8065d472fbSAlexei Starovoitov struct ipv6hdr *ip6h;
8165d472fbSAlexei Starovoitov struct iphdr *iph;
8265d472fbSAlexei Starovoitov uint64_t ihl_len = sizeof(struct ipv6hdr);
8365d472fbSAlexei Starovoitov uint64_t nexthdr;
8465d472fbSAlexei Starovoitov
8565d472fbSAlexei Starovoitov ip6h = data + nh_off;
8665d472fbSAlexei Starovoitov if (ip6h + 1 > data_end)
8765d472fbSAlexei Starovoitov return 0;
8865d472fbSAlexei Starovoitov
8965d472fbSAlexei Starovoitov nexthdr = ip6h->nexthdr;
9065d472fbSAlexei Starovoitov
9165d472fbSAlexei Starovoitov if (nexthdr == IPPROTO_IPIP) {
9265d472fbSAlexei Starovoitov iph = data + nh_off + ihl_len;
9365d472fbSAlexei Starovoitov if (iph + 1 > data_end)
9465d472fbSAlexei Starovoitov return 0;
9565d472fbSAlexei Starovoitov ihl_len += iph->ihl * 4;
9665d472fbSAlexei Starovoitov nexthdr = iph->protocol;
9765d472fbSAlexei Starovoitov } else if (nexthdr == IPPROTO_IPV6) {
9865d472fbSAlexei Starovoitov ip6h = data + nh_off + ihl_len;
9965d472fbSAlexei Starovoitov if (ip6h + 1 > data_end)
10065d472fbSAlexei Starovoitov return 0;
10165d472fbSAlexei Starovoitov ihl_len += sizeof(struct ipv6hdr);
10265d472fbSAlexei Starovoitov nexthdr = ip6h->nexthdr;
10365d472fbSAlexei Starovoitov }
10465d472fbSAlexei Starovoitov
10565d472fbSAlexei Starovoitov if (nexthdr == IPPROTO_TCP)
10665d472fbSAlexei Starovoitov return tcp(data, nh_off + ihl_len, data_end);
10765d472fbSAlexei Starovoitov else if (nexthdr == IPPROTO_UDP)
10865d472fbSAlexei Starovoitov return udp(data, nh_off + ihl_len, data_end);
10965d472fbSAlexei Starovoitov return 0;
11065d472fbSAlexei Starovoitov }
11165d472fbSAlexei Starovoitov
11265d472fbSAlexei Starovoitov SEC("varlen")
handle_ingress(struct __sk_buff * skb)11365d472fbSAlexei Starovoitov int handle_ingress(struct __sk_buff *skb)
11465d472fbSAlexei Starovoitov {
11565d472fbSAlexei Starovoitov void *data = (void *)(long)skb->data;
11665d472fbSAlexei Starovoitov struct ethhdr *eth = data;
11765d472fbSAlexei Starovoitov void *data_end = (void *)(long)skb->data_end;
11865d472fbSAlexei Starovoitov uint64_t h_proto, nh_off;
11965d472fbSAlexei Starovoitov
12065d472fbSAlexei Starovoitov nh_off = sizeof(*eth);
12165d472fbSAlexei Starovoitov if (data + nh_off > data_end)
12265d472fbSAlexei Starovoitov return 0;
12365d472fbSAlexei Starovoitov
12465d472fbSAlexei Starovoitov h_proto = eth->h_proto;
12565d472fbSAlexei Starovoitov
12665d472fbSAlexei Starovoitov if (h_proto == ETH_P_8021Q || h_proto == ETH_P_8021AD) {
12765d472fbSAlexei Starovoitov struct vlan_hdr *vhdr;
12865d472fbSAlexei Starovoitov
12965d472fbSAlexei Starovoitov vhdr = data + nh_off;
13065d472fbSAlexei Starovoitov nh_off += sizeof(struct vlan_hdr);
13165d472fbSAlexei Starovoitov if (data + nh_off > data_end)
13265d472fbSAlexei Starovoitov return 0;
13365d472fbSAlexei Starovoitov h_proto = vhdr->h_vlan_encapsulated_proto;
13465d472fbSAlexei Starovoitov }
13565d472fbSAlexei Starovoitov if (h_proto == ETH_P_8021Q || h_proto == ETH_P_8021AD) {
13665d472fbSAlexei Starovoitov struct vlan_hdr *vhdr;
13765d472fbSAlexei Starovoitov
13865d472fbSAlexei Starovoitov vhdr = data + nh_off;
13965d472fbSAlexei Starovoitov nh_off += sizeof(struct vlan_hdr);
14065d472fbSAlexei Starovoitov if (data + nh_off > data_end)
14165d472fbSAlexei Starovoitov return 0;
14265d472fbSAlexei Starovoitov h_proto = vhdr->h_vlan_encapsulated_proto;
14365d472fbSAlexei Starovoitov }
14465d472fbSAlexei Starovoitov if (h_proto == htons(ETH_P_IP))
14565d472fbSAlexei Starovoitov return parse_ipv4(data, nh_off, data_end);
14665d472fbSAlexei Starovoitov else if (h_proto == htons(ETH_P_IPV6))
14765d472fbSAlexei Starovoitov return parse_ipv6(data, nh_off, data_end);
14865d472fbSAlexei Starovoitov return 0;
14965d472fbSAlexei Starovoitov }
15065d472fbSAlexei Starovoitov char _license[] SEC("license") = "GPL";
151