xref: /OK3568_Linux_fs/kernel/samples/bpf/parse_varlen.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /* Copyright (c) 2016 Facebook
2*4882a593Smuzhiyun  *
3*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or
4*4882a593Smuzhiyun  * modify it under the terms of version 2 of the GNU General Public
5*4882a593Smuzhiyun  * License as published by the Free Software Foundation.
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun #define KBUILD_MODNAME "foo"
8*4882a593Smuzhiyun #include <linux/if_ether.h>
9*4882a593Smuzhiyun #include <linux/if_vlan.h>
10*4882a593Smuzhiyun #include <linux/ip.h>
11*4882a593Smuzhiyun #include <linux/ipv6.h>
12*4882a593Smuzhiyun #include <linux/in.h>
13*4882a593Smuzhiyun #include <linux/tcp.h>
14*4882a593Smuzhiyun #include <linux/udp.h>
15*4882a593Smuzhiyun #include <uapi/linux/bpf.h>
16*4882a593Smuzhiyun #include <net/ip.h>
17*4882a593Smuzhiyun #include <bpf/bpf_helpers.h>
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #define DEFAULT_PKTGEN_UDP_PORT 9
20*4882a593Smuzhiyun #define DEBUG 0
21*4882a593Smuzhiyun 
tcp(void * data,uint64_t tp_off,void * data_end)22*4882a593Smuzhiyun static int tcp(void *data, uint64_t tp_off, void *data_end)
23*4882a593Smuzhiyun {
24*4882a593Smuzhiyun 	struct tcphdr *tcp = data + tp_off;
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun 	if (tcp + 1 > data_end)
27*4882a593Smuzhiyun 		return 0;
28*4882a593Smuzhiyun 	if (tcp->dest == htons(80) || tcp->source == htons(80))
29*4882a593Smuzhiyun 		return TC_ACT_SHOT;
30*4882a593Smuzhiyun 	return 0;
31*4882a593Smuzhiyun }
32*4882a593Smuzhiyun 
udp(void * data,uint64_t tp_off,void * data_end)33*4882a593Smuzhiyun static int udp(void *data, uint64_t tp_off, void *data_end)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun 	struct udphdr *udp = data + tp_off;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	if (udp + 1 > data_end)
38*4882a593Smuzhiyun 		return 0;
39*4882a593Smuzhiyun 	if (udp->dest == htons(DEFAULT_PKTGEN_UDP_PORT) ||
40*4882a593Smuzhiyun 	    udp->source == htons(DEFAULT_PKTGEN_UDP_PORT)) {
41*4882a593Smuzhiyun 		if (DEBUG) {
42*4882a593Smuzhiyun 			char fmt[] = "udp port 9 indeed\n";
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun 			bpf_trace_printk(fmt, sizeof(fmt));
45*4882a593Smuzhiyun 		}
46*4882a593Smuzhiyun 		return TC_ACT_SHOT;
47*4882a593Smuzhiyun 	}
48*4882a593Smuzhiyun 	return 0;
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun 
parse_ipv4(void * data,uint64_t nh_off,void * data_end)51*4882a593Smuzhiyun static int parse_ipv4(void *data, uint64_t nh_off, void *data_end)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun 	struct iphdr *iph;
54*4882a593Smuzhiyun 	uint64_t ihl_len;
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	iph = data + nh_off;
57*4882a593Smuzhiyun 	if (iph + 1 > data_end)
58*4882a593Smuzhiyun 		return 0;
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	if (ip_is_fragment(iph))
61*4882a593Smuzhiyun 		return 0;
62*4882a593Smuzhiyun 	ihl_len = iph->ihl * 4;
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	if (iph->protocol == IPPROTO_IPIP) {
65*4882a593Smuzhiyun 		iph = data + nh_off + ihl_len;
66*4882a593Smuzhiyun 		if (iph + 1 > data_end)
67*4882a593Smuzhiyun 			return 0;
68*4882a593Smuzhiyun 		ihl_len += iph->ihl * 4;
69*4882a593Smuzhiyun 	}
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	if (iph->protocol == IPPROTO_TCP)
72*4882a593Smuzhiyun 		return tcp(data, nh_off + ihl_len, data_end);
73*4882a593Smuzhiyun 	else if (iph->protocol == IPPROTO_UDP)
74*4882a593Smuzhiyun 		return udp(data, nh_off + ihl_len, data_end);
75*4882a593Smuzhiyun 	return 0;
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun 
parse_ipv6(void * data,uint64_t nh_off,void * data_end)78*4882a593Smuzhiyun static int parse_ipv6(void *data, uint64_t nh_off, void *data_end)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun 	struct ipv6hdr *ip6h;
81*4882a593Smuzhiyun 	struct iphdr *iph;
82*4882a593Smuzhiyun 	uint64_t ihl_len = sizeof(struct ipv6hdr);
83*4882a593Smuzhiyun 	uint64_t nexthdr;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	ip6h = data + nh_off;
86*4882a593Smuzhiyun 	if (ip6h + 1 > data_end)
87*4882a593Smuzhiyun 		return 0;
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	nexthdr = ip6h->nexthdr;
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	if (nexthdr == IPPROTO_IPIP) {
92*4882a593Smuzhiyun 		iph = data + nh_off + ihl_len;
93*4882a593Smuzhiyun 		if (iph + 1 > data_end)
94*4882a593Smuzhiyun 			return 0;
95*4882a593Smuzhiyun 		ihl_len += iph->ihl * 4;
96*4882a593Smuzhiyun 		nexthdr = iph->protocol;
97*4882a593Smuzhiyun 	} else if (nexthdr == IPPROTO_IPV6) {
98*4882a593Smuzhiyun 		ip6h = data + nh_off + ihl_len;
99*4882a593Smuzhiyun 		if (ip6h + 1 > data_end)
100*4882a593Smuzhiyun 			return 0;
101*4882a593Smuzhiyun 		ihl_len += sizeof(struct ipv6hdr);
102*4882a593Smuzhiyun 		nexthdr = ip6h->nexthdr;
103*4882a593Smuzhiyun 	}
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	if (nexthdr == IPPROTO_TCP)
106*4882a593Smuzhiyun 		return tcp(data, nh_off + ihl_len, data_end);
107*4882a593Smuzhiyun 	else if (nexthdr == IPPROTO_UDP)
108*4882a593Smuzhiyun 		return udp(data, nh_off + ihl_len, data_end);
109*4882a593Smuzhiyun 	return 0;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun SEC("varlen")
handle_ingress(struct __sk_buff * skb)113*4882a593Smuzhiyun int handle_ingress(struct __sk_buff *skb)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun 	void *data = (void *)(long)skb->data;
116*4882a593Smuzhiyun 	struct ethhdr *eth = data;
117*4882a593Smuzhiyun 	void *data_end = (void *)(long)skb->data_end;
118*4882a593Smuzhiyun 	uint64_t h_proto, nh_off;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	nh_off = sizeof(*eth);
121*4882a593Smuzhiyun 	if (data + nh_off > data_end)
122*4882a593Smuzhiyun 		return 0;
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	h_proto = eth->h_proto;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	if (h_proto == ETH_P_8021Q || h_proto == ETH_P_8021AD) {
127*4882a593Smuzhiyun 		struct vlan_hdr *vhdr;
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 		vhdr = data + nh_off;
130*4882a593Smuzhiyun 		nh_off += sizeof(struct vlan_hdr);
131*4882a593Smuzhiyun 		if (data + nh_off > data_end)
132*4882a593Smuzhiyun 			return 0;
133*4882a593Smuzhiyun 		h_proto = vhdr->h_vlan_encapsulated_proto;
134*4882a593Smuzhiyun 	}
135*4882a593Smuzhiyun 	if (h_proto == ETH_P_8021Q || h_proto == ETH_P_8021AD) {
136*4882a593Smuzhiyun 		struct vlan_hdr *vhdr;
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 		vhdr = data + nh_off;
139*4882a593Smuzhiyun 		nh_off += sizeof(struct vlan_hdr);
140*4882a593Smuzhiyun 		if (data + nh_off > data_end)
141*4882a593Smuzhiyun 			return 0;
142*4882a593Smuzhiyun 		h_proto = vhdr->h_vlan_encapsulated_proto;
143*4882a593Smuzhiyun 	}
144*4882a593Smuzhiyun 	if (h_proto == htons(ETH_P_IP))
145*4882a593Smuzhiyun 		return parse_ipv4(data, nh_off, data_end);
146*4882a593Smuzhiyun 	else if (h_proto == htons(ETH_P_IPV6))
147*4882a593Smuzhiyun 		return parse_ipv6(data, nh_off, data_end);
148*4882a593Smuzhiyun 	return 0;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun char _license[] SEC("license") = "GPL";
151