Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 400356e2ce |
@@ -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
|
all: dns-trace.ebpf.o dns-trace
|
||||||
|
|
||||||
dns-trace.ebpf.o: src/dns-trace.ebpf.c
|
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
|
dns-trace: src/dns-trace.c
|
||||||
$(GCC) $(CFLAGS) src/dns-trace.c -o dns-trace $(LIBS)
|
$(GCC) $(CFLAGS) src/dns-trace.c -o dns-trace $(LIBS)
|
||||||
|
|||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/sh
|
#!/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 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
|
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
|
#endif
|
||||||
|
|||||||
+336
-41
@@ -9,6 +9,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <time.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <net/if.h> /* if_nametoindex */
|
#include <net/if.h> /* if_nametoindex */
|
||||||
#include <linux/if_ether.h>
|
#include <linux/if_ether.h>
|
||||||
@@ -17,10 +18,15 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
|
/* Global variables */
|
||||||
static struct arguments arguments;
|
static struct arguments arguments;
|
||||||
static int running = 1;
|
static int running = 1;
|
||||||
|
static FILE *f;
|
||||||
|
static char hostname[127];
|
||||||
|
|
||||||
|
|
||||||
struct arguments {
|
struct arguments {
|
||||||
|
char *interface;
|
||||||
char *filename;
|
char *filename;
|
||||||
int to_output;
|
int to_output;
|
||||||
};
|
};
|
||||||
@@ -31,7 +37,7 @@ struct arguments {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static char doc[] = "DNS Trace usage:";
|
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){
|
static error_t parse_opts(int key, char *arg, struct argp_state *state){
|
||||||
struct arguments *arguments = state->input;
|
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->filename = arg;
|
||||||
arguments->to_output = 0;
|
arguments->to_output = 0;
|
||||||
break;
|
break;
|
||||||
|
case 'i':
|
||||||
|
arguments->interface = arg;
|
||||||
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
arguments->to_output = 1;
|
arguments->to_output = 1;
|
||||||
break;
|
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[]){
|
struct arguments parse_args(int argc, char *argv[]){
|
||||||
static const struct argp_option opts[] = {
|
static const struct argp_option opts[] = {
|
||||||
|
{"interface", 'i', "INTERFACE", 0, "Ifname for listening"},
|
||||||
{"filename", 'f', "FILENAME", 0, "Save result to logs"},
|
{"filename", 'f', "FILENAME", 0, "Save result to logs"},
|
||||||
{"to-output", 'o', NULL, 0, "Print to output"},
|
{"to-output", 'o', NULL, 0, "Print to output"},
|
||||||
{NULL, 'h', NULL, OPTION_HIDDEN, "help"},
|
{NULL, 'h', NULL, OPTION_HIDDEN, "help"},
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
struct arguments arguments;
|
struct arguments arguments;
|
||||||
|
arguments.interface = NULL;
|
||||||
arguments.filename = NULL;
|
arguments.filename = NULL;
|
||||||
arguments.to_output = 1;
|
arguments.to_output = 1;
|
||||||
static struct argp argp = {opts, parse_opts, args_doc, doc};
|
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){
|
static void signalHandler(int signum){
|
||||||
running = 0;
|
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;
|
struct sockaddr_ll sll;
|
||||||
int sock;
|
int sock;
|
||||||
|
|
||||||
@@ -92,7 +104,6 @@ static int open_raw_sock(const char *name)
|
|||||||
sll.sll_ifindex = if_nametoindex(name);
|
sll.sll_ifindex = if_nametoindex(name);
|
||||||
sll.sll_protocol = htons(ETH_P_ALL);
|
sll.sll_protocol = htons(ETH_P_ALL);
|
||||||
if (bind(sock, (struct sockaddr *)&sll, sizeof(sll)) < 0) {
|
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);
|
printf("Failed to bind the interface %s\n", name);
|
||||||
close(sock);
|
close(sock);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -101,6 +112,9 @@ static int open_raw_sock(const char *name)
|
|||||||
return sock;
|
return sock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function map the type of DNS request
|
||||||
|
*/
|
||||||
static char *mapReqType(const int req){
|
static char *mapReqType(const int req){
|
||||||
char *tmp = malloc(8);
|
char *tmp = malloc(8);
|
||||||
if (tmp == NULL)
|
if (tmp == NULL)
|
||||||
@@ -118,6 +132,9 @@ static char *mapReqType(const int req){
|
|||||||
};
|
};
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* This function map the DNS class RR
|
||||||
|
*/
|
||||||
static char *mapClass(const int class){
|
static char *mapClass(const int class){
|
||||||
char *tmp = malloc(8);
|
char *tmp = malloc(8);
|
||||||
if (tmp == NULL)
|
if (tmp == NULL)
|
||||||
@@ -143,6 +160,9 @@ static char *mapClass(const int class){
|
|||||||
}
|
}
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* This function map the DNS type RR
|
||||||
|
*/
|
||||||
static char *mapType(const int type){
|
static char *mapType(const int type){
|
||||||
char *tmp = malloc(8);
|
char *tmp = malloc(8);
|
||||||
if (tmp == NULL)
|
if (tmp == NULL)
|
||||||
@@ -212,16 +232,43 @@ static char *mapType(const int type){
|
|||||||
return tmp;
|
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){
|
static void print_query(struct event *s_event){
|
||||||
char *req_type, *class, *type;
|
char *req_type, *class, *type;
|
||||||
printf("%s:%-10d", inet_ntoa(*(struct in_addr*)&s_event->client), s_event->dport);
|
char t[32];
|
||||||
printf("%-5x", s_event->tid);
|
time_t ts = time(NULL);
|
||||||
|
syslog_time(ts, t, sizeof(t));
|
||||||
|
printf("%-20s", t);
|
||||||
|
|
||||||
req_type = mapReqType(s_event->req_type);
|
req_type = mapReqType(s_event->req_type);
|
||||||
printf("%-10s", req_type);
|
printf("%s ", req_type);
|
||||||
free(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);
|
class = mapClass(s_event->class);
|
||||||
printf("%-5s", class);
|
printf("%-5s", class);
|
||||||
@@ -231,41 +278,265 @@ static void print_query(struct event *s_event){
|
|||||||
printf("%-5s", type);
|
printf("%-5s", type);
|
||||||
free(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') {
|
||||||
|
if((*buf >= 'a' && *buf <= 'z') || (*buf >= 'A' && *buf <= 'Z'))
|
||||||
|
*(qname + pos) = *buf;
|
||||||
|
else if (*buf >= '0' && *buf <= '9')
|
||||||
|
*(qname + pos) = *buf;
|
||||||
|
else
|
||||||
|
*(qname + pos) = '.';
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
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){
|
int handle_event(void *ctx, void *data, size_t data_sz){
|
||||||
struct event *s_event = (struct event*)data;
|
struct event *s_event = (struct event*)data;
|
||||||
if (s_event->req_type == REQ_QUERY){
|
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){
|
if (s_event->req_type == REQ_ANSWER){
|
||||||
int pos = 0;
|
if (arguments.to_output == 1)
|
||||||
//for(int i = 0; i < 32; i++)
|
print_answer(s_event);
|
||||||
// printf("%d ", s_event->buf[i]);
|
if (arguments.filename != NULL && f != NULL)
|
||||||
//printf("\n");
|
answer_to_log(s_event);
|
||||||
for (int i = 0; i < s_event->numAns; i++){
|
|
||||||
print_query(s_event);
|
|
||||||
uint16_t type2 = (s_event->buf[pos++]) + (s_event->buf[pos++] << 8);
|
|
||||||
uint16_t class2 = (s_event->buf[pos++]) + (s_event->buf[pos++] << 8);
|
|
||||||
uint32_t ttl2 = (s_event->buf[pos++]) + (s_event->buf[pos++] << 8) + (s_event->buf[pos++] << 16) + (s_event->buf[pos++] << 24);
|
|
||||||
uint16_t size2 = (s_event->buf[pos++]) + (s_event->buf[pos++] << 8);
|
|
||||||
type2 = ntohs(type2);
|
|
||||||
class2 = ntohs(class2);
|
|
||||||
ttl2 = ntohl(ttl2);
|
|
||||||
size2 = ntohs(size2);
|
|
||||||
if (type2 == 1) {// -> A
|
|
||||||
uint32_t ip = s_event->buf[pos++] + (s_event->buf[pos++] << 8) + (s_event->buf[pos++] << 16) + (s_event->buf[pos++] << 24);
|
|
||||||
printf("%s (%d)%5d", inet_ntoa(*(struct in_addr*)&ip), type2, ttl2);
|
|
||||||
}
|
|
||||||
if (type2 == 28){ // -> AAAA
|
|
||||||
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
printf("%d\n", pos);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int main(int argc, char *argv[]){
|
int main(int argc, char *argv[]){
|
||||||
@@ -275,9 +546,31 @@ int main(int argc, char *argv[]){
|
|||||||
struct ring_buffer *rb;
|
struct ring_buffer *rb;
|
||||||
int err;
|
int err;
|
||||||
int fd_map_data;
|
int fd_map_data;
|
||||||
|
int sock;
|
||||||
|
|
||||||
arguments = parse_args(argc, argv); // Parsing arguments
|
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);
|
signal(SIGINT, signalHandler);
|
||||||
|
|
||||||
/* Open and load our eBPF object */
|
/* Open and load our eBPF object */
|
||||||
@@ -311,14 +604,13 @@ int main(int argc, char *argv[]){
|
|||||||
}
|
}
|
||||||
|
|
||||||
bpf_program__attach(programSkb);
|
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);
|
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));
|
setsockopt(sock, SOL_SOCKET, SO_ATTACH_BPF, &prog_fd, sizeof(int));
|
||||||
|
|
||||||
|
/* Get the hostname of the system */
|
||||||
|
get_hostname();
|
||||||
|
|
||||||
/* Start the ringbuffer */
|
/* Start the ringbuffer */
|
||||||
rb = ring_buffer__new(fd_map_data, handle_event, NULL, NULL);
|
rb = ring_buffer__new(fd_map_data, handle_event, NULL, NULL);
|
||||||
if (!rb){
|
if (!rb){
|
||||||
@@ -336,6 +628,9 @@ int main(int argc, char *argv[]){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (f != NULL)
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
ring_buffer__free(rb);
|
ring_buffer__free(rb);
|
||||||
bpf_object__close(obj);
|
bpf_object__close(obj);
|
||||||
|
|
||||||
|
|||||||
+36
-256
@@ -16,60 +16,17 @@
|
|||||||
#include "common.h"
|
#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 {
|
struct {
|
||||||
__uint(type, BPF_MAP_TYPE_RINGBUF);
|
__uint(type, BPF_MAP_TYPE_RINGBUF);
|
||||||
__uint(max_entries, 256 * 1024 /* 256kb */);
|
__uint(max_entries, 256 * 1024 /* 256kb */);
|
||||||
} m_data SEC(".maps");
|
} m_data SEC(".maps");
|
||||||
|
|
||||||
struct {
|
static size_t get_labels(struct __sk_buff *skb, size_t offset, struct event *s_event){
|
||||||
__uint(type, BPF_MAP_TYPE_HASH);
|
|
||||||
__uint(max_entries, 32768);
|
|
||||||
__type(key, uint16_t);
|
|
||||||
__type(value, struct dns_answer);
|
|
||||||
} m_tid SEC(".maps");
|
|
||||||
|
|
||||||
static size_t get_labels2(struct __sk_buff *skb, size_t offset, struct event *s_event){
|
|
||||||
char c;
|
char c;
|
||||||
int qname_len = 0;
|
int qname_len = 0;
|
||||||
//bpf_printk("labels off: %d", offset);
|
|
||||||
bpf_skb_load_bytes(skb, offset, &c, 1); // Get the first byte, which is the length
|
bpf_skb_load_bytes(skb, offset, &c, 1); // Get the first byte, which is the length
|
||||||
int pos = 1;
|
int pos = 1;
|
||||||
while (c != '\0') {
|
|
||||||
bpf_skb_load_bytes(skb, offset + pos++, &c, 1);
|
|
||||||
|
|
||||||
if(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')
|
|
||||||
s_event->qname[qname_len] = c;
|
|
||||||
else
|
|
||||||
s_event->qname[qname_len] = '.';
|
|
||||||
qname_len++;
|
|
||||||
if (pos == 128 || c == '\0')
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
static size_t get_labels(struct __sk_buff *skb, size_t offset, size_t end, struct event *s_event, struct query_section *s_query){
|
|
||||||
//size_t len;
|
|
||||||
char buf[256] = {0};
|
|
||||||
char *c;
|
|
||||||
int index = 0;
|
|
||||||
size_t qname_len = 0; // Full length of the qname field
|
|
||||||
|
|
||||||
bpf_skb_load_bytes(skb, offset, &buf, 41);
|
|
||||||
c = buf;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The qname is composed by a the number of bytes then follow by the label
|
* The qname is composed by a the number of bytes then follow by the label
|
||||||
* For instance, for the qname www.bucchino.org,
|
* For instance, for the qname www.bucchino.org,
|
||||||
@@ -79,20 +36,22 @@ static size_t get_labels(struct __sk_buff *skb, size_t offset, size_t end, struc
|
|||||||
* For instance, the result is:
|
* For instance, the result is:
|
||||||
* 03 77 77 77 08 62 75 63 63 68 69 6e 6f 03 6f 72 67 00
|
* 03 77 77 77 08 62 75 63 63 68 69 6e 6f 03 6f 72 67 00
|
||||||
*/
|
*/
|
||||||
while (*(c++) != '\0') {
|
while (c != '\0') {
|
||||||
if(*c >= 'a' && *c <= 'z')
|
bpf_skb_load_bytes(skb, offset + pos++, &c, 1);
|
||||||
s_event->qname[index] = *c;
|
|
||||||
else if(*c >= 'A' && *c <= 'Z')
|
|
||||||
s_event->qname[index] = *c;
|
|
||||||
else
|
|
||||||
s_event->qname[index] = '.';
|
|
||||||
index++;
|
|
||||||
qname_len++;
|
|
||||||
}
|
|
||||||
s_event->qname[--index] = '\0';
|
|
||||||
qname_len++; // For the null character
|
|
||||||
bpf_printk("qname: %s", s_event->qname);
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
else
|
||||||
|
s_event->qname[qname_len] = '.';
|
||||||
|
qname_len++;
|
||||||
|
if (pos == 128 || c == '\0')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
s_event->qname[qname_len - 1] = '\0';
|
||||||
|
qname_len++;
|
||||||
|
// bpf_printk("qname len: %d", qname_len);
|
||||||
return qname_len;
|
return qname_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +64,7 @@ static size_t get_query_section(struct __sk_buff *skb, struct event *s_event, ui
|
|||||||
uint16_t class, type;
|
uint16_t class, type;
|
||||||
|
|
||||||
offset += sizeof(struct dnshdr);
|
offset += sizeof(struct dnshdr);
|
||||||
qname_len = get_labels2(skb, offset, s_event);
|
qname_len = get_labels(skb, offset, s_event);
|
||||||
|
|
||||||
// Get class and type
|
// Get class and type
|
||||||
len = qname_len;
|
len = qname_len;
|
||||||
@@ -118,91 +77,19 @@ static size_t get_query_section(struct __sk_buff *skb, struct event *s_event, ui
|
|||||||
|
|
||||||
return len;
|
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_labels2(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
|
* 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){
|
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 event *s_event;
|
||||||
struct dnshdr dns = {0};
|
struct dnshdr dns = {0};
|
||||||
struct query_section dquery = {0};
|
|
||||||
|
|
||||||
/* Get DNS header */
|
/* Get DNS header */
|
||||||
bpf_skb_load_bytes(skb, sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr), &dns, sizeof(struct dnshdr));
|
bpf_skb_load_bytes(skb, sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr), &dns, sizeof(struct dnshdr));
|
||||||
|
|
||||||
// Check OpCode
|
// Check OpCode
|
||||||
uint16_t qr = ntohs(dns.flags) & 0xF000; // Get the QR code: 0 -> query, 1 -> response
|
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 it's not a query, we do not continue */
|
||||||
if(qr != 0x0)
|
if(qr != 0x0)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -223,7 +110,7 @@ static int dnsquery(struct __sk_buff *skb, struct ethhdr eth, struct iphdr ip, s
|
|||||||
|
|
||||||
/* Get the query section */
|
/* Get the query section */
|
||||||
uint8_t tlen = sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr);
|
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/
|
// https://docs.cilium.io/en/stable/reference-guides/bpf/progtypes/
|
||||||
s_event->dport = dport;
|
s_event->dport = dport;
|
||||||
@@ -234,60 +121,22 @@ static int dnsquery(struct __sk_buff *skb, struct ethhdr eth, struct iphdr ip, s
|
|||||||
return 0;
|
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;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TODO: je recupere tout le skb->data, grace au skb->len
|
* This function read the dns answer section
|
||||||
grace a ca, j'aurai tout le payload udp et toute les donnees dns
|
* All the answer is store in the buf variable and handle in the user space
|
||||||
je pourrai facilement parcourir les data
|
*/
|
||||||
*/
|
|
||||||
static void dnsanswer(struct __sk_buff *skb, struct iphdr ip, struct udphdr udp, int dport, int sport){
|
static void dnsanswer(struct __sk_buff *skb, struct iphdr ip, struct udphdr udp, int dport, int sport){
|
||||||
struct event *s_event;
|
struct event *s_event;
|
||||||
struct dnshdr dns;
|
struct dnshdr dns;
|
||||||
uint16_t tid = 0U;
|
|
||||||
uint32_t offset = sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr);
|
uint32_t offset = sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr);
|
||||||
|
size_t tlen = ntohs(udp.len);
|
||||||
|
unsigned int index = 0U;
|
||||||
|
|
||||||
|
if (tlen < 0 || tlen >= 256)
|
||||||
|
return;
|
||||||
|
|
||||||
// Load dns header
|
// Load dns header
|
||||||
if (bpf_skb_load_bytes(skb, offset, &dns, 12) < 0)
|
if (bpf_skb_load_bytes(skb, offset, &dns, sizeof(struct dnshdr)) < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Check OpCode
|
// Check OpCode
|
||||||
@@ -323,57 +172,25 @@ static void dnsanswer(struct __sk_buff *skb, struct iphdr ip, struct udphdr udp,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ans > 0){
|
s_event->numAns = ans;
|
||||||
/*
|
|
||||||
* We get a least the 5 last answer
|
|
||||||
* In the RFC 1035 (https://datatracker.ietf.org/doc/html/rfc1035#section-2.3.4) the max udp payload is 512 bytes
|
|
||||||
* The program limit size of the answer
|
|
||||||
*/
|
|
||||||
offset += sizeof(struct dnshdr) + query_len; // For the pos in the answer section in the skb
|
|
||||||
unsigned int offset_ans = 0;
|
|
||||||
for (uint16_t i = 0; i < ans; i++){
|
|
||||||
offset_ans += get_answer(skb, s_event, offset, offset_ans);
|
|
||||||
offset += offset_ans + 2; // +2 for the message compression
|
|
||||||
//offset_ans += offset_ans;
|
|
||||||
// For eBPF verifier, to be sure we leave the loop
|
|
||||||
if (i == ans || i == 5 || offset_ans >= 512)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
s_event->numAns = ans;
|
|
||||||
}
|
|
||||||
if (ntohs(dns.nbAuthorityRRs) > 0){
|
|
||||||
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* In the user space, if the haven't have the answer, we can have an error
|
|
||||||
* The solution is to push to the ring buffer and the answer is store in
|
|
||||||
* the struct event
|
|
||||||
* Or, we push to the ring buffer and the query only with the map
|
|
||||||
* but, if we haven't have the answer, we need print the query
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Pour recuperer les infos:
|
* Load query and answers
|
||||||
1 - dans le getquery, on push dans le ringbuffer et dans le userspace, on recupere aussi la reponse
|
* It's a little dirty to do that, to load byte by byte,
|
||||||
mais si la reponse, nous l'avons pas encore, ca fail et dans le get answer on push dans une map
|
* otherwise, I have an issue with the eBPF verifier
|
||||||
2 - on push dans le ring buffer quand on a la reponse avec la requette car c'est dans le field query
|
|
||||||
cependant, si on a pas la reponse, on n'aura jamais la query
|
|
||||||
3 - dans le get query et get answer, on push dans le ring buffer et tout est store dans le struct event
|
|
||||||
*/
|
*/
|
||||||
|
offset += sizeof(struct dnshdr) + query_len;
|
||||||
|
for (index = 0; index < tlen || index == MAX_UDP_PAYLOAD; index++)
|
||||||
|
bpf_skb_load_bytes(skb, offset + index, s_event->buf + index, 1);
|
||||||
|
|
||||||
/* Get the answer */
|
|
||||||
bpf_ringbuf_submit(s_event, 0);
|
bpf_ringbuf_submit(s_event, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* skb -> http://oldvger.kernel.org/~davem/skb_data.html
|
* skb -> http://oldvger.kernel.org/~davem/skb_data.html
|
||||||
*/
|
*/
|
||||||
|
|
||||||
SEC("socket")
|
SEC("socket")
|
||||||
int detect_dns(struct __sk_buff *skb) {
|
int detect_dns(struct __sk_buff *skb) {
|
||||||
//void *data = (void *)(long)skb->data;
|
|
||||||
//void *data_end = (void *)(long)skb->data_end;
|
|
||||||
//struct ethhdr *eth2 = data;
|
|
||||||
struct ethhdr eth = {0};
|
struct ethhdr eth = {0};
|
||||||
struct iphdr ip = {0};
|
struct iphdr ip = {0};
|
||||||
struct udphdr udp = {0};
|
struct udphdr udp = {0};
|
||||||
@@ -381,32 +198,22 @@ int detect_dns(struct __sk_buff *skb) {
|
|||||||
__u32 dport;
|
__u32 dport;
|
||||||
__u32 sport;
|
__u32 sport;
|
||||||
|
|
||||||
//if (data + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr) > data_end)
|
|
||||||
// return 0;
|
|
||||||
|
|
||||||
if (skb->len < sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr))
|
if (skb->len < sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
//bpf_skb_load_bytes(skb, 12, &p, 2);
|
|
||||||
bpf_skb_load_bytes(skb, 0, ð, sizeof(struct ethhdr));
|
bpf_skb_load_bytes(skb, 0, ð, sizeof(struct ethhdr));
|
||||||
p = eth.h_proto;
|
p = eth.h_proto;
|
||||||
if (ntohs(p) != ETH_P_IP)
|
if (ntohs(p) != ETH_P_IP)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// bpf_printk("ip: %d",ntohs(p));
|
|
||||||
|
|
||||||
//ip = (struct iphdr*)(data + sizeof(struct ethhdr));
|
|
||||||
bpf_skb_load_bytes(skb, sizeof(struct ethhdr), &ip, sizeof(struct iphdr));
|
bpf_skb_load_bytes(skb, sizeof(struct ethhdr), &ip, sizeof(struct iphdr));
|
||||||
|
|
||||||
//bpf_skb_load_bytes(data, sizeof(struct ethhdr), ip, sizeof(struct ip));
|
|
||||||
h_proto = ip.protocol;
|
h_proto = ip.protocol;
|
||||||
// If not UDP packet
|
// If not UDP packet
|
||||||
if (h_proto != 17)
|
if (h_proto != 17)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// bpf_printk("proto: %d", h_proto);
|
|
||||||
//udp = (struct udphdr*)(data + sizeof(struct ethhdr) + sizeof(struct iphdr));
|
|
||||||
|
|
||||||
bpf_skb_load_bytes(skb, sizeof(struct ethhdr) + sizeof(struct iphdr), &udp, sizeof(struct udphdr));
|
bpf_skb_load_bytes(skb, sizeof(struct ethhdr) + sizeof(struct iphdr), &udp, sizeof(struct udphdr));
|
||||||
|
|
||||||
if (udp.len == 0)
|
if (udp.len == 0)
|
||||||
@@ -423,31 +230,4 @@ int detect_dns(struct __sk_buff *skb) {
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/*SEC("xdp")
|
|
||||||
int detect_dns(struct xdp_md *ctx){
|
|
||||||
void *data_end = (void *)(long)ctx->data_end;
|
|
||||||
void *data = (void *)(long)ctx->data;
|
|
||||||
struct ethhdr *eth = data;
|
|
||||||
struct iphdr *ip;
|
|
||||||
struct udphdr *udp;
|
|
||||||
__u16 h_proto;
|
|
||||||
__u16 dport;
|
|
||||||
|
|
||||||
if (data + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr) > data_end)
|
|
||||||
return XDP_DROP;
|
|
||||||
|
|
||||||
ip = (struct iphdr*)(data + sizeof(struct ethhdr));
|
|
||||||
udp = (struct udphdr*)(data + sizeof(struct ethhdr) + sizeof(struct iphdr));
|
|
||||||
|
|
||||||
h_proto = ip->protocol;
|
|
||||||
// If not UDP packet
|
|
||||||
if (h_proto != 17)
|
|
||||||
return XDP_PASS;
|
|
||||||
|
|
||||||
// Check if DNS port
|
|
||||||
dport = udp->dest;
|
|
||||||
bpf_printk("Dport: %d", (dport));
|
|
||||||
|
|
||||||
return XDP_PASS;
|
|
||||||
}*/
|
|
||||||
char LICENSE[] SEC("license") = "GPL";
|
char LICENSE[] SEC("license") = "GPL";
|
||||||
|
|||||||
Binary file not shown.
-131837
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user