Last active
April 25, 2016 18:04
-
-
Save valkum/0d70028b864b89639b4c0f6616612463 to your computer and use it in GitHub Desktop.
mailinglist gist
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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