Skip to content

Instantly share code, notes, and snippets.

@valkum
Last active April 25, 2016 18:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save valkum/0d70028b864b89639b4c0f6616612463 to your computer and use it in GitHub Desktop.
Save valkum/0d70028b864b89639b4c0f6616612463 to your computer and use it in GitHub Desktop.
mailinglist gist
#!/usr/bin/python
from __future__ import print_function
from bcc import BPF
from ctypes import *
import sys
import socket
import os
import struct
import hexdump
def encode_dns(name):
size = 32
if len(name) > 253:
raise Exception("DNS Name too long.")
b = bytearray()
elements = name.split(".")
for element in elements:
b.extend(struct.pack("!B", len(element)))
b.extend(element)
blen = len(b)
for i in range(blen, size): # Fill up the bytearray to match our 32 byte c_ubyte_Array_32 size
b.extend(b'\x00')
return (c_ubyte * size).from_buffer(b)
# initialize BPF - load source code from http-parse-simple.c
bpf = BPF(src_file = "test_dns.c", debug=0)
# print(bpf.dump_func("dns_test"))
#load eBPF program http_filter of type SOCKET_FILTER into the kernel eBPF vm
#more info about eBPF program types
#http://man7.org/linux/man-pages/man2/bpf.2.html
function_dns_test = bpf.load_func("dns_test", BPF.SOCKET_FILTER)
#create raw socket, bind it to eth0
#attach bpf program to socket created
BPF.attach_raw_socket(function_dns_test, "eth1")
# Get the table.
cache = bpf.get_table("cache")
# Create first entry for foo.bar
key = cache.Key()
key.p = encode_dns("foo.bar")
response = bytearray("127.0.0.2") # Some dummy content for now for our leaf
rlen = len(response)
for i in range(rlen, 32):
response.extend('\x00')
leaf = cache.Leaf()
leaf.p = (c_ubyte * 32).from_buffer(response)
cache[key] = leaf
# Create second entry for langer.name.bar
key = cache.Key()
key.p = encode_dns("langer.name.bar")
response = bytearray("127.0.0.2")
rlen = len(response)
for i in range(rlen, 32):
response.append(b'\x00')
leaf = cache.Leaf()
leaf.p = (c_ubyte * 32).from_buffer(response)
cache[key] = leaf
# If all works well, a dig @ipOfBPFMachine foo.bar should print now "yes im in cache!"
bpf.trace_print()
while 1:
for key, leaf in cache.items():
# print("%s %s" % (key, name))
hexdump.hexdump(cast(key.p, c_char_p).value)
hexdump.hexdump(cast(leaf.p, c_char_p).value)
#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;
/* number of entries in the question section */
uint16_t qdcount;
/* number of resource records in the answer section */
uint16_t ancount;
/* number of name server resource records in the authority records section*/
uint16_t nscount;
/* number of resource records in the additional records section */
uint16_t arcount;
} BPF_PACKET_HEADER;
struct dns_query_t
{
unsigned char *name;
unsigned short qtype;
unsigned short qclass;
} BPF_PACKET_HEADER;
struct dns_char_t
{
char c;
} BPF_PACKET_HEADER;
struct Key {
unsigned char p[32];
};
struct Leaf {
unsigned char p[32];
};
BPF_TABLE("hash", struct Key, struct Leaf, cache, 128);
int dns_test(struct __sk_buff *skb)
{
u8 *cursor = 0;
struct Key key = {};
struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
if(ethernet->type == ETH_P_IP) {
struct ip_t *ip = cursor_advance(cursor, sizeof(*ip));
u16 hlen_bytes = ip->hlen << 2;
if(ip->nextp == IPPROTO_UDP) {
struct udp_t *udp = cursor_advance(cursor, sizeof(*udp));
if(udp->dport == 53){
u8 *sentinel = cursor + udp->length - sizeof(*udp);
struct dns_hdr_t *dns_hdr = cursor_advance(cursor, sizeof(*dns_hdr));
//u8 *payload = cursor;
if((dns_hdr->flags >>15) != 0) {
// Exit if this packet is not a request.
return 0;
}
u16 i = 0;
struct dns_char_t *c;
//cursor_advance(cursor, 1);
if (cursor == sentinel) goto end; c = cursor_advance(cursor, 1); key.p[i++] = c->c;
if (cursor == sentinel) goto end; c = cursor_advance(cursor, 1); key.p[i++] = c->c;
if (cursor == sentinel) goto end; c = cursor_advance(cursor, 1); key.p[i++] = c->c;
if (cursor == sentinel) goto end; c = cursor_advance(cursor, 1); key.p[i++] = c->c;
if (cursor == sentinel) goto end; c = cursor_advance(cursor, 1); key.p[i++] = c->c;
if (cursor == sentinel) goto end; c = cursor_advance(cursor, 1); key.p[i++] = c->c;
if (cursor == sentinel) goto end; c = cursor_advance(cursor, 1); key.p[i++] = c->c;
if (cursor == sentinel) goto end; c = cursor_advance(cursor, 1); key.p[i++] = c->c;
if (cursor == sentinel) goto end; c = cursor_advance(cursor, 1); key.p[i++] = c->c;
if (cursor == sentinel) goto end; c = cursor_advance(cursor, 1); key.p[i++] = c->c;
if (cursor == sentinel) goto end; c = cursor_advance(cursor, 1); key.p[i++] = c->c;
if (cursor == sentinel) goto end; c = cursor_advance(cursor, 1); key.p[i++] = c->c;
if (cursor == sentinel) goto end; c = cursor_advance(cursor, 1); key.p[i++] = c->c;
if (cursor == sentinel) goto end; c = cursor_advance(cursor, 1); key.p[i++] = c->c;
if (cursor == sentinel) goto end; c = cursor_advance(cursor, 1); key.p[i++] = c->c;
if (cursor == sentinel) goto end; c = cursor_advance(cursor, 1); key.p[i++] = c->c;
if (cursor == sentinel) goto end; c = cursor_advance(cursor, 1); key.p[i++] = c->c;
if (cursor == sentinel) goto end; c = cursor_advance(cursor, 1); key.p[i++] = c->c;
if (cursor == sentinel) goto end; c = cursor_advance(cursor, 1); key.p[i++] = c->c;
if (cursor == sentinel) goto end; c = cursor_advance(cursor, 1); key.p[i++] = c->c;
if (cursor == sentinel) goto end; c = cursor_advance(cursor, 1); key.p[i++] = c->c;
if (cursor == sentinel) goto end; c = cursor_advance(cursor, 1); key.p[i++] = c->c;
if (cursor == sentinel) goto end; c = cursor_advance(cursor, 1); key.p[i++] = c->c;
if (cursor == sentinel) goto end; c = cursor_advance(cursor, 1); key.p[i++] = c->c;
end:
{}
struct Leaf * lookup_leaf = cache.lookup(&key);
bpf_trace_printk("key: %x %s\n", &key, &key);
bpf_trace_printk("leaf: %p %s\n", lookup_leaf);
if(lookup_leaf) {
bpf_trace_printk("yes im in cache");
}
return -1;
}
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment