Update project
This commit is contained in:
parent
65258eb429
commit
9712681972
BIN
dns-trace
Executable file
BIN
dns-trace
Executable file
Binary file not shown.
@ -233,8 +233,8 @@ 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("wlp0s20f3");
|
||||||
int sock = open_raw_sock("enx98e743c667fc");
|
//int sock = open_raw_sock("enx98e743c667fc");
|
||||||
printf("Socket: %d\n", sock);
|
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);
|
printf("Program fd: %d\n", prog_fd);
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#define __TARGET_ARCH_x86
|
#define __TARGET_ARCH_x86
|
||||||
#include <linux/bpf.h>
|
#include <linux/bpf.h>
|
||||||
#include <bpf/bpf_helpers.h>
|
#include <bpf/bpf_helpers.h>
|
||||||
|
#include <bpf/bpf_endian.h>
|
||||||
#include <bpf/bpf_tracing.h>
|
#include <bpf/bpf_tracing.h>
|
||||||
#include <bpf/bpf_core_read.h>
|
#include <bpf/bpf_core_read.h>
|
||||||
#include <linux/if_ether.h>
|
#include <linux/if_ether.h>
|
||||||
@ -36,11 +37,11 @@ struct {
|
|||||||
} m_tid SEC(".maps");
|
} m_tid SEC(".maps");
|
||||||
|
|
||||||
static size_t get_labels(struct __sk_buff *skb, size_t offset, size_t end, struct event *s_event, struct query_section *s_query){
|
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;
|
//size_t len;
|
||||||
unsigned char buf[256];
|
char buf[256] = {0};
|
||||||
unsigned char *c;
|
char *c;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
int qname_len = 0; // Full length of the qname field
|
size_t qname_len = 0; // Full length of the qname field
|
||||||
|
|
||||||
bpf_skb_load_bytes(skb, offset, &buf, 41);
|
bpf_skb_load_bytes(skb, offset, &buf, 41);
|
||||||
c = buf;
|
c = buf;
|
||||||
@ -58,7 +59,7 @@ static size_t get_labels(struct __sk_buff *skb, size_t offset, size_t end, struc
|
|||||||
s_event->qname[--index] = '\0';
|
s_event->qname[--index] = '\0';
|
||||||
qname_len++; // For the null character
|
qname_len++; // For the null character
|
||||||
|
|
||||||
return len;
|
return qname_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -67,11 +68,11 @@ static size_t get_labels(struct __sk_buff *skb, size_t offset, size_t end, struc
|
|||||||
//static size_t get_query_section(struct __sk_buff *skb, struct event *s_event, uint16_t *class, uint16_t *type, uint8_t tlen){
|
//static size_t get_query_section(struct __sk_buff *skb, struct event *s_event, uint16_t *class, uint16_t *type, uint8_t tlen){
|
||||||
static size_t get_query_section(struct __sk_buff *skb, struct event *s_event, struct query_section *s_query, uint8_t offset){
|
static size_t get_query_section(struct __sk_buff *skb, struct event *s_event, struct query_section *s_query, uint8_t offset){
|
||||||
size_t len;
|
size_t len;
|
||||||
char buf[256] = {0};
|
//char buf[256] = {0};
|
||||||
int index = 0;
|
//int index = 0;
|
||||||
int qname_len = 0; // Full length of the qname field
|
int qname_len = 0; // Full length of the qname field
|
||||||
char qname[QNAME_SIZE] = {0};
|
//char qname[QNAME_SIZE] = {0};
|
||||||
char *c;
|
//char *c;
|
||||||
uint8_t flen = skb->len;
|
uint8_t flen = skb->len;
|
||||||
/*
|
/*
|
||||||
We get the size for the buffer
|
We get the size for the buffer
|
||||||
@ -83,11 +84,11 @@ static size_t get_query_section(struct __sk_buff *skb, struct event *s_event, st
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
//bpf_skb_load_bytes(skb, tlen, &buf, l);
|
//bpf_skb_load_bytes(skb, tlen, &buf, l);
|
||||||
bpf_skb_load_bytes(skb, offset, &buf, 41);
|
//bpf_skb_load_bytes(skb, offset, &buf, 41);
|
||||||
c = buf;
|
//c = buf;
|
||||||
|
|
||||||
// get_labels(struct __sk_buff *skb, size_t offset, size_t end, struct event *s_event, struct query_section *s_query)
|
// get_labels(struct __sk_buff *skb, size_t offset, size_t end, struct event *s_event, struct query_section *s_query)
|
||||||
// get_labels(skb, offset, 41, s_event, s_query);
|
qname_len = get_labels(skb, offset, 41, s_event, s_query);
|
||||||
/*
|
/*
|
||||||
* 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,
|
||||||
@ -97,7 +98,7 @@ static size_t get_query_section(struct __sk_buff *skb, struct event *s_event, st
|
|||||||
* 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')
|
if(*c >= 'a' && *c <= 'z')
|
||||||
s_event->qname[index] = *c;
|
s_event->qname[index] = *c;
|
||||||
else if(*c >= 'A' && *c <= 'Z')
|
else if(*c >= 'A' && *c <= 'Z')
|
||||||
@ -108,7 +109,7 @@ static size_t get_query_section(struct __sk_buff *skb, struct event *s_event, st
|
|||||||
qname_len++;
|
qname_len++;
|
||||||
}
|
}
|
||||||
s_event->qname[--index] = '\0';
|
s_event->qname[--index] = '\0';
|
||||||
qname_len++; // For the null character
|
qname_len++; // For the null character*/
|
||||||
// bpf_printk("l: %d", l);
|
// bpf_printk("l: %d", l);
|
||||||
|
|
||||||
// Get class and type
|
// Get class and type
|
||||||
@ -122,7 +123,7 @@ static size_t get_query_section(struct __sk_buff *skb, struct event *s_event, st
|
|||||||
}
|
}
|
||||||
static size_t get_answer(struct __sk_buff *skb, struct event *s_event, size_t tlen){
|
static size_t get_answer(struct __sk_buff *skb, struct event *s_event, size_t tlen){
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
unsigned char buf[256] = {0}; // Need to be unsigned, otherwise, the result is fffff
|
unsigned char buf[25] = {0}; // Need to be unsigned, otherwise, the result is fffff
|
||||||
|
|
||||||
if(bpf_skb_load_bytes(skb, tlen, &buf, 2) < 0)
|
if(bpf_skb_load_bytes(skb, tlen, &buf, 2) < 0)
|
||||||
return 0;
|
return 0;
|
||||||
@ -204,33 +205,97 @@ static int dnsquery(struct __sk_buff *skb, struct ethhdr eth, struct iphdr ip, s
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODO: je recupere tout le skb->data, grace au skb->len
|
||||||
|
grace a ca, j'aurai tout le payload udp et toute les donnees dns
|
||||||
|
je pourrai facilement parcourir les data
|
||||||
|
*/
|
||||||
static int dnsanswer(struct __sk_buff *skb, struct ethhdr eth, struct iphdr ip, struct udphdr udp, int dport, int sport){
|
static int dnsanswer(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;
|
||||||
uint16_t tid = 0;
|
uint16_t tid = 0;
|
||||||
struct dns_answer s_dnsanswer;
|
//struct dns_answer s_dnsanswer;
|
||||||
struct query_section s_query = {0};
|
//struct query_section s_query = {0};
|
||||||
|
unsigned char buf[256] = {0};
|
||||||
|
uint32_t offset = sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr);
|
||||||
|
__be16 udplen;
|
||||||
|
// uint32_t offset2 = sizeof(struct ethhdr) + sizeof(struct iphdr);
|
||||||
|
// bpf_printk("hdr: %d %d %d", sizeof(struct ethhdr), sizeof(struct iphdr), sizeof(struct udphdr)); // -> 14, 20, 8
|
||||||
|
|
||||||
|
if (udp.len == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Get udp len
|
||||||
|
udplen = ntohs(udp.len);
|
||||||
|
|
||||||
|
bpf_printk("udp len: %d", udplen);
|
||||||
|
/* Get DNS header */
|
||||||
|
//bpf_skb_load_bytes(skb, offset, &dns, sizeof(struct dnshdr));
|
||||||
|
|
||||||
|
if (udplen <= 0 || udplen > 256 || udplen < sizeof(struct dnshdr))
|
||||||
|
udplen = sizeof(struct dnshdr);
|
||||||
|
//return 0;
|
||||||
|
|
||||||
|
//if (udplen == offset || udplen < offset)
|
||||||
|
// udplen = sizeof(struct dnshdr);
|
||||||
|
|
||||||
|
//if (udplen > skb->len || udplen > offset)
|
||||||
|
// udplen = sizeof(struct dnshdr);
|
||||||
|
//return 0;
|
||||||
|
//if (udplen > offset) // Works
|
||||||
|
// return 0;
|
||||||
|
if (udplen >= offset && udplen <= skb->len){
|
||||||
|
}
|
||||||
|
bpf_printk("ok");
|
||||||
|
if (udplen < offset)
|
||||||
|
//udplen = sizeof(struct udphdr);
|
||||||
|
udplen = sizeof(struct dnshdr);
|
||||||
|
//return 0;
|
||||||
|
|
||||||
|
//__u32 plen = bpf_ntohs(udp.len) - 8;
|
||||||
|
uint32_t plen = udplen & 0xff;
|
||||||
|
bpf_printk("ok");
|
||||||
|
if (plen < 0 || plen > skb->len)
|
||||||
|
//udplen = sizeof(struct udphdr);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
bpf_printk("payload len: %d", plen);
|
||||||
|
bpf_printk("%d", skb->len);
|
||||||
|
bpf_printk("%d %d %d", offset, udplen, udplen - 8);
|
||||||
|
// bpf_printk("%d", offset + ntohs(udp.len) - 8); // -> we have 99
|
||||||
|
|
||||||
|
if (offset + ntohs(udp.len) > skb->len) {
|
||||||
|
bpf_printk("outbound");
|
||||||
|
//return 0;
|
||||||
|
plen = sizeof(struct dnshdr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bpf_skb_load_bytes(skb, offset, &buf, plen) < 0){
|
||||||
|
bpf_printk("failed");
|
||||||
|
// bpf_ringbuf_discard(s_event, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cast to dnshdr
|
||||||
|
dns = (struct dnshdr*)buf;
|
||||||
|
|
||||||
s_event = bpf_ringbuf_reserve(&m_data, sizeof(*s_event), 0);
|
s_event = bpf_ringbuf_reserve(&m_data, sizeof(*s_event), 0);
|
||||||
if (!s_event)
|
if (!s_event)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Get DNS header */
|
|
||||||
bpf_skb_load_bytes(skb, sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr), &dns, sizeof(struct dnshdr));
|
|
||||||
|
|
||||||
// Check OpCode
|
// Check OpCode
|
||||||
uint16_t flags = ntohs(dns.flags);
|
uint16_t flags = ntohs(dns->flags);
|
||||||
uint16_t qr = flags & 0xF000; // Get the QR code: 0 -> query, 1 -> response
|
uint16_t qr = flags & 0xF000; // Get the QR code: 0 -> query, 1 -> response
|
||||||
if (qr == 0x0){} // Query
|
if (qr == 0x0){} // Query
|
||||||
else if(qr == 0x8000){} // Response
|
else if(qr == 0x8000){} // Response
|
||||||
|
|
||||||
if (ntohs(dns.nbQuestions) == 0 && ntohs(dns.nbAnswerRRs)){
|
if (ntohs(dns->nbQuestions) == 0 && ntohs(dns->nbAnswerRRs)){
|
||||||
bpf_ringbuf_discard(s_event, 0);
|
bpf_ringbuf_discard(s_event, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the Transaction ID */
|
/* Get the Transaction ID */
|
||||||
tid = ntohs(dns.transactionID);
|
tid = ntohs(dns->transactionID);
|
||||||
bpf_printk("tid: %x", tid);
|
bpf_printk("tid: %x", tid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -251,7 +316,7 @@ static int dnsanswer(struct __sk_buff *skb, struct ethhdr eth, struct iphdr ip,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* Get the query response */
|
/* Get the query response */
|
||||||
uint8_t tlen = sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct dnshdr);
|
/*uint8_t tlen = sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct dnshdr);
|
||||||
uint16_t class, type;
|
uint16_t class, type;
|
||||||
// size_t query_len = get_query_section(skb, s_event, &class, &type, tlen);
|
// size_t query_len = get_query_section(skb, s_event, &class, &type, tlen);
|
||||||
size_t query_len = get_query_section(skb, s_event, &s_query, tlen);
|
size_t query_len = get_query_section(skb, s_event, &s_query, tlen);
|
||||||
@ -259,11 +324,11 @@ static int dnsanswer(struct __sk_buff *skb, struct ethhdr eth, struct iphdr ip,
|
|||||||
s_event->dport = dport;
|
s_event->dport = dport;
|
||||||
s_event->sport = sport;
|
s_event->sport = sport;
|
||||||
s_event->class = ntohs(class);
|
s_event->class = ntohs(class);
|
||||||
s_event->type = ntohs(type);
|
s_event->type = ntohs(type);*/
|
||||||
|
|
||||||
/* Get the answer */
|
/* Get the answer */
|
||||||
tlen += query_len;
|
//tlen += query_len;
|
||||||
size_t answer_len = get_answer(skb, s_event, tlen);
|
//size_t answer_len = get_answer(skb, s_event, tlen);
|
||||||
bpf_ringbuf_submit(s_event, 0);
|
bpf_ringbuf_submit(s_event, 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -282,6 +347,8 @@ int detect_dns(struct __sk_buff *skb) {
|
|||||||
|
|
||||||
//if (data + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr) > data_end)
|
//if (data + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr) > data_end)
|
||||||
// return 0;
|
// return 0;
|
||||||
|
if (skb->len < sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr))
|
||||||
|
return 0;
|
||||||
|
|
||||||
//bpf_skb_load_bytes(skb, 12, &p, 2);
|
//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));
|
||||||
@ -305,6 +372,9 @@ int detect_dns(struct __sk_buff *skb) {
|
|||||||
|
|
||||||
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)
|
||||||
|
return 0;
|
||||||
|
|
||||||
// Check if DNS port
|
// Check if DNS port
|
||||||
dport = ntohs(udp.dest);
|
dport = ntohs(udp.dest);
|
||||||
sport = ntohs(udp.source);
|
sport = ntohs(udp.source);
|
||||||
|
381
src/dns-trace.ebpf.c_bck
Normal file
381
src/dns-trace.ebpf.c_bck
Normal file
@ -0,0 +1,381 @@
|
|||||||
|
#define BPF_NO_GLOBAL_DATA
|
||||||
|
#define __TARGET_ARCH_x86
|
||||||
|
#include <linux/bpf.h>
|
||||||
|
#include <bpf/bpf_helpers.h>
|
||||||
|
#include <bpf/bpf_tracing.h>
|
||||||
|
#include <bpf/bpf_core_read.h>
|
||||||
|
#include <linux/if_ether.h>
|
||||||
|
#include <linux/udp.h>
|
||||||
|
#include <linux/net.h>
|
||||||
|
#include <linux/socket.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <linux/net.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netinet/ip.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 {
|
||||||
|
__uint(type, BPF_MAP_TYPE_RINGBUF);
|
||||||
|
__uint(max_entries, 256 * 1024 /* 256kb */);
|
||||||
|
} m_data SEC(".maps");
|
||||||
|
|
||||||
|
struct {
|
||||||
|
__uint(type, BPF_MAP_TYPE_HASH);
|
||||||
|
__uint(max_entries, 32768); // pid_max -> https://linux.die.net/man/5/proc
|
||||||
|
__type(key, uint16_t);
|
||||||
|
__type(value, struct dns_answer);
|
||||||
|
} m_tid SEC(".maps");
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
while (*(c++) != '\0') {
|
||||||
|
if(*c >= 'a' && *c <= 'z')
|
||||||
|
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
|
||||||
|
|
||||||
|
return qname_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function get the query field and the return the length of it
|
||||||
|
*/
|
||||||
|
//static size_t get_query_section(struct __sk_buff *skb, struct event *s_event, uint16_t *class, uint16_t *type, uint8_t tlen){
|
||||||
|
static size_t get_query_section(struct __sk_buff *skb, struct event *s_event, struct query_section *s_query, uint8_t offset){
|
||||||
|
size_t len;
|
||||||
|
//char buf[256] = {0};
|
||||||
|
//int index = 0;
|
||||||
|
int qname_len = 0; // Full length of the qname field
|
||||||
|
//char qname[QNAME_SIZE] = {0};
|
||||||
|
//char *c;
|
||||||
|
uint8_t flen = skb->len;
|
||||||
|
/*
|
||||||
|
We get the size for the buffer
|
||||||
|
We substract the full size of the buffer (skb->len) with the sizes of each headers (eth + ip + udp + dns header)
|
||||||
|
*/
|
||||||
|
uint8_t l = flen - offset;
|
||||||
|
|
||||||
|
if (l < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
//bpf_skb_load_bytes(skb, tlen, &buf, l);
|
||||||
|
//bpf_skb_load_bytes(skb, offset, &buf, 41);
|
||||||
|
//c = buf;
|
||||||
|
|
||||||
|
// get_labels(struct __sk_buff *skb, size_t offset, size_t end, struct event *s_event, struct query_section *s_query)
|
||||||
|
qname_len = get_labels(skb, offset, 41, s_event, s_query);
|
||||||
|
/*
|
||||||
|
* The qname is composed by a the number of bytes then follow by the label
|
||||||
|
* For instance, for the qname www.bucchino.org,
|
||||||
|
* the first byte is the number of byte, here, it's 3, then we have www (in hex)
|
||||||
|
* Then, we have the byte of 8 and follow by the label bucchino (size 8)
|
||||||
|
* And to finish, we have 3 follow by org and we finish with the \0 character
|
||||||
|
* For instance, the result is:
|
||||||
|
* 03 77 77 77 08 62 75 63 63 68 69 6e 6f 03 6f 72 67 00
|
||||||
|
*/
|
||||||
|
/*while (*(c++) != '\0') {
|
||||||
|
if(*c >= 'a' && *c <= 'z')
|
||||||
|
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("l: %d", l);
|
||||||
|
|
||||||
|
// Get class and type
|
||||||
|
len = qname_len;
|
||||||
|
bpf_skb_load_bytes(skb, offset + qname_len, &s_query->type, sizeof(uint16_t));
|
||||||
|
len += 2;
|
||||||
|
bpf_skb_load_bytes(skb, offset + qname_len + 2, &s_query->class, sizeof(uint16_t));
|
||||||
|
len += 2;
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
static size_t get_answer(struct __sk_buff *skb, struct event *s_event, size_t tlen){
|
||||||
|
size_t len = 0;
|
||||||
|
unsigned char buf[25] = {0}; // Need to be unsigned, otherwise, the result is fffff
|
||||||
|
|
||||||
|
if(bpf_skb_load_bytes(skb, tlen, &buf, 2) < 0)
|
||||||
|
return 0;
|
||||||
|
/*
|
||||||
|
* 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 it's the pointer and 0x00c is the position in the DNS header
|
||||||
|
*/
|
||||||
|
if (buf[0] == 0xc0){
|
||||||
|
bpf_printk("Pointer to %x", buf[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* 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};
|
||||||
|
char saddr[32];
|
||||||
|
struct query_section s_query = {0};
|
||||||
|
// bpf_printk("udp len: %d", ntohs(udp.len));
|
||||||
|
|
||||||
|
s_event = bpf_ringbuf_reserve(&m_data, sizeof(*s_event), 0);
|
||||||
|
if (!s_event)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Get IP header */
|
||||||
|
s_event->saddr = ip.saddr;
|
||||||
|
|
||||||
|
/* 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 flags = ntohs(dns.flags);
|
||||||
|
uint16_t qr = flags & 0xF000; // Get the QR code: 0 -> query, 1 -> response
|
||||||
|
if (qr == 0x0)
|
||||||
|
bpf_printk("Query");
|
||||||
|
else if(qr == 0x8000)
|
||||||
|
bpf_printk("Response");
|
||||||
|
bpf_printk("Flags: %x %x", flags, qr);
|
||||||
|
|
||||||
|
if (ntohs(dns.nbQuestions) == 0){
|
||||||
|
bpf_ringbuf_discard(s_event, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bpf_printk("tid: %x", ntohs(dns.transactionID)); // Use as key map
|
||||||
|
bpf_printk("nb question: %d", ntohs(dns.nbQuestions));
|
||||||
|
|
||||||
|
//struct dns_query dquery;
|
||||||
|
//bpf_skb_load_bytes(skb, sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct dnshdr), &dquery, sizeof(struct dns_query));
|
||||||
|
// bpf_printk("size: %d %d %d", tlen, skb->len, (skb->len - tlen));
|
||||||
|
//dlen = (skb->len - tlen);
|
||||||
|
//bpf_printk("DNS packet len: %d", dlen);
|
||||||
|
//qlen = dlen - sizeof(struct dnshdr);
|
||||||
|
//bpf_printk("size: %d %d", sizeof(struct dnshdr), qlen);
|
||||||
|
|
||||||
|
|
||||||
|
/* Get the query structure */
|
||||||
|
uint8_t tlen = sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct dnshdr);
|
||||||
|
// size_t query_len = get_query_section(skb, s_event, &class, &type, tlen);
|
||||||
|
size_t query_len = get_query_section(skb, s_event, &s_query, tlen);
|
||||||
|
|
||||||
|
// https://docs.cilium.io/en/stable/reference-guides/bpf/progtypes/
|
||||||
|
s_event->dport = dport;
|
||||||
|
s_event->sport = sport;
|
||||||
|
s_event->class = ntohs(s_query.class);
|
||||||
|
s_event->type = ntohs(s_query.type);
|
||||||
|
//if(bpf_probe_read_user_str(&s_event->qname, sizeof(s_event->qname), qname) < 0)
|
||||||
|
// bpf_printk("Failed to copy qname");
|
||||||
|
|
||||||
|
// Add to map
|
||||||
|
|
||||||
|
bpf_ringbuf_submit(s_event, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODO: je recupere tout le skb->data, grace au skb->len
|
||||||
|
grace a ca, j'aurai tout le payload udp et toute les donnees dns
|
||||||
|
je pourrai facilement parcourir les data
|
||||||
|
*/
|
||||||
|
static int dnsanswer(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};
|
||||||
|
uint16_t tid = 0;
|
||||||
|
//struct dns_answer s_dnsanswer;
|
||||||
|
//struct query_section s_query = {0};
|
||||||
|
unsigned char buf[256] = {0};
|
||||||
|
uint32_t offset = sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr);
|
||||||
|
uint32_t skblen = skb->len;
|
||||||
|
uint32_t l;
|
||||||
|
|
||||||
|
if (skblen < 1 || skblen == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
bpf_printk("skblen: %d", skb->len);
|
||||||
|
if (skb->len <= -1) {
|
||||||
|
bpf_printk("skblen: %d", skb->len);
|
||||||
|
skblen = 12; // Get the 12 first bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
bpf_printk("%d %d", skblen, offset);
|
||||||
|
if (skblen < offset)
|
||||||
|
return 0;
|
||||||
|
l = skblen - offset;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bpf_printk("size: %d %d", skb->len, l);
|
||||||
|
// if (bpf_skb_load_bytes_relative(skb, offset, &buf, l, BPF_HDR_START_MAC) < 0){
|
||||||
|
if (bpf_skb_load_bytes(skb, offset, &buf, l) < 0){
|
||||||
|
bpf_printk("Failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
s_event = bpf_ringbuf_reserve(&m_data, sizeof(*s_event), 0);
|
||||||
|
if (!s_event)
|
||||||
|
return 0;
|
||||||
|
/* Get Transaction ID */
|
||||||
|
//tid = (uint16_t)buf >> 8;
|
||||||
|
|
||||||
|
//bpf_printk("ttid: %x", ntohs(tid));
|
||||||
|
|
||||||
|
/* 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 flags = ntohs(dns.flags);
|
||||||
|
uint16_t qr = flags & 0xF000; // Get the QR code: 0 -> query, 1 -> response
|
||||||
|
if (qr == 0x0){} // Query
|
||||||
|
else if(qr == 0x8000){} // Response
|
||||||
|
|
||||||
|
if (ntohs(dns.nbQuestions) == 0 && ntohs(dns.nbAnswerRRs)){
|
||||||
|
bpf_ringbuf_discard(s_event, 0);
|
||||||
|
return 0;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/* Get the Transaction ID */
|
||||||
|
//tid = ntohs(dns.transactionID);
|
||||||
|
//bpf_printk("tid: %x", tid);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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:
|
||||||
|
1 - dans le getquery, on push dans le ringbuffer et dans le userspace, on recupere aussi la reponse
|
||||||
|
mais si la reponse, nous l'avons pas encore, ca fail et dans le get answer on push dans une map
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Get the query response */
|
||||||
|
/*uint8_t tlen = sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct dnshdr);
|
||||||
|
uint16_t class, type;
|
||||||
|
// size_t query_len = get_query_section(skb, s_event, &class, &type, tlen);
|
||||||
|
size_t query_len = get_query_section(skb, s_event, &s_query, tlen);
|
||||||
|
bpf_printk("answer qname: %s", s_event->qname);
|
||||||
|
s_event->dport = dport;
|
||||||
|
s_event->sport = sport;
|
||||||
|
s_event->class = ntohs(class);
|
||||||
|
s_event->type = ntohs(type);*/
|
||||||
|
|
||||||
|
/* Get the answer */
|
||||||
|
//tlen += query_len;
|
||||||
|
//size_t answer_len = get_answer(skb, s_event, tlen);
|
||||||
|
bpf_ringbuf_submit(s_event, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
SEC("socket")
|
||||||
|
int detect_dns(struct __sk_buff *skb) {
|
||||||
|
//void *data = (void *)(long)skb->data;
|
||||||
|
//void *data_end = (void *)(long)skb->data_end;
|
||||||
|
//struct ethhdr *eth = data;
|
||||||
|
struct ethhdr eth = {0};
|
||||||
|
struct iphdr ip = {0};
|
||||||
|
struct udphdr udp = {0};
|
||||||
|
unsigned long long h_proto, p;
|
||||||
|
unsigned long long dport;
|
||||||
|
unsigned long long sport;
|
||||||
|
|
||||||
|
//if (data + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr) > data_end)
|
||||||
|
// return 0;
|
||||||
|
|
||||||
|
//bpf_skb_load_bytes(skb, 12, &p, 2);
|
||||||
|
bpf_skb_load_bytes(skb, 0, ð, sizeof(struct ethhdr));
|
||||||
|
p = eth.h_proto;
|
||||||
|
if (ntohs(p) != ETH_P_IP)
|
||||||
|
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(data, sizeof(struct ethhdr), ip, sizeof(struct ip));
|
||||||
|
h_proto = ip.protocol;
|
||||||
|
// If not UDP packet
|
||||||
|
if (h_proto != 17)
|
||||||
|
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));
|
||||||
|
|
||||||
|
// Check if DNS port
|
||||||
|
dport = ntohs(udp.dest);
|
||||||
|
sport = ntohs(udp.source);
|
||||||
|
|
||||||
|
if (dport == 53)
|
||||||
|
dnsquery(skb, eth, ip, udp, dport, sport);
|
||||||
|
else if(sport == 53)
|
||||||
|
dnsanswer(skb, eth, ip, udp, dport, sport);
|
||||||
|
|
||||||
|
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";
|
379
src/dns-trace.ebpf.c_bck2
Normal file
379
src/dns-trace.ebpf.c_bck2
Normal file
@ -0,0 +1,379 @@
|
|||||||
|
#define BPF_NO_GLOBAL_DATA
|
||||||
|
#define __TARGET_ARCH_x86
|
||||||
|
#include <linux/bpf.h>
|
||||||
|
#include <bpf/bpf_helpers.h>
|
||||||
|
#include <bpf/bpf_tracing.h>
|
||||||
|
#include <bpf/bpf_core_read.h>
|
||||||
|
#include <linux/if_ether.h>
|
||||||
|
#include <linux/udp.h>
|
||||||
|
#include <linux/net.h>
|
||||||
|
#include <linux/socket.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <linux/net.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netinet/ip.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 {
|
||||||
|
__uint(type, BPF_MAP_TYPE_RINGBUF);
|
||||||
|
__uint(max_entries, 256 * 1024 /* 256kb */);
|
||||||
|
} m_data SEC(".maps");
|
||||||
|
|
||||||
|
struct {
|
||||||
|
__uint(type, BPF_MAP_TYPE_HASH);
|
||||||
|
__uint(max_entries, 32768); // pid_max -> https://linux.die.net/man/5/proc
|
||||||
|
__type(key, uint16_t);
|
||||||
|
__type(value, struct dns_answer);
|
||||||
|
} m_tid SEC(".maps");
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
while (*(c++) != '\0') {
|
||||||
|
if(*c >= 'a' && *c <= 'z')
|
||||||
|
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
|
||||||
|
|
||||||
|
return qname_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function get the query field and the return the length of it
|
||||||
|
*/
|
||||||
|
//static size_t get_query_section(struct __sk_buff *skb, struct event *s_event, uint16_t *class, uint16_t *type, uint8_t tlen){
|
||||||
|
static size_t get_query_section(struct __sk_buff *skb, struct event *s_event, struct query_section *s_query, uint8_t offset){
|
||||||
|
size_t len;
|
||||||
|
//char buf[256] = {0};
|
||||||
|
//int index = 0;
|
||||||
|
int qname_len = 0; // Full length of the qname field
|
||||||
|
//char qname[QNAME_SIZE] = {0};
|
||||||
|
//char *c;
|
||||||
|
uint8_t flen = skb->len;
|
||||||
|
/*
|
||||||
|
We get the size for the buffer
|
||||||
|
We substract the full size of the buffer (skb->len) with the sizes of each headers (eth + ip + udp + dns header)
|
||||||
|
*/
|
||||||
|
uint8_t l = flen - offset;
|
||||||
|
|
||||||
|
if (l < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
//bpf_skb_load_bytes(skb, tlen, &buf, l);
|
||||||
|
//bpf_skb_load_bytes(skb, offset, &buf, 41);
|
||||||
|
//c = buf;
|
||||||
|
|
||||||
|
// get_labels(struct __sk_buff *skb, size_t offset, size_t end, struct event *s_event, struct query_section *s_query)
|
||||||
|
qname_len = get_labels(skb, offset, 41, s_event, s_query);
|
||||||
|
/*
|
||||||
|
* The qname is composed by a the number of bytes then follow by the label
|
||||||
|
* For instance, for the qname www.bucchino.org,
|
||||||
|
* the first byte is the number of byte, here, it's 3, then we have www (in hex)
|
||||||
|
* Then, we have the byte of 8 and follow by the label bucchino (size 8)
|
||||||
|
* And to finish, we have 3 follow by org and we finish with the \0 character
|
||||||
|
* For instance, the result is:
|
||||||
|
* 03 77 77 77 08 62 75 63 63 68 69 6e 6f 03 6f 72 67 00
|
||||||
|
*/
|
||||||
|
/*while (*(c++) != '\0') {
|
||||||
|
if(*c >= 'a' && *c <= 'z')
|
||||||
|
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("l: %d", l);
|
||||||
|
|
||||||
|
// Get class and type
|
||||||
|
len = qname_len;
|
||||||
|
bpf_skb_load_bytes(skb, offset + qname_len, &s_query->type, sizeof(uint16_t));
|
||||||
|
len += 2;
|
||||||
|
bpf_skb_load_bytes(skb, offset + qname_len + 2, &s_query->class, sizeof(uint16_t));
|
||||||
|
len += 2;
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
static size_t get_answer(struct __sk_buff *skb, struct event *s_event, size_t tlen){
|
||||||
|
size_t len = 0;
|
||||||
|
unsigned char buf[25] = {0}; // Need to be unsigned, otherwise, the result is fffff
|
||||||
|
|
||||||
|
if(bpf_skb_load_bytes(skb, tlen, &buf, 2) < 0)
|
||||||
|
return 0;
|
||||||
|
/*
|
||||||
|
* 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 it's the pointer and 0x00c is the position in the DNS header
|
||||||
|
*/
|
||||||
|
if (buf[0] == 0xc0){
|
||||||
|
bpf_printk("Pointer to %x", buf[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* 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};
|
||||||
|
char saddr[32];
|
||||||
|
struct query_section s_query = {0};
|
||||||
|
// bpf_printk("udp len: %d", ntohs(udp.len));
|
||||||
|
|
||||||
|
s_event = bpf_ringbuf_reserve(&m_data, sizeof(*s_event), 0);
|
||||||
|
if (!s_event)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Get IP header */
|
||||||
|
s_event->saddr = ip.saddr;
|
||||||
|
|
||||||
|
/* 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 flags = ntohs(dns.flags);
|
||||||
|
uint16_t qr = flags & 0xF000; // Get the QR code: 0 -> query, 1 -> response
|
||||||
|
if (qr == 0x0)
|
||||||
|
bpf_printk("Query");
|
||||||
|
else if(qr == 0x8000)
|
||||||
|
bpf_printk("Response");
|
||||||
|
bpf_printk("Flags: %x %x", flags, qr);
|
||||||
|
|
||||||
|
if (ntohs(dns.nbQuestions) == 0){
|
||||||
|
bpf_ringbuf_discard(s_event, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bpf_printk("tid: %x", ntohs(dns.transactionID)); // Use as key map
|
||||||
|
bpf_printk("nb question: %d", ntohs(dns.nbQuestions));
|
||||||
|
|
||||||
|
//struct dns_query dquery;
|
||||||
|
//bpf_skb_load_bytes(skb, sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct dnshdr), &dquery, sizeof(struct dns_query));
|
||||||
|
// bpf_printk("size: %d %d %d", tlen, skb->len, (skb->len - tlen));
|
||||||
|
//dlen = (skb->len - tlen);
|
||||||
|
//bpf_printk("DNS packet len: %d", dlen);
|
||||||
|
//qlen = dlen - sizeof(struct dnshdr);
|
||||||
|
//bpf_printk("size: %d %d", sizeof(struct dnshdr), qlen);
|
||||||
|
|
||||||
|
|
||||||
|
/* Get the query structure */
|
||||||
|
uint8_t tlen = sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct dnshdr);
|
||||||
|
// size_t query_len = get_query_section(skb, s_event, &class, &type, tlen);
|
||||||
|
size_t query_len = get_query_section(skb, s_event, &s_query, tlen);
|
||||||
|
|
||||||
|
// https://docs.cilium.io/en/stable/reference-guides/bpf/progtypes/
|
||||||
|
s_event->dport = dport;
|
||||||
|
s_event->sport = sport;
|
||||||
|
s_event->class = ntohs(s_query.class);
|
||||||
|
s_event->type = ntohs(s_query.type);
|
||||||
|
//if(bpf_probe_read_user_str(&s_event->qname, sizeof(s_event->qname), qname) < 0)
|
||||||
|
// bpf_printk("Failed to copy qname");
|
||||||
|
|
||||||
|
// Add to map
|
||||||
|
|
||||||
|
bpf_ringbuf_submit(s_event, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODO: je recupere tout le skb->data, grace au skb->len
|
||||||
|
grace a ca, j'aurai tout le payload udp et toute les donnees dns
|
||||||
|
je pourrai facilement parcourir les data
|
||||||
|
*/
|
||||||
|
static int dnsanswer(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};
|
||||||
|
uint16_t tid = 0;
|
||||||
|
//struct dns_answer s_dnsanswer;
|
||||||
|
//struct query_section s_query = {0};
|
||||||
|
unsigned char buf[256] = {0};
|
||||||
|
uint32_t offset = sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr);
|
||||||
|
uint32_t skblen = skb->len;
|
||||||
|
uint32_t l;
|
||||||
|
|
||||||
|
if (skblen < 1 || skblen == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
bpf_printk("skblen: %d", skb->len);
|
||||||
|
if (skb->len <= -1) {
|
||||||
|
bpf_printk("skblen: %d", skb->len);
|
||||||
|
skblen = 12; // Get the 12 first bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
bpf_printk("%d %d", skblen, offset);
|
||||||
|
if (skblen < offset)
|
||||||
|
return 0;
|
||||||
|
l = skblen - offset;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bpf_printk("size: %d %d", skb->len, l);
|
||||||
|
// if (bpf_skb_load_bytes_relative(skb, offset, &buf, l, BPF_HDR_START_MAC) < 0){
|
||||||
|
if (bpf_skb_load_bytes(skb, offset, &buf, l) < 0){
|
||||||
|
bpf_printk("Failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
s_event = bpf_ringbuf_reserve(&m_data, sizeof(*s_event), 0);
|
||||||
|
if (!s_event)
|
||||||
|
return 0;
|
||||||
|
/* Get Transaction ID */
|
||||||
|
//tid = (uint16_t)buf >> 8;
|
||||||
|
|
||||||
|
//bpf_printk("ttid: %x", ntohs(tid));
|
||||||
|
|
||||||
|
/* 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 flags = ntohs(dns.flags);
|
||||||
|
uint16_t qr = flags & 0xF000; // Get the QR code: 0 -> query, 1 -> response
|
||||||
|
if (qr == 0x0){} // Query
|
||||||
|
else if(qr == 0x8000){} // Response
|
||||||
|
|
||||||
|
if (ntohs(dns.nbQuestions) == 0 && ntohs(dns.nbAnswerRRs)){
|
||||||
|
bpf_ringbuf_discard(s_event, 0);
|
||||||
|
return 0;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/* Get the Transaction ID */
|
||||||
|
//tid = ntohs(dns.transactionID);
|
||||||
|
//bpf_printk("tid: %x", tid);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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:
|
||||||
|
1 - dans le getquery, on push dans le ringbuffer et dans le userspace, on recupere aussi la reponse
|
||||||
|
mais si la reponse, nous l'avons pas encore, ca fail et dans le get answer on push dans une map
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Get the query response */
|
||||||
|
/*uint8_t tlen = sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct dnshdr);
|
||||||
|
uint16_t class, type;
|
||||||
|
// size_t query_len = get_query_section(skb, s_event, &class, &type, tlen);
|
||||||
|
size_t query_len = get_query_section(skb, s_event, &s_query, tlen);
|
||||||
|
bpf_printk("answer qname: %s", s_event->qname);
|
||||||
|
s_event->dport = dport;
|
||||||
|
s_event->sport = sport;
|
||||||
|
s_event->class = ntohs(class);
|
||||||
|
s_event->type = ntohs(type);*/
|
||||||
|
|
||||||
|
/* Get the answer */
|
||||||
|
//tlen += query_len;
|
||||||
|
//size_t answer_len = get_answer(skb, s_event, tlen);
|
||||||
|
bpf_ringbuf_submit(s_event, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
SEC("socket")
|
||||||
|
int detect_dns(struct __sk_buff *skb) {
|
||||||
|
void *data = (void *)(long)skb->data;
|
||||||
|
void *data_end = (void *)(long)skb->data_end;
|
||||||
|
struct ethhdr *eth = data;
|
||||||
|
struct iphdr *ip;
|
||||||
|
struct udphdr *udp;
|
||||||
|
unsigned long long h_proto, p;
|
||||||
|
unsigned long long dport;
|
||||||
|
unsigned long long sport;
|
||||||
|
unsigned char buf[256];
|
||||||
|
|
||||||
|
if (data + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr) > data_end)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
p = eth->h_proto;
|
||||||
|
if (ntohs(p) != ETH_P_IP)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
//bpf_printk("ip: %d",ntohs(p));
|
||||||
|
//bpf_printk("s: %d", skb->data_end);
|
||||||
|
bpf_skb_load_bytes(skb, 0, &buf, 41);
|
||||||
|
|
||||||
|
ip = (struct iphdr*)(data + sizeof(struct ethhdr));
|
||||||
|
|
||||||
|
h_proto = ip->protocol;
|
||||||
|
// If not UDP packet
|
||||||
|
if (h_proto != 17)
|
||||||
|
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));
|
||||||
|
|
||||||
|
// Check if DNS port
|
||||||
|
dport = ntohs(udp.dest);
|
||||||
|
sport = ntohs(udp.source);
|
||||||
|
|
||||||
|
if (dport == 53)
|
||||||
|
dnsquery(skb, eth, ip, udp, dport, sport);
|
||||||
|
else if(sport == 53)
|
||||||
|
dnsanswer(skb, eth, ip, udp, dport, sport);*/
|
||||||
|
|
||||||
|
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";
|
BIN
src/dns-trace.ebpf.o
Normal file
BIN
src/dns-trace.ebpf.o
Normal file
Binary file not shown.
193018
src/vmlinux.h
193018
src/vmlinux.h
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user