Compare commits

...

9 Commits

Author SHA1 Message Date
8e9822d232 update 2025-02-09 14:52:08 +01:00
65a0f2447d update 2025-02-09 11:14:36 +01:00
8abce2236f Update 2025-02-08 15:12:27 +01:00
be9022d0a6 Update 2025-02-08 15:04:30 +01:00
gbucchino
1449cc961d update 2025-02-06 15:25:34 +01:00
0872e2a6a7 update 2025-02-05 20:02:34 +01:00
gbucchino
6aa4b64a5a Change if 2025-02-05 11:14:06 +01:00
08bc7e98d0 update 2025-02-04 20:01:52 +01:00
adbff3257a Update 2025-02-02 18:31:52 +01:00
17 changed files with 338 additions and 132077 deletions

2
.gitignore vendored Normal file

@ -0,0 +1,2 @@
src/**.swp
**.log

@ -7,7 +7,7 @@ LIBS=-L../libbpf/src -l:libbpf.a -lelf -lz
all: dns-trace.ebpf.o dns-trace
dns-trace.ebpf.o: src/dns-trace.ebpf.c
$(CL) -g -O2 -target bpf -D __TARGET_ARCH_x86_64 -D __BPF_TRACING__ -L../libbpf/src -l:libbpf.a -c src/dns-trace.ebpf.c -o src/dns-trace.ebpf.o
$(CL) -Wall -g -O2 -target bpf -D __TARGET_ARCH_x86_64 -D __BPF_TRACING__ -c src/dns-trace.ebpf.c -o src/dns-trace.ebpf.o
dns-trace: src/dns-trace.c
$(GCC) $(CFLAGS) src/dns-trace.c -o dns-trace $(LIBS)

Binary file not shown.

BIN
dns-trace

Binary file not shown.

BIN
dns.pcap

Binary file not shown.

Binary file not shown.

BIN
dns2.pcap

Binary file not shown.

BIN
dns3.pcap

Binary file not shown.

BIN
dns4.pcap

Binary file not shown.

@ -1,6 +1,6 @@
#!/usr/bin/sh
sudo bpftool btf dump file /sys/kernel/btf/vmlinux format c > src/vmlinux.h
#sudo bpftool btf dump file /sys/kernel/btf/vmlinux format c > src/vmlinux.h
make clean
make all && sudo ./dns-trace
make all && sudo ./dns-trace -i wlp0s20f3 -f dns-trace_`$(echo date '+%F')`.log

@ -32,18 +32,4 @@ struct event {
unsigned char buf[MAX_UDP_PAYLOAD]; // On stocke la data au format size + data
};
struct query_section{
char qname[QNAME_SIZE];
size_t qname_len;
uint16_t class;
uint16_t type;
};
struct dns_answer {
char data[512];
uint16_t class;
uint16_t type;
uint32_t ttl;
};
#endif

@ -9,6 +9,7 @@
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <time.h>
#include <fcntl.h>
#include <net/if.h> /* if_nametoindex */
#include <linux/if_ether.h>
@ -17,10 +18,15 @@
#include "common.h"
/* Global variables */
static struct arguments arguments;
static int running = 1;
static FILE *f;
static char hostname[127];
struct arguments {
char *interface;
char *filename;
int to_output;
};
@ -31,7 +37,7 @@ struct arguments {
*/
static char doc[] = "DNS Trace usage:";
static char args_doc[] = "ARG1 ARG2";
static char args_doc[] = "[ARGS]";
static error_t parse_opts(int key, char *arg, struct argp_state *state){
struct arguments *arguments = state->input;
@ -40,6 +46,9 @@ static error_t parse_opts(int key, char *arg, struct argp_state *state){
arguments->filename = arg;
arguments->to_output = 0;
break;
case 'i':
arguments->interface = arg;
break;
case 'o':
arguments->to_output = 1;
break;
@ -56,12 +65,14 @@ static error_t parse_opts(int key, char *arg, struct argp_state *state){
struct arguments parse_args(int argc, char *argv[]){
static const struct argp_option opts[] = {
{"interface", 'i', "INTERFACE", 0, "Ifname for listening"},
{"filename", 'f', "FILENAME", 0, "Save result to logs"},
{"to-output", 'o', NULL, 0, "Print to output"},
{NULL, 'h', NULL, OPTION_HIDDEN, "help"},
{},
};
struct arguments arguments;
arguments.interface = NULL;
arguments.filename = NULL;
arguments.to_output = 1;
static struct argp argp = {opts, parse_opts, args_doc, doc};
@ -75,9 +86,10 @@ struct arguments parse_args(int argc, char *argv[]){
static void signalHandler(int signum){
running = 0;
}
static int open_raw_sock(const char *name)
{
/*
* This function create a raw socket and bind it to the ifname
*/
static int create_rsock(const char *name) {
struct sockaddr_ll sll;
int sock;
@ -92,7 +104,6 @@ static int open_raw_sock(const char *name)
sll.sll_ifindex = if_nametoindex(name);
sll.sll_protocol = htons(ETH_P_ALL);
if (bind(sock, (struct sockaddr *)&sll, sizeof(sll)) < 0) {
//printf("bind to %s: %s\n", name, strerror(errno));
printf("Failed to bind the interface %s\n", name);
close(sock);
return -1;
@ -101,6 +112,9 @@ static int open_raw_sock(const char *name)
return sock;
}
/*
* This function map the type of DNS request
*/
static char *mapReqType(const int req){
char *tmp = malloc(8);
if (tmp == NULL)
@ -118,6 +132,9 @@ static char *mapReqType(const int req){
};
return tmp;
}
/*
* This function map the DNS class RR
*/
static char *mapClass(const int class){
char *tmp = malloc(8);
if (tmp == NULL)
@ -143,6 +160,9 @@ static char *mapClass(const int class){
}
return tmp;
}
/*
* This function map the DNS type RR
*/
static char *mapType(const int type){
char *tmp = malloc(8);
if (tmp == NULL)
@ -212,16 +232,43 @@ static char *mapType(const int type){
return tmp;
}
/*
* This function get the localtime into the rsyslog format
*/
static int syslog_time(time_t ts, char t[32], size_t l){
const char format[] = "%b %d %T";
struct tm *lt = localtime(&ts);
if(strftime(t, l, format, lt) == 0)
return -1;
return 0;
}
/*
* This function get the hostname of the system
* If not find, the hostname is ubuntu
*/
static void get_hostname(){
/* Get the hostname */
if (gethostname(hostname, 127) == -1){
printf("Failed to get the hostname\n");
strncpy(hostname, "ubuntu", 7);
}
}
/*
* This function print to the stdout the query section
*/
static void print_query(struct event *s_event){
char *req_type, *class, *type;
printf("%s:%-10d", inet_ntoa(*(struct in_addr*)&s_event->client), s_event->dport);
printf("%-5x", s_event->tid);
char t[32];
time_t ts = time(NULL);
syslog_time(ts, t, sizeof(t));
printf("%-20s", t);
req_type = mapReqType(s_event->req_type);
printf("%-10s", req_type);
printf("%s ", req_type);
free(req_type);
printf("%-30s", s_event->qname);
printf("%5s:%d\t", inet_ntoa(*(struct in_addr*)&s_event->client), s_event->dport);
printf("%x\t", s_event->tid);
class = mapClass(s_event->class);
printf("%-5s", class);
@ -231,7 +278,68 @@ static void print_query(struct event *s_event){
printf("%-5s", type);
free(type);
printf("%s", s_event->qname);
printf("\n");
}
/*
* This function save to rsyslog file the common information
*/
static void header_to_log(struct event *s_event){
char t[32];
char tid[12];
char src[40];
char *req_type;
time_t ts = time(NULL);
if (syslog_time(ts, t, sizeof(t)) == 0)
fwrite(t, strlen(t), 1, f);
fwrite(" ", 1, 1, f);
fwrite(hostname, strlen(hostname), 1, f);
fwrite(" dns-trace: ", 12, 1, f);
fwrite("<info> ", 7, 1, f);
req_type = mapReqType(s_event->req_type);
fwrite(req_type, strlen(req_type), 1, f);
free(req_type);
fwrite(";", 1, 1, f);
snprintf(tid, 12, "tid=%x;", s_event->tid);
fwrite(tid, strlen(tid), 1, f);
snprintf(src, 40, "%s:%d;", inet_ntoa(*(struct in_addr*)&s_event->client), s_event->dport);
fwrite(src, strlen(src), 1, f);
}
/*
* This function save to log file the query section in rsylog format
* <time> <hostname> <procname>: <info> <data>
*/
static void query_to_log(struct event *s_event){
char *class, *type;
char s_class[16], s_type[16];
header_to_log(s_event);
class = mapClass(s_event->class);
snprintf(s_class, 16, "class=%s;", class);
fwrite(s_class, strlen(s_class), 1, f);
free(class);
type = mapType(s_event->type);
snprintf(s_type, 16, "type=%s;", type);
fwrite(s_type, strlen(s_type), 1, f);
free(type);
fwrite("domain=", 7, 1, f);
fwrite(s_event->qname, strlen(s_event->qname), 1, f);
fwrite(";\n", 2, 1, f);
}
/*
* This function get labels from DNS answer
*/
static void get_labels(unsigned char *buf, char *qname){
int pos = 0;
while (*buf++ != '\0') {
@ -245,67 +353,190 @@ static void get_labels(unsigned char *buf, char *qname){
}
qname[pos - 1] = '\0';
}
/*
* This function read the event buf which contains the DNS answer section
*/
static void get_answer(struct event *s_event, uint16_t *class, uint16_t *type, uint16_t *size, uint32_t *ttl, int *pos){
int p = *pos;
*type = s_event->buf[p++];
*type |= s_event->buf[p++] << 8;
*class = s_event->buf[p++];
*class |= s_event->buf[p++] << 8;
*ttl = s_event->buf[p++];
*ttl |= s_event->buf[p++] << 8;
*ttl |= s_event->buf[p++] << 16;
*ttl |= s_event->buf[p++] << 24;
*size = s_event->buf[p++];
*size |= s_event->buf[p++] << 8;
*pos = p;
}
/*
* This function save to rsyslog format the answer section
*/
static void answer_to_log(struct event *s_event){
int pos = 0;
for (int i = 0; i < s_event->numAns; i++){
char *s_class, *s_type;
uint16_t i_type, i_class, i_size;
uint32_t i_ttl;
char b_class[16], b_type[16], b_ttl[16];
/*
* According to the RFC 1035 (https://datatracker.ietf.org/doc/html/rfc1035#section-4.1.4)
* In the section 4.1.4, message compression, the first two bits are set at 11 (0xc),
* that's means, it's a pointer.
* For instance, the two bytes 0xc00c, 0xc (11) it's the pointer and 0x00c is the position in the DNS header
*/
uint16_t msg = s_event->buf[pos++];
msg |= s_event->buf[pos++] << 8;
header_to_log(s_event);
get_answer(s_event, &i_class, &i_type, &i_size, &i_ttl, &pos);
i_type = ntohs(i_type);
i_class = ntohs(i_class);
i_ttl = ntohl(i_ttl);
i_size = ntohs(i_size);
s_class = mapClass(i_class);
snprintf(b_class, 16, "class=%s;", s_class);
fwrite(b_class, strlen(b_class), 1, f);
free(s_class);
s_type = mapType(i_type);
snprintf(b_type, 16, "type=%s;", s_type);
fwrite(b_type, strlen(b_type), 1, f);
free(s_type);
snprintf(b_ttl, 16, "ttl=%d;", i_ttl);
fwrite(b_ttl, strlen(b_ttl), 1, f);
// Decode data
if (i_type == 1) { // -> A
uint32_t ip = s_event->buf[pos] + (s_event->buf[pos+1] << 8) + (s_event->buf[pos+2] << 16) + (s_event->buf[pos+3] << 24);
char s_ip[36];
snprintf(s_ip, 36, "ip=%s;", inet_ntoa(*(struct in_addr*)&ip));
fwrite(s_ip, strlen(s_ip), 1, f);
}
if (i_type == 5) { // -> CNAME
char cname[i_size];
char buf[i_size + 7]; // 7 -> cname=;
get_labels(s_event->buf + pos, cname);
snprintf(buf, i_size + 7, "cname=%s;", cname);
fwrite(buf, strlen(buf), 1, f);
}
if (i_type == 28){ // -> AAAA
char buf[128];
snprintf(buf, 128, "ipv6=%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x;",
s_event->buf[pos], s_event->buf[pos + 1],
s_event->buf[pos + 2], s_event->buf[pos + 3],
s_event->buf[pos + 4], s_event->buf[pos + 5],
s_event->buf[pos + 6], s_event->buf[pos + 7],
s_event->buf[pos + 8], s_event->buf[pos + 9],
s_event->buf[pos + 10], s_event->buf[pos + 11],
s_event->buf[pos + 12], s_event->buf[pos + 13],
s_event->buf[pos + 14], s_event->buf[pos + 15]);
fwrite(buf, strlen(buf), 1, f);
}
pos += i_size;
fwrite("\n", 1, 1, f);
}
}
/*
* This function print to the stdout the answer section
*/
static void print_answer(struct event *s_event){
char *req_type;
int pos = 0;
char t[32];
time_t ts = time(NULL);
for (int i = 0; i < s_event->numAns; i++){
uint16_t type, class, size;
char *s_type, *s_class;
uint32_t ttl;
uint16_t msg = s_event->buf[pos++];
msg |= s_event->buf[pos++] << 8;
/* Print answer hdr */
syslog_time(ts, t, sizeof(t));
printf("%-20s", t);
req_type = mapReqType(s_event->req_type);
printf("%s ", req_type);
free(req_type);
printf("%5s:%5d\t", inet_ntoa(*(struct in_addr*)&s_event->client), s_event->dport);
printf("%x\t", s_event->tid);
get_answer(s_event, &class, &type, &size, &ttl, &pos);
type = ntohs(type);
class = ntohs(class);
ttl = ntohl(ttl);
size = ntohs(size);
/* Print answer data */
s_class = mapClass(class);
printf("%-5s", s_class);
free(s_class);
s_type = mapType(type);
printf("%s\t", s_type);
free(s_type);
if (type == 1) { // -> A
uint32_t ip = s_event->buf[pos] + (s_event->buf[pos+1] << 8) + (s_event->buf[pos+2] << 16) + (s_event->buf[pos+3] << 24);
printf("%s %5d", inet_ntoa(*(struct in_addr*)&ip), ttl);
}
if (type == 5) { // -> CNAME
char cname[size];
get_labels(s_event->buf + pos, cname);
printf("%s %d ", cname, ttl);
}
if (type == 28){ // -> AAAA
for (int i = 0; i < size; i++){
if (i % 2 == 0)
printf("%x", s_event->buf[pos]);
else{
if (i < (size - 1))
printf("%x:", s_event->buf[pos]);
else
printf("%x", s_event->buf[pos]);
}
pos++;
}
printf(" %d ", ttl);
}
pos += size;
printf("\n");
}
}
/*
* This function is called when a new event is pushed in the ring buffer from the eBPf program
*/
int handle_event(void *ctx, void *data, size_t data_sz){
struct event *s_event = (struct event*)data;
if (s_event->req_type == REQ_QUERY){
print_query(s_event);
if (arguments.to_output == 1)
print_query(s_event);
if (arguments.filename != NULL && f != NULL)
query_to_log(s_event);
}
if (s_event->req_type == REQ_ANSWER){
int pos = 0;
/*for (int i = 0; i < 50; i++)
printf("%d ", s_event->buf[i]);
printf("\n");*/
for (int i = 0; i < s_event->numAns; i++){
print_query(s_event);
uint16_t msg = s_event->buf[pos++];
msg |= s_event->buf[pos++] << 8;
uint16_t type = s_event->buf[pos++];
type |= s_event->buf[pos++] << 8;
uint16_t class = s_event->buf[pos++];
class |= s_event->buf[pos++] << 8;
uint32_t ttl = s_event->buf[pos++];
ttl |= s_event->buf[pos++] << 8;
ttl |= s_event->buf[pos++] << 16;
ttl |= s_event->buf[pos++] << 24;
uint16_t size = s_event->buf[pos++];
size |= s_event->buf[pos++] << 8;
type = ntohs(type);
class = ntohs(class);
ttl = ntohl(ttl);
size = ntohs(size);
if (type == 1) { // -> A
uint32_t ip = s_event->buf[pos] + (s_event->buf[pos+1] << 8) + (s_event->buf[pos+2] << 16) + (s_event->buf[pos+3] << 24);
printf("%s (%d)%5d", inet_ntoa(*(struct in_addr*)&ip), type, ttl);
}
if (type == 5) { // -> CNAME
char cname[size];
get_labels(s_event->buf + pos, cname);
printf("%s ", cname);
}
if (type == 28){ // -> AAAA
int p = 0;
for (int i = 0; i < size; i++){
if (i % 2 == 0)
printf("%x", s_event->buf[pos + p++]);
else{
if (i<size - 1)
printf("%x:", s_event->buf[pos + p++]);
else
printf("%x", s_event->buf[pos + p++]);
}
}
}
pos += size;
printf("\n");
}
if (arguments.to_output == 1)
print_answer(s_event);
if (arguments.filename != NULL && f != NULL)
answer_to_log(s_event);
}
printf("\n");
return 0;
}
int main(int argc, char *argv[]){
@ -315,9 +546,31 @@ int main(int argc, char *argv[]){
struct ring_buffer *rb;
int err;
int fd_map_data;
int sock;
arguments = parse_args(argc, argv); // Parsing arguments
if (arguments.interface == NULL){
printf("You must specified the interface name\n");
exit(-1);
}
printf("Listen to %s\n", arguments.interface);
sock = create_rsock(arguments.interface);
if (sock == -1){
printf("Failed to listen to the interface %s\n", arguments.interface);
exit(-1);
}
if (arguments.filename != NULL){
f = fopen(arguments.filename, "a");
if (f == NULL){
printf("Failed to create the file %s\n", arguments.filename);
return -1;
}
printf("Save to %s\n", arguments.filename);
}
signal(SIGINT, signalHandler);
/* Open and load our eBPF object */
@ -351,14 +604,13 @@ int main(int argc, char *argv[]){
}
bpf_program__attach(programSkb);
// int sock = open_raw_sock("wlp0s20f3");
//int sock = open_raw_sock("enx98e743c667fc");
int sock = open_raw_sock("lo");
printf("Socket: %d\n", sock);
int prog_fd = bpf_program__fd(programSkb);
printf("Program fd: %d\n", prog_fd);
setsockopt(sock, SOL_SOCKET, SO_ATTACH_BPF, &prog_fd, sizeof(int));
/* Get the hostname of the system */
get_hostname();
/* Start the ringbuffer */
rb = ring_buffer__new(fd_map_data, handle_event, NULL, NULL);
if (!rb){
@ -376,6 +628,9 @@ int main(int argc, char *argv[]){
}
}
if (f != NULL)
fclose(f);
ring_buffer__free(rb);
bpf_object__close(obj);

@ -16,14 +16,6 @@
#include "common.h"
/*
* Helper:
* Issue: invalid indirect read from stack R2 off
* Fix: check if all variables is initialised
* Issue: R1 invalid mem access 'inv'
* Fix: the value can be NULL
*/
struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 256 * 1024 /* 256kb */);
@ -47,7 +39,7 @@ static size_t get_labels(struct __sk_buff *skb, size_t offset, struct event *s_e
while (c != '\0') {
bpf_skb_load_bytes(skb, offset + pos++, &c, 1);
if(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')
if((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
s_event->qname[qname_len] = c;
else if(c >= '0' && c <= '9')
s_event->qname[qname_len] = c;
@ -59,8 +51,6 @@ static size_t get_labels(struct __sk_buff *skb, size_t offset, struct event *s_e
}
s_event->qname[qname_len - 1] = '\0';
qname_len++;
// dquery->qname_len = qname_len;
// bpf_printk("qname: %s", s_event->qname);
// bpf_printk("qname len: %d", qname_len);
return qname_len;
}
@ -87,91 +77,19 @@ static size_t get_query_section(struct __sk_buff *skb, struct event *s_event, ui
return len;
}
static unsigned int get_answer(struct __sk_buff *skb, struct event *s_event, size_t tlen, unsigned int index){
unsigned char buf[2] = {0}; // Need to be unsigned, otherwise, the result is fffff
unsigned int offset = index;
// Get the 2 first bytes to identify if it's a message compression or not
if(bpf_skb_load_bytes(skb, tlen, &buf, 2) < 0)
return 0;
tlen += 2; // For the message compression
/*
* According to the RFC 1035 (https://datatracker.ietf.org/doc/html/rfc1035#section-4.1.4)
* In the section 4.1.4, message compression, the first two bits are set at 11 (0xc),
* that's means, it's a pointer.
* For instance, the two bytes 0xc00c, 0xc (11) it's the pointer and 0x00c is the position in the DNS header
*/
if (buf[0] == 0xc0){
/*
* I cannot read the labels, because the eBPF verifier considerate as a infinity loop
*/
/*
* According to the RFC 1035, the structure of answer is like that:
* https://datatracker.ietf.org/doc/html/rfc1035#section-4.1.3
*/
// Get the class and type
if ((void*)(offset) >= MAX_UDP_PAYLOAD - sizeof(uint16_t))
return 0;
bpf_skb_load_bytes(skb, tlen, s_event->buf + offset, sizeof(uint16_t));
uint16_t type = s_event->buf[0] + (s_event->buf[1] << 8);
tlen += 2;
if ((void*)(offset += 2) >= MAX_UDP_PAYLOAD - sizeof(uint16_t))
return 0;
//offset += 2;
// For class
if(bpf_skb_load_bytes(skb, tlen, s_event->buf + offset, sizeof(uint16_t)) < 0)
return 0;
tlen += 2;
if ((void*)(offset += 2) >= MAX_UDP_PAYLOAD - sizeof(uint16_t))
return 0;
// Get ttl
if(bpf_skb_load_bytes(skb, tlen, s_event->buf + offset, sizeof(uint32_t)) < 0)
return 0;
if ((void*)(offset += 4) >= MAX_UDP_PAYLOAD - sizeof(uint32_t))
return 0;
tlen += 4;
// Get data size
uint16_t size;
bpf_skb_load_bytes(skb, tlen, &size, sizeof(uint16_t));
bpf_skb_load_bytes(skb, tlen, s_event->buf + offset, sizeof(uint16_t));
if ((void*)(offset += 2) >= MAX_UDP_PAYLOAD - sizeof(uint16_t))
return 0;
tlen += 2;
uint32_t data;
if (s_event->type == 1) { // -> A
bpf_skb_load_bytes(skb, tlen, s_event->buf + offset, sizeof(uint32_t));
}
if ((void*)(offset += ntohs(size)) >= MAX_UDP_PAYLOAD - sizeof(uint16_t))
return 0;
tlen += ntohs(size);
}
else {
// get_labels(skb, sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct dnshdr), s_event);
}
bpf_printk("End offset: %d", offset);
return offset;
}
/*
* https://datatracker.ietf.org/doc/html/rfc1035
*/
static int dnsquery(struct __sk_buff *skb, struct ethhdr eth, struct iphdr ip, struct udphdr udp, int dport, int sport){
struct event *s_event;
struct dnshdr dns = {0};
struct query_section dquery = {0};
/* Get DNS header */
bpf_skb_load_bytes(skb, sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr), &dns, sizeof(struct dnshdr));
// Check OpCode
uint16_t qr = ntohs(dns.flags) & 0xF000; // Get the QR code: 0 -> query, 1 -> response
/* If it's not a query, we do not continue */
if(qr != 0x0)
return 0;
@ -192,7 +110,7 @@ static int dnsquery(struct __sk_buff *skb, struct ethhdr eth, struct iphdr ip, s
/* Get the query section */
uint8_t tlen = sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr);
size_t query_len = get_query_section(skb, s_event, tlen);
get_query_section(skb, s_event, tlen);
// https://docs.cilium.io/en/stable/reference-guides/bpf/progtypes/
s_event->dport = dport;
@ -203,60 +121,20 @@ static int dnsquery(struct __sk_buff *skb, struct ethhdr eth, struct iphdr ip, s
return 0;
}
static void dnsanswer_old(struct __sk_buff *skb, struct iphdr ip, struct udphdr udp, int dport, int sport){
char buf[256] = {0}; // Max dns domain name length
//__u16 udplen = 0U;
// Check with ip.len
//const __u32 tot_len = ntohs(ip.tot_len);
// __u32 payload_len = (ntohs(ip.tot_len) - sizeof(struct iphdr) - sizeof(struct udphdr));
__u32 payload_len = (ntohs(ip.tot_len) - sizeof(struct iphdr) - sizeof(struct udphdr)) & 0xff;
if (payload_len > skb->len)
return;
bpf_printk("payload len %d", payload_len);
if (payload_len <= -1) {
bpf_printk("payload len %d", payload_len);
}
// Get udp len
//udplen = ntohs(udp.len);
//bpf_printk("udp len: %d", udplen);
//if (udplen <= 0)
// return 0;
/*if (offset + udplen > skb->len) {
bpf_printk("outbound");
plen = sizeof(struct dnshdr);
}*/
/*long err = bpf_skb_load_bytes(skb, offset, &buf, payload_len);
if(err < 0){
bpf_printk("failed");
// bpf_ringbuf_discard(s_event, 0);
return;
}*/
// Cast to dnshdr
// dns = (struct dnshdr*)buf;
}
/*
* This function read the dns answer section
* All the answer is store in the buf variable and handle in the user space
*/
static void dnsanswer(struct __sk_buff *skb, struct iphdr ip, struct udphdr udp, int dport, int sport){
struct event *s_event;
struct dnshdr dns;
uint16_t tid = 0U;
uint32_t offset = sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr);
size_t tlen = ntohs(udp.len);
int index = 0;
unsigned int index = 0U;
if (tlen < 0 || tlen >= 256)
return;
bpf_printk("udp len: %d", tlen);
// Load dns header
if (bpf_skb_load_bytes(skb, offset, &dns, sizeof(struct dnshdr)) < 0)
return;
@ -294,27 +172,18 @@ static void dnsanswer(struct __sk_buff *skb, struct iphdr ip, struct udphdr udp,
return;
}
/*if (ans > 0){
s_event->numAns = ans;
}*/
s_event->numAns = ans;
// Load query and answer
/*
* Load query and answers
* It's a little dirty to do that, to load byte by byte,
* otherwise, I have an issue with the eBPF verifier
*/
offset += sizeof(struct dnshdr) + query_len;
//offset += 2; // We bypass message compression
while (index < tlen){
for (index = 0; index < tlen || index == MAX_UDP_PAYLOAD; index++)
bpf_skb_load_bytes(skb, offset + index, s_event->buf + index, 1);
index++;
}
bpf_ringbuf_submit(s_event, 0);
//if(bpf_skb_load_bytes(skb, offset, &buf, tlen) < 0)
// bpf_printk("Failed");
}
/*

Binary file not shown.

131837
src/vmlinux.h

File diff suppressed because it is too large Load Diff

BIN
test

Binary file not shown.

14
test.c

@ -1,14 +0,0 @@
#include <stdio.h>
int main(void){
char buf[128] = "Hello world!";
char t = 'a';
//char *c = buf;
char *c = &t;
printf("%c\n", *c);
*c = buf[0];
printf("%c\n", *c);
return 0;
}