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);
}
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){
struct event *s_event = (struct event*)data;
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){
int pos = 0;
//for(int i = 0; i < 32; i++)
// printf("%d ", s_event->buf[i]);
//printf("\n");
/*for (int i = 0; i < 50; i++)
printf("%d ", s_event->buf[i]);
printf("\n");*/
for (int i = 0; i < s_event->numAns; i++){
print_query(s_event);
uint16_t 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("%d\n", pos);
}
}
+39 -128
View File
@@ -29,24 +29,28 @@ struct {
__uint(max_entries, 256 * 1024 /* 256kb */);
} m_data SEC(".maps");
struct {
__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){
static size_t get_labels(struct __sk_buff *skb, size_t offset, struct event *s_event){
char c;
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
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') {
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 if(c >= '0' && c <= '9')
s_event->qname[qname_len] = c;
else
s_event->qname[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);
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
@@ -105,7 +74,7 @@ static size_t get_query_section(struct __sk_buff *skb, struct event *s_event, ui
uint16_t class, type;
offset += sizeof(struct dnshdr);
qname_len = get_labels2(skb, offset, s_event);
qname_len = get_labels(skb, offset, s_event);
// Get class and type
len = qname_len;
@@ -185,7 +154,7 @@ static unsigned int get_answer(struct __sk_buff *skb, struct event *s_event, siz
tlen += ntohs(size);
}
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);
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){
struct event *s_event;
struct dnshdr dns;
uint16_t tid = 0U;
uint32_t offset = sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr);
size_t tlen = ntohs(udp.len);
int index = 0;
if (tlen < 0 || tlen >= 256)
return;
bpf_printk("udp len: %d", tlen);
// 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;
// Check OpCode
@@ -323,57 +294,34 @@ static void dnsanswer(struct __sk_buff *skb, struct iphdr ip, struct udphdr udp,
return;
}
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;
}
/*if (ans > 0){
s_event->numAns = ans;
}*/
s_event->numAns = ans;
}
if (ntohs(dns.nbAuthorityRRs) > 0){
}
// Load query and answer
/*
* 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
* Load query and answers
* It's a little dirty to do that, to load byte by byte,
* otherwise, I have an issue with the eBPF verifier
*/
/*
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 answer */
offset += sizeof(struct dnshdr) + query_len;
//offset += 2; // We bypass message compression
while (index < tlen){
bpf_skb_load_bytes(skb, offset + index, s_event->buf + index, 1);
index++;
}
bpf_ringbuf_submit(s_event, 0);
//if(bpf_skb_load_bytes(skb, offset, &buf, tlen) < 0)
// bpf_printk("Failed");
}
/*
* skb -> http://oldvger.kernel.org/~davem/skb_data.html
*/
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 *eth2 = data;
struct ethhdr eth = {0};
struct iphdr ip = {0};
struct udphdr udp = {0};
@@ -381,32 +329,22 @@ int detect_dns(struct __sk_buff *skb) {
__u32 dport;
__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))
return 0;
//bpf_skb_load_bytes(skb, 12, &p, 2);
bpf_skb_load_bytes(skb, 0, &eth, 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));
if (udp.len == 0)
@@ -423,31 +361,4 @@ int detect_dns(struct __sk_buff *skb) {
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";
Binary file not shown.