mirror of https://github.com/ValdikSS/GoodbyeDPI
committed by
GitHub
21 changed files with 0 additions and 3820 deletions
@ -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) |
|
@ -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 <windows.h> |
|
||||
#include <stdio.h> |
|
||||
#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; |
|
||||
} |
|
@ -1,2 +0,0 @@ |
|||||
int blackwhitelist_load_list(const char *filename); |
|
||||
int blackwhitelist_check_hostname(const char *host_addr, size_t host_len); |
|
@ -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 <windows.h> |
|
||||
#include <time.h> |
|
||||
#include <stdio.h> |
|
||||
#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; |
|
||||
} |
|
@ -1,39 +0,0 @@ |
|||||
#ifndef _DNSREDIR_H |
|
||||
#define _DNSREDIR_H |
|
||||
#include <stdint.h> |
|
||||
|
|
||||
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 |
|
@ -1,197 +0,0 @@ |
|||||
#include <stdio.h> |
|
||||
#include <stdlib.h> |
|
||||
#include <ctype.h> |
|
||||
#include <unistd.h> |
|
||||
#include <in6addr.h> |
|
||||
#include <ws2tcpip.h> |
|
||||
#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); |
|
||||
} |
|
@ -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 |
|
||||
); |
|
@ -1,2 +0,0 @@ |
|||||
1 24 "goodbyedpi.exe.manifest" |
|
||||
id ICON "icon.ico" |
|
File diff suppressed because it is too large
@ -1,12 +0,0 @@ |
|||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> |
|
||||
<assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="GoodbyeDPI" type="win32"/> |
|
||||
<description>GoodbyeDPI</description> |
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"> |
|
||||
<security> |
|
||||
<requestedPrivileges> |
|
||||
<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/> |
|
||||
</requestedPrivileges> |
|
||||
</security> |
|
||||
</trustInfo> |
|
||||
</assembly> |
|
@ -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(); |
|
Before Width: | Height: | Size: 12 KiB |
@ -1,96 +0,0 @@ |
|||||
#include <windows.h> |
|
||||
#include <stdio.h> |
|
||||
#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; |
|
||||
} |
|
@ -1,3 +0,0 @@ |
|||||
int service_register(); |
|
||||
void service_main(int argc, char *argv[]); |
|
||||
void service_controlhandler(DWORD request); |
|
@ -1,252 +0,0 @@ |
|||||
/**
|
|
||||
* TCP (TTL) Connection Tracker for GoodbyeDPI |
|
||||
* |
|
||||
* Monitors SYN/ACK only, to extract the TTL value of the remote server. |
|
||||
* |
|
||||
*/ |
|
||||
|
|
||||
#include <windows.h> |
|
||||
#include <time.h> |
|
||||
#include <stdio.h> |
|
||||
#include <math.h> |
|
||||
#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; |
|
||||
} |
|
@ -1,27 +0,0 @@ |
|||||
#ifndef _TTLTRACK_H |
|
||||
#define _TTLTRACK_H |
|
||||
#include <stdint.h> |
|
||||
#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 |
|
@ -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 <stdio.h> |
|
||||
#include <stdlib.h> |
|
||||
#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 |
|
@ -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 |
|
@ -1,90 +0,0 @@ |
|||||
#include <string.h> |
|
||||
#include <stdlib.h> |
|
||||
#include <stddef.h> |
|
||||
|
|
||||
#if (__STDC_VERSION__ >= 199901L) |
|
||||
#include <stdint.h> |
|
||||
#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; |
|
||||
} |
|
@ -1 +0,0 @@ |
|||||
char *repl_str(const char *str, const char *from, const char *to); |
|
File diff suppressed because it is too large
Loading…
Reference in new issue