diff --git a/README.md b/README.md index 56ac7fe..7f9a757 100644 --- a/README.md +++ b/README.md @@ -17,27 +17,30 @@ Usage: goodbyedpi.exe [OPTION...] -r replace Host with hoSt -s remove space between host header and its value -m mix Host header case (test.com -> tEsT.cOm) - -f [value] set HTTP fragmentation to value - -k [value] enable HTTP persistent (keep-alive) fragmentation and set it to value + -f set HTTP fragmentation to value + -k enable HTTP persistent (keep-alive) fragmentation and set it to value -n do not wait for first segment ACK when -k is enabled - -e [value] set HTTPS fragmentation to value + -e set HTTPS fragmentation to value -a additional space between Method and Request-URI (enables -s, may break sites) -w try to find and parse HTTP traffic on all processed ports (not only on port 80) - --port [value] additional TCP port to perform fragmentation on (and HTTP tricks with -w) - --ip-id [value] handle additional IP ID (decimal, drop redirects and TCP RSTs with this ID). + --port additional TCP port to perform fragmentation on (and HTTP tricks with -w) + --ip-id handle additional IP ID (decimal, drop redirects and TCP RSTs with this ID). This option can be supplied multiple times. - --dns-addr [value] redirect UDP DNS requests to the supplied IP address (experimental) - --dns-port [value] redirect UDP DNS requests to the supplied port (53 by default) - --dnsv6-addr [value] redirect UDPv6 DNS requests to the supplied IPv6 address (experimental) - --dnsv6-port [value] redirect UDPv6 DNS requests to the supplied port (53 by default) + --dns-addr redirect UDP DNS requests to the supplied IP address (experimental) + --dns-port redirect UDP DNS requests to the supplied port (53 by default) + --dnsv6-addr redirect UDPv6 DNS requests to the supplied IPv6 address (experimental) + --dnsv6-port redirect UDPv6 DNS requests to the supplied port (53 by default) --dns-verb print verbose DNS redirection messages - --blacklist [txtfile] perform circumvention tricks only to host names and subdomains from + --blacklist perform circumvention tricks only to host names and subdomains from supplied text file (HTTP Host/TLS SNI). This option can be supplied multiple times. - --set-ttl [value] activate Fake Request Mode and send it with supplied TTL value. + --set-ttl activate Fake Request Mode and send it with supplied TTL value. DANGEROUS! May break websites in unexpected ways. Use with care. + --auto-ttl [decttl] activate Fake Request Mode, automatically detect TTL and decrease + it from standard 64 or 128 by decttl (128/64 - TTL - 2 by default). --wrong-chksum activate Fake Request Mode and send it with incorrect TCP checksum. May not work in a VM or with some routers, but is safer than set-ttl. + --wrong-seq activate Fake Request Mode and send it with TCP SEQ/ACK in the past. --native-frag fragment (split) the packets by sending them in smaller packets, without shrinking the Window Size. Works faster (does not slow down the connection) and better. diff --git a/src/dnsredir.h b/src/dnsredir.h index 106c6fb..d5fed65 100644 --- a/src/dnsredir.h +++ b/src/dnsredir.h @@ -1,3 +1,5 @@ +#ifndef _DNSREDIR_H +#define _DNSREDIR_H #include typedef struct conntrack_info { @@ -34,3 +36,4 @@ int dns_handle_outgoing(const uint32_t srcip[4], const uint16_t srcport, 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 index 5c9dd74..7fa7750 100644 --- a/src/fakepackets.c +++ b/src/fakepackets.c @@ -53,7 +53,8 @@ static int send_fake_data(const HANDLE w_filter, const BOOL is_ipv6, const BOOL is_https, const BYTE set_ttl, - const BYTE set_checksum + const BYTE set_checksum, + const BYTE set_seq ) { char packet_fake[MAX_PACKET_SIZE]; WINDIVERT_ADDRESS addr_new; @@ -69,6 +70,9 @@ static int send_fake_data(const HANDLE w_filter, memcpy(&addr_new, addr, sizeof(WINDIVERT_ADDRESS)); memcpy(packet_fake, pkt, packetLen); + addr_new.PseudoTCPChecksum = 0; + addr_new.PseudoIPChecksum = 0; + if (!is_ipv6) { // IPv4 TCP Data packet if (!WinDivertHelperParsePacket(packet_fake, packetLen, &ppIpHdr, @@ -107,8 +111,15 @@ static int send_fake_data(const HANDLE w_filter, 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 - addr_new.PseudoTCPChecksum = 0; WinDivertHelperCalcChecksums(packet_fake, packetLen_new, &addr_new, NULL); if (set_checksum) { @@ -127,23 +138,46 @@ static int send_fake_data(const HANDLE w_filter, 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_checksum, + const BYTE set_seq ) { - return send_fake_data(w_filter, - addr, - pkt, - packetLen, - is_ipv6, - FALSE, - set_ttl, - set_checksum - ); + 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, @@ -152,15 +186,10 @@ int send_fake_https_request(const HANDLE w_filter, const UINT packetLen, const BOOL is_ipv6, const BYTE set_ttl, - const BYTE set_checksum + const BYTE set_checksum, + const BYTE set_seq ) { - return send_fake_data(w_filter, - addr, - pkt, - packetLen, - is_ipv6, - TRUE, - set_ttl, - set_checksum - ); + 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 index de20c7e..9bb44d4 100644 --- a/src/fakepackets.h +++ b/src/fakepackets.h @@ -4,7 +4,8 @@ int send_fake_http_request(const HANDLE w_filter, const UINT packetLen, const BOOL is_ipv6, const BYTE set_ttl, - const BYTE set_checksum + const BYTE set_checksum, + const BYTE set_seq ); int send_fake_https_request(const HANDLE w_filter, const PWINDIVERT_ADDRESS addr, @@ -12,5 +13,6 @@ int send_fake_https_request(const HANDLE w_filter, const UINT packetLen, const BOOL is_ipv6, const BYTE set_ttl, - const BYTE set_checksum + const BYTE set_checksum, + const BYTE set_seq ); diff --git a/src/goodbyedpi.c b/src/goodbyedpi.c index e9c60af..a17e3f0 100644 --- a/src/goodbyedpi.c +++ b/src/goodbyedpi.c @@ -16,6 +16,7 @@ #include "utils/repl_str.h" #include "service.h" #include "dnsredir.h" +#include "ttltrack.h" #include "blackwhitelist.h" #include "fakepackets.h" @@ -94,6 +95,22 @@ WINSOCK_API_LINKAGE INT WSAAPI inet_pton(INT Family, LPCSTR pStringBuf, PVOID pA } \ } while (0) +#define TCP_HANDLE_OUTGOING_ADJUST_TTL() do { \ + 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))) \ + { \ + ttl_of_fake_packet = tcp_get_auto_ttl(tcp_conn_info.ttl, do_auto_ttl); \ + if (do_tcp_verb) { \ + printf("Connection TTL = %d, Fake TTL = %d\n", tcp_conn_info.ttl, ttl_of_fake_packet); \ + } \ + } \ +} while (0) + static int running_from_service = 0; static HANDLE filters[MAX_FILTERS]; static int filter_num = 0; @@ -124,7 +141,9 @@ static struct option long_options[] = { {"blacklist", required_argument, 0, 'b' }, {"ip-id", required_argument, 0, 'i' }, {"set-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, '(' }, {0, 0, 0, 0 } @@ -487,6 +506,7 @@ int main(int argc, char *argv[]) { 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, @@ -496,9 +516,11 @@ int main(int argc, char *argv[]) { do_http_allports = 0, do_host_mixedcase = 0, do_dnsv4_redirect = 0, do_dnsv6_redirect = 0, - do_dns_verb = 0, do_blacklist = 0, + do_dns_verb = 0, do_tcp_verb = 0, do_blacklist = 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; @@ -695,6 +717,7 @@ int main(int argc, char *argv[]) { break; case 'v': do_dns_verb = 1; + do_tcp_verb = 1; break; case 'b': do_blacklist = 1; @@ -707,10 +730,23 @@ int main(int argc, char *argv[]) { do_fake_packet = 1; ttl_of_fake_packet = atoub(optarg, "Set TTL parameter error!"); break; + case '+': + do_fake_packet = 1; + do_auto_ttl = 2; + if (optarg) { + do_auto_ttl = atoub(optarg, "Set Auto TTL parameter error!"); + } else if (argv[optind] && argv[optind][0] != '-') { + do_auto_ttl = atoub(argv[optind], "Set Auto TTL parameter error!"); + } + break; case '%': do_fake_packet = 1; do_wrong_chksum = 1; break; + case ')': + do_fake_packet = 1; + do_wrong_seq = 1; + break; case '*': do_native_frag = 1; do_fragment_http_persistent = 1; @@ -729,27 +765,29 @@ int main(int argc, char *argv[]) { " -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 [value] set HTTP fragmentation to value\n" - " -k [value] enable HTTP persistent (keep-alive) fragmentation and set it to value\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 [value] set HTTPS fragmentation to value\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 [value] additional TCP port to perform fragmentation on (and HTTP tricks with -w)\n" - " --ip-id [value] handle additional IP ID (decimal, drop redirects and TCP RSTs with this ID).\n" - " --dns-addr [value] redirect UDPv4 DNS requests to the supplied IPv4 address (experimental)\n" - " --dns-port [value] redirect UDPv4 DNS requests to the supplied port (53 by default)\n" - " --dnsv6-addr [value] redirect UDPv6 DNS requests to the supplied IPv6 address (experimental)\n" - " --dnsv6-port [value] redirect UDPv6 DNS requests to the supplied port (53 by default)\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 [txtfile] perform circumvention tricks only to host names and subdomains from\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" - " --set-ttl [value] activate Fake Request Mode and send it with supplied TTL value.\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.\n" - " Could be combined with --wrong-chksum.\n" + " --auto-ttl [decttl] activate Fake Request Mode, automatically detect TTL and decrease\n" + " it from standard 64 or 128 by decttl (128/64 - TTL - 2 by default).\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" @@ -776,14 +814,16 @@ int main(int argc, char *argv[]) { "hoSt: %d\nHost no space: %d\nAdditional space: %d\n" "Mix Host: %d\nHTTP AllPorts: %d\nHTTP Persistent Nowait: %d\n" "DNS redirect: %d\nDNSv6 redirect: %d\n" - "Fake requests, TTL: %hu\nFake requests, wrong checksum: %d\n", + "Fake requests, TTL: %hu (auto: %hu)\nFake requests, wrong checksum: %d\n" + "Fake requests, wrong SEQ/ACK: %d\n", do_passivedpi, (do_fragment_http ? http_fragment_size : 0), (do_fragment_http_persistent ? http_fragment_size : 0), (do_fragment_https ? https_fragment_size : 0), do_native_frag, do_reverse_frag, do_host, do_host_removespace, do_additional_space, do_host_mixedcase, do_http_allports, do_fragment_http_persistent_nowait, do_dnsv4_redirect, - do_dnsv6_redirect, ttl_of_fake_packet, do_wrong_chksum + do_dnsv6_redirect, ttl_of_fake_packet, do_auto_ttl, + do_wrong_chksum, do_wrong_seq ); if (do_fragment_http && http_fragment_size > 2) { @@ -922,8 +962,11 @@ int main(int argc, char *argv[]) { printf("Blocked HTTPS website SNI: %s\n", lsni); #endif if (do_fake_packet) { + if (do_auto_ttl) { + TCP_HANDLE_OUTGOING_ADJUST_TTL(); + } send_fake_https_request(w_filter, &addr, packet, packetLen, packet_v6, - ttl_of_fake_packet, do_wrong_chksum); + ttl_of_fake_packet, do_wrong_chksum, do_wrong_seq); } if (do_native_frag) { // Signal for native fragmentation code handler @@ -963,9 +1006,13 @@ int main(int argc, char *argv[]) { should_recalc_checksum = 1; } - if (do_fake_packet) + if (do_fake_packet) { + if (do_auto_ttl) { + TCP_HANDLE_OUTGOING_ADJUST_TTL(); + } send_fake_http_request(w_filter, &addr, packet, packetLen, packet_v6, - ttl_of_fake_packet, do_wrong_chksum); + ttl_of_fake_packet, do_wrong_chksum, do_wrong_seq); + } if (do_host_mixedcase) { mix_case(host_addr, host_len); @@ -1078,20 +1125,36 @@ int main(int argc, char *argv[]) { else if (packet_type == ipv4_tcp || packet_type == ipv6_tcp) { /* If we got INBOUND SYN+ACK packet */ if (addr.Direction == WINDIVERT_DIRECTION_INBOUND && - ppTcpHdr->Syn == 1 && ppTcpHdr->Ack == 1 && - !do_native_frag) { + 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_fragment_http && ppTcpHdr->SrcPort == htons(80)) { - change_window_size(ppTcpHdr, http_fragment_size); - should_recalc_checksum = 1; + + if (do_fake_packet && do_auto_ttl) { + if (!((packet_v4 && tcp_handle_incoming(&ppIpHdr->SrcAddr, &ppIpHdr->DstAddr, + ppTcpHdr->SrcPort, ppTcpHdr->DstPort, + 0, ppIpHdr->TTL)) + || + (packet_v6 && tcp_handle_incoming(&ppIpV6Hdr->SrcAddr, &ppIpV6Hdr->DstAddr, + ppTcpHdr->SrcPort, ppTcpHdr->DstPort, + 1, ppIpV6Hdr->HopLimit)))) + { + if (do_tcp_verb) + puts("[TCP WARN] Can't add TCP connection record."); + } } - else if (do_fragment_https && ppTcpHdr->SrcPort != htons(80)) { - change_window_size(ppTcpHdr, https_fragment_size); - should_recalc_checksum = 1; + + 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; + } } } } diff --git a/src/ttltrack.c b/src/ttltrack.c new file mode 100644 index 0000000..97aeb82 --- /dev/null +++ b/src/ttltrack.c @@ -0,0 +1,235 @@ +/** + * TCP (TTL) Connection Tracker for GoodbyeDPI + * + * Monitors SYN/ACK only, to extract the TTL value of the remote server. + * + */ + +#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) +{ + 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) +{ + 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(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) +{ + 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(const uint32_t srcip[4], const uint32_t dstip[4], + const uint16_t srcport, const uint16_t dstport, + tcp_conntrack_info_t *conn_info, + const 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 decrease_for) { + uint8_t ttl_of_fake_packet = 0; + + if (ttl > 64 && ttl < 128) { + ttl_of_fake_packet = 128 - ttl - decrease_for; + } + else if (ttl > 34 && ttl < 64) { + ttl_of_fake_packet = 64 - ttl - decrease_for; + } + else { + ttl_of_fake_packet = 0; + } + + return ttl_of_fake_packet; +} \ No newline at end of file diff --git a/src/ttltrack.h b/src/ttltrack.h new file mode 100644 index 0000000..2447588 --- /dev/null +++ b/src/ttltrack.h @@ -0,0 +1,25 @@ +#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(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); + +int tcp_handle_outgoing(const uint32_t srcip[4], const uint32_t dstip[4], + const uint16_t srcport, const uint16_t dstport, + tcp_conntrack_info_t *conn_info, + const uint8_t is_ipv6); + +int tcp_get_auto_ttl(const uint8_t ttl, const uint8_t decrease_for); +#endif