Update
This commit is contained in:
@@ -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) -Wall -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.
@@ -0,0 +1,18 @@
|
|||||||
|
Feb 08 13:24:15 pc-geoffrey dns-trace: <info> Query;tid=671c;192.168.1.37:53;class=IN;type=AAAA;
|
||||||
|
Feb 08 13:24:16 pc-geoffrey dns-trace: <info> Query;tid=c537;192.168.1.37:53;class=IN;type=A;
|
||||||
|
Feb 08 13:24:17 pc-geoffrey dns-trace: <info> Query;tid=12ba;192.168.1.37:53;class=IN;type=A;
|
||||||
|
Feb 08 14:17:10 pc-geoffrey dns-trace: <info> Query;tid=fa8f;192.168.1.37:53;class=IN;type=A;
|
||||||
|
Feb 08 14:17:20 pc-geoffrey dns-trace: <info> Query;tid=a417;192.168.1.37:53;class=IN;type=A;
|
||||||
|
Feb 08 14:21:36 pc-geoffrey dns-trace: <info> Query;tid=34f;192.168.1.37:53;class=IN;type=A;
|
||||||
|
Feb 08 14:23:23 pc-geoffrey dns-trace: <info> Query;tid=23c8;192.168.1.37:53;class=IN;type=A;
|
||||||
|
Feb 08 14:25:11 pc-geoffrey dns-trace: <info> Query;tid=e74;192.168.1.37:53;class=IN;type=A;
|
||||||
|
Feb 08 14:25:21 pc-geoffrey dns-trace: <info> Query;tid=3844;192.168.1.37:53;class=IN;type=A;
|
||||||
|
Feb 08 14:25:28 pc-geoffrey dns-trace: <info> Query;tid=de58;192.168.1.37:53;class=IN;type=A;
|
||||||
|
Feb 08 14:27:39 pc-geoffrey dns-trace: <info> Query;tid=4600;192.168.1.37:53;class=IN;type=A;
|
||||||
|
Feb 08 14:28:04 pc-geoffrey dns-trace: <info> Query;tid=1f5a;192.168.1.37:53;class=IN;type=A;
|
||||||
|
Feb 08 14:29:20 pc-geoffrey dns-trace: <info> Query;tid=3cc6;192.168.1.37:53;class=IN;type=A;
|
||||||
|
Feb 08 14:35:12 pc-geoffrey dns-trace: <info> Query;tid=a8d2;192.168.1.37:53;class=IN;type=A;
|
||||||
|
Feb 08 14:35:12 pc-geoffrey dns-trace: <info> Query;tid=e7ae;192.168.1.37:53;class=IN;type=AAAA;
|
||||||
|
Feb 08 14:35:16 pc-geoffrey dns-trace: <info> Query;tid=ed16;192.168.1.37:53;class=IN;type=A;
|
||||||
|
Feb 08 14:35:31 pc-geoffrey dns-trace: <info> Query;tid=28a6;192.168.1.37:53;class=IN;type=A;
|
||||||
|
Feb 08 14:50:39 pc-geoffrey dns-trace: <info> Query;tid=b19f;192.168.1.37:53;class=IN;type=AAAA;
|
||||||
BIN
Binary file not shown.
@@ -3,4 +3,4 @@
|
|||||||
|
|
||||||
#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 -i enx98e743c667fc
|
make all && sudo ./dns-trace -i wlp0s20f3 -f dns-trace_`$(echo date '+%F')`.log
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
+181
-71
@@ -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,8 +18,12 @@
|
|||||||
|
|
||||||
#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 *interface;
|
||||||
@@ -216,13 +221,38 @@ 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;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
char t[32];
|
||||||
|
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("%s ", req_type);
|
printf("%s ", req_type);
|
||||||
free(req_type);
|
free(req_type);
|
||||||
|
|
||||||
printf("%5s:%d\t\t", inet_ntoa(*(struct in_addr*)&s_event->client), s_event->dport);
|
printf("%5s:%d\t", inet_ntoa(*(struct in_addr*)&s_event->client), s_event->dport);
|
||||||
printf("%x\t", s_event->tid);
|
printf("%x\t", s_event->tid);
|
||||||
|
|
||||||
class = mapClass(s_event->class);
|
class = mapClass(s_event->class);
|
||||||
@@ -235,6 +265,53 @@ static void print_query(struct event *s_event){
|
|||||||
|
|
||||||
printf("%s", s_event->qname);
|
printf("%s", s_event->qname);
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* 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 t[32];
|
||||||
|
time_t ts = time(NULL);
|
||||||
|
char *req_type, *class, *type;
|
||||||
|
char tid[12];
|
||||||
|
char src[40];
|
||||||
|
char s_class[16], s_type[16];
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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("\n", 1, 1, f);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* This function get labels from DNS answer
|
||||||
|
*/
|
||||||
static void get_labels(unsigned char *buf, char *qname){
|
static void get_labels(unsigned char *buf, char *qname){
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
while (*buf++ != '\0') {
|
while (*buf++ != '\0') {
|
||||||
@@ -248,93 +325,111 @@ static void get_labels(unsigned char *buf, char *qname){
|
|||||||
}
|
}
|
||||||
qname[pos - 1] = '\0';
|
qname[pos - 1] = '\0';
|
||||||
}
|
}
|
||||||
static void print_answer_hdr(struct event *s_event, int *pos, uint16_t *type, uint16_t *size, uint16_t *class, uint32_t *ttl){
|
/*
|
||||||
int p = *pos;
|
* This function save to rsyslog format the answer section
|
||||||
uint16_t msg = s_event->buf[p++];
|
*/
|
||||||
msg |= s_event->buf[p++] << 8;
|
static void answer_to_log(struct event *s_event){
|
||||||
// printf("%x\n", ntohs(msg));
|
|
||||||
|
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* This function print to the stdout the answer section
|
||||||
|
*/
|
||||||
|
static void print_answer(struct event *s_event){
|
||||||
char *req_type;
|
char *req_type;
|
||||||
req_type = mapReqType(s_event->req_type);
|
int pos = 0;
|
||||||
printf("%s ", req_type);
|
char t[32];
|
||||||
free(req_type);
|
time_t ts = time(NULL);
|
||||||
|
|
||||||
printf("%5s:%5d\t", inet_ntoa(*(struct in_addr*)&s_event->client), s_event->dport);
|
for (int i = 0; i < s_event->numAns; i++){
|
||||||
printf("%x\t", s_event->tid);
|
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;
|
||||||
|
|
||||||
*type = s_event->buf[p++];
|
/* Print answer hdr */
|
||||||
*type |= s_event->buf[p++] << 8;
|
syslog_time(ts, t, sizeof(t));
|
||||||
|
printf("%-20s", t);
|
||||||
|
|
||||||
*class = s_event->buf[p++];
|
req_type = mapReqType(s_event->req_type);
|
||||||
*class |= s_event->buf[p++] << 8;
|
printf("%s ", req_type);
|
||||||
|
free(req_type);
|
||||||
|
|
||||||
*ttl = s_event->buf[p++];
|
printf("%5s:%5d\t", inet_ntoa(*(struct in_addr*)&s_event->client), s_event->dport);
|
||||||
*ttl |= s_event->buf[p++] << 8;
|
printf("%x\t", s_event->tid);
|
||||||
*ttl |= s_event->buf[p++] << 16;
|
|
||||||
*ttl |= s_event->buf[p++] << 24;
|
|
||||||
|
|
||||||
*size = s_event->buf[p++];
|
type = s_event->buf[pos++];
|
||||||
*size |= s_event->buf[p++] << 8;
|
type |= s_event->buf[pos++] << 8;
|
||||||
|
|
||||||
*type = ntohs(*type);
|
class = s_event->buf[pos++];
|
||||||
*class = ntohs(*class);
|
class |= s_event->buf[pos++] << 8;
|
||||||
*ttl = ntohl(*ttl);
|
|
||||||
*size = ntohs(*size);
|
|
||||||
|
|
||||||
*pos = p;
|
ttl = s_event->buf[pos++];
|
||||||
|
ttl |= s_event->buf[pos++] << 8;
|
||||||
|
ttl |= s_event->buf[pos++] << 16;
|
||||||
|
ttl |= s_event->buf[pos++] << 24;
|
||||||
|
|
||||||
|
size = s_event->buf[pos++];
|
||||||
|
size |= s_event->buf[pos++] << 8;
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
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 < s_event->numAns; i++){
|
print_answer(s_event);
|
||||||
// print_query(s_event);
|
if (arguments.filename != NULL && f != NULL)
|
||||||
uint16_t type, size, class;
|
answer_to_log(s_event);
|
||||||
uint32_t ttl;
|
|
||||||
char *s_type, *s_class;
|
|
||||||
print_answer_hdr(s_event, &pos, &type, &size, &class, &ttl);
|
|
||||||
|
|
||||||
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
|
|
||||||
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++]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf(" %d ", ttl);
|
|
||||||
}
|
|
||||||
pos += size;
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int main(int argc, char *argv[]){
|
int main(int argc, char *argv[]){
|
||||||
@@ -349,7 +444,7 @@ int main(int argc, char *argv[]){
|
|||||||
arguments = parse_args(argc, argv); // Parsing arguments
|
arguments = parse_args(argc, argv); // Parsing arguments
|
||||||
|
|
||||||
if (arguments.interface == NULL){
|
if (arguments.interface == NULL){
|
||||||
printf("You must specified the interface name");
|
printf("You must specified the interface name\n");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
printf("Listen to %s\n", arguments.interface);
|
printf("Listen to %s\n", arguments.interface);
|
||||||
@@ -360,6 +455,15 @@ int main(int argc, char *argv[]){
|
|||||||
exit(-1);
|
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 */
|
||||||
@@ -397,6 +501,9 @@ int main(int argc, char *argv[]){
|
|||||||
|
|
||||||
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){
|
||||||
@@ -414,6 +521,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);
|
||||||
|
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ static void dnsanswer(struct __sk_buff *skb, struct iphdr ip, struct udphdr udp,
|
|||||||
struct dnshdr dns;
|
struct dnshdr dns;
|
||||||
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);
|
size_t tlen = ntohs(udp.len);
|
||||||
int index = 0;
|
unsigned int index = 0U;
|
||||||
|
|
||||||
if (tlen < 0 || tlen >= 256)
|
if (tlen < 0 || tlen >= 256)
|
||||||
return;
|
return;
|
||||||
@@ -297,13 +297,12 @@ static void dnsanswer(struct __sk_buff *skb, struct iphdr ip, struct udphdr udp,
|
|||||||
* otherwise, I have an issue with the eBPF verifier
|
* otherwise, I have an issue with the eBPF verifier
|
||||||
*/
|
*/
|
||||||
offset += sizeof(struct dnshdr) + query_len;
|
offset += sizeof(struct dnshdr) + query_len;
|
||||||
while (index < tlen){
|
//while (index < tlen){
|
||||||
|
for (index = 0; index < tlen || index == MAX_UDP_PAYLOAD; index++) {
|
||||||
bpf_skb_load_bytes(skb, offset + index, s_event->buf + index, 1);
|
bpf_skb_load_bytes(skb, offset + index, s_event->buf + index, 1);
|
||||||
index++;
|
// index++;
|
||||||
}
|
}
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user