From f861764dfa4841a5743b49f33df923bfe75a7f84 Mon Sep 17 00:00:00 2001 From: netblue30 Date: Fri, 8 Apr 2022 08:49:51 -0400 Subject: nettrace dns and sni --- src/fnettrace-dns/Makefile.in | 17 ++++ src/fnettrace-dns/fnettrace_dns.h | 34 ++++++++ src/fnettrace-dns/main.c | 162 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 213 insertions(+) create mode 100644 src/fnettrace-dns/Makefile.in create mode 100644 src/fnettrace-dns/fnettrace_dns.h create mode 100644 src/fnettrace-dns/main.c (limited to 'src/fnettrace-dns') diff --git a/src/fnettrace-dns/Makefile.in b/src/fnettrace-dns/Makefile.in new file mode 100644 index 000000000..6c11e5bc8 --- /dev/null +++ b/src/fnettrace-dns/Makefile.in @@ -0,0 +1,17 @@ +.PHONY: all +all: fnettrace-dns + +include ../common.mk + +%.o : %.c $(H_FILE_LIST) + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@ + +fnettrace-dns: $(OBJS) + $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(EXTRA_LDFLAGS) + +.PHONY: clean +clean:; rm -fr *.o fnettrace-dns *.gcov *.gcda *.gcno *.plist + +.PHONY: distclean +distclean: clean + rm -fr Makefile diff --git a/src/fnettrace-dns/fnettrace_dns.h b/src/fnettrace-dns/fnettrace_dns.h new file mode 100644 index 000000000..db2e1a668 --- /dev/null +++ b/src/fnettrace-dns/fnettrace_dns.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2014-2022 Firejail Authors + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef FNETTRACE_DNS_H +#define FNETTRACE_DNS_H + +#include "../include/common.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif \ No newline at end of file diff --git a/src/fnettrace-dns/main.c b/src/fnettrace-dns/main.c new file mode 100644 index 000000000..0281b5157 --- /dev/null +++ b/src/fnettrace-dns/main.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2014-2022 Firejail Authors + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "fnettrace_dns.h" +#include +#include +#include +#include +#define MAX_BUF_SIZE (64 * 1024) + +// pkt - start of DNS layer +void print_dns(uint32_t ip_src, unsigned char *pkt) { + assert(pkt); + + char ip[30]; + sprintf(ip, "%d.%d.%d.%d", PRINT_IP(ip_src)); + time_t seconds = time(NULL); + struct tm *t = localtime(&seconds); + + // expecting a single question count + if (pkt[4] != 0 || pkt[5] != 1) + goto errout; + + // check cname + unsigned char *ptr = pkt + 12; + int len = 0; + while (*ptr != 0 && len < 255) { // 255 is the maximum length of a domain name including multiple '.' + if (*ptr > 63) // the name left of a '.' is 63 length maximum + goto errout; + + int delta = *ptr + 1; + *ptr = '.'; + len += delta;; + ptr += delta; + } + + printf("%02d:%02d:%02d %15s %s\n", t->tm_hour, t->tm_min, t->tm_sec, ip, pkt + 12 + 1); + return; + +errout: + printf("%02d:%02d:%02d %15s Error: invalid DNS packet\n", t->tm_hour, t->tm_min, t->tm_sec, ip); +} + +// https://www.kernel.org/doc/html/latest/networking/filter.html +static void custom_bpf(int sock) { + struct sock_filter code[] = { + // sudo tcpdump ip and udp and src port 53 -dd + { 0x28, 0, 0, 0x0000000c }, + { 0x15, 0, 8, 0x00000800 }, + { 0x30, 0, 0, 0x00000017 }, + { 0x15, 0, 6, 0x00000011 }, + { 0x28, 0, 0, 0x00000014 }, + { 0x45, 4, 0, 0x00001fff }, + { 0xb1, 0, 0, 0x0000000e }, + { 0x48, 0, 0, 0x0000000e }, + { 0x15, 0, 1, 0x00000035 }, + { 0x6, 0, 0, 0x00040000 }, + { 0x6, 0, 0, 0x00000000 }, + }; + + struct sock_fprog bpf = { + .len = (unsigned short) sizeof(code) / sizeof(code[0]), + .filter = code, + }; + + int rv = setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf)); + if (rv < 0) { + fprintf(stderr, "Error: cannot attach BPF filter\n"); + exit(1); + } +} + +static void run_trace(void) { + // grab all Ethernet packets and use a custom BPF filter to get only UDP from source port 53 + int s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + if (s < 0) + errExit("socket"); + custom_bpf(s); + + unsigned char buf[MAX_BUF_SIZE]; + while (1) { + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(s, &rfds); + struct timeval tv; + tv.tv_sec = 1; + tv.tv_usec = 0; + int rv = select(s + 1, &rfds, NULL, NULL, &tv); + if (rv < 0) + errExit("select"); + else if (rv == 0) + continue; + unsigned bytes = recvfrom(s, buf, MAX_BUF_SIZE, 0, NULL, NULL); + + if (bytes >= (14 + 20 + 8)) { // size of MAC + IP + UDP headers + uint8_t ip_hlen = (buf[14] & 0x0f) * 4; + uint16_t port_src; + memcpy(&port_src, buf + 14 + ip_hlen, 2); + port_src = ntohs(port_src); + uint8_t protocol = buf[14 + 9]; + uint32_t ip_src; + memcpy(&ip_src, buf + 14 + 12, 4); + ip_src = ntohl(ip_src); + + // if DNS packet, extract the query + if (port_src == 53 && protocol == 0x11) // UDP protocol + print_dns(ip_src, buf + 14 + ip_hlen + 8); // IP and UDP header len + } + } + + close(s); +} + + +static void usage(void) { + printf("Usage: fnettrace-dns [OPTIONS]\n"); + printf("Options:\n"); + printf(" --help, -? - this help screen\n"); + printf("\n"); +} + +int main(int argc, char **argv) { + int i; + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-?") == 0) { + usage(); + return 0; + } + else { + fprintf(stderr, "Error: invalid argument\n"); + return 1; + } + } + + if (getuid() != 0) { + fprintf(stderr, "Error: you need to be root to run this program\n"); + return 1; + } + + time_t now = time(NULL); + printf("DNS trace for %s\n", ctime(&now)); + run_trace(); + + return 0; +} -- cgit v1.2.3-70-g09d2