104 lines
2.3 KiB
C
104 lines
2.3 KiB
C
/*
|
|
* dns_matching.c Drop DNS packets requesting DNS name contained in hash map
|
|
* For Linux, uses BCC, eBPF. See .py file.
|
|
*
|
|
* Copyright (c) 2016 Rudi Floren.
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of version 2 of the GNU General Public
|
|
* License as published by the Free Software Foundation.
|
|
*
|
|
* 11-May-2016 Rudi Floren Created this.
|
|
*/
|
|
|
|
#include <uapi/linux/bpf.h>
|
|
#include <uapi/linux/if_ether.h>
|
|
#include <uapi/linux/if_packet.h>
|
|
#include <uapi/linux/ip.h>
|
|
#include <uapi/linux/in.h>
|
|
#include <uapi/linux/udp.h>
|
|
#include <bcc/proto.h>
|
|
|
|
#define ETH_LEN 14
|
|
|
|
struct dns_hdr_t
|
|
{
|
|
uint16_t id;
|
|
uint16_t flags;
|
|
uint16_t qdcount;
|
|
uint16_t ancount;
|
|
uint16_t nscount;
|
|
uint16_t arcount;
|
|
} BPF_PACKET_HEADER;
|
|
|
|
|
|
struct dns_query_flags_t
|
|
{
|
|
uint16_t qtype;
|
|
uint16_t qclass;
|
|
} BPF_PACKET_HEADER;
|
|
|
|
struct dns_char_t
|
|
{
|
|
char c;
|
|
} BPF_PACKET_HEADER;
|
|
|
|
struct Key {
|
|
unsigned char p[255];
|
|
};
|
|
|
|
struct Leaf {
|
|
// Not really needed in this example
|
|
unsigned char p[4];
|
|
};
|
|
|
|
BPF_HASH(cache, struct Key, struct Leaf, 128);
|
|
|
|
int dns_matching(struct __sk_buff *skb)
|
|
{
|
|
u8 *cursor = 0;
|
|
struct Key key = {};
|
|
// Check of ethernet/IP frame.
|
|
struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
|
|
if(ethernet->type == ETH_P_IP) {
|
|
|
|
// Check for UDP.
|
|
struct ip_t *ip = cursor_advance(cursor, sizeof(*ip));
|
|
u16 hlen_bytes = ip->hlen << 2;
|
|
if(ip->nextp == IPPROTO_UDP) {
|
|
|
|
// Check for Port 53, DNS packet.
|
|
struct udp_t *udp = cursor_advance(cursor, sizeof(*udp));
|
|
if(udp->dport == 53){
|
|
|
|
struct dns_hdr_t *dns_hdr = cursor_advance(cursor, sizeof(*dns_hdr));
|
|
|
|
// Do nothing if packet is not a request.
|
|
if((dns_hdr->flags >>15) != 0) {
|
|
// Exit if this packet is not a request.
|
|
return -1;
|
|
}
|
|
|
|
u16 i = 0;
|
|
struct dns_char_t *c;
|
|
#pragma unroll
|
|
for(i = 0; i<255;i++){
|
|
c = cursor_advance(cursor, 1);
|
|
if (c->c == 0)
|
|
break;
|
|
key.p[i] = c->c;
|
|
}
|
|
|
|
struct Leaf * lookup_leaf = cache.lookup(&key);
|
|
|
|
// If DNS name is contained in our map, keep the packet
|
|
if(lookup_leaf) {
|
|
bpf_trace_printk("Matched1\n");
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Drop the packet
|
|
return 0;
|
|
}
|