Update project

This commit is contained in:
geoffrey 2025-01-21 21:04:27 +01:00
parent 157577613a
commit 08ece6a46e
7 changed files with 149 additions and 149 deletions

BIN
dns-trace

Binary file not shown.

@ -3,6 +3,9 @@
#define QNAME_SIZE 128
#define REQ_QUERY 0x00
#define REQ_ANSWER 0x01
struct dnshdr {
uint16_t transactionID;
uint16_t flags;
@ -22,6 +25,8 @@ struct event {
uint32_t saddr;
int dport;
int sport;
uint16_t tid;
int req_type;
char qname[QNAME_SIZE];
int class;
int type;

@ -101,6 +101,18 @@ static int open_raw_sock(const char *name)
return sock;
}
static void mapReqType(const int req){
switch(req){
case 0x00:
printf("Query\n");
break;
case 0x01:
printf("Answer\n");
break;
default:
printf("Unknown");
};
}
static void mapClass(const int class){
switch(class){
case 1:
@ -182,6 +194,9 @@ int handle_event(void *ctx, void *data, size_t data_sz){
printf("IP: %s\n", inet_ntoa(*(struct in_addr*)&s_event->saddr));
printf("dport: %d\n", s_event->dport);
printf("sport: %d\n", s_event->sport);
printf("Transaction ID: %x\n", s_event->tid);
printf("Request type: ");
mapReqType(s_event->req_type);
printf("qname: %s\n", s_event->qname);
printf("Class: ");
mapClass(s_event->class);

@ -36,6 +36,27 @@ struct {
__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;
int qname_len = 0;
bpf_skb_load_bytes(skb, offset + sizeof(struct dnshdr), &c, 1);
int pos = 1;
while (c != '\0') {
bpf_skb_load_bytes(skb, offset + 12 + 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)
break;
}
s_event->qname[qname_len - 1] = '\0';
qname_len++;
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};
@ -46,6 +67,15 @@ static size_t get_labels(struct __sk_buff *skb, size_t offset, size_t end, struc
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
* 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;
@ -58,6 +88,7 @@ static size_t get_labels(struct __sk_buff *skb, size_t offset, size_t end, struc
}
s_event->qname[--index] = '\0';
qname_len++; // For the null character
bpf_printk("qname: %s", s_event->qname);
return qname_len;
}
@ -65,58 +96,20 @@ static size_t get_labels(struct __sk_buff *skb, size_t offset, size_t end, struc
/*
* 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){
static size_t get_query_section(struct __sk_buff *skb, struct event *s_event, 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;
size_t qname_len = 0; // Full length of the qname field
uint16_t class, type;
//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);
qname_len = get_labels2(skb, offset, s_event);
// Get class and type
len = qname_len;
bpf_skb_load_bytes(skb, offset + qname_len, &s_query->type, sizeof(uint16_t));
bpf_skb_load_bytes(skb, offset + 12 + qname_len, &type, sizeof(uint16_t));
s_event->type = ntohs(type);
len += 2;
bpf_skb_load_bytes(skb, offset + qname_len + 2, &s_query->class, sizeof(uint16_t));
bpf_skb_load_bytes(skb, offset + 12 + qname_len + 2, &class, sizeof(uint16_t));
s_event->class = ntohs(class);
len += 2;
return len;
@ -146,7 +139,6 @@ static int dnsquery(struct __sk_buff *skb, struct ethhdr eth, struct iphdr ip, s
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);
@ -163,7 +155,7 @@ static int dnsquery(struct __sk_buff *skb, struct ethhdr eth, struct iphdr ip, s
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");
s_event->req_type = REQ_QUERY;
else if(qr == 0x8000)
bpf_printk("Response");
bpf_printk("Flags: %x %x", flags, qr);
@ -173,8 +165,7 @@ static int dnsquery(struct __sk_buff *skb, struct ethhdr eth, struct iphdr ip, s
return 0;
}
bpf_printk("tid: %x", ntohs(dns.transactionID)); // Use as key map
bpf_printk("nb question: %d", ntohs(dns.nbQuestions));
s_event->tid = ntohs(dns.transactionID); // Use as key map
//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));
@ -185,128 +176,105 @@ static int dnsquery(struct __sk_buff *skb, struct ethhdr eth, struct iphdr ip, s
//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);
/* Get the query section */
// 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);
size_t query_len = get_query_section(skb, s_event, 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;
}
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
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 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 = 0;
//struct dns_answer s_dnsanswer;
//struct query_section s_query = {0};
unsigned char buf[256] = {0}; // Max dns domain name length
struct dnshdr dns;
uint16_t tid = 0U;
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)
return 0;
if (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;
if (udplen > offset)
udplen = sizeof(struct dnshdr);
//__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 + udplen > skb->len) {
bpf_printk("outbound");
//return 0;
plen = sizeof(struct dnshdr);
}
// plen = 57;
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;
// Load dns header
if (bpf_skb_load_bytes(skb, offset, &dns, 12) < 0)
return;
s_event = bpf_ringbuf_reserve(&m_data, sizeof(*s_event), 0);
if (!s_event)
return 0;
return;
// 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
if (qr == 0x0){} // Query
else if(qr == 0x8000){} // Response
if (qr == 0x0) // Query
s_event->req_type = REQ_QUERY;
else if(qr == 0x8000) // Response
s_event->req_type = REQ_ANSWER;
if (ntohs(dns->nbQuestions) == 0 && ntohs(dns->nbAnswerRRs)){
if (ntohs(dns.nbQuestions) == 0 && ntohs(dns.nbAnswerRRs)){
bpf_ringbuf_discard(s_event, 0);
return 0;
return;
}
/* Get the Transaction ID */
tid = ntohs(dns->transactionID);
bpf_printk("tid: %x", tid);
s_event->tid = ntohs(dns.transactionID);
/* Get the query section */
size_t query_len = get_query_section(skb, s_event, offset);
/* Get answer section */
for (int i = 0; i < ntohs(dns.nbAnswerRRs); i++){
}
/*
* 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
@ -339,8 +307,6 @@ static int dnsanswer(struct __sk_buff *skb, struct ethhdr eth, struct iphdr ip,
//tlen += query_len;
//size_t answer_len = get_answer(skb, s_event, tlen);
bpf_ringbuf_submit(s_event, 0);
return 0;
}
/*
@ -355,9 +321,9 @@ int detect_dns(struct __sk_buff *skb) {
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;
__u32 h_proto, p;
__u32 dport;
__u32 sport;
//if (data + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr) > data_end)
// return 0;
@ -397,7 +363,7 @@ int detect_dns(struct __sk_buff *skb) {
if (dport == 53)
dnsquery(skb, eth, ip, udp, dport, sport);
else if(sport == 53)
dnsanswer(skb, eth, ip, udp, dport, sport);
dnsanswer(skb, ip, udp, dport, sport);
return 0;
}

Binary file not shown.

BIN
test Executable file

Binary file not shown.

14
test.c Normal file

@ -0,0 +1,14 @@
#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;
}