Fake Request Mode

This commit is contained in:
ValdikSS 2019-10-05 02:38:29 +03:00
parent 2b3e4a4683
commit f2de8fce8d
5 changed files with 243 additions and 5 deletions

View File

@ -33,6 +33,10 @@ Usage: goodbyedpi.exe [OPTION...]
--dns-verb print verbose DNS redirection messages
--blacklist [txtfile] perform HTTP tricks only to host names and subdomains from
supplied text file. This option can be supplied multiple times.
--set-ttl [value] activate Fake Request Mode and send it with supplied TTL value.
DANGEROUS! May break websites in unexpected ways. Use with care.
--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.
-1 -p -r -s -f 2 -k 2 -n -e 2 (most compatible mode, default)
-2 -p -r -s -f 2 -k 2 -n -e 40 (better speed for HTTPS yet still compatible)
@ -56,7 +60,7 @@ Most Passive DPI send HTTP 302 Redirect if you try to access blocked website ove
### Active DPI
Active DPI is more tricky to fool. Currently the software uses 6 methods to circumvent Active DPI:
Active DPI is more tricky to fool. Currently the software uses 7 methods to circumvent Active DPI:
* TCP-level fragmentation for first data packet
* TCP-level fragmentation for persistent (keep-alive) HTTP sessions
@ -64,6 +68,7 @@ Active DPI is more tricky to fool. Currently the software uses 6 methods to circ
* Removing space between header name and value in `Host` header
* Adding additional space between HTTP Method (GET, POST etc) and URI
* Mixing case of Host header value
* Sending fake HTTP/HTTPS packets with low Time-To-Live value or incorrect checksum to fool DPI and prevent delivering them to the destination
These methods should not break any website as they're fully compatible with TCP and HTTP standards, yet it's sufficient to prevent DPI data classification and to circumvent censorship. Additional space may break some websites, although it's acceptable by HTTP/1.1 specification (see 19.3 Tolerant Applications).

166
src/fakepackets.c Normal file
View File

@ -0,0 +1,166 @@
#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 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
) {
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;
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);
if (!is_ipv6) {
// IPv4 TCP Data packet
if (!WinDivertHelperParsePacket(packet_fake, packetLen, &ppIpHdr,
NULL, NULL, NULL, &ppTcpHdr, NULL, &packet_data, &packet_dataLen))
return 1;
}
else {
// IPv6 TCP Data packet
if (!WinDivertHelperParsePacket(packet_fake, packetLen, NULL,
&ppIpV6Hdr, NULL, NULL, &ppTcpHdr, NULL, &packet_data, &packet_dataLen))
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;
}
// Recalculate the checksum
addr_new.PseudoTCPChecksum = 0;
WinDivertHelperCalcChecksums(packet_fake, packetLen_new, &addr_new, NULL);
if (set_checksum) {
// ...and damage it
ppTcpHdr->Checksum = htons(ntohs(ppTcpHdr->Checksum) - 1);
}
//printf("Pseudo checksum: %d\n", addr_new.PseudoTCPChecksum);
WinDivertSend(
w_filter, packet_fake,
packetLen_new,
&addr_new, NULL
);
debug("Fake packet: OK");
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
) {
return send_fake_data(w_filter,
addr,
pkt,
packetLen,
is_ipv6,
FALSE,
set_ttl,
set_checksum
);
}
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
) {
return send_fake_data(w_filter,
addr,
pkt,
packetLen,
is_ipv6,
TRUE,
set_ttl,
set_checksum
);
}

16
src/fakepackets.h Normal file
View File

@ -0,0 +1,16 @@
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
);
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
);

View File

@ -17,6 +17,7 @@
#include "service.h"
#include "dnsredir.h"
#include "blackwhitelist.h"
#include "fakepackets.h"
// My mingw installation does not load inet_pton definition for some reason
WINSOCK_API_LINKAGE INT WSAAPI inet_pton(INT Family, LPCSTR pStringBuf, PVOID pAddr);
@ -26,7 +27,6 @@ WINSOCK_API_LINKAGE INT WSAAPI inet_pton(INT Family, LPCSTR pStringBuf, PVOID pA
#define die() do { sleep(20); exit(EXIT_FAILURE); } while (0)
#define MAX_FILTERS 4
#define MAX_PACKET_SIZE 9016
#define DIVERT_NO_LOCALNETSv4_DST "(" \
"(ip.DstAddr < 127.0.0.1 or ip.DstAddr > 127.255.255.255) and " \
@ -123,6 +123,8 @@ static struct option long_options[] = {
{"dns-verb", no_argument, 0, 'v' },
{"blacklist", required_argument, 0, 'b' },
{"ip-id", required_argument, 0, 'i' },
{"set-ttl", required_argument, 0, '$' },
{"wrong-chksum",no_argument, 0, '%' },
{0, 0, 0, 0 }
};
@ -205,6 +207,19 @@ unsigned short int atousi(const char *str, const char *msg) {
return (unsigned short int)res;
}
BYTE atoub(const char *str, const char *msg) {
long unsigned int res = strtoul(str, NULL, 10u);
enum {
limitValue=0xFFu
};
if(res > limitValue) {
puts(msg);
exit(EXIT_FAILURE);
}
return (BYTE)res;
}
static HANDLE init(char *filter, UINT64 flags) {
LPTSTR errormessage = NULL;
@ -367,9 +382,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_blacklist = 0,
do_wrong_chksum = 0;
unsigned int http_fragment_size = 0;
unsigned int https_fragment_size = 0;
BYTE ttl_of_fake_packet = 0;
uint32_t dnsv4_addr = 0;
struct in6_addr dnsv6_addr = {0};
struct in6_addr dns_temp_addr = {0};
@ -566,6 +583,12 @@ int main(int argc, char *argv[]) {
exit(EXIT_FAILURE);
}
break;
case '$':
ttl_of_fake_packet = atoub(optarg, "Set TTL parameter error!");
break;
case '%':
do_wrong_chksum = 1;
break;
default:
puts("Usage: goodbyedpi.exe [OPTION...]\n"
" -p block passive DPI\n"
@ -587,6 +610,12 @@ int main(int argc, char *argv[]) {
" --dns-verb print verbose DNS redirection messages\n"
" --blacklist [txtfile] perform HTTP tricks only to host names and subdomains from\n"
" supplied text file. This option can be supplied multiple times.\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"
" Could be combined with --wrong-chksum.\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."
"\n"
" -1 -p -r -s -f 2 -k 2 -n -e 2 (most compatible mode, default)\n"
" -2 -p -r -s -f 2 -k 2 -n -e 40 (better speed for HTTPS yet still compatible)\n"
@ -604,13 +633,14 @@ int main(int argc, char *argv[]) {
printf("Block passive: %d\nFragment HTTP: %d\nFragment persistent HTTP: %d\n"
"Fragment HTTPS: %d\nhoSt: %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",
"DNS redirect: %d\nDNSv6 redirect: %d\n"
"Fake requests, TTL: %hu\nFake requests, wrong checksum: %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_host, do_host_removespace, do_additional_space, do_host_mixedcase,
do_http_allports, do_fragment_http_persistent_nowait, do_dnsv4_redirect,
do_dnsv6_redirect
do_dnsv6_redirect, ttl_of_fake_packet, do_wrong_chksum
);
if (do_fragment_http && http_fragment_size > 2) {
@ -724,6 +754,21 @@ int main(int argc, char *argv[]) {
}
}
}
/* Handle OUTBOUND packet on port 443, search for something that resembles
* TLS handshake, send fake request.
*/
else if (addr.Direction == WINDIVERT_DIRECTION_OUTBOUND &&
((do_fragment_https ? packet_dataLen == https_fragment_size : 0) ||
packet_dataLen > 16) &&
ppTcpHdr->DstPort != htons(80) &&
(ttl_of_fake_packet || do_wrong_chksum)
)
{
if (packet_dataLen >=2 && memcmp(packet_data, "\x16\x03", 2) == 0) {
send_fake_https_request(w_filter, &addr, packet, packetLen, packet_v6,
ttl_of_fake_packet, do_wrong_chksum);
}
}
/* Handle OUTBOUND packet on port 80, search for Host header */
else if (addr.Direction == WINDIVERT_DIRECTION_OUTBOUND &&
packet_dataLen > 16 &&
@ -744,6 +789,11 @@ int main(int argc, char *argv[]) {
host_addr = hdr_value_addr;
host_len = hdr_value_len;
if (ttl_of_fake_packet || do_wrong_chksum)
send_fake_http_request(w_filter, &addr, packet, packetLen, packet_v6,
ttl_of_fake_packet, do_wrong_chksum);
/*
* Handle new HTTP request in new
* connection (when Window Size modification disabled)

View File

@ -1,4 +1,5 @@
#define HOST_MAXLEN 253
#define MAX_PACKET_SIZE 9016
#ifndef DEBUG
#define debug(...) do {} while (0)