3 Commits

Author SHA1 Message Date
gbucchino aa64b8f160 update code 2025-02-01 16:58:29 +00:00
gbucchino 1436099101 Update 2025-01-31 18:36:55 +00:00
gbucchino c775f97f3c Update 2025-01-30 18:55:58 +00:00
4 changed files with 98 additions and 147 deletions
BIN
View File
Binary file not shown.
+57 -17
View File
@@ -232,6 +232,19 @@ static void print_query(struct event *s_event){
free(type); free(type);
} }
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';
}
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){
@@ -239,28 +252,55 @@ int handle_event(void *ctx, void *data, size_t data_sz){
} }
if (s_event->req_type == REQ_ANSWER){ if (s_event->req_type == REQ_ANSWER){
int pos = 0; int pos = 0;
//for(int i = 0; i < 32; i++) /*for (int i = 0; i < 50; i++)
// printf("%d ", s_event->buf[i]); printf("%d ", s_event->buf[i]);
//printf("\n"); printf("\n");*/
for (int i = 0; i < s_event->numAns; i++){ for (int i = 0; i < s_event->numAns; i++){
print_query(s_event); 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
uint16_t msg = s_event->buf[pos++];
msg |= s_event->buf[pos++] << 8;
uint16_t type = s_event->buf[pos++];
type |= s_event->buf[pos++] << 8;
uint16_t class = s_event->buf[pos++];
class |= s_event->buf[pos++] << 8;
uint32_t ttl = s_event->buf[pos++];
ttl |= s_event->buf[pos++] << 8;
ttl |= s_event->buf[pos++] << 16;
ttl |= s_event->buf[pos++] << 24;
uint16_t size = s_event->buf[pos++];
size |= s_event->buf[pos++] << 8;
type = ntohs(type);
class = ntohs(class);
ttl = ntohl(ttl);
size = ntohs(size);
if (type == 1) { // -> A
uint32_t ip = s_event->buf[pos] + (s_event->buf[pos+1] << 8) + (s_event->buf[pos+2] << 16) + (s_event->buf[pos+3] << 24);
printf("%s (%d)%5d", inet_ntoa(*(struct in_addr*)&ip), type, ttl);
} }
if (type == 5) { // -> CNAME
char cname[size];
get_labels(s_event->buf + pos, cname);
printf("%s ", cname);
}
if (type == 28){ // -> AAAA
int p = 0;
for (int i = 0; i < size; i++){
if (i % 2 == 0)
printf("%x", s_event->buf[pos + p++]);
else{
if (i<size - 1)
printf("%x:", s_event->buf[pos + p++]);
else
printf("%x", s_event->buf[pos + p++]);
}
}
}
pos += size;
printf("\n"); printf("\n");
printf("%d\n", pos);
} }
} }
+40 -129
View File
@@ -29,24 +29,28 @@ struct {
__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;
/*
* 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') { while (c != '\0') {
bpf_skb_load_bytes(skb, offset + pos++, &c, 1); bpf_skb_load_bytes(skb, offset + pos++, &c, 1);
if(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z') if(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')
s_event->qname[qname_len] = c; s_event->qname[qname_len] = c;
else if(c >= '0' && c <= '9')
s_event->qname[qname_len] = c;
else else
s_event->qname[qname_len] = '.'; s_event->qname[qname_len] = '.';
qname_len++; qname_len++;
@@ -60,41 +64,6 @@ static size_t get_labels2(struct __sk_buff *skb, size_t offset, struct event *s_
// bpf_printk("qname len: %d", qname_len); // bpf_printk("qname len: %d", qname_len);
return 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
* 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("qname: %s", s_event->qname);
return qname_len;
}
/* /*
* This function get the query field and the return the length of it * This function get the query field and the return the length of it
@@ -105,7 +74,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;
@@ -154,7 +123,7 @@ static unsigned int get_answer(struct __sk_buff *skb, struct event *s_event, siz
return 0; return 0;
//offset += 2; //offset += 2;
// For class // For class
if(bpf_skb_load_bytes(skb, tlen, s_event->buf + offset, sizeof(uint16_t)) < 0) if(bpf_skb_load_bytes(skb, tlen, s_event->buf + offset, sizeof(uint16_t)) < 0)
return 0; return 0;
tlen += 2; tlen += 2;
@@ -185,7 +154,7 @@ static unsigned int get_answer(struct __sk_buff *skb, struct event *s_event, siz
tlen += ntohs(size); tlen += ntohs(size);
} }
else { else {
// get_labels2(skb, sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct dnshdr), s_event); // get_labels(skb, sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct dnshdr), s_event);
} }
bpf_printk("End offset: %d", offset); bpf_printk("End offset: %d", offset);
return offset; return offset;
@@ -275,19 +244,21 @@ static void dnsanswer_old(struct __sk_buff *skb, struct iphdr ip, struct udphdr
} }
/*
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 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; 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);
int index = 0;
if (tlen < 0 || tlen >= 256)
return;
bpf_printk("udp len: %d", tlen);
// 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 +294,34 @@ static void dnsanswer(struct __sk_buff *skb, struct iphdr ip, struct udphdr udp,
return; return;
} }
if (ans > 0){ /*if (ans > 0){
/*
* 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; s_event->numAns = ans;
} }*/
if (ntohs(dns.nbAuthorityRRs) > 0){ s_event->numAns = ans;
}
// Load query and answer
/* /*
* In the user space, if the haven't have the answer, we can have an error * Load query and answers
* The solution is to push to the ring buffer and the answer is store in * It's a little dirty to do that, to load byte by byte,
* the struct event * otherwise, I have an issue with the eBPF verifier
* 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
*/ */
offset += sizeof(struct dnshdr) + query_len;
/* //offset += 2; // We bypass message compression
Pour recuperer les infos: while (index < tlen){
1 - dans le getquery, on push dans le ringbuffer et dans le userspace, on recupere aussi la reponse bpf_skb_load_bytes(skb, offset + index, s_event->buf + index, 1);
mais si la reponse, nous l'avons pas encore, ca fail et dans le get answer on push dans une map index++;
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 answer */
bpf_ringbuf_submit(s_event, 0); bpf_ringbuf_submit(s_event, 0);
//if(bpf_skb_load_bytes(skb, offset, &buf, tlen) < 0)
// bpf_printk("Failed");
} }
/* /*
* 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 +329,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, &eth, sizeof(struct ethhdr)); bpf_skb_load_bytes(skb, 0, &eth, 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 +361,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.