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