From 703ece8a8c62b8e9b2cb1fe31fbac5939525b60e Mon Sep 17 00:00:00 2001 From: Gaponovoz <105719188+Gaponovoz@users.noreply.github.com> Date: Wed, 10 Aug 2022 18:50:33 +0300 Subject: [PATCH] Delete src directory --- src/Makefile | 55 -- src/blackwhitelist.c | 110 --- src/blackwhitelist.h | 2 - src/dnsredir.c | 244 ------ src/dnsredir.h | 39 - src/fakepackets.c | 197 ----- src/fakepackets.h | 18 - src/goodbyedpi-rc.rc | 2 - src/goodbyedpi.c | 1426 ----------------------------------- src/goodbyedpi.exe.manifest | 12 - src/goodbyedpi.h | 11 - src/icon.ico | Bin 11744 -> 0 bytes src/service.c | 96 --- src/service.h | 3 - src/ttltrack.c | 252 ------- src/ttltrack.h | 27 - src/utils/getline.c | 92 --- src/utils/getline.h | 7 - src/utils/repl_str.c | 90 --- src/utils/repl_str.h | 1 - src/utils/uthash.h | 1136 ---------------------------- 21 files changed, 3820 deletions(-) delete mode 100644 src/Makefile delete mode 100644 src/blackwhitelist.c delete mode 100644 src/blackwhitelist.h delete mode 100644 src/dnsredir.c delete mode 100644 src/dnsredir.h delete mode 100644 src/fakepackets.c delete mode 100644 src/fakepackets.h delete mode 100644 src/goodbyedpi-rc.rc delete mode 100644 src/goodbyedpi.c delete mode 100644 src/goodbyedpi.exe.manifest delete mode 100644 src/goodbyedpi.h delete mode 100644 src/icon.ico delete mode 100644 src/service.c delete mode 100644 src/service.h delete mode 100644 src/ttltrack.c delete mode 100644 src/ttltrack.h delete mode 100644 src/utils/getline.c delete mode 100644 src/utils/getline.h delete mode 100644 src/utils/repl_str.c delete mode 100644 src/utils/repl_str.h delete mode 100644 src/utils/uthash.h diff --git a/src/Makefile b/src/Makefile deleted file mode 100644 index d6c7829..0000000 --- a/src/Makefile +++ /dev/null @@ -1,55 +0,0 @@ -ifndef MSYSTEM - CPREFIX = x86_64-w64-mingw32- -endif - -WINDIVERTHEADERS = ../../../include -WINDIVERTLIBS = ../../binary -MINGWLIB = /usr/x86_64-w64-mingw32/lib/ - -TARGET = goodbyedpi.exe -# Linking SSP does not work for some reason, the executable doesn't start. -#LIBS = -L$(WINDIVERTLIBS) -Wl,-Bstatic -lssp -Wl,-Bdynamic -lWinDivert -lws2_32 -LIBS = -L$(WINDIVERTLIBS) -lWinDivert -lws2_32 -l:libssp.a -CC = $(CPREFIX)gcc -CCWINDRES = $(CPREFIX)windres -CFLAGS = -std=c99 -pie -fPIE -pipe -I$(WINDIVERTHEADERS) -L$(WINDIVERTLIBS) \ - -O2 -D_FORTIFY_SOURCE=2 -fstack-protector \ - -Wall -Wextra -Wpedantic -Wformat=2 -Wformat-overflow=2 -Wformat-truncation=2 \ - -Wformat-security -Wno-format-nonliteral -Wshadow -Wstrict-aliasing=1 \ - -Wnull-dereference -Warray-bounds=2 -Wimplicit-fallthrough=3 \ - -Wstringop-overflow=4 \ - -Wformat-signedness -Wstrict-overflow=2 -Wcast-align=strict \ - -Wfloat-equal -Wcast-align -Wsign-conversion \ - #-fstack-protector-strong -LDFLAGS = -fstack-protector -Wl,-O1,-pie,--dynamicbase,--nxcompat,--sort-common,--as-needed \ --Wl,--image-base,0x140000000 -Wl,--disable-auto-image-base - -ifdef BIT64 - LDFLAGS += -Wl,--high-entropy-va -Wl,--pic-executable,-e,mainCRTStartup -else - CFLAGS += -m32 - LDFLAGS += -Wl,--pic-executable,-e,_mainCRTStartup -m32 -endif - -.PHONY: default all clean - -default: $(TARGET) -all: default - -OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c utils/*.c)) goodbyedpi-rc.o -HEADERS = $(wildcard *.h utils/*.h) - -%.o: %.c $(HEADERS) - $(CC) $(CFLAGS) -c $< -o $@ - -goodbyedpi-rc.o: - $(CCWINDRES) goodbyedpi-rc.rc goodbyedpi-rc.o - -.PRECIOUS: $(TARGET) $(OBJECTS) - -$(TARGET): $(OBJECTS) - $(CC) $(OBJECTS) $(LDFLAGS) $(LIBS) -s -o $@ - -clean: - -rm -f *.o utils/*.o - -rm -f $(TARGET) diff --git a/src/blackwhitelist.c b/src/blackwhitelist.c deleted file mode 100644 index e59b59d..0000000 --- a/src/blackwhitelist.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Blacklist for GoodbyeDPI HTTP DPI circumvention tricks - * - * This is a simple domain hash table. - * Domain records are added from a text file, where every - * domain is separated with a new line. - */ -#include -#include -#include "goodbyedpi.h" -#include "utils/uthash.h" -#include "utils/getline.h" - -typedef struct blackwhitelist_record { - const char *host; - UT_hash_handle hh; /* makes this structure hashable */ -} blackwhitelist_record_t; - -static blackwhitelist_record_t *blackwhitelist = NULL; - -static int check_get_hostname(const char *host) { - blackwhitelist_record_t *tmp_record = NULL; - if (!blackwhitelist) return FALSE; - - HASH_FIND_STR(blackwhitelist, host, tmp_record); - if (tmp_record) { - debug("check_get_hostname found host\n"); - return TRUE; - } - debug("check_get_hostname host not found\n"); - return FALSE; -} - -static int add_hostname(const char *host) { - if (!host) - return FALSE; - - blackwhitelist_record_t *tmp_record = malloc(sizeof(blackwhitelist_record_t)); - char *host_c = NULL; - - if (!check_get_hostname(host)) { - host_c = strdup(host); - tmp_record->host = host_c; - HASH_ADD_KEYPTR(hh, blackwhitelist, tmp_record->host, - strlen(tmp_record->host), tmp_record); - debug("Added host %s\n", host_c); - return TRUE; - } - debug("Not added host %s\n", host); - free(tmp_record); - if (host_c) - free(host_c); - return FALSE; -} - -int blackwhitelist_load_list(const char *filename) { - char *line = malloc(HOST_MAXLEN + 1); - size_t linelen = HOST_MAXLEN + 1; - int cnt = 0; - ssize_t read; - - FILE *fp = fopen(filename, "r"); - if (!fp) return FALSE; - - while ((read = getline(&line, &linelen, fp)) != -1) { - /* works with both \n and \r\n */ - line[strcspn(line, "\r\n")] = '\0'; - if (strlen(line) > HOST_MAXLEN) { - printf("WARNING: host %s exceeds maximum host length and has not been added\n", - line); - continue; - } - if (strlen(line) < 3) { - printf("WARNING: host %s is less than 3 bytes, skipping\n", line); - continue; - } - if (add_hostname(line)) - cnt++; - } - free(line); - if (!blackwhitelist) return FALSE; - printf("Loaded %d hosts from file %s\n", cnt, filename); - fclose(fp); - return TRUE; -} - -int blackwhitelist_check_hostname(const char *host_addr, size_t host_len) { - char current_host[HOST_MAXLEN + 1]; - char *tokenized_host = NULL; - - if (host_len > HOST_MAXLEN) return FALSE; - if (host_addr && host_len) { - memcpy(current_host, host_addr, host_len); - current_host[host_len] = '\0'; - } - - if (check_get_hostname(current_host)) - return TRUE; - - tokenized_host = strchr(current_host, '.'); - while (tokenized_host != NULL && tokenized_host < (current_host + HOST_MAXLEN)) { - /* Search hostname only if there is next token */ - if (strchr(tokenized_host + 1, '.') && check_get_hostname(tokenized_host + 1)) - return TRUE; - tokenized_host = strchr(tokenized_host + 1, '.'); - } - - debug("____blackwhitelist_check_hostname FALSE: host %s\n", current_host); - return FALSE; -} diff --git a/src/blackwhitelist.h b/src/blackwhitelist.h deleted file mode 100644 index f8122a3..0000000 --- a/src/blackwhitelist.h +++ /dev/null @@ -1,2 +0,0 @@ -int blackwhitelist_load_list(const char *filename); -int blackwhitelist_check_hostname(const char *host_addr, size_t host_len); diff --git a/src/dnsredir.c b/src/dnsredir.c deleted file mode 100644 index a63e074..0000000 --- a/src/dnsredir.c +++ /dev/null @@ -1,244 +0,0 @@ -/* - * DNS UDP Connection Tracker for GoodbyeDPI - * - * This is a simple connection tracker for DNS UDP data. - * It's not a proper one. The caveats as follows: - * * Uses only source IP address and port as a hash key; - * * One-shot only. Removes conntrack record as soon as gets the reply; - * * Does not properly parse DNS request and response, only checks some bytes; - * - * But anyway, it works fine for DNS. - */ - -#include -#include -#include -#include "goodbyedpi.h" -#include "dnsredir.h" -#include "utils/uthash.h" - -/* key ('4' for IPv4 or '6' for IPv6 + srcip[16] + srcport[2]) */ -#define UDP_CONNRECORD_KEY_LEN 19 - -#define DNS_CLEANUP_INTERVAL_SEC 30 - -/* HACK! - * uthash uses strlen() for HASH_FIND_STR. - * We have null bytes in our key, so we can't use strlen() - * And since it's always UDP_CONNRECORD_KEY_LEN bytes long, - * we don't need to use any string function to determine length. - */ -#undef uthash_strlen -#define uthash_strlen(s) UDP_CONNRECORD_KEY_LEN - -typedef struct udp_connrecord { - /* key ('4' for IPv4 or '6' for IPv6 + srcip[16] + srcport[2]) */ - char key[UDP_CONNRECORD_KEY_LEN]; - time_t time; /* time when this record was added */ - uint32_t dstip[4]; - uint16_t dstport; - UT_hash_handle hh; /* makes this structure hashable */ -} udp_connrecord_t; - -static time_t last_cleanup = 0; -static udp_connrecord_t *conntrack = NULL; - -void flush_dns_cache() { - INT_PTR WINAPI (*DnsFlushResolverCache)(); - - HMODULE dnsapi = LoadLibrary("dnsapi.dll"); - if (dnsapi == NULL) - { - printf("Can't load dnsapi.dll to flush DNS cache!\n"); - exit(EXIT_FAILURE); - } - - DnsFlushResolverCache = GetProcAddress(dnsapi, "DnsFlushResolverCache"); - if (DnsFlushResolverCache == NULL || !DnsFlushResolverCache()) - printf("Can't flush DNS cache!"); - FreeLibrary(dnsapi); -} - -inline static void fill_key_data(char *key, const uint8_t is_ipv6, const uint32_t srcip[4], - const uint16_t srcport) -{ - if (is_ipv6) { - *(uint8_t*)(key) = '6'; - ipv6_copy_addr((uint32_t*)(key + sizeof(uint8_t)), srcip); - } - else { - *(uint8_t*)(key) = '4'; - ipv4_copy_addr((uint32_t*)(key + sizeof(uint8_t)), srcip); - } - - *(uint16_t*)(key + sizeof(uint8_t) + sizeof(uint32_t) * 4) = srcport; -} - -inline static void fill_data_from_key(uint8_t *is_ipv6, uint32_t srcip[4], uint16_t *srcport, - const char *key) -{ - if (key[0] == '6') { - *is_ipv6 = 1; - ipv6_copy_addr(srcip, (uint32_t*)(key + sizeof(uint8_t))); - } - else { - *is_ipv6 = 0; - ipv4_copy_addr(srcip, (uint32_t*)(key + sizeof(uint8_t))); - } - *srcport = *(uint16_t*)(key + sizeof(uint8_t) + sizeof(uint32_t) * 4); -} - -inline static void construct_key(const uint32_t srcip[4], const uint16_t srcport, - char *key, const uint8_t is_ipv6) -{ - debug("Construct key enter\n"); - if (key) { - debug("Constructing key\n"); - fill_key_data(key, is_ipv6, srcip, srcport); - } - debug("Construct key end\n"); -} - -inline static void deconstruct_key(const char *key, const udp_connrecord_t *connrecord, - conntrack_info_t *conn_info) -{ - debug("Deconstruct key enter\n"); - if (key && conn_info) { - debug("Deconstructing key\n"); - fill_data_from_key(&conn_info->is_ipv6, conn_info->srcip, - &conn_info->srcport, key); - - if (conn_info->is_ipv6) - ipv6_copy_addr(conn_info->dstip, connrecord->dstip); - else - ipv4_copy_addr(conn_info->dstip, connrecord->dstip); - - conn_info->dstport = connrecord->dstport; - } - debug("Deconstruct key end\n"); -} - -static int check_get_udp_conntrack_key(const char *key, udp_connrecord_t **connrecord) { - udp_connrecord_t *tmp_connrecord = NULL; - if (!conntrack) return FALSE; - - HASH_FIND_STR(conntrack, key, tmp_connrecord); - if (tmp_connrecord) { - if (connrecord) - *connrecord = tmp_connrecord; - debug("check_get_udp_conntrack_key found key\n"); - return TRUE; - } - debug("check_get_udp_conntrack_key key not found\n"); - return FALSE; -} - -static int add_udp_conntrack(const uint32_t srcip[4], const uint16_t srcport, - const uint32_t dstip[4], const uint16_t dstport, - const uint8_t is_ipv6 - ) -{ - if (!(srcip && srcport && dstip && dstport)) - return FALSE; - - udp_connrecord_t *tmp_connrecord = malloc(sizeof(udp_connrecord_t)); - construct_key(srcip, srcport, tmp_connrecord->key, is_ipv6); - - if (!check_get_udp_conntrack_key(tmp_connrecord->key, NULL)) { - tmp_connrecord->time = time(NULL); - - if (is_ipv6) { - ipv6_copy_addr(tmp_connrecord->dstip, dstip); - } - else { - ipv4_copy_addr(tmp_connrecord->dstip, dstip); - } - tmp_connrecord->dstport = dstport; - HASH_ADD_STR(conntrack, key, tmp_connrecord); - debug("Added UDP conntrack\n"); - return TRUE; - } - debug("Not added UDP conntrack\n"); - free(tmp_connrecord); - return FALSE; -} - -static void dns_cleanup() { - udp_connrecord_t *tmp_connrecord, *tmp_connrecord2 = NULL; - - if (last_cleanup == 0) { - last_cleanup = time(NULL); - return; - } - - if (difftime(time(NULL), last_cleanup) >= DNS_CLEANUP_INTERVAL_SEC) { - last_cleanup = time(NULL); - - HASH_ITER(hh, conntrack, tmp_connrecord, tmp_connrecord2) { - if (difftime(last_cleanup, tmp_connrecord->time) >= DNS_CLEANUP_INTERVAL_SEC) { - HASH_DEL(conntrack, tmp_connrecord); - free(tmp_connrecord); - } - } - } -} - -int dns_is_dns_packet(const char *packet_data, const UINT packet_dataLen, const int outgoing) { - if (packet_dataLen < 16) return FALSE; - - if (outgoing && (ntohs(*(const uint16_t*)(packet_data + 2)) & 0xFA00) == 0 && - (ntohs(*(const uint32_t*)(packet_data + 6))) == 0) { - return TRUE; - } - else if (!outgoing && - (ntohs(*(const uint16_t*)(packet_data + 2)) & 0xF800) == 0x8000) { - return TRUE; - } - return FALSE; -} - -int dns_handle_outgoing(const uint32_t srcip[4], const uint16_t srcport, - const uint32_t dstip[4], const uint16_t dstport, - const char *packet_data, const UINT packet_dataLen, - const uint8_t is_ipv6) -{ - if (packet_dataLen < 16) - return FALSE; - - dns_cleanup(); - - if (dns_is_dns_packet(packet_data, packet_dataLen, 1)) { - /* Looks like DNS request */ - debug("trying to add srcport = %hu, dstport = %hu\n", ntohs(srcport), ntohs(dstport)); - return add_udp_conntrack(srcip, srcport, dstip, dstport, is_ipv6); - } - debug("____dns_handle_outgoing FALSE: srcport = %hu, dstport = %hu\n", ntohs(srcport), ntohs(dstport)); - return FALSE; -} - -int dns_handle_incoming(const uint32_t srcip[4], const uint16_t srcport, - const char *packet_data, const UINT packet_dataLen, - conntrack_info_t *conn_info, const uint8_t is_ipv6) -{ - char key[UDP_CONNRECORD_KEY_LEN]; - udp_connrecord_t *tmp_connrecord = NULL; - - if (packet_dataLen < 16 || !conn_info) - return FALSE; - - dns_cleanup(); - - if (dns_is_dns_packet(packet_data, packet_dataLen, 0)) { - /* Looks like DNS response */ - construct_key(srcip, srcport, key, is_ipv6); - if (check_get_udp_conntrack_key(key, &tmp_connrecord) && tmp_connrecord) { - /* Connection exists in conntrack, moving on */ - deconstruct_key(key, tmp_connrecord, conn_info); - HASH_DEL(conntrack, tmp_connrecord); - free(tmp_connrecord); - return TRUE; - } - } - debug("____dns_handle_incoming FALSE: srcport = %hu\n", ntohs(srcport)); - return FALSE; -} diff --git a/src/dnsredir.h b/src/dnsredir.h deleted file mode 100644 index d5fed65..0000000 --- a/src/dnsredir.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _DNSREDIR_H -#define _DNSREDIR_H -#include - -typedef struct conntrack_info { - uint8_t is_ipv6; - uint32_t srcip[4]; - uint16_t srcport; - uint32_t dstip[4]; - uint16_t dstport; -} conntrack_info_t; - -inline static void ipv4_copy_addr(uint32_t dst[4], const uint32_t src[4]) { - dst[0] = src[0]; - dst[1] = 0; - dst[2] = 0; - dst[3] = 0; -} - -inline static void ipv6_copy_addr(uint32_t dst[4], const uint32_t src[4]) { - dst[0] = src[0]; - dst[1] = src[1]; - dst[2] = src[2]; - dst[3] = src[3]; -} - -int dns_handle_incoming(const uint32_t srcip[4], const uint16_t srcport, - const char *packet_data, const UINT packet_dataLen, - conntrack_info_t *conn_info, const uint8_t is_ipv6); - -int dns_handle_outgoing(const uint32_t srcip[4], const uint16_t srcport, - const uint32_t dstip[4], const uint16_t dstport, - const char *packet_data, const UINT packet_dataLen, - const uint8_t is_ipv6 - ); - -void flush_dns_cache(); -int dns_is_dns_packet(const char *packet_data, const UINT packet_dataLen, const int outgoing); -#endif diff --git a/src/fakepackets.c b/src/fakepackets.c deleted file mode 100644 index 6d59cd8..0000000 --- a/src/fakepackets.c +++ /dev/null @@ -1,197 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "windivert.h" -#include "goodbyedpi.h" - -static const unsigned char fake_http_request[] = "GET / HTTP/1.1\r\nHost: www.w3.org\r\n" - "User-Agent: curl/7.65.3\r\nAccept: */*\r\n" - "Accept-Encoding: deflate, gzip, br\r\n\r\n"; -static const unsigned char fake_https_request[] = { - 0x16, 0x03, 0x01, 0x02, 0x00, 0x01, 0x00, 0x01, 0xfc, 0x03, 0x03, 0x9a, 0x8f, 0xa7, 0x6a, 0x5d, - 0x57, 0xf3, 0x62, 0x19, 0xbe, 0x46, 0x82, 0x45, 0xe2, 0x59, 0x5c, 0xb4, 0x48, 0x31, 0x12, 0x15, - 0x14, 0x79, 0x2c, 0xaa, 0xcd, 0xea, 0xda, 0xf0, 0xe1, 0xfd, 0xbb, 0x20, 0xf4, 0x83, 0x2a, 0x94, - 0xf1, 0x48, 0x3b, 0x9d, 0xb6, 0x74, 0xba, 0x3c, 0x81, 0x63, 0xbc, 0x18, 0xcc, 0x14, 0x45, 0x57, - 0x6c, 0x80, 0xf9, 0x25, 0xcf, 0x9c, 0x86, 0x60, 0x50, 0x31, 0x2e, 0xe9, 0x00, 0x22, 0x13, 0x01, - 0x13, 0x03, 0x13, 0x02, 0xc0, 0x2b, 0xc0, 0x2f, 0xcc, 0xa9, 0xcc, 0xa8, 0xc0, 0x2c, 0xc0, 0x30, - 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x13, 0xc0, 0x14, 0x00, 0x33, 0x00, 0x39, 0x00, 0x2f, 0x00, 0x35, - 0x01, 0x00, 0x01, 0x91, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0d, 0x00, 0x00, 0x0a, 0x77, 0x77, 0x77, - 0x2e, 0x77, 0x33, 0x2e, 0x6f, 0x72, 0x67, 0x00, 0x17, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x0a, 0x00, 0x0e, 0x00, 0x0c, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0e, - 0x00, 0x0c, 0x02, 0x68, 0x32, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31, 0x00, 0x05, - 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x6b, 0x00, 0x69, 0x00, 0x1d, 0x00, - 0x20, 0xb0, 0xe4, 0xda, 0x34, 0xb4, 0x29, 0x8d, 0xd3, 0x5c, 0x70, 0xd3, 0xbe, 0xe8, 0xa7, 0x2a, - 0x6b, 0xe4, 0x11, 0x19, 0x8b, 0x18, 0x9d, 0x83, 0x9a, 0x49, 0x7c, 0x83, 0x7f, 0xa9, 0x03, 0x8c, - 0x3c, 0x00, 0x17, 0x00, 0x41, 0x04, 0x4c, 0x04, 0xa4, 0x71, 0x4c, 0x49, 0x75, 0x55, 0xd1, 0x18, - 0x1e, 0x22, 0x62, 0x19, 0x53, 0x00, 0xde, 0x74, 0x2f, 0xb3, 0xde, 0x13, 0x54, 0xe6, 0x78, 0x07, - 0x94, 0x55, 0x0e, 0xb2, 0x6c, 0xb0, 0x03, 0xee, 0x79, 0xa9, 0x96, 0x1e, 0x0e, 0x98, 0x17, 0x78, - 0x24, 0x44, 0x0c, 0x88, 0x80, 0x06, 0x8b, 0xd4, 0x80, 0xbf, 0x67, 0x7c, 0x37, 0x6a, 0x5b, 0x46, - 0x4c, 0xa7, 0x98, 0x6f, 0xb9, 0x22, 0x00, 0x2b, 0x00, 0x09, 0x08, 0x03, 0x04, 0x03, 0x03, 0x03, - 0x02, 0x03, 0x01, 0x00, 0x0d, 0x00, 0x18, 0x00, 0x16, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x08, - 0x04, 0x08, 0x05, 0x08, 0x06, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, 0x03, 0x02, 0x01, 0x00, - 0x2d, 0x00, 0x02, 0x01, 0x01, 0x00, 0x1c, 0x00, 0x02, 0x40, 0x01, 0x00, 0x15, 0x00, 0x96, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static int send_fake_data(const HANDLE w_filter, - const PWINDIVERT_ADDRESS addr, - const char *pkt, - const UINT packetLen, - const BOOL is_ipv6, - const BOOL is_https, - const BYTE set_ttl, - const BYTE set_checksum, - const BYTE set_seq - ) { - char packet_fake[MAX_PACKET_SIZE]; - WINDIVERT_ADDRESS addr_new; - PVOID packet_data; - UINT packet_dataLen; - UINT packetLen_new; - PWINDIVERT_IPHDR ppIpHdr; - PWINDIVERT_IPV6HDR ppIpV6Hdr; - PWINDIVERT_TCPHDR ppTcpHdr; - unsigned const char *fake_request_data = is_https ? fake_https_request : fake_http_request; - UINT fake_request_size = is_https ? sizeof(fake_https_request) : sizeof(fake_http_request) - 1; - - memcpy(&addr_new, addr, sizeof(WINDIVERT_ADDRESS)); - memcpy(packet_fake, pkt, packetLen); - - addr_new.TCPChecksum = 0; - addr_new.IPChecksum = 0; - - if (!is_ipv6) { - // IPv4 TCP Data packet - if (!WinDivertHelperParsePacket(packet_fake, packetLen, &ppIpHdr, - NULL, NULL, NULL, NULL, &ppTcpHdr, NULL, &packet_data, &packet_dataLen, - NULL, NULL)) - return 1; - } - else { - // IPv6 TCP Data packet - if (!WinDivertHelperParsePacket(packet_fake, packetLen, NULL, - &ppIpV6Hdr, NULL, NULL, NULL, &ppTcpHdr, NULL, &packet_data, &packet_dataLen, - NULL, NULL)) - return 1; - } - - if (packetLen + fake_request_size + 1 > MAX_PACKET_SIZE) - return 2; - - memcpy(packet_data, fake_request_data, fake_request_size); - packetLen_new = packetLen - packet_dataLen + fake_request_size; - - if (!is_ipv6) { - ppIpHdr->Length = htons( - ntohs(ppIpHdr->Length) - - packet_dataLen + fake_request_size - ); - - if (set_ttl) - ppIpHdr->TTL = set_ttl; - } - else { - ppIpV6Hdr->Length = htons( - ntohs(ppIpV6Hdr->Length) - - packet_dataLen + fake_request_size - ); - - if (set_ttl) - ppIpV6Hdr->HopLimit = set_ttl; - } - - if (set_seq) { - // This is the smallest ACK drift Linux can't handle already, since at least v2.6.18. - // https://github.com/torvalds/linux/blob/v2.6.18/net/netfilter/nf_conntrack_proto_tcp.c#L395 - ppTcpHdr->AckNum = htonl(ntohl(ppTcpHdr->AckNum) - 66000); - // This is just random, no specifics about this value. - ppTcpHdr->SeqNum = htonl(ntohl(ppTcpHdr->SeqNum) - 10000); - } - - // Recalculate the checksum - WinDivertHelperCalcChecksums(packet_fake, packetLen_new, &addr_new, 0ULL); - - if (set_checksum) { - // ...and damage it - ppTcpHdr->Checksum = htons(ntohs(ppTcpHdr->Checksum) - 1); - } - //printf("Pseudo checksum: %d\n", addr_new.TCPChecksum); - - WinDivertSend( - w_filter, packet_fake, - packetLen_new, - NULL, &addr_new - ); - debug("Fake packet: OK"); - - return 0; -} - -static int send_fake_request(const HANDLE w_filter, - const PWINDIVERT_ADDRESS addr, - const char *pkt, - const UINT packetLen, - const BOOL is_ipv6, - const BOOL is_https, - const BYTE set_ttl, - const BYTE set_checksum, - const BYTE set_seq - ) { - if (set_ttl) { - send_fake_data(w_filter, addr, pkt, packetLen, - is_ipv6, is_https, - set_ttl, FALSE, FALSE); - } - if (set_checksum) { - send_fake_data(w_filter, addr, pkt, packetLen, - is_ipv6, is_https, - FALSE, set_checksum, FALSE); - } - if (set_seq) { - send_fake_data(w_filter, addr, pkt, packetLen, - is_ipv6, is_https, - FALSE, FALSE, set_seq); - } - return 0; -} - -int send_fake_http_request(const HANDLE w_filter, - const PWINDIVERT_ADDRESS addr, - const char *pkt, - const UINT packetLen, - const BOOL is_ipv6, - const BYTE set_ttl, - const BYTE set_checksum, - const BYTE set_seq - ) { - return send_fake_request(w_filter, addr, pkt, packetLen, - is_ipv6, FALSE, - set_ttl, set_checksum, set_seq); -} - -int send_fake_https_request(const HANDLE w_filter, - const PWINDIVERT_ADDRESS addr, - const char *pkt, - const UINT packetLen, - const BOOL is_ipv6, - const BYTE set_ttl, - const BYTE set_checksum, - const BYTE set_seq - ) { - return send_fake_request(w_filter, addr, pkt, packetLen, - is_ipv6, TRUE, - set_ttl, set_checksum, set_seq); -} diff --git a/src/fakepackets.h b/src/fakepackets.h deleted file mode 100644 index 9bb44d4..0000000 --- a/src/fakepackets.h +++ /dev/null @@ -1,18 +0,0 @@ -int send_fake_http_request(const HANDLE w_filter, - const PWINDIVERT_ADDRESS addr, - const char *pkt, - const UINT packetLen, - const BOOL is_ipv6, - const BYTE set_ttl, - const BYTE set_checksum, - const BYTE set_seq - ); -int send_fake_https_request(const HANDLE w_filter, - const PWINDIVERT_ADDRESS addr, - const char *pkt, - const UINT packetLen, - const BOOL is_ipv6, - const BYTE set_ttl, - const BYTE set_checksum, - const BYTE set_seq - ); diff --git a/src/goodbyedpi-rc.rc b/src/goodbyedpi-rc.rc deleted file mode 100644 index f820576..0000000 --- a/src/goodbyedpi-rc.rc +++ /dev/null @@ -1,2 +0,0 @@ -1 24 "goodbyedpi.exe.manifest" -id ICON "icon.ico" diff --git a/src/goodbyedpi.c b/src/goodbyedpi.c deleted file mode 100644 index f80581f..0000000 --- a/src/goodbyedpi.c +++ /dev/null @@ -1,1426 +0,0 @@ -/* - * GoodbyeDPI — Passive DPI blocker and Active DPI circumvention utility. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "windivert.h" -#include "goodbyedpi.h" -#include "utils/repl_str.h" -#include "service.h" -#include "dnsredir.h" -#include "ttltrack.h" -#include "blackwhitelist.h" -#include "fakepackets.h" - -// My mingw installation does not load inet_pton definition for some reason -WINSOCK_API_LINKAGE INT WSAAPI inet_pton(INT Family, LPCSTR pStringBuf, PVOID pAddr); - -#define GOODBYEDPI_VERSION "v0.2.2" - -#define die() do { sleep(20); exit(EXIT_FAILURE); } while (0) - -#define MAX_FILTERS 4 - -#define DIVERT_NO_LOCALNETSv4_DST "(" \ - "(ip.DstAddr < 127.0.0.1 or ip.DstAddr > 127.255.255.255) and " \ - "(ip.DstAddr < 10.0.0.0 or ip.DstAddr > 10.255.255.255) and " \ - "(ip.DstAddr < 192.168.0.0 or ip.DstAddr > 192.168.255.255) and " \ - "(ip.DstAddr < 172.16.0.0 or ip.DstAddr > 172.31.255.255) and " \ - "(ip.DstAddr < 169.254.0.0 or ip.DstAddr > 169.254.255.255)" \ - ")" -#define DIVERT_NO_LOCALNETSv4_SRC "(" \ - "(ip.SrcAddr < 127.0.0.1 or ip.SrcAddr > 127.255.255.255) and " \ - "(ip.SrcAddr < 10.0.0.0 or ip.SrcAddr > 10.255.255.255) and " \ - "(ip.SrcAddr < 192.168.0.0 or ip.SrcAddr > 192.168.255.255) and " \ - "(ip.SrcAddr < 172.16.0.0 or ip.SrcAddr > 172.31.255.255) and " \ - "(ip.SrcAddr < 169.254.0.0 or ip.SrcAddr > 169.254.255.255)" \ - ")" - -#define DIVERT_NO_LOCALNETSv6_DST "(" \ - "(ipv6.DstAddr > ::1) and " \ - "(ipv6.DstAddr < 2001::0 or ipv6.DstAddr > 2001:1::0) and " \ - "(ipv6.DstAddr < fc00::0 or ipv6.DstAddr > fe00::0) and " \ - "(ipv6.DstAddr < fe80::0 or ipv6.DstAddr > fec0::0) and " \ - "(ipv6.DstAddr < ff00::0 or ipv6.DstAddr > ffff::0)" \ - ")" -#define DIVERT_NO_LOCALNETSv6_SRC "(" \ - "(ipv6.SrcAddr > ::1) and " \ - "(ipv6.SrcAddr < 2001::0 or ipv6.SrcAddr > 2001:1::0) and " \ - "(ipv6.SrcAddr < fc00::0 or ipv6.SrcAddr > fe00::0) and " \ - "(ipv6.SrcAddr < fe80::0 or ipv6.SrcAddr > fec0::0) and " \ - "(ipv6.SrcAddr < ff00::0 or ipv6.SrcAddr > ffff::0)" \ - ")" - -/* #IPID# is a template to find&replace */ -#define IPID_TEMPLATE "#IPID#" -#define MAXPAYLOADSIZE_TEMPLATE "#MAXPAYLOADSIZE#" -#define FILTER_STRING_TEMPLATE \ - "(tcp and !impostor and !loopback " MAXPAYLOADSIZE_TEMPLATE " and " \ - "((inbound and (" \ - "(" \ - "(" \ - "(ipv6 or (ip.Id >= 0x0 and ip.Id <= 0xF) " IPID_TEMPLATE \ - ") and " \ - "tcp.SrcPort == 80 and tcp.Ack" \ - ") or " \ - "((tcp.SrcPort == 80 or tcp.SrcPort == 443) and tcp.Ack and tcp.Syn)" \ - ")" \ - " and (" DIVERT_NO_LOCALNETSv4_SRC " or " DIVERT_NO_LOCALNETSv6_SRC "))) or " \ - "(outbound and " \ - "(tcp.DstPort == 80 or tcp.DstPort == 443) and tcp.Ack and " \ - "(" DIVERT_NO_LOCALNETSv4_DST " or " DIVERT_NO_LOCALNETSv6_DST "))" \ - "))" -#define FILTER_PASSIVE_STRING_TEMPLATE "inbound and ip and tcp and " \ - "!impostor and !loopback and " \ - "((ip.Id <= 0xF and ip.Id >= 0x0) " IPID_TEMPLATE ") and " \ - "(tcp.SrcPort == 443 or tcp.SrcPort == 80) and tcp.Rst and " \ - DIVERT_NO_LOCALNETSv4_SRC - -#define SET_HTTP_FRAGMENT_SIZE_OPTION(fragment_size) do { \ - if (!http_fragment_size) { \ - http_fragment_size = (unsigned int)fragment_size; \ - } \ - else if (http_fragment_size != (unsigned int)fragment_size) { \ - printf( \ - "WARNING: HTTP fragment size is already set to %u, not changing.\n", \ - http_fragment_size \ - ); \ - } \ -} while (0) - -#define TCP_HANDLE_OUTGOING_TTL_PARSE_PACKET_IF() \ - if ((packet_v4 && tcp_handle_outgoing(&ppIpHdr->SrcAddr, &ppIpHdr->DstAddr, \ - ppTcpHdr->SrcPort, ppTcpHdr->DstPort, \ - &tcp_conn_info, 0)) \ - || \ - (packet_v6 && tcp_handle_outgoing(ppIpV6Hdr->SrcAddr, ppIpV6Hdr->DstAddr, \ - ppTcpHdr->SrcPort, ppTcpHdr->DstPort, \ - &tcp_conn_info, 1))) - -#define TCP_HANDLE_OUTGOING_FAKE_PACKET(func) do { \ - should_send_fake = 1; \ - if (do_auto_ttl || ttl_min_nhops) { \ - TCP_HANDLE_OUTGOING_TTL_PARSE_PACKET_IF() { \ - if (do_auto_ttl) { \ - /* If Auto TTL mode */ \ - ttl_of_fake_packet = tcp_get_auto_ttl(tcp_conn_info.ttl, auto_ttl_1, auto_ttl_2, \ - ttl_min_nhops, auto_ttl_max); \ - if (do_tcp_verb) { \ - printf("Connection TTL = %d, Fake TTL = %d\n", tcp_conn_info.ttl, ttl_of_fake_packet); \ - } \ - } \ - else if (ttl_min_nhops) { \ - /* If not Auto TTL mode but --min-ttl is set */ \ - if (!tcp_get_auto_ttl(tcp_conn_info.ttl, 0, 0, ttl_min_nhops, 0)) { \ - /* Send only if nhops >= min_ttl */ \ - should_send_fake = 0; \ - } \ - } \ - } \ - } \ - if (should_send_fake) \ - func(w_filter, &addr, packet, packetLen, packet_v6, \ - ttl_of_fake_packet, do_wrong_chksum, do_wrong_seq); \ -} while (0) - - -static int running_from_service = 0; -static int exiting = 0; -static HANDLE filters[MAX_FILTERS]; -static int filter_num = 0; -static const char http10_redirect_302[] = "HTTP/1.0 302 "; -static const char http11_redirect_302[] = "HTTP/1.1 302 "; -static const char http_host_find[] = "\r\nHost: "; -static const char http_host_replace[] = "\r\nhoSt: "; -static const char http_useragent_find[] = "\r\nUser-Agent: "; -static const char location_http[] = "\r\nLocation: http://"; -static const char connection_close[] = "\r\nConnection: close"; -static const char *http_methods[] = { - "GET ", - "HEAD ", - "POST ", - "PUT ", - "DELETE ", - "CONNECT ", - "OPTIONS ", -}; - -static struct option long_options[] = { - {"port", required_argument, 0, 'z' }, - {"dns-addr", required_argument, 0, 'd' }, - {"dns-port", required_argument, 0, 'g' }, - {"dnsv6-addr", required_argument, 0, '!' }, - {"dnsv6-port", required_argument, 0, '@' }, - {"dns-verb", no_argument, 0, 'v' }, - {"blacklist", required_argument, 0, 'b' }, - {"allow-no-sni",no_argument, 0, ']' }, - {"ip-id", required_argument, 0, 'i' }, - {"set-ttl", required_argument, 0, '$' }, - {"min-ttl", required_argument, 0, '[' }, - {"auto-ttl", optional_argument, 0, '+' }, - {"wrong-chksum",no_argument, 0, '%' }, - {"wrong-seq", no_argument, 0, ')' }, - {"native-frag", no_argument, 0, '*' }, - {"reverse-frag",no_argument, 0, '(' }, - {"max-payload", optional_argument, 0, '|' }, - {0, 0, 0, 0 } -}; - -static char *filter_string = NULL; -static char *filter_passive_string = NULL; - -static void add_filter_str(int proto, int port) { - const char *udp = " or (udp and !impostor and !loopback and " \ - "(udp.SrcPort == %d or udp.DstPort == %d))"; - const char *tcp = " or (tcp and !impostor and !loopback " MAXPAYLOADSIZE_TEMPLATE " and " \ - "(tcp.SrcPort == %d or tcp.DstPort == %d))"; - - char *current_filter = filter_string; - size_t new_filter_size = strlen(current_filter) + - (proto == IPPROTO_UDP ? strlen(udp) : strlen(tcp)) + 16; - char *new_filter = malloc(new_filter_size); - - strcpy(new_filter, current_filter); - if (proto == IPPROTO_UDP) - sprintf(new_filter + strlen(new_filter), udp, port, port); - else - sprintf(new_filter + strlen(new_filter), tcp, port, port); - - filter_string = new_filter; - free(current_filter); -} - -static void add_ip_id_str(int id) { - char *newstr; - const char *ipid = " or ip.Id == %d"; - char *addfilter = malloc(strlen(ipid) + 16); - - sprintf(addfilter, ipid, id); - - newstr = repl_str(filter_string, IPID_TEMPLATE, addfilter); - free(filter_string); - filter_string = newstr; - - newstr = repl_str(filter_passive_string, IPID_TEMPLATE, addfilter); - free(filter_passive_string); - filter_passive_string = newstr; -} - -static void add_maxpayloadsize_str(unsigned short maxpayload) { - char *newstr; - /* 0x47455420 is "GET ", 0x504F5354 is "POST", big endian. */ - const char *maxpayloadsize_str = "and (tcp.PayloadLength ? tcp.PayloadLength < %hu or tcp.Payload32[0] == 0x47455420 or tcp.Payload32[0] == 0x504F5354 : true)"; - char *addfilter = malloc(strlen(maxpayloadsize_str) + 16); - - sprintf(addfilter, maxpayloadsize_str, maxpayload); - - newstr = repl_str(filter_string, MAXPAYLOADSIZE_TEMPLATE, addfilter); - free(filter_string); - filter_string = newstr; -} - -static void finalize_filter_strings() { - char *newstr, *newstr2; - - newstr2 = repl_str(filter_string, IPID_TEMPLATE, ""); - newstr = repl_str(newstr2, MAXPAYLOADSIZE_TEMPLATE, ""); - free(filter_string); - free(newstr2); - filter_string = newstr; - - newstr = repl_str(filter_passive_string, IPID_TEMPLATE, ""); - free(filter_passive_string); - filter_passive_string = newstr; -} - -static char* dumb_memmem(const char* haystack, unsigned int hlen, - const char* needle, unsigned int nlen) -{ - // naive implementation - if (nlen > hlen) return NULL; - size_t i; - for (i=0; i limitValue) { - puts(msg); - exit(EXIT_FAILURE); - } - return (unsigned short int)res; -} - -BYTE atoub(const char *str, const char *msg) { - long unsigned int res = strtoul(str, NULL, 10u); - enum { - limitValue=0xFFu - }; - - if(res > limitValue) { - puts(msg); - exit(EXIT_FAILURE); - } - return (BYTE)res; -} - - -static HANDLE init(char *filter, UINT64 flags) { - LPTSTR errormessage = NULL; - DWORD errorcode = 0; - filter = WinDivertOpen(filter, WINDIVERT_LAYER_NETWORK, 0, flags); - if (filter != INVALID_HANDLE_VALUE) - return filter; - errorcode = GetLastError(); - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, errorcode, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), - (LPTSTR)&errormessage, 0, NULL); - printf("Error opening filter: %s", errormessage); - LocalFree(errormessage); - if (errorcode == 577) - printf("Windows Server 2016 systems must have secure boot disabled to be " - "able to load WinDivert driver.\n" - "Windows 7 systems must be up-to-date or at least have KB3033929 installed.\n" - "https://www.microsoft.com/en-us/download/details.aspx?id=46078\n\n" - "WARNING! If you see this error on Windows 7, it means your system is horribly " - "outdated and SHOULD NOT BE USED TO ACCESS THE INTERNET!\n" - "Most probably, you don't have security patches installed and anyone in you LAN or " - "public Wi-Fi network can get full access to your computer (MS17-010 and others).\n" - "You should install updates IMMEDIATELY.\n"); - return NULL; -} - -static int deinit(HANDLE handle) { - if (handle) { - WinDivertShutdown(handle, WINDIVERT_SHUTDOWN_BOTH); - WinDivertClose(handle); - return TRUE; - } - return FALSE; -} - -void deinit_all() { - for (int i = 0; i < filter_num; i++) { - deinit(filters[i]); - } -} - -static void sigint_handler(int sig __attribute__((unused))) { - exiting = 1; - deinit_all(); - exit(EXIT_SUCCESS); -} - -static void mix_case(char *pktdata, unsigned int pktlen) { - unsigned int i; - - if (pktlen <= 0) return; - for (i = 0; i < pktlen; i++) { - if (i % 2) { - pktdata[i] = (char) toupper(pktdata[i]); - } - } -} - -static int is_passivedpi_redirect(const char *pktdata, unsigned int pktlen) { - /* First check if this is HTTP 302 redirect */ - if (memcmp(pktdata, http11_redirect_302, sizeof(http11_redirect_302)-1) == 0 || - memcmp(pktdata, http10_redirect_302, sizeof(http10_redirect_302)-1) == 0) - { - /* Then check if this is a redirect to new http site with Connection: close */ - if (dumb_memmem(pktdata, pktlen, location_http, sizeof(location_http)-1) && - dumb_memmem(pktdata, pktlen, connection_close, sizeof(connection_close)-1)) { - return TRUE; - } - } - return FALSE; -} - -static int find_header_and_get_info(const char *pktdata, unsigned int pktlen, - const char *hdrname, - char **hdrnameaddr, - char **hdrvalueaddr, unsigned int *hdrvaluelen) { - char *data_addr_rn; - char *hdr_begin; - - *hdrvaluelen = 0u; - *hdrnameaddr = NULL; - *hdrvalueaddr = NULL; - - /* Search for the header */ - hdr_begin = dumb_memmem(pktdata, pktlen, - hdrname, strlen(hdrname)); - if (!hdr_begin) return FALSE; - if (pktdata > hdr_begin) return FALSE; - - /* Set header address */ - *hdrnameaddr = hdr_begin; - *hdrvalueaddr = hdr_begin + strlen(hdrname); - - /* Search for header end (\r\n) */ - data_addr_rn = dumb_memmem(*hdrvalueaddr, - pktlen - (uintptr_t)(*hdrvalueaddr - pktdata), - "\r\n", 2); - if (data_addr_rn) { - *hdrvaluelen = (uintptr_t)(data_addr_rn - *hdrvalueaddr); - if (*hdrvaluelen >= 3 && *hdrvaluelen <= HOST_MAXLEN) - return TRUE; - } - return FALSE; -} - -/** - * Very crude Server Name Indication (TLS ClientHello hostname) extractor. - */ -static int extract_sni(const char *pktdata, unsigned int pktlen, - char **hostnameaddr, unsigned int *hostnamelen) { - unsigned int ptr = 0; - unsigned const char *d = (unsigned const char *)pktdata; - unsigned const char *hnaddr = 0; - int hnlen = 0; - - while (ptr + 8 < pktlen) { - /* Search for specific Extensions sequence */ - if (d[ptr] == '\0' && d[ptr+1] == '\0' && d[ptr+2] == '\0' && - d[ptr+4] == '\0' && d[ptr+6] == '\0' && d[ptr+7] == '\0' && - /* Check Extension length, Server Name list length - * and Server Name length relations - */ - d[ptr+3] - d[ptr+5] == 2 && d[ptr+5] - d[ptr+8] == 3) - { - if (ptr + 8 + d[ptr+8] > pktlen) { - return FALSE; - } - hnaddr = &d[ptr+9]; - hnlen = d[ptr+8]; - /* Limit hostname size up to 253 bytes */ - if (hnlen < 3 || hnlen > HOST_MAXLEN) { - return FALSE; - } - /* Validate that hostname has only ascii lowercase characters */ - for (int i=0; i= '0' && hnaddr[i] <= '9') || - (hnaddr[i] >= 'a' && hnaddr[i] <= 'z') || - hnaddr[i] == '.' || hnaddr[i] == '-')) - { - return FALSE; - } - } - *hostnameaddr = (char*)hnaddr; - *hostnamelen = (unsigned int)hnlen; - return TRUE; - } - ptr++; - } - return FALSE; -} - -static inline void change_window_size(const PWINDIVERT_TCPHDR ppTcpHdr, unsigned int size) { - if (size >= 1 && size <= 0xFFFFu) { - ppTcpHdr->Window = htons((u_short)size); - } -} - -/* HTTP method end without trailing space */ -static PVOID find_http_method_end(const char *pkt, unsigned int http_frag, int *is_fragmented) { - unsigned int i; - for (i = 0; i<(sizeof(http_methods) / sizeof(*http_methods)); i++) { - if (memcmp(pkt, http_methods[i], strlen(http_methods[i])) == 0) { - if (is_fragmented) - *is_fragmented = 0; - return (char*)pkt + strlen(http_methods[i]) - 1; - } - /* Try to find HTTP method in a second part of fragmented packet */ - if ((http_frag == 1 || http_frag == 2) && - memcmp(pkt, http_methods[i] + http_frag, - strlen(http_methods[i]) - http_frag) == 0 - ) - { - if (is_fragmented) - *is_fragmented = 1; - return (char*)pkt + strlen(http_methods[i]) - http_frag - 1; - } - } - return NULL; -} - -/** Fragment and send the packet. - * - * This function cuts off the end of the packet (step=0) or - * the beginning of the packet (step=1) with fragment_size bytes. - */ -static void send_native_fragment(HANDLE w_filter, WINDIVERT_ADDRESS addr, - char *packet, UINT packetLen, PVOID packet_data, - UINT packet_dataLen, int packet_v4, int packet_v6, - PWINDIVERT_IPHDR ppIpHdr, PWINDIVERT_IPV6HDR ppIpV6Hdr, - PWINDIVERT_TCPHDR ppTcpHdr, - unsigned int fragment_size, int step) { - char packet_bak[MAX_PACKET_SIZE]; - memcpy(packet_bak, packet, packetLen); - UINT orig_packetLen = packetLen; - - if (fragment_size >= packet_dataLen) { - if (step == 1) - fragment_size = 0; - else - return; - } - - if (step == 0) { - if (packet_v4) - ppIpHdr->Length = htons( - ntohs(ppIpHdr->Length) - - packet_dataLen + fragment_size - ); - else if (packet_v6) - ppIpV6Hdr->Length = htons( - ntohs(ppIpV6Hdr->Length) - - packet_dataLen + fragment_size - ); - //printf("step0 (%d:%d), pp:%d, was:%d, now:%d\n", - // packet_v4, packet_v6, ntohs(ppIpHdr->Length), - // packetLen, packetLen - packet_dataLen + fragment_size); - packetLen = packetLen - packet_dataLen + fragment_size; - } - - else if (step == 1) { - if (packet_v4) - ppIpHdr->Length = htons( - ntohs(ppIpHdr->Length) - fragment_size - ); - else if (packet_v6) - ppIpV6Hdr->Length = htons( - ntohs(ppIpV6Hdr->Length) - fragment_size - ); - //printf("step1 (%d:%d), pp:%d, was:%d, now:%d\n", packet_v4, packet_v6, ntohs(ppIpHdr->Length), - // packetLen, packetLen - fragment_size); - memmove(packet_data, - (char*)packet_data + fragment_size, - packet_dataLen - fragment_size); - packetLen -= fragment_size; - - ppTcpHdr->SeqNum = htonl(ntohl(ppTcpHdr->SeqNum) + fragment_size); - } - - addr.IPChecksum = 0; - addr.TCPChecksum = 0; - - WinDivertHelperCalcChecksums( - packet, packetLen, &addr, 0 - ); - WinDivertSend( - w_filter, packet, - packetLen, - NULL, &addr - ); - memcpy(packet, packet_bak, orig_packetLen); - //printf("Sent native fragment of %d size (step%d)\n", packetLen, step); -} - -int main(int argc, char *argv[]) { - static enum packet_type_e { - unknown, - ipv4_tcp, ipv4_tcp_data, ipv4_udp_data, - ipv6_tcp, ipv6_tcp_data, ipv6_udp_data - } packet_type; - int i, should_reinject, should_recalc_checksum = 0; - int sni_ok = 0; - int opt; - int packet_v4, packet_v6; - HANDLE w_filter = NULL; - WINDIVERT_ADDRESS addr; - char packet[MAX_PACKET_SIZE]; - PVOID packet_data; - UINT packetLen; - UINT packet_dataLen; - PWINDIVERT_IPHDR ppIpHdr; - PWINDIVERT_IPV6HDR ppIpV6Hdr; - PWINDIVERT_TCPHDR ppTcpHdr; - PWINDIVERT_UDPHDR ppUdpHdr; - conntrack_info_t dns_conn_info; - tcp_conntrack_info_t tcp_conn_info; - - int do_passivedpi = 0, do_fragment_http = 0, - do_fragment_http_persistent = 0, - do_fragment_http_persistent_nowait = 0, - do_fragment_https = 0, do_host = 0, - do_host_removespace = 0, do_additional_space = 0, - do_http_allports = 0, - do_host_mixedcase = 0, - do_dnsv4_redirect = 0, do_dnsv6_redirect = 0, - do_dns_verb = 0, do_tcp_verb = 0, do_blacklist = 0, - do_allow_no_sni = 0, - do_fake_packet = 0, - do_auto_ttl = 0, - do_wrong_chksum = 0, - do_wrong_seq = 0, - do_native_frag = 0, do_reverse_frag = 0; - unsigned int http_fragment_size = 0; - unsigned int https_fragment_size = 0; - unsigned int current_fragment_size = 0; - unsigned short max_payload_size = 0; - BYTE should_send_fake = 0; - BYTE ttl_of_fake_packet = 0; - BYTE ttl_min_nhops = 0; - BYTE auto_ttl_1 = 0; - BYTE auto_ttl_2 = 0; - BYTE auto_ttl_max = 0; - uint32_t dnsv4_addr = 0; - struct in6_addr dnsv6_addr = {0}; - struct in6_addr dns_temp_addr = {0}; - uint16_t dnsv4_port = htons(53); - uint16_t dnsv6_port = htons(53); - char *host_addr, *useragent_addr, *method_addr; - unsigned int host_len, useragent_len; - int http_req_fragmented; - - char *hdr_name_addr = NULL, *hdr_value_addr = NULL; - unsigned int hdr_value_len; - - // Make sure to search DLLs only in safe path, not in current working dir. - SetDllDirectory(""); - SetSearchPathMode(BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE | BASE_SEARCH_PATH_PERMANENT); - - if (!running_from_service) { - running_from_service = 1; - if (service_register(argc, argv)) { - /* We've been called as a service. Register service - * and exit this thread. main() would be called from - * service.c next time. - * - * Note that if service_register() succeedes it does - * not return until the service is stopped. - * That is why we should set running_from_service - * before calling service_register and unset it - * afterwards. - */ - return 0; - } - running_from_service = 0; - } - - if (filter_string == NULL) - filter_string = strdup(FILTER_STRING_TEMPLATE); - if (filter_passive_string == NULL) - filter_passive_string = strdup(FILTER_PASSIVE_STRING_TEMPLATE); - - printf( - "GoodbyeDPI " GOODBYEDPI_VERSION - ": Passive DPI blocker and Active DPI circumvention utility\n" - "https://github.com/ValdikSS/GoodbyeDPI\n\n" - ); - - if (argc == 1) { - /* enable mode -5 by default */ - do_fragment_http = do_fragment_https = 1; - do_reverse_frag = do_native_frag = 1; - http_fragment_size = https_fragment_size = 2; - do_fragment_http_persistent = do_fragment_http_persistent_nowait = 1; - do_fake_packet = 1; - do_auto_ttl = 1; - max_payload_size = 1200; - } - - while ((opt = getopt_long(argc, argv, "123456prsaf:e:mwk:n", long_options, NULL)) != -1) { - switch (opt) { - case '1': - do_passivedpi = do_host = do_host_removespace \ - = do_fragment_http = do_fragment_https \ - = do_fragment_http_persistent \ - = do_fragment_http_persistent_nowait = 1; - break; - case '2': - do_passivedpi = do_host = do_host_removespace \ - = do_fragment_http = do_fragment_https \ - = do_fragment_http_persistent \ - = do_fragment_http_persistent_nowait = 1; - https_fragment_size = 40u; - break; - case '3': - do_passivedpi = do_host = do_host_removespace \ - = do_fragment_https = 1; - https_fragment_size = 40u; - break; - case '4': - do_passivedpi = do_host = do_host_removespace = 1; - break; - case '5': - do_fragment_http = do_fragment_https = 1; - do_reverse_frag = do_native_frag = 1; - http_fragment_size = https_fragment_size = 2; - do_fragment_http_persistent = do_fragment_http_persistent_nowait = 1; - do_fake_packet = 1; - do_auto_ttl = 1; - max_payload_size = 1200; - break; - case '6': - do_fragment_http = do_fragment_https = 1; - do_reverse_frag = do_native_frag = 1; - http_fragment_size = https_fragment_size = 2; - do_fragment_http_persistent = do_fragment_http_persistent_nowait = 1; - do_fake_packet = 1; - do_wrong_seq = 1; - max_payload_size = 1200; - break; - case 'p': - do_passivedpi = 1; - break; - case 'r': - do_host = 1; - break; - case 's': - do_host_removespace = 1; - break; - case 'a': - do_additional_space = 1; - do_host_removespace = 1; - break; - case 'm': - do_host_mixedcase = 1; - break; - case 'f': - do_fragment_http = 1; - SET_HTTP_FRAGMENT_SIZE_OPTION(atousi(optarg, "Fragment size should be in range [0 - 0xFFFF]\n")); - break; - case 'k': - do_fragment_http_persistent = 1; - do_native_frag = 1; - SET_HTTP_FRAGMENT_SIZE_OPTION(atousi(optarg, "Fragment size should be in range [0 - 0xFFFF]\n")); - break; - case 'n': - do_fragment_http_persistent = 1; - do_fragment_http_persistent_nowait = 1; - do_native_frag = 1; - break; - case 'e': - do_fragment_https = 1; - https_fragment_size = atousi(optarg, "Fragment size should be in range [0 - 65535]\n"); - break; - case 'w': - do_http_allports = 1; - break; - case 'z': // --port - /* i is used as a temporary variable here */ - i = atoi(optarg); - if (i <= 0 || i > 65535) { - printf("Port parameter error!\n"); - exit(EXIT_FAILURE); - } - if (i != 80 && i != 443) - add_filter_str(IPPROTO_TCP, i); - i = 0; - break; - case 'i': // --ip-id - /* i is used as a temporary variable here */ - i = atousi(optarg, "IP ID parameter error!\n"); - add_ip_id_str(i); - i = 0; - break; - case 'd': // --dns-addr - if ((inet_pton(AF_INET, optarg, dns_temp_addr.s6_addr) == 1) && - !do_dnsv4_redirect) - { - do_dnsv4_redirect = 1; - if (inet_pton(AF_INET, optarg, &dnsv4_addr) != 1) { - puts("DNS address parameter error!"); - exit(EXIT_FAILURE); - } - add_filter_str(IPPROTO_UDP, 53); - flush_dns_cache(); - break; - } - puts("DNS address parameter error!"); - exit(EXIT_FAILURE); - break; - case '!': // --dnsv6-addr - if ((inet_pton(AF_INET6, optarg, dns_temp_addr.s6_addr) == 1) && - !do_dnsv6_redirect) - { - do_dnsv6_redirect = 1; - if (inet_pton(AF_INET6, optarg, dnsv6_addr.s6_addr) != 1) { - puts("DNS address parameter error!"); - exit(EXIT_FAILURE); - } - add_filter_str(IPPROTO_UDP, 53); - flush_dns_cache(); - break; - } - puts("DNS address parameter error!"); - exit(EXIT_FAILURE); - break; - case 'g': // --dns-port - if (!do_dnsv4_redirect) { - puts("--dns-port should be used with --dns-addr!\n" - "Make sure you use --dns-addr and pass it before " - "--dns-port"); - exit(EXIT_FAILURE); - } - dnsv4_port = atousi(optarg, "DNS port parameter error!"); - if (dnsv4_port != 53) { - add_filter_str(IPPROTO_UDP, dnsv4_port); - } - dnsv4_port = htons(dnsv4_port); - break; - case '@': // --dnsv6-port - if (!do_dnsv6_redirect) { - puts("--dnsv6-port should be used with --dnsv6-addr!\n" - "Make sure you use --dnsv6-addr and pass it before " - "--dnsv6-port"); - exit(EXIT_FAILURE); - } - dnsv6_port = atousi(optarg, "DNS port parameter error!"); - if (dnsv6_port != 53) { - add_filter_str(IPPROTO_UDP, dnsv6_port); - } - dnsv6_port = htons(dnsv6_port); - break; - case 'v': - do_dns_verb = 1; - do_tcp_verb = 1; - break; - case 'b': // --blacklist - do_blacklist = 1; - if (!blackwhitelist_load_list(optarg)) { - printf("Can't load blacklist from file!\n"); - exit(EXIT_FAILURE); - } - break; - case ']': // --allow-no-sni - do_allow_no_sni = 1; - break; - case '$': // --set-ttl - do_auto_ttl = auto_ttl_1 = auto_ttl_2 = auto_ttl_max = 0; - do_fake_packet = 1; - ttl_of_fake_packet = atoub(optarg, "Set TTL parameter error!"); - break; - case '[': // --min-ttl - do_fake_packet = 1; - ttl_min_nhops = atoub(optarg, "Set Minimum TTL number of hops parameter error!"); - break; - case '+': // --auto-ttl - do_fake_packet = 1; - do_auto_ttl = 1; - - if (!optarg && argv[optind] && argv[optind][0] != '-') - optarg = argv[optind]; - - if (optarg) { - char *autottl_copy = strdup(optarg); - if (strchr(autottl_copy, '-')) { - // token "-" found, start X-Y parser - char *autottl_current = strtok(autottl_copy, "-"); - auto_ttl_1 = atoub(autottl_current, "Set Auto TTL parameter error!"); - autottl_current = strtok(NULL, "-"); - if (!autottl_current) { - puts("Set Auto TTL parameter error!"); - exit(EXIT_FAILURE); - } - auto_ttl_2 = atoub(autottl_current, "Set Auto TTL parameter error!"); - autottl_current = strtok(NULL, "-"); - if (!autottl_current) { - puts("Set Auto TTL parameter error!"); - exit(EXIT_FAILURE); - } - auto_ttl_max = atoub(autottl_current, "Set Auto TTL parameter error!"); - } - else { - // single digit parser - auto_ttl_2 = atoub(optarg, "Set Auto TTL parameter error!"); - auto_ttl_1 = auto_ttl_2; - } - free(autottl_copy); - } - break; - case '%': // --wrong-chksum - do_fake_packet = 1; - do_wrong_chksum = 1; - break; - case ')': // --wrong-seq - do_fake_packet = 1; - do_wrong_seq = 1; - break; - case '*': // --native-frag - do_native_frag = 1; - do_fragment_http_persistent = 1; - do_fragment_http_persistent_nowait = 1; - break; - case '(': // --reverse-frag - do_reverse_frag = 1; - do_native_frag = 1; - do_fragment_http_persistent = 1; - do_fragment_http_persistent_nowait = 1; - break; - case '|': // --max-payload - if (!optarg && argv[optind] && argv[optind][0] != '-') - optarg = argv[optind]; - if (optarg) - max_payload_size = atousi(optarg, "Max payload size parameter error!"); - else - max_payload_size = 1200; - break; - default: - puts("Usage: goodbyedpi.exe [OPTION...]\n" - " -p block passive DPI\n" - " -r replace Host with hoSt\n" - " -s remove space between host header and its value\n" - " -a additional space between Method and Request-URI (enables -s, may break sites)\n" - " -m mix Host header case (test.com -> tEsT.cOm)\n" - " -f set HTTP fragmentation to value\n" - " -k enable HTTP persistent (keep-alive) fragmentation and set it to value\n" - " -n do not wait for first segment ACK when -k is enabled\n" - " -e set HTTPS fragmentation to value\n" - " -w try to find and parse HTTP traffic on all processed ports (not only on port 80)\n" - " --port additional TCP port to perform fragmentation on (and HTTP tricks with -w)\n" - " --ip-id handle additional IP ID (decimal, drop redirects and TCP RSTs with this ID).\n" - " --dns-addr redirect UDPv4 DNS requests to the supplied IPv4 address (experimental)\n" - " --dns-port redirect UDPv4 DNS requests to the supplied port (53 by default)\n" - " --dnsv6-addr redirect UDPv6 DNS requests to the supplied IPv6 address (experimental)\n" - " --dnsv6-port redirect UDPv6 DNS requests to the supplied port (53 by default)\n" - " --dns-verb print verbose DNS redirection messages\n" - " --blacklist perform circumvention tricks only to host names and subdomains from\n" - " supplied text file (HTTP Host/TLS SNI).\n" - " This option can be supplied multiple times.\n" - " --allow-no-sni perform circumvention if TLS SNI can't be detected with --blacklist enabled.\n" - " --set-ttl activate Fake Request Mode and send it with supplied TTL value.\n" - " DANGEROUS! May break websites in unexpected ways. Use with care (or --blacklist).\n" - " --auto-ttl [a1-a2-m] activate Fake Request Mode, automatically detect TTL and decrease\n" - " it based on a distance. If the distance is shorter than a2, TTL is decreased\n" - " by a2. If it's longer, (a1; a2) scale is used with the distance as a weight.\n" - " If the resulting TTL is more than m(ax), set it to m.\n" - " Default (if set): --auto-ttl 1-4-10. Also sets --min-ttl 3.\n" - " DANGEROUS! May break websites in unexpected ways. Use with care (or --blacklist).\n" - " --min-ttl minimum TTL distance (128/64 - TTL) for which to send Fake Request\n" - " in --set-ttl and --auto-ttl modes.\n" - " --wrong-chksum activate Fake Request Mode and send it with incorrect TCP checksum.\n" - " May not work in a VM or with some routers, but is safer than set-ttl.\n" - " Could be combined with --set-ttl\n" - " --wrong-seq activate Fake Request Mode and send it with TCP SEQ/ACK in the past.\n" - " --native-frag fragment (split) the packets by sending them in smaller packets, without\n" - " shrinking the Window Size. Works faster (does not slow down the connection)\n" - " and better.\n" - " --reverse-frag fragment (split) the packets just as --native-frag, but send them in the\n" - " reversed order. Works with the websites which could not handle segmented\n" - " HTTPS TLS ClientHello (because they receive the TCP flow \"combined\").\n" - " --max-payload [value] packets with TCP payload data more than [value] won't be processed.\n" - " Use this option to reduce CPU usage by skipping huge amount of data\n" - " (like file transfers) in already established sessions.\n" - " May skip some huge HTTP requests from being processed.\n" - " Default (if set): --max-payload 1200.\n" - "\n"); - puts("LEGACY modesets:\n" - " -1 -p -r -s -f 2 -k 2 -n -e 2 (most compatible mode)\n" - " -2 -p -r -s -f 2 -k 2 -n -e 40 (better speed for HTTPS yet still compatible)\n" - " -3 -p -r -s -e 40 (better speed for HTTP and HTTPS)\n" - " -4 -p -r -s (best speed)" - "\n" - "Modern modesets (more stable, more compatible, faster):\n" - " -5 -f 2 -e 2 --auto-ttl --reverse-frag --max-payload (this is the default)\n" - " -6 -f 2 -e 2 --wrong-seq --reverse-frag --max-payload\n"); - exit(EXIT_FAILURE); - } - } - - if (!http_fragment_size) - http_fragment_size = 2; - if (!https_fragment_size) - https_fragment_size = 2; - if (!auto_ttl_1) - auto_ttl_1 = 1; - if (!auto_ttl_2) - auto_ttl_2 = 4; - if (do_auto_ttl) { - if (!ttl_min_nhops) - ttl_min_nhops = 3; - if (!auto_ttl_max) - auto_ttl_max = 10; - } - - printf("Block passive: %d\n" /* 1 */ - "Fragment HTTP: %u\n" /* 2 */ - "Fragment persistent HTTP: %u\n" /* 3 */ - "Fragment HTTPS: %u\n" /* 4 */ - "Native fragmentation (splitting): %d\n" /* 5 */ - "Fragments sending in reverse: %d\n" /* 6 */ - "hoSt: %d\n" /* 7 */ - "Host no space: %d\n" /* 8 */ - "Additional space: %d\n" /* 9 */ - "Mix Host: %d\n" /* 10 */ - "HTTP AllPorts: %d\n" /* 11 */ - "HTTP Persistent Nowait: %d\n" /* 12 */ - "DNS redirect: %d\n" /* 13 */ - "DNSv6 redirect: %d\n" /* 14 */ - "Allow missing SNI: %d\n" /* 15 */ - "Fake requests, TTL: %s (fixed: %hu, auto: %hu-%hu-%hu, min distance: %hu)\n" /* 16 */ - "Fake requests, wrong checksum: %d\n" /* 17 */ - "Fake requests, wrong SEQ/ACK: %d\n" /* 18 */ - "Max payload size: %hu\n", /* 19 */ - do_passivedpi, /* 1 */ - (do_fragment_http ? http_fragment_size : 0), /* 2 */ - (do_fragment_http_persistent ? http_fragment_size : 0),/* 3 */ - (do_fragment_https ? https_fragment_size : 0), /* 4 */ - do_native_frag, /* 5 */ - do_reverse_frag, /* 6 */ - do_host, /* 7 */ - do_host_removespace, /* 8 */ - do_additional_space, /* 9 */ - do_host_mixedcase, /* 10 */ - do_http_allports, /* 11 */ - do_fragment_http_persistent_nowait, /* 12 */ - do_dnsv4_redirect, /* 13 */ - do_dnsv6_redirect, /* 14 */ - do_allow_no_sni, /* 15 */ - do_auto_ttl ? "auto" : (do_fake_packet ? "fixed" : "disabled"), /* 16 */ - ttl_of_fake_packet, do_auto_ttl ? auto_ttl_1 : 0, do_auto_ttl ? auto_ttl_2 : 0, - do_auto_ttl ? auto_ttl_max : 0, ttl_min_nhops, - do_wrong_chksum, /* 17 */ - do_wrong_seq, /* 18 */ - max_payload_size /* 19 */ - ); - - if (do_fragment_http && http_fragment_size > 2 && !do_native_frag) { - puts("\nWARNING: HTTP fragmentation values > 2 are not fully compatible " - "with other options. Please use values <= 2 or disable HTTP fragmentation " - "completely."); - } - - if (do_native_frag && !(do_fragment_http || do_fragment_https)) { - puts("\nERROR: Native fragmentation is enabled but fragment sizes are not set.\n" - "Fragmentation has no effect."); - die(); - } - - if (max_payload_size) - add_maxpayloadsize_str(max_payload_size); - finalize_filter_strings(); - puts("\nOpening filter"); - filter_num = 0; - - if (do_passivedpi) { - /* IPv4 only filter for inbound RST packets with ID [0x0; 0xF] */ - filters[filter_num] = init( - filter_passive_string, - WINDIVERT_FLAG_DROP); - if (filters[filter_num] == NULL) - die(); - filter_num++; - } - - /* - * IPv4 & IPv6 filter for inbound HTTP redirection packets and - * active DPI circumvention - */ - filters[filter_num] = init(filter_string, 0); - - w_filter = filters[filter_num]; - filter_num++; - - for (i = 0; i < filter_num; i++) { - if (filters[i] == NULL) - die(); - } - - printf("Filter activated, GoodbyeDPI is now running!\n"); - signal(SIGINT, sigint_handler); - - while (1) { - if (WinDivertRecv(w_filter, packet, sizeof(packet), &packetLen, &addr)) { - debug("Got %s packet, len=%d!\n", addr.Outbound ? "outbound" : "inbound", - packetLen); - should_reinject = 1; - should_recalc_checksum = 0; - - ppIpHdr = (PWINDIVERT_IPHDR)NULL; - ppIpV6Hdr = (PWINDIVERT_IPV6HDR)NULL; - ppTcpHdr = (PWINDIVERT_TCPHDR)NULL; - ppUdpHdr = (PWINDIVERT_UDPHDR)NULL; - packet_v4 = packet_v6 = 0; - packet_type = unknown; - - // Parse network packet and set it's type - if (WinDivertHelperParsePacket(packet, packetLen, &ppIpHdr, - &ppIpV6Hdr, NULL, NULL, NULL, &ppTcpHdr, &ppUdpHdr, &packet_data, &packet_dataLen, - NULL, NULL)) - { - if (ppIpHdr) { - packet_v4 = 1; - if (ppTcpHdr) { - packet_type = ipv4_tcp; - if (packet_data) { - packet_type = ipv4_tcp_data; - } - } - else if (ppUdpHdr && packet_data) { - packet_type = ipv4_udp_data; - } - } - - else if (ppIpV6Hdr) { - packet_v6 = 1; - if (ppTcpHdr) { - packet_type = ipv6_tcp; - if (packet_data) { - packet_type = ipv6_tcp_data; - } - } - else if (ppUdpHdr && packet_data) { - packet_type = ipv6_udp_data; - } - } - } - - debug("packet_type: %d, packet_v4: %d, packet_v6: %d\n", packet_type, packet_v4, packet_v6); - - if (packet_type == ipv4_tcp_data || packet_type == ipv6_tcp_data) { - //printf("Got parsed packet, len=%d!\n", packet_dataLen); - /* Got a TCP packet WITH DATA */ - - /* Handle INBOUND packet with data and find HTTP REDIRECT in there */ - if (!addr.Outbound && packet_dataLen > 16) { - /* If INBOUND packet with DATA (tcp.Ack) */ - - /* Drop packets from filter with HTTP 30x Redirect */ - if (do_passivedpi && is_passivedpi_redirect(packet_data, packet_dataLen)) { - if (packet_v4) { - //printf("Dropping HTTP Redirect packet!\n"); - should_reinject = 0; - } - else if (packet_v6 && WINDIVERT_IPV6HDR_GET_FLOWLABEL(ppIpV6Hdr) == 0x0) { - /* Contrary to IPv4 where we get only packets with IP ID 0x0-0xF, - * for IPv6 we got all the incoming data packets since we can't - * filter them in a driver. - * - * Handle only IPv6 Flow Label == 0x0 for now - */ - //printf("Dropping HTTP Redirect packet!\n"); - should_reinject = 0; - } - } - } - /* Handle OUTBOUND packet on port 443, search for something that resembles - * TLS handshake, send fake request. - */ - else if (addr.Outbound && - ((do_fragment_https ? packet_dataLen == https_fragment_size : 0) || - packet_dataLen > 16) && - ppTcpHdr->DstPort != htons(80) && - (do_fake_packet || do_native_frag) - ) - { - /** - * In case of Window Size fragmentation=2, we'll receive only 2 byte packet. - * But if the packet is more than 2 bytes, check ClientHello byte. - */ - if ((packet_dataLen == 2 && memcmp(packet_data, "\x16\x03", 2) == 0) || - (packet_dataLen >= 3 && memcmp(packet_data, "\x16\x03\x01", 3) == 0)) - { - if (do_blacklist) { - sni_ok = extract_sni(packet_data, packet_dataLen, - &host_addr, &host_len); - } - if ( - (do_blacklist && sni_ok && - blackwhitelist_check_hostname(host_addr, host_len) - ) || - (do_blacklist && !sni_ok && do_allow_no_sni) || - (!do_blacklist) - ) - { -#ifdef DEBUG - char lsni[HOST_MAXLEN + 1] = {0}; - extract_sni(packet_data, packet_dataLen, - &host_addr, &host_len); - memcpy(lsni, host_addr, host_len); - printf("Blocked HTTPS website SNI: %s\n", lsni); -#endif - if (do_fake_packet) { - TCP_HANDLE_OUTGOING_FAKE_PACKET(send_fake_https_request); - } - if (do_native_frag) { - // Signal for native fragmentation code handler - should_recalc_checksum = 1; - } - } - } - } - /* Handle OUTBOUND packet on port 80, search for Host header */ - else if (addr.Outbound && - packet_dataLen > 16 && - (do_http_allports ? 1 : (ppTcpHdr->DstPort == htons(80))) && - find_http_method_end(packet_data, - (do_fragment_http ? http_fragment_size : 0u), - &http_req_fragmented) && - (do_host || do_host_removespace || - do_host_mixedcase || do_fragment_http_persistent || - do_fake_packet)) - { - - /* Find Host header */ - if (find_header_and_get_info(packet_data, packet_dataLen, - http_host_find, &hdr_name_addr, &hdr_value_addr, &hdr_value_len) && - hdr_value_len > 0 && hdr_value_len <= HOST_MAXLEN && - (do_blacklist ? blackwhitelist_check_hostname(hdr_value_addr, hdr_value_len) : 1)) - { - host_addr = hdr_value_addr; - host_len = hdr_value_len; -#ifdef DEBUG - char lhost[HOST_MAXLEN + 1] = {0}; - memcpy(lhost, host_addr, host_len); - printf("Blocked HTTP website Host: %s\n", lhost); -#endif - - if (do_native_frag) { - // Signal for native fragmentation code handler - should_recalc_checksum = 1; - } - - if (do_fake_packet) { - TCP_HANDLE_OUTGOING_FAKE_PACKET(send_fake_http_request); - } - - if (do_host_mixedcase) { - mix_case(host_addr, host_len); - should_recalc_checksum = 1; - } - - if (do_host) { - /* Replace "Host: " with "hoSt: " */ - memcpy(hdr_name_addr, http_host_replace, strlen(http_host_replace)); - should_recalc_checksum = 1; - //printf("Replaced Host header!\n"); - } - - /* If removing space between host header and its value - * and adding additional space between Method and Request-URI */ - if (do_additional_space && do_host_removespace) { - /* End of "Host:" without trailing space */ - method_addr = find_http_method_end(packet_data, - (do_fragment_http ? http_fragment_size : 0), - NULL); - - if (method_addr) { - memmove(method_addr + 1, method_addr, - (size_t)(host_addr - method_addr - 1)); - should_recalc_checksum = 1; - } - } - /* If just removing space between host header and its value */ - else if (do_host_removespace) { - if (find_header_and_get_info(packet_data, packet_dataLen, - http_useragent_find, &hdr_name_addr, - &hdr_value_addr, &hdr_value_len)) - { - useragent_addr = hdr_value_addr; - useragent_len = hdr_value_len; - - /* We move Host header value by one byte to the left and then - * "insert" stolen space to the end of User-Agent value because - * some web servers are not tolerant to additional space in the - * end of Host header. - * - * Nothing is done if User-Agent header is missing. - */ - if (useragent_addr && useragent_len > 0) { - /* useragent_addr is in the beginning of User-Agent value */ - - if (useragent_addr > host_addr) { - /* Move one byte to the LEFT from "Host:" - * to the end of User-Agent - */ - memmove(host_addr - 1, host_addr, - (size_t)(useragent_addr + useragent_len - host_addr)); - host_addr -= 1; - /* Put space in the end of User-Agent header */ - *(char*)((unsigned char*)useragent_addr + useragent_len - 1) = ' '; - should_recalc_checksum = 1; - //printf("Replaced Host header!\n"); - } - else { - /* User-Agent goes BEFORE Host header */ - - /* Move one byte to the RIGHT from the end of User-Agent - * to the "Host:" - */ - memmove(useragent_addr + useragent_len + 1, - useragent_addr + useragent_len, - (size_t)(host_addr - 1 - (useragent_addr + useragent_len))); - /* Put space in the end of User-Agent header */ - *(char*)((unsigned char*)useragent_addr + useragent_len) = ' '; - should_recalc_checksum = 1; - //printf("Replaced Host header!\n"); - } - } /* if (host_len <= HOST_MAXLEN && useragent_addr) */ - } /* if (find_header_and_get_info http_useragent) */ - } /* else if (do_host_removespace) */ - } /* if (find_header_and_get_info http_host) */ - } /* Handle OUTBOUND packet with data */ - - /* - * should_recalc_checksum mean we have detected a packet to handle and - * modified it in some way. - * Handle native fragmentation here, incl. sending the packet. - */ - if (should_reinject && should_recalc_checksum && do_native_frag) - { - current_fragment_size = 0; - if (do_fragment_http && ppTcpHdr->DstPort == htons(80)) { - current_fragment_size = http_fragment_size; - } - else if (do_fragment_https && ppTcpHdr->DstPort != htons(80)) { - current_fragment_size = https_fragment_size; - } - - if (current_fragment_size) { - send_native_fragment(w_filter, addr, packet, packetLen, packet_data, - packet_dataLen,packet_v4, packet_v6, - ppIpHdr, ppIpV6Hdr, ppTcpHdr, - current_fragment_size, do_reverse_frag); - - send_native_fragment(w_filter, addr, packet, packetLen, packet_data, - packet_dataLen,packet_v4, packet_v6, - ppIpHdr, ppIpV6Hdr, ppTcpHdr, - current_fragment_size, !do_reverse_frag); - continue; - } - } - } /* Handle TCP packet with data */ - - /* Else if we got TCP packet without data */ - else if (packet_type == ipv4_tcp || packet_type == ipv6_tcp) { - /* If we got INBOUND SYN+ACK packet */ - if (!addr.Outbound && - ppTcpHdr->Syn == 1 && ppTcpHdr->Ack == 1) { - //printf("Changing Window Size!\n"); - /* - * Window Size is changed even if do_fragment_http_persistent - * is enabled as there could be non-HTTP data on port 80 - */ - - if (do_fake_packet && (do_auto_ttl || ttl_min_nhops)) { - if (!((packet_v4 && tcp_handle_incoming(&ppIpHdr->SrcAddr, &ppIpHdr->DstAddr, - ppTcpHdr->SrcPort, ppTcpHdr->DstPort, - 0, ppIpHdr->TTL)) - || - (packet_v6 && tcp_handle_incoming((uint32_t*)&ppIpV6Hdr->SrcAddr, - (uint32_t*)&ppIpV6Hdr->DstAddr, - ppTcpHdr->SrcPort, ppTcpHdr->DstPort, - 1, ppIpV6Hdr->HopLimit)))) - { - if (do_tcp_verb) - puts("[TCP WARN] Can't add TCP connection record."); - } - } - - if (!do_native_frag) { - if (do_fragment_http && ppTcpHdr->SrcPort == htons(80)) { - change_window_size(ppTcpHdr, http_fragment_size); - should_recalc_checksum = 1; - } - else if (do_fragment_https && ppTcpHdr->SrcPort != htons(80)) { - change_window_size(ppTcpHdr, https_fragment_size); - should_recalc_checksum = 1; - } - } - } - } - - /* Else if we got UDP packet with data */ - else if ((do_dnsv4_redirect && (packet_type == ipv4_udp_data)) || - (do_dnsv6_redirect && (packet_type == ipv6_udp_data))) - { - if (!addr.Outbound) { - if ((packet_v4 && dns_handle_incoming(&ppIpHdr->DstAddr, ppUdpHdr->DstPort, - packet_data, packet_dataLen, - &dns_conn_info, 0)) - || - (packet_v6 && dns_handle_incoming(ppIpV6Hdr->DstAddr, ppUdpHdr->DstPort, - packet_data, packet_dataLen, - &dns_conn_info, 1))) - { - /* Changing source IP and port to the values - * from DNS conntrack */ - if (packet_v4) - ppIpHdr->SrcAddr = dns_conn_info.dstip[0]; - else if (packet_v6) - ipv6_copy_addr(ppIpV6Hdr->SrcAddr, dns_conn_info.dstip); - ppUdpHdr->DstPort = dns_conn_info.srcport; - ppUdpHdr->SrcPort = dns_conn_info.dstport; - should_recalc_checksum = 1; - } - else { - if (dns_is_dns_packet(packet_data, packet_dataLen, 0)) - should_reinject = 0; - - if (do_dns_verb && !should_reinject) { - printf("[DNS] Error handling incoming packet: srcport = %hu, dstport = %hu\n", - ntohs(ppUdpHdr->SrcPort), ntohs(ppUdpHdr->DstPort)); - } - } - } - - else if (addr.Outbound) { - if ((packet_v4 && dns_handle_outgoing(&ppIpHdr->SrcAddr, ppUdpHdr->SrcPort, - &ppIpHdr->DstAddr, ppUdpHdr->DstPort, - packet_data, packet_dataLen, 0)) - || - (packet_v6 && dns_handle_outgoing(ppIpV6Hdr->SrcAddr, ppUdpHdr->SrcPort, - ppIpV6Hdr->DstAddr, ppUdpHdr->DstPort, - packet_data, packet_dataLen, 1))) - { - /* Changing destination IP and port to the values - * from configuration */ - if (packet_v4) { - ppIpHdr->DstAddr = dnsv4_addr; - ppUdpHdr->DstPort = dnsv4_port; - } - else if (packet_v6) { - ipv6_copy_addr(ppIpV6Hdr->DstAddr, (uint32_t*)dnsv6_addr.s6_addr); - ppUdpHdr->DstPort = dnsv6_port; - } - should_recalc_checksum = 1; - } - else { - if (dns_is_dns_packet(packet_data, packet_dataLen, 1)) - should_reinject = 0; - - if (do_dns_verb && !should_reinject) { - printf("[DNS] Error handling outgoing packet: srcport = %hu, dstport = %hu\n", - ntohs(ppUdpHdr->SrcPort), ntohs(ppUdpHdr->DstPort)); - } - } - } - } - - if (should_reinject) { - //printf("Re-injecting!\n"); - if (should_recalc_checksum) { - WinDivertHelperCalcChecksums(packet, packetLen, &addr, (UINT64)0LL); - } - WinDivertSend(w_filter, packet, packetLen, NULL, &addr); - } - } - else { - // error, ignore - if (!exiting) - printf("Error receiving packet!\n"); - break; - } - } -} diff --git a/src/goodbyedpi.exe.manifest b/src/goodbyedpi.exe.manifest deleted file mode 100644 index 02047ab..0000000 --- a/src/goodbyedpi.exe.manifest +++ /dev/null @@ -1,12 +0,0 @@ - - - - GoodbyeDPI - - - - - - - - diff --git a/src/goodbyedpi.h b/src/goodbyedpi.h deleted file mode 100644 index 5dd3d47..0000000 --- a/src/goodbyedpi.h +++ /dev/null @@ -1,11 +0,0 @@ -#define HOST_MAXLEN 253 -#define MAX_PACKET_SIZE 9016 - -#ifndef DEBUG -#define debug(...) do {} while (0) -#else -#define debug(...) printf(__VA_ARGS__) -#endif - -int main(int argc, char *argv[]); -void deinit_all(); diff --git a/src/icon.ico b/src/icon.ico deleted file mode 100644 index dc18d25fa7998953b7927d565dfdb980f5a17ff6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11744 zcmaiaRa9I}(CrNF65K7p-5r9vyOZEfU~qdJ7&5@(^hD^OP z_tol2RC(x0RNGHDKk>-X7V?R-N|6mb10J{z8M(3r*w|(@RR4YRzXNSp@fYi1T(g}B zZcUUB&GmG8kfXqqE_4DouwOP#JOnuS#ewh^C@>ZUg+^HFH5RDCZx6N`J2ll7 zjF8L}UmiI{A^9~@cJVH4ztc@8IH&_4BXqXyyy|WH%MTZC+85W|;rYXpsicJV^I`2=A>}$x)c{Iv&Tig@@P(b)r1Z1opvvF|3n79 zzh2A%Yr&Fk9Nd!pY4m$gN!F199!xc*#eOeth>nYj9B&Lv-b!a>bj=><-4ABr&# z4*2Q6xO z+Ve`hsdCa0q?iWAKDW$uoS9IT&}=Yf2OhKMtf+M(qirWQ8x%71n{|xR^msFmPG^YhOjWtDMR+=md9>txks&)iksFsr{ul%Aq z({+yfHq^LXg;ABs4pT3J0fR~_J7rGsu6YBF=k%^*jLuIINeHfv(0|I#JKoQp3zd9- zjj(j+@O6@0tP!*Ny{#Yo%j3c`oXMIlLRRUF@g8v6Xi*3V0~O<3^Rl$EvV0@k*-3}7 zA!Qzd(7h%>D~WK>32HVCdw$MkuY4`* z<}1e#viYjd2NrC=-e_{^Nci);D48x+HSdkWm|67i{49=(CKsQx-Jj6Va^3Gpu8I4Z zBMA!&?KEWo%I;PN9qpsw#4@5eEkCa>=AS@4rEWBpUT%>szSQmuY=NF?d2 zR7xtV<6Yj>F3sRS=&I0A8D4|Wl#~&8RW&(z8fA0d&C^mm zpH{1t9_w})Idfb<2Vho;O)owW{RI4!C#kTHg3ZiBTcFssoONjEV4!wpBC-wYuk8V4 z$-wW+^}T(!iAS@~2B&pXQxBOtDFO^wVg>Z4h>|?zysOn{55c2wtJPbrf;eNSsvJJ# z|9NkdkavB7+bPlR&d{_&xXH5E>l29A=fO9L`87${moz591s5(&BnBL;59gi@egzVX zfRPFkP)PVQTU*87nP?yE@{&7LkY=JO6sdN9O4ZvWrjYdgwmk4)kkZ}o#oE;FEa2_` z6;%^9MYCMC*IWW6xSp?3tXK7}%8ZI5^f_c$?kK<6aER1>q?l=fe+}UH8 z?$HRQ_$*>+dA{F=7s6pNno(-n)8%u&x*6I?DVFHmhSFih@sJ*Ikd za48Us?gyvRW;((WTWI+Dr>l?V3P*JH0m~MW1m&U@Y1jk&#c{7O^nJ(WFBst3cX<1& zjgdEcKI6k++cv6nt>y@#BqBZ!_<#u!k%Xj*)XB!niWAoR+=TF@S95d4TvkI1Jo>oHpsn-Dt}V(420!n(q3Ej%v=%u>V==U5hR?D&)pCq>ioJUPMRso5Jh3 zHPM$5X?6M%c9N~|53?V>g3JzsL3sp7OAd?SFc>usms^fh@1*$7Lge|JE%A?Jl`zCa z>v^!qZ%SFhB*pso)X^jY6xVwd`T7mseBc)qkq0kA1Lzsk?-Tr_5O)j*=Ar!1NcW7Q z-#Pi=qoypUW$X~G1iy9%o%<)}<6uojh(%3@`}!QyN@I?Wn0Uw?u!281rZqY3{Q~yJ=ER+Dnky1R=pF~#EoI62(Y_4H$ZKf=a{zYQJStZF>v z3g_Z-7Ke-LD6sbKQ0XW)mtPWTIQ>W*kAiOlix5?R#deFqPP*P@w!{1JjTI`k0E=<; zqfEt{U0m;lQPfm*$vB##OW`|G+dH z*f)0=sRT%s(7*iSHL=C;@i(nguU6!nO$(spH5E{T;Qh#-S@Lw+&DiOwMc>zAvQdde zU*BGnOb_sURrj2Q5gH+K?}%j`OE#}s;5m@yEa(*X1g82NN<`7W+L z1DKor@KL8)J_%>+YuJql?VZY=OUx%$nuGy9q}QJ2NCMlkemd~> zLmn9fu7Dl6SjY1Fm&YJ(B-Gy~!2y1kgiK8|%9(K$ZY!Ce$1L>l!mCjSd^I&ej4?jD zvlSM!mu*+} zol?20Cz{Sc`k9PuAfKkmhBycI2|6ZSavC4TB=f+(;%m9w8RU;tYpX8HPx3m&{2A6q zd_%|tBe4nr#I+%Tvs5KVnmSfHQ%~_#{VQd4a%t7rZk+aA#;N$HEIR@B5WU4R4#gO05aY7(6x2X?|?mEZS+RM*Z@za2SOaDNaf8X-9lXg|4Ij~oX zT=!STeKlz}6s=nP?>?sLBKgN#Xu5kelra8hS$ASph8+jC9a8p0Ei2WAe5R_^JhTnU z-c&yoZ)5VpxS`cT2N|Mbnn{*$6m}5ZsLrxFJpxeq9R_J40gG~aU@I_{(HG+M1D zZ0Q`);NqZ?Ip&LAK1RtE!9-RGidX{F{O3L9Zk%K%Kq^6$}$K> zLZmN&E@rUW^fmX0&-K94$j5;ni@HPECyU5hP*6O-T1M7%v&TYeilH(_byNjoY~bZ5 zwlaBQ9AMVJuG#dq)Jkc=S({x>39<7oaswIZ5=}laMWnps4$Wf(7F`aJGGaG3!XYLk zxTgStTt6FNj2pWrECjSmjyil%IpOw;@wcX;9KoUmn?Dc7_n?HFa&jtsqpSLnO zt0R98VdoH(wkrMfNZcsAckr)5fXu^0CcZ#^09o|;ZfIwZd85-mZ>G|hYPsP&LL%2r zzwxiE_+Rdhk>bg^6JntkxC2*Ia$EgE`T+&NSW!JUgaE1iC&z*u6jKD{ajk<6sMxG< ze)7bkhOv%`>Y+)jF2{omJzT#&C?KmoBS}%I&cj&9xbd7O*}z%y${ZQ5G7cIZtVTN6 z*mzWK^vXi&eWK;+OO8b|?y@u$K0(*Y?VLZF%Jl~b^EcbxTZh^y-_EW*Tf#fby^b-a z?0vq+xSri6^YGzC&Em|VoJh-bSmD?dVv*7!cd|CM`m`jRlHeK=8X8F=AfBDas9#U9 z6~s)B6cIYOH`elnyS~cxm|L%V)2a98Y2k8>1rt^yHJMucuz96KaY>ki&cHD66mi$0 z%0QFuiwoXRO~wnJPh;LFQ<<8z1A3i}ahn&}V#m8o9K6R`Ya$fM&Tg`0GSc`$J(G~P zFulL1vTluqcL~BA$Ha?t_86sh=dNv|G6EN<=V=X=h#3eDOp_MC0!qNJ8$$;_H|2ufS(RM@GD2) zvGX-)0e%N`T0G?-<^#(6M+M0ZIT)646;7iGSNyr`E^=9!Mx%PW$4U(hYM%RAPKR^~ zCcPCbpyP61o9{-a>d**7D1D9j2&q3>^m^9JuzRVOYvh?a-V0H?BMy?NdtRMp1{okh z&OPS9l{YrAPO(r?|MTS6j|{OsfjTtw=J-Cpci=vLwFO;jYJ{RiK3N3O)yY2Yrt~j1 z>b80q zdTtaruG7HivDmIYMVDskMne_SKb_-2p6zziSdl?J&2z6tl8RPsCs91YKW66-Pq}RC zkzEsuGQD_?TBOH!7PPd=7c`K392_!5-GM9D&^VFr9GHP*jgDJ(`9yPvA6U@-_OhGk z*do}VoBjBc{h^-?6R?KAUb7#oQMIOj*0|kA3&~t^TyNL@$e&c@05nSJpAHOQ#%v## zg|?rea55%cE4r3CEr@AsWxf4!9CX~9J>?O*oC_`Hg+Lo2<%Qp+*q-AZJvTjRR6aYH z+?AFwZ!Y|KWYql|Ju?#$;otbLbZ19urX(JNEdX$L`W#2(@W5cA98#hB7UR;&x~YQ5 zvuKm;MzG=Bp*W3tjEU!zzfZNxRYzD{P}(Om#h`q>qwZM!ZSiSvlM$0bSU3q9er-G1 z_=l`4ft)IVzEJ_Tfcx2gX_?q(>NV9`pU2XBLLLXGRCaLAWNd*Y20O$_%OHdd1ZXALo=b2d`Ae_QkHQpXZop%c?ZG zE-u$62?-)L&-Z?-Xm?GQVVOv{(lgtwRuK7QAf0gRZrs2dRb?IwV6|Gf2bv{U!w%Ff z?YH$y$=-_BhVyi3bs$NxMHQ)gb8BJn<7W}#8 zUb+kmT9qL}IecaIkL1RvY2f*G?``mwluKc^lSmcJp!O2l`?SugFjrs5#|*N$A#!Y67IU$ZfVI(Ot0Um?Bvq^ctT`g>`X& zU^^L)zb6M-9<3jR`nmG%9&^}CnRdv{4SY8iHSc`b3Hup&BoU7~KgcWg=@y>de7KxZ zG2#?~{BH-g2k*rE-p#?_=%;jfcuNUA1LEhxvD{m9-1q0bv0~?p`1q0WjOT6=foPN! zUw7ja{@a{EIxR<|gOx{RGjrb?Y|clNqzX`bAzkqo)+$$T%b;4~D>73a@h(@BIRb4; zZY~zv!C*yioy0mW8?`d^B5D%;d>HWKE)_1LPC;eMIGdc%1s@*`+gO|ExPb6Q=M;Na zkE4_GN3N~yk2JRb3p=!`Yx6P7*=z}=*NX4GptPMI_gP&5K-gb|tjb8v^-%UnyP#5*v z_pBBE>VL@pWGlAFyU<{c7V0xBBYaH7MNn}U0Dt}%4o*~kbv?=Ud149%KpGSZp(9rF zhm(eQ##AnZefyQhTHCB~SjdbbT!>Ab%?YS((yTaxryNLN3(O;LwSX}%tJ>^B;avicvOnwB&D#adjS4{U&?!ItOB9FL1G7$1~V(4 z--=6>3KTua_|L({?Ha4i_bb;eBPA|MbsI@?j$iniTCTF*eTq?uAJPZM#|w}5?2H@y zH+{aqFvlz*{6=1ZrxoQOhj}3MSUPqyf^qWH=sR|^Y2bEymE?S}La6R)Bqh&Yf)lU> zuT^%S);~6v3xA)cr{{o_K%k3(cK!Im(BFdRPX+JS1FZli2$z>pykH-$N%6QJS=eGS zueu=u;Tl4YMJrlgyK)YbdC{B^f`R}XG)7W| z7Y)VEUx7h^;UwC5fT$dZeDEYc9zro+Nz=JcbN0f*oUt=o25HE^BQI6%`@ssC_;>{F z-U(H$#5akbZXr4p(Ew$y)$!8~+-|5?C_AV#sB!24AOc#u<4d(^TL(T{F3amP&1Ac8 zf-!-vp?H6*W^2nW=hu?^f1K2ETFFU>Ikdl?v^(|u2wzR!ujfT+>ypzTFysRo?R2q( zn3$Q|&RZD$F=Qv&Z@pnITf>P&q2vM+B0Rt7R`u1Ioog7I)F=bQ9K~%?J)Np_sp*}} z`2ktYf=77(qXuXg{Fv zRdWW9gRFNXPAofenj-$N_;leA)j%Wxug&goGO^2^0y#gwn4Z8YNSmk9h-rI_rz5W! zu3Jxnoys2JH2k{B;{=-`PBGbdXz3|n{?q`d0FS0m&FJ)n5PBQ3*HGF@253gia?G=~ z-y-5dBATi)*6!{W8+H3O5G|-xKG?rM9U5lcb#s_!^(l2kq{9$FGzKV}?`9uW?>$lZ zvSnKno}|DG|6ypp&d=mLfNn-@h^J8l$2%U7cG!es*YsoOh~#Wv^Le zsuG*QW$RY$w8;LTB)0gMKbYADmlQmyC^E|2hb?C{W0qit$+@Rg&f{{FCC(jwzWa&B{&S~Zt z{>fd{cp@*O2nGcRuAyGNPovf0l;3k=o9kg}I>){|pJ}&&=LY1cilxa*f!XjS^ySBp zf#2$Jm3KY{9T5fNFh+&W03rl~ImSyL@?&oQrvd40`A8n=56>9^2RKuL&#m42*M>SZ z76Qj}r%>eVf7w{tA85nE{+OASlk@N>J1*u^4f*cHw+a1L7S^3eWcZShkU(L+_=%Q@ z8^)$Gk!Ec6Bh1K+xcxF}s9DiK!brLoWxwDdhkNa-o!M1AXL~X|%!8J()(f1Tm6h$F zBS>0GJ8xeey4qa?EZ8AU7m0L3fQX}6@2F|qr|{YO4RfszTllSOK2uX`n`w@2K4?wr z50;epvGwPr7&v7=; zA+DYpn;?PpdNBk^xsqAcL0BJ{8}6GwPim)-7(-I7?qfIR%jS$X`y$cA#fu-8G5ax@ zyx=77ke8(K)o-$C^`Vl;bC4Nh%;erxcxrZdfLay7|*i0K5 z9&dhp-E50ax3jpjr|S8MeR*f0X++|aRm~HT?=f9(ugE@6T189O=5gs&2wzL3b@(xd zHH;GtT@Eo*1Pz~0H*?_c;?*gb6jf)1q3%hTo zIA>uBUvk@`9@xL8q*6`QU@bPft)H>=J12dDes))t3?K}nM>L_RO;N2w!3~^lb=X&h zjFaN%&ZpOl@f76|>Hr~7A4(eWmyVsHw&M=V4JGQsE1<@V(r*A{-T9715yeM~%-Lrx zGUQ&q-Z9M2&*4KCWT&-z9HG-V!a3u6j32u>)G7qyP{Ig}u+1KP54r#bAziSVh$G}r z(3mN5DK1My4A%b}94`IYK0Iuxuq)25@V7^_FV}~~Bqyi!aBNM%6GgH#>KNwcVOB36 z^JE(&z%bdi@U#U3Yh?jXKdIax>V9Mf@(co0Qc3iqWAWRwC1^qjZ3k({6^?NGv8^&z zgTv8<9^iGDf*uBaFlK&y78xH>83yZ=16^M@&zWx^#j>ZdbDM}-5P6sr>pV`Vr&Qqx z=gy$1txOMIVXGQ%IX_Z}r^*k#Wl}zK zq1rSQ)eb)CH3}Zl-8{_r;NxFaK)vmN1dzY3=XHC4Yu&2cBpV2!nYy91yKPeHf$<;u zmW5=`ZJ*2r`89kVJCjFC<$r7|j{f5=Rcjj*n_AwkN{u1*?cuFc&ZP7sG6wZC!cAXL z7{p|LWyMkh%UpMY?ur}af1?ZPpa*I`ibGM8fCSJ1wPbI>zdFt&w_jekb1Z+vU>BH2 z46$?8UTaF@i*UsxnPzNBnk`!$GE`x-AK3)v+5z4^qWc6QRn{Zk&B83>ZAv)_T(5sH z`Nwi1xL{`ez!pY78vlV-2TM1|Nk8jF7_}mykdU2D)o*R13{i!MezRBasvDmM{S)Ro z=bqW1y)Z+B_OUp1E!WMMqwUq0XUio7MhobgVxfdv`=TDWUah>W#ZL6i7co@Czi~i8 z9M)&aPno=XZk0ffKRV$&xq*SbZed|BDZ#Q`kpNRoEf!)t)u;tv_{WgpzXc3*5|kynhkxG2B{DSwy1 zc{%g*PDIrkRLJ_2wCrCxNcF?+byP}=34PxLNhz((Sn49WqT0axeRD=l)DSOnt18hm zHAC}ND7XF7I3dU0=4KRO(BE&8XaHz<>hQ&yRf86-{?U|(#r9WkU$IYqJu3}w_)jOb zbS^=^epOZ-0kb~+#^ivLg9eww=Ryg!v<5(~dU$EX!uc@}c2P}g3q##)%~OW9THaaR zPK4BxnSC>BYc<$8+~YFe-0A5{LnCa*^c@T0(qD*h86T4RBIZ@Kv?!?ZC?BUI<04&( zS^+}pUDYW5s?qbOFStUeKR5wfU#gay7VL=dvq(ws;AbiW@Bb~(S1qSJ_bfEZ0laVW zf;DZXxda7Y{I<6AA~sCm5fT54rtTINAFy*+f+fCwWpitZDp4ofx$hwB9*W-|nqa|& z*e%z?y02$gInI{)DvMrvN8XB>L3hBT5h}8e77yz|#s9I$#ze4mS5mbJPnrev4xkeX zTdAn6bp50m8lDoLd3fN?FH)wYq)cC|N&f3zMfwee#0#FKLogGKSw38Bdh5pG;^ikpbOhKCY zs&xkGD7oa3B=g4_qSV5n`*mX~>F9JS?W#3u=n;6b@;D}a;noC*i-&qB#FA3<5hhuB z%*9jV@T!>MLncU6|68V!Lm29(e&x&y?GCYzdR}~<)L2{uZbe1j!C!OTtJ`^@tCL0K zx8|!Wxs+e*H7GK0R_kB`6_ZIIXF6&bO~fQ{HR!;OlK|0Y@2dDR$!)mle!vRQh9;+d zeOM*9&7{4Mk#|1Y_0ya6d%sM*gOHe1KN39yNE&pq;4LFB&vjk%iJZY!WPif=jdV3Z zT}8#mWu9k)1QTH%xC&}qw{igC{rGqK23FS^_#&NW-_@11<&=+Wzp9v(r8L-A6@|s- zZ138%2DLY)FI%QH=6O^C9~NG!xSz%6;x8F7_t))ooaBS_@ovlAGJc=RLc!pHZAAPH ztrM6Ds;4J=m;?78yX`f$^Wy{*GD!~qtFKm(qc1hz~ZJZ|>&9bY#cbE;s zWa*5E!rR1D?j>9=qC`Aq)xW+m#lps;;qgT!jrFk&>*9Na#YF*c3~maGBD!}zSx8y+z9&sVT&|a;`?Cl~RUjd^ zTmk%zF>@<=E-f;6N)!;A8l30c$T+Sp*}I4OV<=MN-*dY#`In%ej@re(; z*yB#y8W|JP)6~<;0Uga$=2l;PQ*w4*`*x9uP1#4i3nDxD`c7;R{?_)Q4bUNf>F{Lz zq=r1{XLVWgO_aR5dnzWM`@Kwc73vk9;?vSoC-bH&>Qhq5R2m9Q{Y+U;6;$=d&h#6^ zopqY)NzSStlz8)qE4iEH!@R#ca|8!V_~o4NmyY){>xR6CO}#t=sQ@QtmbIYRrPY%czYj z0sjAR8ss1E$^VDbaPjiG0RZ6F{^K-sf)bOxU2$e{`u+CTE)a5YSXEgIDAi34)S4Mp zNa+d5MGNwKnMqSFSOrlKU~`zmkmyxBIbkJ$K^mTBqADm1*78DWV*q48L+l-Snfb4)SuM)ZH_fQ4 zwRiw3h?l6ZNu#+Hk?ZswG;m~+Qkm%MOjIe%24VGpW-pYgC>Yz~3FymrYYsFdmJBZ{ZW_x;?qa%aEa+N2XnPt7E-J|vDnaUr!d{Xh*956CDso0`~ z7D%8{ig$bbtZBX*0>#GkbR#Py=&%A==DjC1MLG+ac-5ZD31nh-2ObvgyZLY^7LpZj%vJ@VEAqcV{$ zVu<;SCGzDY%=SjPu6C1)BqVkY{(W0~bEq|F`D-v-8Gdv6TrMGbOQ0VC+%>=gO`jbe z*&MbsM$VW>mSiH4bKhNN)!PlBhleI4Yk!p0T+H9!wkavqbaWW=q?oWV<1nfAGH4Qf zDg|OS^OsU+Y3uFBs4*W>-63EWdqETUjlgHAEq}q6K^(U?!(Kqm>C*ZWA_Vf(-M8PtUVnr3}NU+o)K0%Y zrHjUq7upzRN)StVT2Y{ewE$-T6%|KL4rBQESzH0@g7=ROXKER*ZttF!CnT^qw* zT{#lx6~p_?FE}xU$Z*{Ti}TqC5$r6%#9PjbHt0+^MykI%I>AW?{flD(&DQ4tFX?LI za@T26nDTpRo_tq%W^hpNO_a7ODv_YePL;cbM+InF35t6SW@Rkc6AB#xP@X+s5Wb*!@2f-!&d zD$#;kuGFzrU^zwU0&o%mLClRV3B6&n_9FV4Vq5Uc@QHFD9Mg+(EEijU=$UIw`Zpu% zvb4M9wJx;8G)N_>K-17`7IM6P7S3gH=17Jf-I1=JtLrHj$~~}*vfM1+VM&052BTYJ zk6{ubKT{4Ke)Jw>uZ8kG{92FzwRA`D`$lcNxU7gBT;qvld@hjf6Ga5Cf+U7I3df^A z2GtrBOf(|6p*k{2-*gsOJN7s233~vtM~d`jWMZ|6T58>se1G8l{<}XaPq)^}2Y~ow zte-v>iLSiytiN>=pZRJgzF(_6?T<(b|AJOw2wVo`K>wqPSGSa#?aTOp%mR0gC!aqdyl^7{B^bV*FhjCjm1w3L+7h2}+Bj5G6)h!amtns8sJ_~%Sox#VyzRz73E*~;R(;6!InH@sox5yqJ z!T-cvnxP4uD!=X%BB{@Xz1REgC)9fFAKQ>-(%EXCBmA^5Yb7dt8&3S;e@4`b4?5Dx zplZa$-%)Mp8|dDjE`tW9nmO)tp>=#;9ky4HQHZHh&YsSX^EVpaP2Ccnl9!E8M|HV>y>^IU;EBuo&BCSDnnMf+r=nCf z7CfdM;Vt%(lmnYCWx -#include -#include "goodbyedpi.h" -#include "service.h" - -#define SERVICE_NAME "GoodbyeDPI" - -static SERVICE_STATUS ServiceStatus; -static SERVICE_STATUS_HANDLE hStatus; -static int service_argc = 0; -static char **service_argv = NULL; - -int service_register(int argc, char *argv[]) -{ - int i, ret; - SERVICE_TABLE_ENTRY ServiceTable[] = { - {SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)service_main}, - {NULL, NULL} - }; - /* - * Save argc & argv as service_main is called with different - * arguments, which are passed from "start" command, not - * from the program command line. - * We don't need this behaviour. - * - * Note that if StartServiceCtrlDispatcher() succeedes - * it does not return until the service is stopped, - * so we should copy all arguments first and then - * handle the failure. - */ - if (!service_argc && !service_argv) { - service_argc = argc; - service_argv = calloc((size_t)(argc + 1), sizeof(void*)); - for (i = 0; i < argc; i++) { - service_argv[i] = strdup(argv[i]); - } - } - - ret = StartServiceCtrlDispatcher(ServiceTable); - - if (service_argc && service_argv) { - for (i = 0; i < service_argc; i++) { - free(service_argv[i]); - } - free(service_argv); - } - - return ret; -} - -void service_main(int argc __attribute__((unused)), - char *argv[] __attribute__((unused))) -{ - ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; - ServiceStatus.dwCurrentState = SERVICE_RUNNING; - ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; - ServiceStatus.dwWin32ExitCode = 0; - ServiceStatus.dwServiceSpecificExitCode = 0; - ServiceStatus.dwCheckPoint = 1; - ServiceStatus.dwWaitHint = 0; - - hStatus = RegisterServiceCtrlHandler( - SERVICE_NAME, - (LPHANDLER_FUNCTION)service_controlhandler); - if (hStatus == (SERVICE_STATUS_HANDLE)0) - { - // Registering Control Handler failed - return; - } - - SetServiceStatus(hStatus, &ServiceStatus); - - // Calling main with saved argc & argv - ServiceStatus.dwWin32ExitCode = (DWORD)main(service_argc, service_argv); - ServiceStatus.dwCurrentState = SERVICE_STOPPED; - SetServiceStatus(hStatus, &ServiceStatus); - return; -} - -// Control handler function -void service_controlhandler(DWORD request) -{ - switch(request) - { - case SERVICE_CONTROL_STOP: - case SERVICE_CONTROL_SHUTDOWN: - deinit_all(); - ServiceStatus.dwWin32ExitCode = 0; - ServiceStatus.dwCurrentState = SERVICE_STOPPED; - default: - break; - } - // Report current status - SetServiceStatus(hStatus, &ServiceStatus); - return; -} diff --git a/src/service.h b/src/service.h deleted file mode 100644 index 67cd7bb..0000000 --- a/src/service.h +++ /dev/null @@ -1,3 +0,0 @@ -int service_register(); -void service_main(int argc, char *argv[]); -void service_controlhandler(DWORD request); diff --git a/src/ttltrack.c b/src/ttltrack.c deleted file mode 100644 index acac061..0000000 --- a/src/ttltrack.c +++ /dev/null @@ -1,252 +0,0 @@ -/** - * TCP (TTL) Connection Tracker for GoodbyeDPI - * - * Monitors SYN/ACK only, to extract the TTL value of the remote server. - * - */ - -#include -#include -#include -#include -#include "goodbyedpi.h" -#include "ttltrack.h" -#include "utils/uthash.h" - - -/* key ('4' for IPv4 or '6' for IPv6 + srcip[16] + dstip[16] + srcport[2] + dstport[2]) */ -#define TCP_CONNRECORD_KEY_LEN 37 - -#define TCP_CLEANUP_INTERVAL_SEC 30 - -/* HACK! - * uthash uses strlen() for HASH_FIND_STR. - * We have null bytes in our key, so we can't use strlen() - * And since it's always TCP_CONNRECORD_KEY_LEN bytes long, - * we don't need to use any string function to determine length. - */ -#undef uthash_strlen -#define uthash_strlen(s) TCP_CONNRECORD_KEY_LEN - -typedef struct tcp_connrecord { - /* key ('4' for IPv4 or '6' for IPv6 + srcip[16] + dstip[16] + srcport[2] + dstport[2]) */ - char key[TCP_CONNRECORD_KEY_LEN]; - time_t time; /* time when this record was added */ - uint16_t ttl; - UT_hash_handle hh; /* makes this structure hashable */ -} tcp_connrecord_t; - -static time_t last_cleanup = 0; -static tcp_connrecord_t *conntrack = NULL; - -inline static void fill_key_data(char *key, const uint8_t is_ipv6, const uint32_t srcip[4], - const uint32_t dstip[4], const uint16_t srcport, const uint16_t dstport) -{ - unsigned int offset = 0; - - if (is_ipv6) { - *(uint8_t*)(key) = '6'; - offset += sizeof(uint8_t); - ipv6_copy_addr((uint32_t*)(key + offset), srcip); - offset += sizeof(uint32_t) * 4; - ipv6_copy_addr((uint32_t*)(key + offset), dstip); - offset += sizeof(uint32_t) * 4; - } - else { - *(uint8_t*)(key) = '4'; - offset += sizeof(uint8_t); - ipv4_copy_addr((uint32_t*)(key + offset), srcip); - offset += sizeof(uint32_t) * 4; - ipv4_copy_addr((uint32_t*)(key + offset), dstip); - offset += sizeof(uint32_t) * 4; - } - - *(uint16_t*)(key + offset) = srcport; - offset += sizeof(srcport); - *(uint16_t*)(key + offset) = dstport; - offset += sizeof(dstport); -} - -inline static void fill_data_from_key(uint8_t *is_ipv6, uint32_t srcip[4], uint32_t dstip[4], - uint16_t *srcport, uint16_t *dstport, const char *key) -{ - unsigned int offset = 0; - - if (key[0] == '6') { - *is_ipv6 = 1; - offset += sizeof(uint8_t); - ipv6_copy_addr(srcip, (uint32_t*)(key + offset)); - offset += sizeof(uint32_t) * 4; - ipv6_copy_addr(dstip, (uint32_t*)(key + offset)); - offset += sizeof(uint32_t) * 4; - } - else { - *is_ipv6 = 0; - offset += sizeof(uint8_t); - ipv4_copy_addr(srcip, (uint32_t*)(key + offset)); - offset += sizeof(uint32_t) * 4; - ipv4_copy_addr(dstip, (uint32_t*)(key + offset)); - offset += sizeof(uint32_t) * 4; - } - *srcport = *(uint16_t*)(key + offset); - offset += sizeof(*srcport); - *dstport = *(uint16_t*)(key + offset); - offset += sizeof(*dstport); -} - -inline static void construct_key(const uint32_t srcip[4], const uint32_t dstip[4], - const uint16_t srcport, const uint16_t dstport, - char *key, const uint8_t is_ipv6) -{ - debug("Construct key enter\n"); - if (key) { - debug("Constructing key\n"); - fill_key_data(key, is_ipv6, srcip, dstip, srcport, dstport); - } - debug("Construct key end\n"); -} - -inline static void deconstruct_key(const char *key, const tcp_connrecord_t *connrecord, - tcp_conntrack_info_t *conn_info) -{ - debug("Deconstruct key enter\n"); - if (key && conn_info) { - debug("Deconstructing key\n"); - fill_data_from_key(&conn_info->is_ipv6, - conn_info->srcip, conn_info->dstip, - &conn_info->srcport, &conn_info->dstport, - key); - - conn_info->ttl = connrecord->ttl; - } - debug("Deconstruct key end\n"); -} - -static int check_get_tcp_conntrack_key(const char *key, tcp_connrecord_t **connrecord) { - tcp_connrecord_t *tmp_connrecord = NULL; - if (!conntrack) return FALSE; - - HASH_FIND_STR(conntrack, key, tmp_connrecord); - if (tmp_connrecord) { - if (connrecord) - *connrecord = tmp_connrecord; - debug("check_get_tcp_conntrack_key found key\n"); - return TRUE; - } - debug("check_get_tcp_conntrack_key key not found\n"); - return FALSE; -} - -static int add_tcp_conntrack(const uint32_t srcip[4], const uint32_t dstip[4], - const uint16_t srcport, const uint16_t dstport, - const uint8_t is_ipv6, const uint8_t ttl - ) -{ - if (!(srcip && srcport && dstip && dstport)) - return FALSE; - - tcp_connrecord_t *tmp_connrecord = malloc(sizeof(tcp_connrecord_t)); - construct_key(srcip, dstip, srcport, dstport, tmp_connrecord->key, is_ipv6); - - if (!check_get_tcp_conntrack_key(tmp_connrecord->key, NULL)) { - tmp_connrecord->time = time(NULL); - tmp_connrecord->ttl = ttl; - HASH_ADD_STR(conntrack, key, tmp_connrecord); - debug("Added TCP conntrack %u:%hu - %u:%hu\n", srcip[0], ntohs(srcport), dstip[0], ntohs(dstport)); - return TRUE; - } - debug("Not added TCP conntrack %u:%hu - %u:%hu\n", srcip[0], ntohs(srcport), dstip[0], ntohs(dstport)); - free(tmp_connrecord); - return FALSE; -} - -static void tcp_cleanup() { - tcp_connrecord_t *tmp_connrecord, *tmp_connrecord2 = NULL; - - if (last_cleanup == 0) { - last_cleanup = time(NULL); - return; - } - - if (difftime(time(NULL), last_cleanup) >= TCP_CLEANUP_INTERVAL_SEC) { - last_cleanup = time(NULL); - - HASH_ITER(hh, conntrack, tmp_connrecord, tmp_connrecord2) { - if (difftime(last_cleanup, tmp_connrecord->time) >= TCP_CLEANUP_INTERVAL_SEC) { - HASH_DEL(conntrack, tmp_connrecord); - free(tmp_connrecord); - } - } - } -} - -int tcp_handle_incoming(uint32_t srcip[4], uint32_t dstip[4], - uint16_t srcport, uint16_t dstport, - uint8_t is_ipv6, uint8_t ttl) -{ - tcp_cleanup(); - - debug("trying to add TCP srcport = %hu, dstport = %hu\n", ntohs(srcport), ntohs(dstport)); - return add_tcp_conntrack(srcip, dstip, srcport, dstport, is_ipv6, ttl); - - debug("____tcp_handle_incoming FALSE: srcport = %hu, dstport = %hu\n", ntohs(srcport), ntohs(dstport)); - return FALSE; -} - -int tcp_handle_outgoing(uint32_t srcip[4], uint32_t dstip[4], - uint16_t srcport, uint16_t dstport, - tcp_conntrack_info_t *conn_info, - uint8_t is_ipv6) -{ - char key[TCP_CONNRECORD_KEY_LEN]; - tcp_connrecord_t *tmp_connrecord = NULL; - - if (!conn_info) - return FALSE; - - tcp_cleanup(); - construct_key(dstip, srcip, dstport, srcport, key, is_ipv6); - if (check_get_tcp_conntrack_key(key, &tmp_connrecord) && tmp_connrecord) { - /* Connection exists in conntrack, moving on */ - deconstruct_key(key, tmp_connrecord, conn_info); - HASH_DEL(conntrack, tmp_connrecord); - free(tmp_connrecord); - debug("____tcp_handle_outgoing TRUE: srcport = %hu\n", ntohs(srcport)); - return TRUE; - } - - debug("____tcp_handle_outgoing FALSE: srcport = %hu\n", ntohs(srcport)); - return FALSE; -} - -int tcp_get_auto_ttl(const uint8_t ttl, const uint8_t autottl1, - const uint8_t autottl2, const uint8_t minhops, - const uint8_t maxttl) { - uint8_t nhops = 0; - uint8_t ttl_of_fake_packet = 0; - - if (ttl > 98 && ttl < 128) { - nhops = 128 - ttl; - } - else if (ttl > 34 && ttl < 64) { - nhops = 64 - ttl; - } - else { - return 0; - } - - if (nhops <= autottl1 || nhops < minhops) { - return 0; - } - - ttl_of_fake_packet = nhops - autottl2; - if (ttl_of_fake_packet < autottl2 && nhops <= 9) { - ttl_of_fake_packet = nhops - autottl1 - trunc((autottl2 - autottl1) * ((float)nhops/10)); - } - - if (maxttl && ttl_of_fake_packet > maxttl) { - ttl_of_fake_packet = maxttl; - } - - return ttl_of_fake_packet; -} \ No newline at end of file diff --git a/src/ttltrack.h b/src/ttltrack.h deleted file mode 100644 index 2836a71..0000000 --- a/src/ttltrack.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef _TTLTRACK_H -#define _TTLTRACK_H -#include -#include "dnsredir.h" - -typedef struct tcp_conntrack_info { - uint8_t is_ipv6; - uint8_t ttl; - uint32_t srcip[4]; - uint16_t srcport; - uint32_t dstip[4]; - uint16_t dstport; -} tcp_conntrack_info_t; - -int tcp_handle_incoming(uint32_t srcip[4], uint32_t dstip[4], - uint16_t srcport, uint16_t dstport, - uint8_t is_ipv6, uint8_t ttl); - -int tcp_handle_outgoing(uint32_t srcip[4], uint32_t dstip[4], - uint16_t srcport, uint16_t dstport, - tcp_conntrack_info_t *conn_info, - uint8_t is_ipv6); - -int tcp_get_auto_ttl(const uint8_t ttl, const uint8_t autottl1, - const uint8_t autottl2, const uint8_t minhops, - const uint8_t maxttl); -#endif diff --git a/src/utils/getline.c b/src/utils/getline.c deleted file mode 100644 index 5896867..0000000 --- a/src/utils/getline.c +++ /dev/null @@ -1,92 +0,0 @@ -/* $NetBSD: getdelim.c,v 1.2 2015/12/25 20:12:46 joerg Exp $ */ -/* NetBSD-src: getline.c,v 1.2 2014/09/16 17:23:50 christos Exp */ - -/*- - * Copyright (c) 2011 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Christos Zoulas. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include "getline.h" - -#if !HAVE_GETDELIM - -ssize_t -getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp) -{ - char *ptr, *eptr; - - - if (*buf == NULL || *bufsiz == 0) { - *bufsiz = BUFSIZ; - if ((*buf = malloc(*bufsiz)) == NULL) - return -1; - } - - for (ptr = *buf, eptr = *buf + *bufsiz;;) { - int c = fgetc(fp); - if (c == -1) { - if (feof(fp)) { - ssize_t diff = (ssize_t)(ptr - *buf); - if (diff != 0) { - *ptr = '\0'; - return diff; - } - } - return -1; - } - *ptr++ = c; - if (c == delimiter) { - *ptr = '\0'; - return ptr - *buf; - } - if (ptr + 2 >= eptr) { - char *nbuf; - size_t nbufsiz = *bufsiz * 2; - ssize_t d = ptr - *buf; - if ((nbuf = realloc(*buf, nbufsiz)) == NULL) - return -1; - *buf = nbuf; - *bufsiz = nbufsiz; - eptr = nbuf + nbufsiz; - ptr = nbuf + d; - } - } -} - -#endif - -#if !HAVE_GETLINE - -ssize_t -getline(char **buf, size_t *bufsiz, FILE *fp) -{ - return getdelim(buf, bufsiz, '\n', fp); -} - -#endif diff --git a/src/utils/getline.h b/src/utils/getline.h deleted file mode 100644 index 6ace508..0000000 --- a/src/utils/getline.h +++ /dev/null @@ -1,7 +0,0 @@ -#if !HAVE_GETDELIM -ssize_t getdelim(char **, size_t *, int, FILE *); -#endif - -#if !HAVE_GETLINE -ssize_t getline(char **, size_t *, FILE *); -#endif diff --git a/src/utils/repl_str.c b/src/utils/repl_str.c deleted file mode 100644 index 5331b41..0000000 --- a/src/utils/repl_str.c +++ /dev/null @@ -1,90 +0,0 @@ -#include -#include -#include - -#if (__STDC_VERSION__ >= 199901L) -#include -#endif - -char *repl_str(const char *str, const char *from, const char *to) { - - /* Adjust each of the below values to suit your needs. */ - - /* Increment positions cache size initially by this number. */ - size_t cache_sz_inc = 16; - /* Thereafter, each time capacity needs to be increased, - * multiply the increment by this factor. */ - const size_t cache_sz_inc_factor = 3; - /* But never increment capacity by more than this number. */ - const size_t cache_sz_inc_max = 1048576; - - char *pret, *ret = NULL; - const char *pstr2, *pstr = str; - size_t i, count = 0; - #if (__STDC_VERSION__ >= 199901L) - uintptr_t *pos_cache_tmp, *pos_cache = NULL; - #else - ptrdiff_t *pos_cache_tmp, *pos_cache = NULL; - #endif - size_t cache_sz = 0; - size_t cpylen, orglen, retlen, tolen, fromlen = strlen(from); - - /* Find all matches and cache their positions. */ - while ((pstr2 = strstr(pstr, from)) != NULL) { - count++; - - /* Increase the cache size when necessary. */ - if (cache_sz < count) { - cache_sz += cache_sz_inc; - pos_cache_tmp = realloc(pos_cache, sizeof(*pos_cache) * cache_sz); - if (pos_cache_tmp == NULL) { - goto end_repl_str; - } else pos_cache = pos_cache_tmp; - cache_sz_inc *= cache_sz_inc_factor; - if (cache_sz_inc > cache_sz_inc_max) { - cache_sz_inc = cache_sz_inc_max; - } - } - - pos_cache[count-1] = (uintptr_t)(pstr2 - str); - pstr = pstr2 + fromlen; - } - - orglen = (size_t)(pstr - str) + strlen(pstr); - - /* Allocate memory for the post-replacement string. */ - if (count > 0) { - tolen = strlen(to); - retlen = orglen + (tolen - fromlen) * count; - } else retlen = orglen; - ret = malloc(retlen + 1); - if (ret == NULL) { - goto end_repl_str; - } - - if (count == 0) { - /* If no matches, then just duplicate the string. */ - strcpy(ret, str); - } else { - /* Otherwise, duplicate the string whilst performing - * the replacements using the position cache. */ - pret = ret; - memcpy(pret, str, pos_cache[0]); - pret += pos_cache[0]; - for (i = 0; i < count; i++) { - memcpy(pret, to, tolen); - pret += tolen; - pstr = str + pos_cache[i] + fromlen; - cpylen = (i == count-1 ? orglen : pos_cache[i+1]) - pos_cache[i] - fromlen; - memcpy(pret, pstr, cpylen); - pret += cpylen; - } - ret[retlen] = '\0'; - } - -end_repl_str: - /* Free the cache and return the post-replacement string, - * which will be NULL in the event of an error. */ - free(pos_cache); - return ret; -} diff --git a/src/utils/repl_str.h b/src/utils/repl_str.h deleted file mode 100644 index ffd28d8..0000000 --- a/src/utils/repl_str.h +++ /dev/null @@ -1 +0,0 @@ -char *repl_str(const char *str, const char *from, const char *to); diff --git a/src/utils/uthash.h b/src/utils/uthash.h deleted file mode 100644 index 9a396b6..0000000 --- a/src/utils/uthash.h +++ /dev/null @@ -1,1136 +0,0 @@ -/* -Copyright (c) 2003-2021, Troy D. Hanson http://troydhanson.github.io/uthash/ -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef UTHASH_H -#define UTHASH_H - -#define UTHASH_VERSION 2.3.0 - -#include /* memcmp, memset, strlen */ -#include /* ptrdiff_t */ -#include /* exit */ - -#if defined(HASH_DEFINE_OWN_STDINT) && HASH_DEFINE_OWN_STDINT -/* This codepath is provided for backward compatibility, but I plan to remove it. */ -#warning "HASH_DEFINE_OWN_STDINT is deprecated; please use HASH_NO_STDINT instead" -typedef unsigned int uint32_t; -typedef unsigned char uint8_t; -#elif defined(HASH_NO_STDINT) && HASH_NO_STDINT -#else -#include /* uint8_t, uint32_t */ -#endif - -/* These macros use decltype or the earlier __typeof GNU extension. - As decltype is only available in newer compilers (VS2010 or gcc 4.3+ - when compiling c++ source) this code uses whatever method is needed - or, for VS2008 where neither is available, uses casting workarounds. */ -#if !defined(DECLTYPE) && !defined(NO_DECLTYPE) -#if defined(_MSC_VER) /* MS compiler */ -#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ -#define DECLTYPE(x) (decltype(x)) -#else /* VS2008 or older (or VS2010 in C mode) */ -#define NO_DECLTYPE -#endif -#elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__) -#define NO_DECLTYPE -#else /* GNU, Sun and other compilers */ -#define DECLTYPE(x) (__typeof(x)) -#endif -#endif - -#ifdef NO_DECLTYPE -#define DECLTYPE(x) -#define DECLTYPE_ASSIGN(dst,src) \ -do { \ - char **_da_dst = (char**)(&(dst)); \ - *_da_dst = (char*)(src); \ -} while (0) -#else -#define DECLTYPE_ASSIGN(dst,src) \ -do { \ - (dst) = DECLTYPE(dst)(src); \ -} while (0) -#endif - -#ifndef uthash_malloc -#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ -#endif -#ifndef uthash_free -#define uthash_free(ptr,sz) free(ptr) /* free fcn */ -#endif -#ifndef uthash_bzero -#define uthash_bzero(a,n) memset(a,'\0',n) -#endif -#ifndef uthash_strlen -#define uthash_strlen(s) strlen(s) -#endif - -#ifndef HASH_FUNCTION -#define HASH_FUNCTION(keyptr,keylen,hashv) HASH_JEN(keyptr, keylen, hashv) -#endif - -#ifndef HASH_KEYCMP -#define HASH_KEYCMP(a,b,n) memcmp(a,b,n) -#endif - -#ifndef uthash_noexpand_fyi -#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ -#endif -#ifndef uthash_expand_fyi -#define uthash_expand_fyi(tbl) /* can be defined to log expands */ -#endif - -#ifndef HASH_NONFATAL_OOM -#define HASH_NONFATAL_OOM 0 -#endif - -#if HASH_NONFATAL_OOM -/* malloc failures can be recovered from */ - -#ifndef uthash_nonfatal_oom -#define uthash_nonfatal_oom(obj) do {} while (0) /* non-fatal OOM error */ -#endif - -#define HASH_RECORD_OOM(oomed) do { (oomed) = 1; } while (0) -#define IF_HASH_NONFATAL_OOM(x) x - -#else -/* malloc failures result in lost memory, hash tables are unusable */ - -#ifndef uthash_fatal -#define uthash_fatal(msg) exit(-1) /* fatal OOM error */ -#endif - -#define HASH_RECORD_OOM(oomed) uthash_fatal("out of memory") -#define IF_HASH_NONFATAL_OOM(x) - -#endif - -/* initial number of buckets */ -#define HASH_INITIAL_NUM_BUCKETS 32U /* initial number of buckets */ -#define HASH_INITIAL_NUM_BUCKETS_LOG2 5U /* lg2 of initial number of buckets */ -#define HASH_BKT_CAPACITY_THRESH 10U /* expand when bucket count reaches */ - -/* calculate the element whose hash handle address is hhp */ -#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) -/* calculate the hash handle from element address elp */ -#define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle*)(void*)(((char*)(elp)) + ((tbl)->hho))) - -#define HASH_ROLLBACK_BKT(hh, head, itemptrhh) \ -do { \ - struct UT_hash_handle *_hd_hh_item = (itemptrhh); \ - unsigned _hd_bkt; \ - HASH_TO_BKT(_hd_hh_item->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ - (head)->hh.tbl->buckets[_hd_bkt].count++; \ - _hd_hh_item->hh_next = NULL; \ - _hd_hh_item->hh_prev = NULL; \ -} while (0) - -#define HASH_VALUE(keyptr,keylen,hashv) \ -do { \ - HASH_FUNCTION(keyptr, keylen, hashv); \ -} while (0) - -#define HASH_FIND_BYHASHVALUE(hh,head,keyptr,keylen,hashval,out) \ -do { \ - (out) = NULL; \ - if (head) { \ - unsigned _hf_bkt; \ - HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt); \ - if (HASH_BLOOM_TEST((head)->hh.tbl, hashval) != 0) { \ - HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], keyptr, keylen, hashval, out); \ - } \ - } \ -} while (0) - -#define HASH_FIND(hh,head,keyptr,keylen,out) \ -do { \ - (out) = NULL; \ - if (head) { \ - unsigned _hf_hashv; \ - HASH_VALUE(keyptr, keylen, _hf_hashv); \ - HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out); \ - } \ -} while (0) - -#ifdef HASH_BLOOM -#define HASH_BLOOM_BITLEN (1UL << HASH_BLOOM) -#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8UL) + (((HASH_BLOOM_BITLEN%8UL)!=0UL) ? 1UL : 0UL) -#define HASH_BLOOM_MAKE(tbl,oomed) \ -do { \ - (tbl)->bloom_nbits = HASH_BLOOM; \ - (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ - if (!(tbl)->bloom_bv) { \ - HASH_RECORD_OOM(oomed); \ - } else { \ - uthash_bzero((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ - (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ - } \ -} while (0) - -#define HASH_BLOOM_FREE(tbl) \ -do { \ - uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ -} while (0) - -#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8U] |= (1U << ((idx)%8U))) -#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8U] & (1U << ((idx)%8U))) - -#define HASH_BLOOM_ADD(tbl,hashv) \ - HASH_BLOOM_BITSET((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) - -#define HASH_BLOOM_TEST(tbl,hashv) \ - HASH_BLOOM_BITTEST((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) - -#else -#define HASH_BLOOM_MAKE(tbl,oomed) -#define HASH_BLOOM_FREE(tbl) -#define HASH_BLOOM_ADD(tbl,hashv) -#define HASH_BLOOM_TEST(tbl,hashv) (1) -#define HASH_BLOOM_BYTELEN 0U -#endif - -#define HASH_MAKE_TABLE(hh,head,oomed) \ -do { \ - (head)->hh.tbl = (UT_hash_table*)uthash_malloc(sizeof(UT_hash_table)); \ - if (!(head)->hh.tbl) { \ - HASH_RECORD_OOM(oomed); \ - } else { \ - uthash_bzero((head)->hh.tbl, sizeof(UT_hash_table)); \ - (head)->hh.tbl->tail = &((head)->hh); \ - (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ - (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ - (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ - (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ - HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ - (head)->hh.tbl->signature = HASH_SIGNATURE; \ - if (!(head)->hh.tbl->buckets) { \ - HASH_RECORD_OOM(oomed); \ - uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ - } else { \ - uthash_bzero((head)->hh.tbl->buckets, \ - HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ - HASH_BLOOM_MAKE((head)->hh.tbl, oomed); \ - IF_HASH_NONFATAL_OOM( \ - if (oomed) { \ - uthash_free((head)->hh.tbl->buckets, \ - HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ - uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ - } \ - ) \ - } \ - } \ -} while (0) - -#define HASH_REPLACE_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,replaced,cmpfcn) \ -do { \ - (replaced) = NULL; \ - HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ - if (replaced) { \ - HASH_DELETE(hh, head, replaced); \ - } \ - HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn); \ -} while (0) - -#define HASH_REPLACE_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add,replaced) \ -do { \ - (replaced) = NULL; \ - HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ - if (replaced) { \ - HASH_DELETE(hh, head, replaced); \ - } \ - HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add); \ -} while (0) - -#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \ -do { \ - unsigned _hr_hashv; \ - HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ - HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced); \ -} while (0) - -#define HASH_REPLACE_INORDER(hh,head,fieldname,keylen_in,add,replaced,cmpfcn) \ -do { \ - unsigned _hr_hashv; \ - HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ - HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced, cmpfcn); \ -} while (0) - -#define HASH_APPEND_LIST(hh, head, add) \ -do { \ - (add)->hh.next = NULL; \ - (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ - (head)->hh.tbl->tail->next = (add); \ - (head)->hh.tbl->tail = &((add)->hh); \ -} while (0) - -#define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \ -do { \ - do { \ - if (cmpfcn(DECLTYPE(head)(_hs_iter), add) > 0) { \ - break; \ - } \ - } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ -} while (0) - -#ifdef NO_DECLTYPE -#undef HASH_AKBI_INNER_LOOP -#define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \ -do { \ - char *_hs_saved_head = (char*)(head); \ - do { \ - DECLTYPE_ASSIGN(head, _hs_iter); \ - if (cmpfcn(head, add) > 0) { \ - DECLTYPE_ASSIGN(head, _hs_saved_head); \ - break; \ - } \ - DECLTYPE_ASSIGN(head, _hs_saved_head); \ - } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ -} while (0) -#endif - -#if HASH_NONFATAL_OOM - -#define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \ -do { \ - if (!(oomed)) { \ - unsigned _ha_bkt; \ - (head)->hh.tbl->num_items++; \ - HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ - HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \ - if (oomed) { \ - HASH_ROLLBACK_BKT(hh, head, &(add)->hh); \ - HASH_DELETE_HH(hh, head, &(add)->hh); \ - (add)->hh.tbl = NULL; \ - uthash_nonfatal_oom(add); \ - } else { \ - HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ - HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ - } \ - } else { \ - (add)->hh.tbl = NULL; \ - uthash_nonfatal_oom(add); \ - } \ -} while (0) - -#else - -#define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \ -do { \ - unsigned _ha_bkt; \ - (head)->hh.tbl->num_items++; \ - HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ - HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \ - HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ - HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ -} while (0) - -#endif - - -#define HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh,head,keyptr,keylen_in,hashval,add,cmpfcn) \ -do { \ - IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \ - (add)->hh.hashv = (hashval); \ - (add)->hh.key = (char*) (keyptr); \ - (add)->hh.keylen = (unsigned) (keylen_in); \ - if (!(head)) { \ - (add)->hh.next = NULL; \ - (add)->hh.prev = NULL; \ - HASH_MAKE_TABLE(hh, add, _ha_oomed); \ - IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \ - (head) = (add); \ - IF_HASH_NONFATAL_OOM( } ) \ - } else { \ - void *_hs_iter = (head); \ - (add)->hh.tbl = (head)->hh.tbl; \ - HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn); \ - if (_hs_iter) { \ - (add)->hh.next = _hs_iter; \ - if (((add)->hh.prev = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev)) { \ - HH_FROM_ELMT((head)->hh.tbl, (add)->hh.prev)->next = (add); \ - } else { \ - (head) = (add); \ - } \ - HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev = (add); \ - } else { \ - HASH_APPEND_LIST(hh, head, add); \ - } \ - } \ - HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ - HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE_INORDER"); \ -} while (0) - -#define HASH_ADD_KEYPTR_INORDER(hh,head,keyptr,keylen_in,add,cmpfcn) \ -do { \ - unsigned _hs_hashv; \ - HASH_VALUE(keyptr, keylen_in, _hs_hashv); \ - HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, _hs_hashv, add, cmpfcn); \ -} while (0) - -#define HASH_ADD_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,cmpfcn) \ - HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn) - -#define HASH_ADD_INORDER(hh,head,fieldname,keylen_in,add,cmpfcn) \ - HASH_ADD_KEYPTR_INORDER(hh, head, &((add)->fieldname), keylen_in, add, cmpfcn) - -#define HASH_ADD_KEYPTR_BYHASHVALUE(hh,head,keyptr,keylen_in,hashval,add) \ -do { \ - IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \ - (add)->hh.hashv = (hashval); \ - (add)->hh.key = (const void*) (keyptr); \ - (add)->hh.keylen = (unsigned) (keylen_in); \ - if (!(head)) { \ - (add)->hh.next = NULL; \ - (add)->hh.prev = NULL; \ - HASH_MAKE_TABLE(hh, add, _ha_oomed); \ - IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \ - (head) = (add); \ - IF_HASH_NONFATAL_OOM( } ) \ - } else { \ - (add)->hh.tbl = (head)->hh.tbl; \ - HASH_APPEND_LIST(hh, head, add); \ - } \ - HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ - HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE"); \ -} while (0) - -#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ -do { \ - unsigned _ha_hashv; \ - HASH_VALUE(keyptr, keylen_in, _ha_hashv); \ - HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, _ha_hashv, add); \ -} while (0) - -#define HASH_ADD_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add) \ - HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add) - -#define HASH_ADD(hh,head,fieldname,keylen_in,add) \ - HASH_ADD_KEYPTR(hh, head, &((add)->fieldname), keylen_in, add) - -#define HASH_TO_BKT(hashv,num_bkts,bkt) \ -do { \ - bkt = ((hashv) & ((num_bkts) - 1U)); \ -} while (0) - -/* delete "delptr" from the hash table. - * "the usual" patch-up process for the app-order doubly-linked-list. - * The use of _hd_hh_del below deserves special explanation. - * These used to be expressed using (delptr) but that led to a bug - * if someone used the same symbol for the head and deletee, like - * HASH_DELETE(hh,users,users); - * We want that to work, but by changing the head (users) below - * we were forfeiting our ability to further refer to the deletee (users) - * in the patch-up process. Solution: use scratch space to - * copy the deletee pointer, then the latter references are via that - * scratch pointer rather than through the repointed (users) symbol. - */ -#define HASH_DELETE(hh,head,delptr) \ - HASH_DELETE_HH(hh, head, &(delptr)->hh) - -#define HASH_DELETE_HH(hh,head,delptrhh) \ -do { \ - struct UT_hash_handle *_hd_hh_del = (delptrhh); \ - if ((_hd_hh_del->prev == NULL) && (_hd_hh_del->next == NULL)) { \ - HASH_BLOOM_FREE((head)->hh.tbl); \ - uthash_free((head)->hh.tbl->buckets, \ - (head)->hh.tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ - uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ - (head) = NULL; \ - } else { \ - unsigned _hd_bkt; \ - if (_hd_hh_del == (head)->hh.tbl->tail) { \ - (head)->hh.tbl->tail = HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev); \ - } \ - if (_hd_hh_del->prev != NULL) { \ - HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev)->next = _hd_hh_del->next; \ - } else { \ - DECLTYPE_ASSIGN(head, _hd_hh_del->next); \ - } \ - if (_hd_hh_del->next != NULL) { \ - HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->next)->prev = _hd_hh_del->prev; \ - } \ - HASH_TO_BKT(_hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ - HASH_DEL_IN_BKT((head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ - (head)->hh.tbl->num_items--; \ - } \ - HASH_FSCK(hh, head, "HASH_DELETE_HH"); \ -} while (0) - -/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ -#define HASH_FIND_STR(head,findstr,out) \ -do { \ - unsigned _uthash_hfstr_keylen = (unsigned)uthash_strlen(findstr); \ - HASH_FIND(hh, head, findstr, _uthash_hfstr_keylen, out); \ -} while (0) -#define HASH_ADD_STR(head,strfield,add) \ -do { \ - unsigned _uthash_hastr_keylen = (unsigned)uthash_strlen((add)->strfield); \ - HASH_ADD(hh, head, strfield[0], _uthash_hastr_keylen, add); \ -} while (0) -#define HASH_REPLACE_STR(head,strfield,add,replaced) \ -do { \ - unsigned _uthash_hrstr_keylen = (unsigned)uthash_strlen((add)->strfield); \ - HASH_REPLACE(hh, head, strfield[0], _uthash_hrstr_keylen, add, replaced); \ -} while (0) -#define HASH_FIND_INT(head,findint,out) \ - HASH_FIND(hh,head,findint,sizeof(int),out) -#define HASH_ADD_INT(head,intfield,add) \ - HASH_ADD(hh,head,intfield,sizeof(int),add) -#define HASH_REPLACE_INT(head,intfield,add,replaced) \ - HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced) -#define HASH_FIND_PTR(head,findptr,out) \ - HASH_FIND(hh,head,findptr,sizeof(void *),out) -#define HASH_ADD_PTR(head,ptrfield,add) \ - HASH_ADD(hh,head,ptrfield,sizeof(void *),add) -#define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \ - HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced) -#define HASH_DEL(head,delptr) \ - HASH_DELETE(hh,head,delptr) - -/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. - * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. - */ -#ifdef HASH_DEBUG -#include /* fprintf, stderr */ -#define HASH_OOPS(...) do { fprintf(stderr, __VA_ARGS__); exit(-1); } while (0) -#define HASH_FSCK(hh,head,where) \ -do { \ - struct UT_hash_handle *_thh; \ - if (head) { \ - unsigned _bkt_i; \ - unsigned _count = 0; \ - char *_prev; \ - for (_bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; ++_bkt_i) { \ - unsigned _bkt_count = 0; \ - _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ - _prev = NULL; \ - while (_thh) { \ - if (_prev != (char*)(_thh->hh_prev)) { \ - HASH_OOPS("%s: invalid hh_prev %p, actual %p\n", \ - (where), (void*)_thh->hh_prev, (void*)_prev); \ - } \ - _bkt_count++; \ - _prev = (char*)(_thh); \ - _thh = _thh->hh_next; \ - } \ - _count += _bkt_count; \ - if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ - HASH_OOPS("%s: invalid bucket count %u, actual %u\n", \ - (where), (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ - } \ - } \ - if (_count != (head)->hh.tbl->num_items) { \ - HASH_OOPS("%s: invalid hh item count %u, actual %u\n", \ - (where), (head)->hh.tbl->num_items, _count); \ - } \ - _count = 0; \ - _prev = NULL; \ - _thh = &(head)->hh; \ - while (_thh) { \ - _count++; \ - if (_prev != (char*)_thh->prev) { \ - HASH_OOPS("%s: invalid prev %p, actual %p\n", \ - (where), (void*)_thh->prev, (void*)_prev); \ - } \ - _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ - _thh = (_thh->next ? HH_FROM_ELMT((head)->hh.tbl, _thh->next) : NULL); \ - } \ - if (_count != (head)->hh.tbl->num_items) { \ - HASH_OOPS("%s: invalid app item count %u, actual %u\n", \ - (where), (head)->hh.tbl->num_items, _count); \ - } \ - } \ -} while (0) -#else -#define HASH_FSCK(hh,head,where) -#endif - -/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to - * the descriptor to which this macro is defined for tuning the hash function. - * The app can #include to get the prototype for write(2). */ -#ifdef HASH_EMIT_KEYS -#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ -do { \ - unsigned _klen = fieldlen; \ - write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ - write(HASH_EMIT_KEYS, keyptr, (unsigned long)fieldlen); \ -} while (0) -#else -#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) -#endif - -/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */ -#define HASH_BER(key,keylen,hashv) \ -do { \ - unsigned _hb_keylen = (unsigned)keylen; \ - const unsigned char *_hb_key = (const unsigned char*)(key); \ - (hashv) = 0; \ - while (_hb_keylen-- != 0U) { \ - (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; \ - } \ -} while (0) - - -/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at - * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ -#define HASH_SAX(key,keylen,hashv) \ -do { \ - unsigned _sx_i; \ - const unsigned char *_hs_key = (const unsigned char*)(key); \ - hashv = 0; \ - for (_sx_i=0; _sx_i < keylen; _sx_i++) { \ - hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ - } \ -} while (0) -/* FNV-1a variation */ -#define HASH_FNV(key,keylen,hashv) \ -do { \ - unsigned _fn_i; \ - const unsigned char *_hf_key = (const unsigned char*)(key); \ - (hashv) = 2166136261U; \ - for (_fn_i=0; _fn_i < keylen; _fn_i++) { \ - hashv = hashv ^ _hf_key[_fn_i]; \ - hashv = hashv * 16777619U; \ - } \ -} while (0) - -#define HASH_OAT(key,keylen,hashv) \ -do { \ - unsigned _ho_i; \ - const unsigned char *_ho_key=(const unsigned char*)(key); \ - hashv = 0; \ - for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ - hashv += _ho_key[_ho_i]; \ - hashv += (hashv << 10); \ - hashv ^= (hashv >> 6); \ - } \ - hashv += (hashv << 3); \ - hashv ^= (hashv >> 11); \ - hashv += (hashv << 15); \ -} while (0) - -#define HASH_JEN_MIX(a,b,c) \ -do { \ - a -= b; a -= c; a ^= ( c >> 13 ); \ - b -= c; b -= a; b ^= ( a << 8 ); \ - c -= a; c -= b; c ^= ( b >> 13 ); \ - a -= b; a -= c; a ^= ( c >> 12 ); \ - b -= c; b -= a; b ^= ( a << 16 ); \ - c -= a; c -= b; c ^= ( b >> 5 ); \ - a -= b; a -= c; a ^= ( c >> 3 ); \ - b -= c; b -= a; b ^= ( a << 10 ); \ - c -= a; c -= b; c ^= ( b >> 15 ); \ -} while (0) - -#define HASH_JEN(key,keylen,hashv) \ -do { \ - unsigned _hj_i,_hj_j,_hj_k; \ - unsigned const char *_hj_key=(unsigned const char*)(key); \ - hashv = 0xfeedbeefu; \ - _hj_i = _hj_j = 0x9e3779b9u; \ - _hj_k = (unsigned)(keylen); \ - while (_hj_k >= 12U) { \ - _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ - + ( (unsigned)_hj_key[2] << 16 ) \ - + ( (unsigned)_hj_key[3] << 24 ) ); \ - _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ - + ( (unsigned)_hj_key[6] << 16 ) \ - + ( (unsigned)_hj_key[7] << 24 ) ); \ - hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ - + ( (unsigned)_hj_key[10] << 16 ) \ - + ( (unsigned)_hj_key[11] << 24 ) ); \ - \ - HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ - \ - _hj_key += 12; \ - _hj_k -= 12U; \ - } \ - hashv += (unsigned)(keylen); \ - switch ( _hj_k ) { \ - case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); /* FALLTHROUGH */ \ - case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); /* FALLTHROUGH */ \ - case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); /* FALLTHROUGH */ \ - case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); /* FALLTHROUGH */ \ - case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); /* FALLTHROUGH */ \ - case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); /* FALLTHROUGH */ \ - case 5: _hj_j += _hj_key[4]; /* FALLTHROUGH */ \ - case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); /* FALLTHROUGH */ \ - case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); /* FALLTHROUGH */ \ - case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); /* FALLTHROUGH */ \ - case 1: _hj_i += _hj_key[0]; /* FALLTHROUGH */ \ - default: ; \ - } \ - HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ -} while (0) - -/* The Paul Hsieh hash function */ -#undef get16bits -#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ - || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) -#define get16bits(d) (*((const uint16_t *) (d))) -#endif - -#if !defined (get16bits) -#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ - +(uint32_t)(((const uint8_t *)(d))[0]) ) -#endif -#define HASH_SFH(key,keylen,hashv) \ -do { \ - unsigned const char *_sfh_key=(unsigned const char*)(key); \ - uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen; \ - \ - unsigned _sfh_rem = _sfh_len & 3U; \ - _sfh_len >>= 2; \ - hashv = 0xcafebabeu; \ - \ - /* Main loop */ \ - for (;_sfh_len > 0U; _sfh_len--) { \ - hashv += get16bits (_sfh_key); \ - _sfh_tmp = ((uint32_t)(get16bits (_sfh_key+2)) << 11) ^ hashv; \ - hashv = (hashv << 16) ^ _sfh_tmp; \ - _sfh_key += 2U*sizeof (uint16_t); \ - hashv += hashv >> 11; \ - } \ - \ - /* Handle end cases */ \ - switch (_sfh_rem) { \ - case 3: hashv += get16bits (_sfh_key); \ - hashv ^= hashv << 16; \ - hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)]) << 18; \ - hashv += hashv >> 11; \ - break; \ - case 2: hashv += get16bits (_sfh_key); \ - hashv ^= hashv << 11; \ - hashv += hashv >> 17; \ - break; \ - case 1: hashv += *_sfh_key; \ - hashv ^= hashv << 10; \ - hashv += hashv >> 1; \ - break; \ - default: ; \ - } \ - \ - /* Force "avalanching" of final 127 bits */ \ - hashv ^= hashv << 3; \ - hashv += hashv >> 5; \ - hashv ^= hashv << 4; \ - hashv += hashv >> 17; \ - hashv ^= hashv << 25; \ - hashv += hashv >> 6; \ -} while (0) - -/* iterate over items in a known bucket to find desired item */ -#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,hashval,out) \ -do { \ - if ((head).hh_head != NULL) { \ - DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (head).hh_head)); \ - } else { \ - (out) = NULL; \ - } \ - while ((out) != NULL) { \ - if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) { \ - if (HASH_KEYCMP((out)->hh.key, keyptr, keylen_in) == 0) { \ - break; \ - } \ - } \ - if ((out)->hh.hh_next != NULL) { \ - DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (out)->hh.hh_next)); \ - } else { \ - (out) = NULL; \ - } \ - } \ -} while (0) - -/* add an item to a bucket */ -#define HASH_ADD_TO_BKT(head,hh,addhh,oomed) \ -do { \ - UT_hash_bucket *_ha_head = &(head); \ - _ha_head->count++; \ - (addhh)->hh_next = _ha_head->hh_head; \ - (addhh)->hh_prev = NULL; \ - if (_ha_head->hh_head != NULL) { \ - _ha_head->hh_head->hh_prev = (addhh); \ - } \ - _ha_head->hh_head = (addhh); \ - if ((_ha_head->count >= ((_ha_head->expand_mult + 1U) * HASH_BKT_CAPACITY_THRESH)) \ - && !(addhh)->tbl->noexpand) { \ - HASH_EXPAND_BUCKETS(addhh,(addhh)->tbl, oomed); \ - IF_HASH_NONFATAL_OOM( \ - if (oomed) { \ - HASH_DEL_IN_BKT(head,addhh); \ - } \ - ) \ - } \ -} while (0) - -/* remove an item from a given bucket */ -#define HASH_DEL_IN_BKT(head,delhh) \ -do { \ - UT_hash_bucket *_hd_head = &(head); \ - _hd_head->count--; \ - if (_hd_head->hh_head == (delhh)) { \ - _hd_head->hh_head = (delhh)->hh_next; \ - } \ - if ((delhh)->hh_prev) { \ - (delhh)->hh_prev->hh_next = (delhh)->hh_next; \ - } \ - if ((delhh)->hh_next) { \ - (delhh)->hh_next->hh_prev = (delhh)->hh_prev; \ - } \ -} while (0) - -/* Bucket expansion has the effect of doubling the number of buckets - * and redistributing the items into the new buckets. Ideally the - * items will distribute more or less evenly into the new buckets - * (the extent to which this is true is a measure of the quality of - * the hash function as it applies to the key domain). - * - * With the items distributed into more buckets, the chain length - * (item count) in each bucket is reduced. Thus by expanding buckets - * the hash keeps a bound on the chain length. This bounded chain - * length is the essence of how a hash provides constant time lookup. - * - * The calculation of tbl->ideal_chain_maxlen below deserves some - * explanation. First, keep in mind that we're calculating the ideal - * maximum chain length based on the *new* (doubled) bucket count. - * In fractions this is just n/b (n=number of items,b=new num buckets). - * Since the ideal chain length is an integer, we want to calculate - * ceil(n/b). We don't depend on floating point arithmetic in this - * hash, so to calculate ceil(n/b) with integers we could write - * - * ceil(n/b) = (n/b) + ((n%b)?1:0) - * - * and in fact a previous version of this hash did just that. - * But now we have improved things a bit by recognizing that b is - * always a power of two. We keep its base 2 log handy (call it lb), - * so now we can write this with a bit shift and logical AND: - * - * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) - * - */ -#define HASH_EXPAND_BUCKETS(hh,tbl,oomed) \ -do { \ - unsigned _he_bkt; \ - unsigned _he_bkt_i; \ - struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ - UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ - _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ - sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \ - if (!_he_new_buckets) { \ - HASH_RECORD_OOM(oomed); \ - } else { \ - uthash_bzero(_he_new_buckets, \ - sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \ - (tbl)->ideal_chain_maxlen = \ - ((tbl)->num_items >> ((tbl)->log2_num_buckets+1U)) + \ - ((((tbl)->num_items & (((tbl)->num_buckets*2U)-1U)) != 0U) ? 1U : 0U); \ - (tbl)->nonideal_items = 0; \ - for (_he_bkt_i = 0; _he_bkt_i < (tbl)->num_buckets; _he_bkt_i++) { \ - _he_thh = (tbl)->buckets[ _he_bkt_i ].hh_head; \ - while (_he_thh != NULL) { \ - _he_hh_nxt = _he_thh->hh_next; \ - HASH_TO_BKT(_he_thh->hashv, (tbl)->num_buckets * 2U, _he_bkt); \ - _he_newbkt = &(_he_new_buckets[_he_bkt]); \ - if (++(_he_newbkt->count) > (tbl)->ideal_chain_maxlen) { \ - (tbl)->nonideal_items++; \ - if (_he_newbkt->count > _he_newbkt->expand_mult * (tbl)->ideal_chain_maxlen) { \ - _he_newbkt->expand_mult++; \ - } \ - } \ - _he_thh->hh_prev = NULL; \ - _he_thh->hh_next = _he_newbkt->hh_head; \ - if (_he_newbkt->hh_head != NULL) { \ - _he_newbkt->hh_head->hh_prev = _he_thh; \ - } \ - _he_newbkt->hh_head = _he_thh; \ - _he_thh = _he_hh_nxt; \ - } \ - } \ - uthash_free((tbl)->buckets, (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ - (tbl)->num_buckets *= 2U; \ - (tbl)->log2_num_buckets++; \ - (tbl)->buckets = _he_new_buckets; \ - (tbl)->ineff_expands = ((tbl)->nonideal_items > ((tbl)->num_items >> 1)) ? \ - ((tbl)->ineff_expands+1U) : 0U; \ - if ((tbl)->ineff_expands > 1U) { \ - (tbl)->noexpand = 1; \ - uthash_noexpand_fyi(tbl); \ - } \ - uthash_expand_fyi(tbl); \ - } \ -} while (0) - - -/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ -/* Note that HASH_SORT assumes the hash handle name to be hh. - * HASH_SRT was added to allow the hash handle name to be passed in. */ -#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) -#define HASH_SRT(hh,head,cmpfcn) \ -do { \ - unsigned _hs_i; \ - unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ - struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ - if (head != NULL) { \ - _hs_insize = 1; \ - _hs_looping = 1; \ - _hs_list = &((head)->hh); \ - while (_hs_looping != 0U) { \ - _hs_p = _hs_list; \ - _hs_list = NULL; \ - _hs_tail = NULL; \ - _hs_nmerges = 0; \ - while (_hs_p != NULL) { \ - _hs_nmerges++; \ - _hs_q = _hs_p; \ - _hs_psize = 0; \ - for (_hs_i = 0; _hs_i < _hs_insize; ++_hs_i) { \ - _hs_psize++; \ - _hs_q = ((_hs_q->next != NULL) ? \ - HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ - if (_hs_q == NULL) { \ - break; \ - } \ - } \ - _hs_qsize = _hs_insize; \ - while ((_hs_psize != 0U) || ((_hs_qsize != 0U) && (_hs_q != NULL))) { \ - if (_hs_psize == 0U) { \ - _hs_e = _hs_q; \ - _hs_q = ((_hs_q->next != NULL) ? \ - HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ - _hs_qsize--; \ - } else if ((_hs_qsize == 0U) || (_hs_q == NULL)) { \ - _hs_e = _hs_p; \ - if (_hs_p != NULL) { \ - _hs_p = ((_hs_p->next != NULL) ? \ - HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ - } \ - _hs_psize--; \ - } else if ((cmpfcn( \ - DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_p)), \ - DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_q)) \ - )) <= 0) { \ - _hs_e = _hs_p; \ - if (_hs_p != NULL) { \ - _hs_p = ((_hs_p->next != NULL) ? \ - HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ - } \ - _hs_psize--; \ - } else { \ - _hs_e = _hs_q; \ - _hs_q = ((_hs_q->next != NULL) ? \ - HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ - _hs_qsize--; \ - } \ - if ( _hs_tail != NULL ) { \ - _hs_tail->next = ((_hs_e != NULL) ? \ - ELMT_FROM_HH((head)->hh.tbl, _hs_e) : NULL); \ - } else { \ - _hs_list = _hs_e; \ - } \ - if (_hs_e != NULL) { \ - _hs_e->prev = ((_hs_tail != NULL) ? \ - ELMT_FROM_HH((head)->hh.tbl, _hs_tail) : NULL); \ - } \ - _hs_tail = _hs_e; \ - } \ - _hs_p = _hs_q; \ - } \ - if (_hs_tail != NULL) { \ - _hs_tail->next = NULL; \ - } \ - if (_hs_nmerges <= 1U) { \ - _hs_looping = 0; \ - (head)->hh.tbl->tail = _hs_tail; \ - DECLTYPE_ASSIGN(head, ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ - } \ - _hs_insize *= 2U; \ - } \ - HASH_FSCK(hh, head, "HASH_SRT"); \ - } \ -} while (0) - -/* This function selects items from one hash into another hash. - * The end result is that the selected items have dual presence - * in both hashes. There is no copy of the items made; rather - * they are added into the new hash through a secondary hash - * hash handle that must be present in the structure. */ -#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ -do { \ - unsigned _src_bkt, _dst_bkt; \ - void *_last_elt = NULL, *_elt; \ - UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ - ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ - if ((src) != NULL) { \ - for (_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ - for (_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ - _src_hh != NULL; \ - _src_hh = _src_hh->hh_next) { \ - _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ - if (cond(_elt)) { \ - IF_HASH_NONFATAL_OOM( int _hs_oomed = 0; ) \ - _dst_hh = (UT_hash_handle*)(void*)(((char*)_elt) + _dst_hho); \ - _dst_hh->key = _src_hh->key; \ - _dst_hh->keylen = _src_hh->keylen; \ - _dst_hh->hashv = _src_hh->hashv; \ - _dst_hh->prev = _last_elt; \ - _dst_hh->next = NULL; \ - if (_last_elt_hh != NULL) { \ - _last_elt_hh->next = _elt; \ - } \ - if ((dst) == NULL) { \ - DECLTYPE_ASSIGN(dst, _elt); \ - HASH_MAKE_TABLE(hh_dst, dst, _hs_oomed); \ - IF_HASH_NONFATAL_OOM( \ - if (_hs_oomed) { \ - uthash_nonfatal_oom(_elt); \ - (dst) = NULL; \ - continue; \ - } \ - ) \ - } else { \ - _dst_hh->tbl = (dst)->hh_dst.tbl; \ - } \ - HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ - HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt], hh_dst, _dst_hh, _hs_oomed); \ - (dst)->hh_dst.tbl->num_items++; \ - IF_HASH_NONFATAL_OOM( \ - if (_hs_oomed) { \ - HASH_ROLLBACK_BKT(hh_dst, dst, _dst_hh); \ - HASH_DELETE_HH(hh_dst, dst, _dst_hh); \ - _dst_hh->tbl = NULL; \ - uthash_nonfatal_oom(_elt); \ - continue; \ - } \ - ) \ - HASH_BLOOM_ADD(_dst_hh->tbl, _dst_hh->hashv); \ - _last_elt = _elt; \ - _last_elt_hh = _dst_hh; \ - } \ - } \ - } \ - } \ - HASH_FSCK(hh_dst, dst, "HASH_SELECT"); \ -} while (0) - -#define HASH_CLEAR(hh,head) \ -do { \ - if ((head) != NULL) { \ - HASH_BLOOM_FREE((head)->hh.tbl); \ - uthash_free((head)->hh.tbl->buckets, \ - (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ - uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ - (head) = NULL; \ - } \ -} while (0) - -#define HASH_OVERHEAD(hh,head) \ - (((head) != NULL) ? ( \ - (size_t)(((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ - ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ - sizeof(UT_hash_table) + \ - (HASH_BLOOM_BYTELEN))) : 0U) - -#ifdef NO_DECLTYPE -#define HASH_ITER(hh,head,el,tmp) \ -for(((el)=(head)), ((*(char**)(&(tmp)))=(char*)((head!=NULL)?(head)->hh.next:NULL)); \ - (el) != NULL; ((el)=(tmp)), ((*(char**)(&(tmp)))=(char*)((tmp!=NULL)?(tmp)->hh.next:NULL))) -#else -#define HASH_ITER(hh,head,el,tmp) \ -for(((el)=(head)), ((tmp)=DECLTYPE(el)((head!=NULL)?(head)->hh.next:NULL)); \ - (el) != NULL; ((el)=(tmp)), ((tmp)=DECLTYPE(el)((tmp!=NULL)?(tmp)->hh.next:NULL))) -#endif - -/* obtain a count of items in the hash */ -#define HASH_COUNT(head) HASH_CNT(hh,head) -#define HASH_CNT(hh,head) ((head != NULL)?((head)->hh.tbl->num_items):0U) - -typedef struct UT_hash_bucket { - struct UT_hash_handle *hh_head; - unsigned count; - - /* expand_mult is normally set to 0. In this situation, the max chain length - * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If - * the bucket's chain exceeds this length, bucket expansion is triggered). - * However, setting expand_mult to a non-zero value delays bucket expansion - * (that would be triggered by additions to this particular bucket) - * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. - * (The multiplier is simply expand_mult+1). The whole idea of this - * multiplier is to reduce bucket expansions, since they are expensive, in - * situations where we know that a particular bucket tends to be overused. - * It is better to let its chain length grow to a longer yet-still-bounded - * value, than to do an O(n) bucket expansion too often. - */ - unsigned expand_mult; - -} UT_hash_bucket; - -/* random signature used only to find hash tables in external analysis */ -#define HASH_SIGNATURE 0xa0111fe1u -#define HASH_BLOOM_SIGNATURE 0xb12220f2u - -typedef struct UT_hash_table { - UT_hash_bucket *buckets; - unsigned num_buckets, log2_num_buckets; - unsigned num_items; - struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ - ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ - - /* in an ideal situation (all buckets used equally), no bucket would have - * more than ceil(#items/#buckets) items. that's the ideal chain length. */ - unsigned ideal_chain_maxlen; - - /* nonideal_items is the number of items in the hash whose chain position - * exceeds the ideal chain maxlen. these items pay the penalty for an uneven - * hash distribution; reaching them in a chain traversal takes >ideal steps */ - unsigned nonideal_items; - - /* ineffective expands occur when a bucket doubling was performed, but - * afterward, more than half the items in the hash had nonideal chain - * positions. If this happens on two consecutive expansions we inhibit any - * further expansion, as it's not helping; this happens when the hash - * function isn't a good fit for the key domain. When expansion is inhibited - * the hash will still work, albeit no longer in constant time. */ - unsigned ineff_expands, noexpand; - - uint32_t signature; /* used only to find hash tables in external analysis */ -#ifdef HASH_BLOOM - uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ - uint8_t *bloom_bv; - uint8_t bloom_nbits; -#endif - -} UT_hash_table; - -typedef struct UT_hash_handle { - struct UT_hash_table *tbl; - void *prev; /* prev element in app order */ - void *next; /* next element in app order */ - struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ - struct UT_hash_handle *hh_next; /* next hh in bucket order */ - const void *key; /* ptr to enclosing struct's key */ - unsigned keylen; /* enclosing struct's key len */ - unsigned hashv; /* result of hash-fcn(key) */ -} UT_hash_handle; - -#endif /* UTHASH_H */