Home | History | Annotate | Download | only in dns_matching
      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 
     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