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