1 /*
2 * dns_matching.c Drop DNS packets requesting DNS name contained in hash map
3 * For Linux, uses BCC, eBPF. See .py file.
4 *
5 * Copyright (c) 2016 Rudi Floren.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * 11-May-2016 Rudi Floren Created this.
11 */
12
13 #include <uapi/linux/bpf.h>
14 #include <uapi/linux/if_ether.h>
15 #include <uapi/linux/if_packet.h>
16 #include <uapi/linux/ip.h>
17 #include <uapi/linux/in.h>
18 #include <uapi/linux/udp.h>
19 #include <bcc/proto.h>
20
21 #define ETH_LEN 14
22
23 struct dns_hdr_t
24 {
25 uint16_t id;
26 uint16_t flags;
27 uint16_t qdcount;
28 uint16_t ancount;
29 uint16_t nscount;
30 uint16_t arcount;
31 } BPF_PACKET_HEADER;
32
33
34 struct dns_query_flags_t
35 {
36 uint16_t qtype;
37 uint16_t qclass;
38 } BPF_PACKET_HEADER;
39
40 struct dns_char_t
41 {
42 char c;
43 } BPF_PACKET_HEADER;
44
45 struct Key {
46 unsigned char p[255];
47 };
48
49 struct Leaf {
50 // Not really needed in this example
51 unsigned char p[4];
52 };
53
54 BPF_HASH(cache, struct Key, struct Leaf, 128);
55
dns_matching(struct __sk_buff * skb)56 int dns_matching(struct __sk_buff *skb)
57 {
58 u8 *cursor = 0;
59 struct Key key = {};
60 // Check of ethernet/IP frame.
61 struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
62 if(ethernet->type == ETH_P_IP) {
63
64 // Check for UDP.
65 struct ip_t *ip = cursor_advance(cursor, sizeof(*ip));
66 u16 hlen_bytes = ip->hlen << 2;
67 if(ip->nextp == IPPROTO_UDP) {
68
69 // Check for Port 53, DNS packet.
70 struct udp_t *udp = cursor_advance(cursor, sizeof(*udp));
71 if(udp->dport == 53){
72
73 struct dns_hdr_t *dns_hdr = cursor_advance(cursor, sizeof(*dns_hdr));
74
75 // Do nothing if packet is not a request.
76 if((dns_hdr->flags >>15) != 0) {
77 // Exit if this packet is not a request.
78 return -1;
79 }
80
81 u16 i = 0;
82 struct dns_char_t *c;
83 #pragma unroll
84 for(i = 0; i<255;i++){
85 c = cursor_advance(cursor, 1);
86 if (c->c == 0)
87 break;
88 key.p[i] = c->c;
89 }
90
91 struct Leaf * lookup_leaf = cache.lookup(&key);
92
93 // If DNS name is contained in our map, keep the packet
94 if(lookup_leaf) {
95 bpf_trace_printk("Matched1\n");
96 return -1;
97 }
98 }
99 }
100 }
101 // Drop the packet
102 return 0;
103 }
104