Merge branch 'badseq_for_master' into master

This commit is contained in:
ValdikSS 2021-12-25 12:30:08 +03:00
commit 88d4a60cdf
7 changed files with 421 additions and 61 deletions

View File

@ -17,27 +17,30 @@ Usage: goodbyedpi.exe [OPTION...]
-r replace Host with hoSt -r replace Host with hoSt
-s remove space between host header and its value -s remove space between host header and its value
-m mix Host header case (test.com -> tEsT.cOm) -m mix Host header case (test.com -> tEsT.cOm)
-f [value] set HTTP fragmentation to value -f <value> set HTTP fragmentation to value
-k [value] enable HTTP persistent (keep-alive) fragmentation and set it to value -k <value> enable HTTP persistent (keep-alive) fragmentation and set it to value
-n do not wait for first segment ACK when -k is enabled -n do not wait for first segment ACK when -k is enabled
-e [value] set HTTPS fragmentation to value -e <value> set HTTPS fragmentation to value
-a additional space between Method and Request-URI (enables -s, may break sites) -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) -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) --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). --ip-id <value> handle additional IP ID (decimal, drop redirects and TCP RSTs with this ID).
This option can be supplied multiple times. This option can be supplied multiple times.
--dns-addr [value] redirect UDP DNS requests to the supplied IP address (experimental) --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) --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-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) --dnsv6-port <value> redirect UDPv6 DNS requests to the supplied port (53 by default)
--dns-verb print verbose DNS redirection messages --dns-verb print verbose DNS redirection messages
--blacklist [txtfile] perform circumvention tricks only to host names and subdomains from --blacklist <txtfile> perform circumvention tricks only to host names and subdomains from
supplied text file (HTTP Host/TLS SNI). supplied text file (HTTP Host/TLS SNI).
This option can be supplied multiple times. This option can be supplied multiple times.
--set-ttl [value] activate Fake Request Mode and send it with supplied TTL value. --set-ttl <value> activate Fake Request Mode and send it with supplied TTL value.
DANGEROUS! May break websites in unexpected ways. Use with care. 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. --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. 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 --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) shrinking the Window Size. Works faster (does not slow down the connection)
and better. and better.

View File

@ -1,3 +1,5 @@
#ifndef _DNSREDIR_H
#define _DNSREDIR_H
#include <stdint.h> #include <stdint.h>
typedef struct conntrack_info { 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(); void flush_dns_cache();
int dns_is_dns_packet(const char *packet_data, const UINT packet_dataLen, const int outgoing); int dns_is_dns_packet(const char *packet_data, const UINT packet_dataLen, const int outgoing);
#endif

View File

@ -53,7 +53,8 @@ static int send_fake_data(const HANDLE w_filter,
const BOOL is_ipv6, const BOOL is_ipv6,
const BOOL is_https, const BOOL is_https,
const BYTE set_ttl, const BYTE set_ttl,
const BYTE set_checksum const BYTE set_checksum,
const BYTE set_seq
) { ) {
char packet_fake[MAX_PACKET_SIZE]; char packet_fake[MAX_PACKET_SIZE];
WINDIVERT_ADDRESS addr_new; 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(&addr_new, addr, sizeof(WINDIVERT_ADDRESS));
memcpy(packet_fake, pkt, packetLen); memcpy(packet_fake, pkt, packetLen);
addr_new.PseudoTCPChecksum = 0;
addr_new.PseudoIPChecksum = 0;
if (!is_ipv6) { if (!is_ipv6) {
// IPv4 TCP Data packet // IPv4 TCP Data packet
if (!WinDivertHelperParsePacket(packet_fake, packetLen, &ppIpHdr, if (!WinDivertHelperParsePacket(packet_fake, packetLen, &ppIpHdr,
@ -107,8 +111,15 @@ static int send_fake_data(const HANDLE w_filter,
ppIpV6Hdr->HopLimit = 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 // Recalculate the checksum
addr_new.PseudoTCPChecksum = 0;
WinDivertHelperCalcChecksums(packet_fake, packetLen_new, &addr_new, NULL); WinDivertHelperCalcChecksums(packet_fake, packetLen_new, &addr_new, NULL);
if (set_checksum) { if (set_checksum) {
@ -127,23 +138,46 @@ static int send_fake_data(const HANDLE w_filter,
return 0; 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, int send_fake_http_request(const HANDLE w_filter,
const PWINDIVERT_ADDRESS addr, const PWINDIVERT_ADDRESS addr,
const char *pkt, const char *pkt,
const UINT packetLen, const UINT packetLen,
const BOOL is_ipv6, const BOOL is_ipv6,
const BYTE set_ttl, const BYTE set_ttl,
const BYTE set_checksum const BYTE set_checksum,
const BYTE set_seq
) { ) {
return send_fake_data(w_filter, return send_fake_request(w_filter, addr, pkt, packetLen,
addr, is_ipv6, FALSE,
pkt, set_ttl, set_checksum, set_seq);
packetLen,
is_ipv6,
FALSE,
set_ttl,
set_checksum
);
} }
int send_fake_https_request(const HANDLE w_filter, 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 UINT packetLen,
const BOOL is_ipv6, const BOOL is_ipv6,
const BYTE set_ttl, const BYTE set_ttl,
const BYTE set_checksum const BYTE set_checksum,
const BYTE set_seq
) { ) {
return send_fake_data(w_filter, return send_fake_request(w_filter, addr, pkt, packetLen,
addr, is_ipv6, TRUE,
pkt, set_ttl, set_checksum, set_seq);
packetLen,
is_ipv6,
TRUE,
set_ttl,
set_checksum
);
} }

View File

@ -4,7 +4,8 @@ int send_fake_http_request(const HANDLE w_filter,
const UINT packetLen, const UINT packetLen,
const BOOL is_ipv6, const BOOL is_ipv6,
const BYTE set_ttl, 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, int send_fake_https_request(const HANDLE w_filter,
const PWINDIVERT_ADDRESS addr, const PWINDIVERT_ADDRESS addr,
@ -12,5 +13,6 @@ int send_fake_https_request(const HANDLE w_filter,
const UINT packetLen, const UINT packetLen,
const BOOL is_ipv6, const BOOL is_ipv6,
const BYTE set_ttl, const BYTE set_ttl,
const BYTE set_checksum const BYTE set_checksum,
const BYTE set_seq
); );

View File

@ -16,6 +16,7 @@
#include "utils/repl_str.h" #include "utils/repl_str.h"
#include "service.h" #include "service.h"
#include "dnsredir.h" #include "dnsredir.h"
#include "ttltrack.h"
#include "blackwhitelist.h" #include "blackwhitelist.h"
#include "fakepackets.h" #include "fakepackets.h"
@ -94,6 +95,22 @@ WINSOCK_API_LINKAGE INT WSAAPI inet_pton(INT Family, LPCSTR pStringBuf, PVOID pA
} \ } \
} while (0) } 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 int running_from_service = 0;
static HANDLE filters[MAX_FILTERS]; static HANDLE filters[MAX_FILTERS];
static int filter_num = 0; static int filter_num = 0;
@ -124,7 +141,9 @@ static struct option long_options[] = {
{"blacklist", required_argument, 0, 'b' }, {"blacklist", required_argument, 0, 'b' },
{"ip-id", required_argument, 0, 'i' }, {"ip-id", required_argument, 0, 'i' },
{"set-ttl", required_argument, 0, '$' }, {"set-ttl", required_argument, 0, '$' },
{"auto-ttl", optional_argument, 0, '+' },
{"wrong-chksum",no_argument, 0, '%' }, {"wrong-chksum",no_argument, 0, '%' },
{"wrong-seq", no_argument, 0, ')' },
{"native-frag", no_argument, 0, '*' }, {"native-frag", no_argument, 0, '*' },
{"reverse-frag",no_argument, 0, '(' }, {"reverse-frag",no_argument, 0, '(' },
{0, 0, 0, 0 } {0, 0, 0, 0 }
@ -487,6 +506,7 @@ int main(int argc, char *argv[]) {
PWINDIVERT_TCPHDR ppTcpHdr; PWINDIVERT_TCPHDR ppTcpHdr;
PWINDIVERT_UDPHDR ppUdpHdr; PWINDIVERT_UDPHDR ppUdpHdr;
conntrack_info_t dns_conn_info; conntrack_info_t dns_conn_info;
tcp_conntrack_info_t tcp_conn_info;
int do_passivedpi = 0, do_fragment_http = 0, int do_passivedpi = 0, do_fragment_http = 0,
do_fragment_http_persistent = 0, do_fragment_http_persistent = 0,
@ -496,9 +516,11 @@ int main(int argc, char *argv[]) {
do_http_allports = 0, do_http_allports = 0,
do_host_mixedcase = 0, do_host_mixedcase = 0,
do_dnsv4_redirect = 0, do_dnsv6_redirect = 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_fake_packet = 0,
do_auto_ttl = 0,
do_wrong_chksum = 0, do_wrong_chksum = 0,
do_wrong_seq = 0,
do_native_frag = 0, do_reverse_frag = 0; do_native_frag = 0, do_reverse_frag = 0;
unsigned int http_fragment_size = 0; unsigned int http_fragment_size = 0;
unsigned int https_fragment_size = 0; unsigned int https_fragment_size = 0;
@ -695,6 +717,7 @@ int main(int argc, char *argv[]) {
break; break;
case 'v': case 'v':
do_dns_verb = 1; do_dns_verb = 1;
do_tcp_verb = 1;
break; break;
case 'b': case 'b':
do_blacklist = 1; do_blacklist = 1;
@ -707,10 +730,23 @@ int main(int argc, char *argv[]) {
do_fake_packet = 1; do_fake_packet = 1;
ttl_of_fake_packet = atoub(optarg, "Set TTL parameter error!"); ttl_of_fake_packet = atoub(optarg, "Set TTL parameter error!");
break; 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 '%': case '%':
do_fake_packet = 1; do_fake_packet = 1;
do_wrong_chksum = 1; do_wrong_chksum = 1;
break; break;
case ')':
do_fake_packet = 1;
do_wrong_seq = 1;
break;
case '*': case '*':
do_native_frag = 1; do_native_frag = 1;
do_fragment_http_persistent = 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" " -s remove space between host header and its value\n"
" -a additional space between Method and Request-URI (enables -s, may break sites)\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" " -m mix Host header case (test.com -> tEsT.cOm)\n"
" -f [value] set HTTP fragmentation to value\n" " -f <value> set HTTP fragmentation to value\n"
" -k [value] enable HTTP persistent (keep-alive) fragmentation and set it to value\n" " -k <value> 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" " -n do not wait for first segment ACK when -k is enabled\n"
" -e [value] set HTTPS fragmentation to value\n" " -e <value> set HTTPS fragmentation to value\n"
" -w try to find and parse HTTP traffic on all processed ports (not only on port 80)\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" " --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" " --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-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" " --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-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" " --dnsv6-port <value> redirect UDPv6 DNS requests to the supplied port (53 by default)\n"
" --dns-verb print verbose DNS redirection messages\n" " --dns-verb print verbose DNS redirection messages\n"
" --blacklist [txtfile] perform circumvention tricks only to host names and subdomains from\n" " --blacklist <txtfile> perform circumvention tricks only to host names and subdomains from\n"
" supplied text file (HTTP Host/TLS SNI).\n" " supplied text file (HTTP Host/TLS SNI).\n"
" This option can be supplied multiple times.\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 <value> activate Fake Request Mode and send it with supplied TTL value.\n"
" DANGEROUS! May break websites in unexpected ways. Use with care.\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" " --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" " May not work in a VM or with some routers, but is safer than set-ttl.\n"
" Could be combined with --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" " --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" " shrinking the Window Size. Works faster (does not slow down the connection)\n"
" and better.\n" " and better.\n"
@ -776,14 +814,16 @@ int main(int argc, char *argv[]) {
"hoSt: %d\nHost no space: %d\nAdditional space: %d\n" "hoSt: %d\nHost no space: %d\nAdditional space: %d\n"
"Mix Host: %d\nHTTP AllPorts: %d\nHTTP Persistent Nowait: %d\n" "Mix Host: %d\nHTTP AllPorts: %d\nHTTP Persistent Nowait: %d\n"
"DNS redirect: %d\nDNSv6 redirect: %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_passivedpi, (do_fragment_http ? http_fragment_size : 0),
(do_fragment_http_persistent ? http_fragment_size : 0), (do_fragment_http_persistent ? http_fragment_size : 0),
(do_fragment_https ? https_fragment_size : 0), (do_fragment_https ? https_fragment_size : 0),
do_native_frag, do_reverse_frag, do_native_frag, do_reverse_frag,
do_host, do_host_removespace, do_additional_space, do_host_mixedcase, do_host, do_host_removespace, do_additional_space, do_host_mixedcase,
do_http_allports, do_fragment_http_persistent_nowait, do_dnsv4_redirect, 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) { 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); printf("Blocked HTTPS website SNI: %s\n", lsni);
#endif #endif
if (do_fake_packet) { if (do_fake_packet) {
if (do_auto_ttl) {
TCP_HANDLE_OUTGOING_ADJUST_TTL();
}
send_fake_https_request(w_filter, &addr, packet, packetLen, packet_v6, 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) { if (do_native_frag) {
// Signal for native fragmentation code handler // Signal for native fragmentation code handler
@ -963,9 +1006,13 @@ int main(int argc, char *argv[]) {
should_recalc_checksum = 1; 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, 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) { if (do_host_mixedcase) {
mix_case(host_addr, host_len); mix_case(host_addr, host_len);
@ -1078,13 +1125,28 @@ int main(int argc, char *argv[]) {
else if (packet_type == ipv4_tcp || packet_type == ipv6_tcp) { else if (packet_type == ipv4_tcp || packet_type == ipv6_tcp) {
/* If we got INBOUND SYN+ACK packet */ /* If we got INBOUND SYN+ACK packet */
if (addr.Direction == WINDIVERT_DIRECTION_INBOUND && if (addr.Direction == WINDIVERT_DIRECTION_INBOUND &&
ppTcpHdr->Syn == 1 && ppTcpHdr->Ack == 1 && ppTcpHdr->Syn == 1 && ppTcpHdr->Ack == 1) {
!do_native_frag) {
//printf("Changing Window Size!\n"); //printf("Changing Window Size!\n");
/* /*
* Window Size is changed even if do_fragment_http_persistent * Window Size is changed even if do_fragment_http_persistent
* is enabled as there could be non-HTTP data on port 80 * is enabled as there could be non-HTTP data on port 80
*/ */
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.");
}
}
if (!do_native_frag) {
if (do_fragment_http && ppTcpHdr->SrcPort == htons(80)) { if (do_fragment_http && ppTcpHdr->SrcPort == htons(80)) {
change_window_size(ppTcpHdr, http_fragment_size); change_window_size(ppTcpHdr, http_fragment_size);
should_recalc_checksum = 1; should_recalc_checksum = 1;
@ -1095,6 +1157,7 @@ int main(int argc, char *argv[]) {
} }
} }
} }
}
/* Else if we got UDP packet with data */ /* Else if we got UDP packet with data */
else if ((do_dnsv4_redirect && (packet_type == ipv4_udp_data)) || else if ((do_dnsv4_redirect && (packet_type == ipv4_udp_data)) ||

235
src/ttltrack.c Normal file
View File

@ -0,0 +1,235 @@
/**
* 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 "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;
}

25
src/ttltrack.h Normal file
View File

@ -0,0 +1,25 @@
#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(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