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