goodbyedpi.c
1 /* 2 * GoodbyeDPI — Passive DPI blocker and Active DPI circumvention utility. 3 */ 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <ctype.h> 8 #include <signal.h> 9 #include <unistd.h> 10 #include <string.h> 11 #include <getopt.h> 12 #include <in6addr.h> 13 #include <ws2tcpip.h> 14 #include "windivert.h" 15 #include "goodbyedpi.h" 16 #include "utils/repl_str.h" 17 #include "service.h" 18 #include "dnsredir.h" 19 #include "ttltrack.h" 20 #include "blackwhitelist.h" 21 #include "fakepackets.h" 22 23 // My mingw installation does not load inet_pton definition for some reason 24 WINSOCK_API_LINKAGE INT WSAAPI inet_pton(INT Family, LPCSTR pStringBuf, PVOID pAddr); 25 26 #define GOODBYEDPI_VERSION "v0.2.2" 27 28 #define die() do { sleep(20); exit(EXIT_FAILURE); } while (0) 29 30 #define MAX_FILTERS 4 31 32 #define DIVERT_NO_LOCALNETSv4_DST "(" \ 33 "(ip.DstAddr < 127.0.0.1 or ip.DstAddr > 127.255.255.255) and " \ 34 "(ip.DstAddr < 10.0.0.0 or ip.DstAddr > 10.255.255.255) and " \ 35 "(ip.DstAddr < 192.168.0.0 or ip.DstAddr > 192.168.255.255) and " \ 36 "(ip.DstAddr < 172.16.0.0 or ip.DstAddr > 172.31.255.255) and " \ 37 "(ip.DstAddr < 169.254.0.0 or ip.DstAddr > 169.254.255.255)" \ 38 ")" 39 #define DIVERT_NO_LOCALNETSv4_SRC "(" \ 40 "(ip.SrcAddr < 127.0.0.1 or ip.SrcAddr > 127.255.255.255) and " \ 41 "(ip.SrcAddr < 10.0.0.0 or ip.SrcAddr > 10.255.255.255) and " \ 42 "(ip.SrcAddr < 192.168.0.0 or ip.SrcAddr > 192.168.255.255) and " \ 43 "(ip.SrcAddr < 172.16.0.0 or ip.SrcAddr > 172.31.255.255) and " \ 44 "(ip.SrcAddr < 169.254.0.0 or ip.SrcAddr > 169.254.255.255)" \ 45 ")" 46 47 #define DIVERT_NO_LOCALNETSv6_DST "(" \ 48 "(ipv6.DstAddr > ::1) and " \ 49 "(ipv6.DstAddr < 2001::0 or ipv6.DstAddr > 2001:1::0) and " \ 50 "(ipv6.DstAddr < fc00::0 or ipv6.DstAddr > fe00::0) and " \ 51 "(ipv6.DstAddr < fe80::0 or ipv6.DstAddr > fec0::0) and " \ 52 "(ipv6.DstAddr < ff00::0 or ipv6.DstAddr > ffff::0)" \ 53 ")" 54 #define DIVERT_NO_LOCALNETSv6_SRC "(" \ 55 "(ipv6.SrcAddr > ::1) and " \ 56 "(ipv6.SrcAddr < 2001::0 or ipv6.SrcAddr > 2001:1::0) and " \ 57 "(ipv6.SrcAddr < fc00::0 or ipv6.SrcAddr > fe00::0) and " \ 58 "(ipv6.SrcAddr < fe80::0 or ipv6.SrcAddr > fec0::0) and " \ 59 "(ipv6.SrcAddr < ff00::0 or ipv6.SrcAddr > ffff::0)" \ 60 ")" 61 62 /* #IPID# is a template to find&replace */ 63 #define IPID_TEMPLATE "#IPID#" 64 #define MAXPAYLOADSIZE_TEMPLATE "#MAXPAYLOADSIZE#" 65 #define FILTER_STRING_TEMPLATE \ 66 "(tcp and !impostor and !loopback " MAXPAYLOADSIZE_TEMPLATE " and " \ 67 "((inbound and (" \ 68 "(" \ 69 "(" \ 70 "(ipv6 or (ip.Id >= 0x0 and ip.Id <= 0xF) " IPID_TEMPLATE \ 71 ") and " \ 72 "tcp.SrcPort == 80 and tcp.Ack" \ 73 ") or " \ 74 "((tcp.SrcPort == 80 or tcp.SrcPort == 443) and tcp.Ack and tcp.Syn)" \ 75 ")" \ 76 " and (" DIVERT_NO_LOCALNETSv4_SRC " or " DIVERT_NO_LOCALNETSv6_SRC "))) or " \ 77 "(outbound and " \ 78 "(tcp.DstPort == 80 or tcp.DstPort == 443) and tcp.Ack and " \ 79 "(" DIVERT_NO_LOCALNETSv4_DST " or " DIVERT_NO_LOCALNETSv6_DST "))" \ 80 "))" 81 #define FILTER_PASSIVE_STRING_TEMPLATE "inbound and ip and tcp and " \ 82 "!impostor and !loopback and " \ 83 "((ip.Id <= 0xF and ip.Id >= 0x0) " IPID_TEMPLATE ") and " \ 84 "(tcp.SrcPort == 443 or tcp.SrcPort == 80) and tcp.Rst and " \ 85 DIVERT_NO_LOCALNETSv4_SRC 86 87 #define SET_HTTP_FRAGMENT_SIZE_OPTION(fragment_size) do { \ 88 if (!http_fragment_size) { \ 89 http_fragment_size = (unsigned int)fragment_size; \ 90 } \ 91 else if (http_fragment_size != (unsigned int)fragment_size) { \ 92 printf( \ 93 "WARNING: HTTP fragment size is already set to %u, not changing.\n", \ 94 http_fragment_size \ 95 ); \ 96 } \ 97 } while (0) 98 99 #define TCP_HANDLE_OUTGOING_TTL_PARSE_PACKET_IF() \ 100 if ((packet_v4 && tcp_handle_outgoing(&ppIpHdr->SrcAddr, &ppIpHdr->DstAddr, \ 101 ppTcpHdr->SrcPort, ppTcpHdr->DstPort, \ 102 &tcp_conn_info, 0)) \ 103 || \ 104 (packet_v6 && tcp_handle_outgoing(ppIpV6Hdr->SrcAddr, ppIpV6Hdr->DstAddr, \ 105 ppTcpHdr->SrcPort, ppTcpHdr->DstPort, \ 106 &tcp_conn_info, 1))) 107 108 #define TCP_HANDLE_OUTGOING_FAKE_PACKET(func) do { \ 109 should_send_fake = 1; \ 110 if (do_auto_ttl || ttl_min_nhops) { \ 111 TCP_HANDLE_OUTGOING_TTL_PARSE_PACKET_IF() { \ 112 if (do_auto_ttl) { \ 113 /* If Auto TTL mode */ \ 114 ttl_of_fake_packet = tcp_get_auto_ttl(tcp_conn_info.ttl, auto_ttl_1, auto_ttl_2, \ 115 ttl_min_nhops, auto_ttl_max); \ 116 if (do_tcp_verb) { \ 117 printf("Connection TTL = %d, Fake TTL = %d\n", tcp_conn_info.ttl, ttl_of_fake_packet); \ 118 } \ 119 } \ 120 else if (ttl_min_nhops) { \ 121 /* If not Auto TTL mode but --min-ttl is set */ \ 122 if (!tcp_get_auto_ttl(tcp_conn_info.ttl, 0, 0, ttl_min_nhops, 0)) { \ 123 /* Send only if nhops >= min_ttl */ \ 124 should_send_fake = 0; \ 125 } \ 126 } \ 127 } \ 128 } \ 129 if (should_send_fake) \ 130 func(w_filter, &addr, packet, packetLen, packet_v6, \ 131 ttl_of_fake_packet, do_wrong_chksum, do_wrong_seq); \ 132 } while (0) 133 134 135 static int running_from_service = 0; 136 static int exiting = 0; 137 static HANDLE filters[MAX_FILTERS]; 138 static int filter_num = 0; 139 static const char http10_redirect_302[] = "HTTP/1.0 302 "; 140 static const char http11_redirect_302[] = "HTTP/1.1 302 "; 141 static const char http_host_find[] = "\r\nHost: "; 142 static const char http_host_replace[] = "\r\nhoSt: "; 143 static const char http_useragent_find[] = "\r\nUser-Agent: "; 144 static const char location_http[] = "\r\nLocation: http://"; 145 static const char connection_close[] = "\r\nConnection: close"; 146 static const char *http_methods[] = { 147 "GET ", 148 "HEAD ", 149 "POST ", 150 "PUT ", 151 "DELETE ", 152 "CONNECT ", 153 "OPTIONS ", 154 }; 155 156 static struct option long_options[] = { 157 {"port", required_argument, 0, 'z' }, 158 {"dns-addr", required_argument, 0, 'd' }, 159 {"dns-port", required_argument, 0, 'g' }, 160 {"dnsv6-addr", required_argument, 0, '!' }, 161 {"dnsv6-port", required_argument, 0, '@' }, 162 {"dns-verb", no_argument, 0, 'v' }, 163 {"blacklist", required_argument, 0, 'b' }, 164 {"allow-no-sni",no_argument, 0, ']' }, 165 {"frag-by-sni", no_argument, 0, '>' }, 166 {"ip-id", required_argument, 0, 'i' }, 167 {"set-ttl", required_argument, 0, '$' }, 168 {"min-ttl", required_argument, 0, '[' }, 169 {"auto-ttl", optional_argument, 0, '+' }, 170 {"wrong-chksum",no_argument, 0, '%' }, 171 {"wrong-seq", no_argument, 0, ')' }, 172 {"native-frag", no_argument, 0, '*' }, 173 {"reverse-frag",no_argument, 0, '(' }, 174 {"max-payload", optional_argument, 0, '|' }, 175 {0, 0, 0, 0 } 176 }; 177 178 static char *filter_string = NULL; 179 static char *filter_passive_string = NULL; 180 181 static void add_filter_str(int proto, int port) { 182 const char *udp = " or (udp and !impostor and !loopback and " \ 183 "(udp.SrcPort == %d or udp.DstPort == %d))"; 184 const char *tcp = " or (tcp and !impostor and !loopback " MAXPAYLOADSIZE_TEMPLATE " and " \ 185 "(tcp.SrcPort == %d or tcp.DstPort == %d))"; 186 187 char *current_filter = filter_string; 188 size_t new_filter_size = strlen(current_filter) + 189 (proto == IPPROTO_UDP ? strlen(udp) : strlen(tcp)) + 16; 190 char *new_filter = malloc(new_filter_size); 191 192 strcpy(new_filter, current_filter); 193 if (proto == IPPROTO_UDP) 194 sprintf(new_filter + strlen(new_filter), udp, port, port); 195 else 196 sprintf(new_filter + strlen(new_filter), tcp, port, port); 197 198 filter_string = new_filter; 199 free(current_filter); 200 } 201 202 static void add_ip_id_str(int id) { 203 char *newstr; 204 const char *ipid = " or ip.Id == %d"; 205 char *addfilter = malloc(strlen(ipid) + 16); 206 207 sprintf(addfilter, ipid, id); 208 209 newstr = repl_str(filter_string, IPID_TEMPLATE, addfilter); 210 free(filter_string); 211 filter_string = newstr; 212 213 newstr = repl_str(filter_passive_string, IPID_TEMPLATE, addfilter); 214 free(filter_passive_string); 215 filter_passive_string = newstr; 216 } 217 218 static void add_maxpayloadsize_str(unsigned short maxpayload) { 219 char *newstr; 220 /* 0x47455420 is "GET ", 0x504F5354 is "POST", big endian. */ 221 const char *maxpayloadsize_str = "and (tcp.PayloadLength ? tcp.PayloadLength < %hu or tcp.Payload32[0] == 0x47455420 or tcp.Payload32[0] == 0x504F5354 : true)"; 222 char *addfilter = malloc(strlen(maxpayloadsize_str) + 16); 223 224 sprintf(addfilter, maxpayloadsize_str, maxpayload); 225 226 newstr = repl_str(filter_string, MAXPAYLOADSIZE_TEMPLATE, addfilter); 227 free(filter_string); 228 filter_string = newstr; 229 } 230 231 static void finalize_filter_strings() { 232 char *newstr, *newstr2; 233 234 newstr2 = repl_str(filter_string, IPID_TEMPLATE, ""); 235 newstr = repl_str(newstr2, MAXPAYLOADSIZE_TEMPLATE, ""); 236 free(filter_string); 237 free(newstr2); 238 filter_string = newstr; 239 240 newstr = repl_str(filter_passive_string, IPID_TEMPLATE, ""); 241 free(filter_passive_string); 242 filter_passive_string = newstr; 243 } 244 245 static char* dumb_memmem(const char* haystack, unsigned int hlen, 246 const char* needle, unsigned int nlen) 247 { 248 // naive implementation 249 if (nlen > hlen) return NULL; 250 size_t i; 251 for (i=0; i<hlen-nlen+1; i++) { 252 if (memcmp(haystack+i,needle,nlen)==0) { 253 return (char*)(haystack+i); 254 } 255 } 256 return NULL; 257 } 258 259 unsigned short int atousi(const char *str, const char *msg) { 260 long unsigned int res = strtoul(str, NULL, 10u); 261 enum { 262 limitValue=0xFFFFu 263 }; 264 265 if(res > limitValue) { 266 puts(msg); 267 exit(EXIT_FAILURE); 268 } 269 return (unsigned short int)res; 270 } 271 272 BYTE atoub(const char *str, const char *msg) { 273 long unsigned int res = strtoul(str, NULL, 10u); 274 enum { 275 limitValue=0xFFu 276 }; 277 278 if(res > limitValue) { 279 puts(msg); 280 exit(EXIT_FAILURE); 281 } 282 return (BYTE)res; 283 } 284 285 286 static HANDLE init(char *filter, UINT64 flags) { 287 LPTSTR errormessage = NULL; 288 DWORD errorcode = 0; 289 filter = WinDivertOpen(filter, WINDIVERT_LAYER_NETWORK, 0, flags); 290 if (filter != INVALID_HANDLE_VALUE) 291 return filter; 292 errorcode = GetLastError(); 293 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | 294 FORMAT_MESSAGE_IGNORE_INSERTS, 295 NULL, errorcode, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), 296 (LPTSTR)&errormessage, 0, NULL); 297 printf("Error opening filter: %d %s\n", errorcode, errormessage); 298 LocalFree(errormessage); 299 if (errorcode == 2) 300 printf("The driver files WinDivert32.sys or WinDivert64.sys were not found.\n"); 301 else if (errorcode == 654) 302 printf("An incompatible version of the WinDivert driver is currently loaded.\n" 303 "Please unload it with the following commands ran as administrator:\n\n" 304 "sc stop windivert\n" 305 "sc delete windivert\n" 306 "sc stop windivert14" 307 "sc delete windivert14\n"); 308 else if (errorcode == 1275) 309 printf("This error occurs for various reasons, including:\n" 310 "the WinDivert driver is blocked by security software; or\n" 311 "you are using a virtualization environment that does not support drivers.\n"); 312 else if (errorcode == 1753) 313 printf("This error occurs when the Base Filtering Engine service has been disabled.\n" 314 "Enable Base Filtering Engine service.\n"); 315 else if (errorcode == 577) 316 printf("Could not load driver due to invalid digital signature.\n" 317 "Windows Server 2016 systems must have secure boot disabled to be \n" 318 "able to load WinDivert driver.\n" 319 "Windows 7 systems must be up-to-date or at least have KB3033929 installed.\n" 320 "https://www.microsoft.com/en-us/download/details.aspx?id=46078\n\n" 321 "WARNING! If you see this error on Windows 7, it means your system is horribly " 322 "outdated and SHOULD NOT BE USED TO ACCESS THE INTERNET!\n" 323 "Most probably, you don't have security patches installed and anyone in you LAN or " 324 "public Wi-Fi network can get full access to your computer (MS17-010 and others).\n" 325 "You should install updates IMMEDIATELY.\n"); 326 return NULL; 327 } 328 329 static int deinit(HANDLE handle) { 330 if (handle) { 331 WinDivertShutdown(handle, WINDIVERT_SHUTDOWN_BOTH); 332 WinDivertClose(handle); 333 return TRUE; 334 } 335 return FALSE; 336 } 337 338 void deinit_all() { 339 for (int i = 0; i < filter_num; i++) { 340 deinit(filters[i]); 341 } 342 } 343 344 static void sigint_handler(int sig __attribute__((unused))) { 345 exiting = 1; 346 deinit_all(); 347 exit(EXIT_SUCCESS); 348 } 349 350 static void mix_case(char *pktdata, unsigned int pktlen) { 351 unsigned int i; 352 353 if (pktlen <= 0) return; 354 for (i = 0; i < pktlen; i++) { 355 if (i % 2) { 356 pktdata[i] = (char) toupper(pktdata[i]); 357 } 358 } 359 } 360 361 static int is_passivedpi_redirect(const char *pktdata, unsigned int pktlen) { 362 /* First check if this is HTTP 302 redirect */ 363 if (memcmp(pktdata, http11_redirect_302, sizeof(http11_redirect_302)-1) == 0 || 364 memcmp(pktdata, http10_redirect_302, sizeof(http10_redirect_302)-1) == 0) 365 { 366 /* Then check if this is a redirect to new http site with Connection: close */ 367 if (dumb_memmem(pktdata, pktlen, location_http, sizeof(location_http)-1) && 368 dumb_memmem(pktdata, pktlen, connection_close, sizeof(connection_close)-1)) { 369 return TRUE; 370 } 371 } 372 return FALSE; 373 } 374 375 static int find_header_and_get_info(const char *pktdata, unsigned int pktlen, 376 const char *hdrname, 377 char **hdrnameaddr, 378 char **hdrvalueaddr, unsigned int *hdrvaluelen) { 379 char *data_addr_rn; 380 char *hdr_begin; 381 382 *hdrvaluelen = 0u; 383 *hdrnameaddr = NULL; 384 *hdrvalueaddr = NULL; 385 386 /* Search for the header */ 387 hdr_begin = dumb_memmem(pktdata, pktlen, 388 hdrname, strlen(hdrname)); 389 if (!hdr_begin) return FALSE; 390 if (pktdata > hdr_begin) return FALSE; 391 392 /* Set header address */ 393 *hdrnameaddr = hdr_begin; 394 *hdrvalueaddr = hdr_begin + strlen(hdrname); 395 396 /* Search for header end (\r\n) */ 397 data_addr_rn = dumb_memmem(*hdrvalueaddr, 398 pktlen - (uintptr_t)(*hdrvalueaddr - pktdata), 399 "\r\n", 2); 400 if (data_addr_rn) { 401 *hdrvaluelen = (uintptr_t)(data_addr_rn - *hdrvalueaddr); 402 if (*hdrvaluelen >= 3 && *hdrvaluelen <= HOST_MAXLEN) 403 return TRUE; 404 } 405 return FALSE; 406 } 407 408 /** 409 * Very crude Server Name Indication (TLS ClientHello hostname) extractor. 410 */ 411 static int extract_sni(const char *pktdata, unsigned int pktlen, 412 char **hostnameaddr, unsigned int *hostnamelen) { 413 unsigned int ptr = 0; 414 unsigned const char *d = (unsigned const char *)pktdata; 415 unsigned const char *hnaddr = 0; 416 int hnlen = 0; 417 418 while (ptr + 8 < pktlen) { 419 /* Search for specific Extensions sequence */ 420 if (d[ptr] == '\0' && d[ptr+1] == '\0' && d[ptr+2] == '\0' && 421 d[ptr+4] == '\0' && d[ptr+6] == '\0' && d[ptr+7] == '\0' && 422 /* Check Extension length, Server Name list length 423 * and Server Name length relations 424 */ 425 d[ptr+3] - d[ptr+5] == 2 && d[ptr+5] - d[ptr+8] == 3) 426 { 427 if (ptr + 8 + d[ptr+8] > pktlen) { 428 return FALSE; 429 } 430 hnaddr = &d[ptr+9]; 431 hnlen = d[ptr+8]; 432 /* Limit hostname size up to 253 bytes */ 433 if (hnlen < 3 || hnlen > HOST_MAXLEN) { 434 return FALSE; 435 } 436 /* Validate that hostname has only ascii lowercase characters */ 437 for (int i=0; i<hnlen; i++) { 438 if (!( (hnaddr[i] >= '0' && hnaddr[i] <= '9') || 439 (hnaddr[i] >= 'a' && hnaddr[i] <= 'z') || 440 hnaddr[i] == '.' || hnaddr[i] == '-')) 441 { 442 return FALSE; 443 } 444 } 445 *hostnameaddr = (char*)hnaddr; 446 *hostnamelen = (unsigned int)hnlen; 447 return TRUE; 448 } 449 ptr++; 450 } 451 return FALSE; 452 } 453 454 static inline void change_window_size(const PWINDIVERT_TCPHDR ppTcpHdr, unsigned int size) { 455 if (size >= 1 && size <= 0xFFFFu) { 456 ppTcpHdr->Window = htons((u_short)size); 457 } 458 } 459 460 /* HTTP method end without trailing space */ 461 static PVOID find_http_method_end(const char *pkt, unsigned int http_frag, int *is_fragmented) { 462 unsigned int i; 463 for (i = 0; i<(sizeof(http_methods) / sizeof(*http_methods)); i++) { 464 if (memcmp(pkt, http_methods[i], strlen(http_methods[i])) == 0) { 465 if (is_fragmented) 466 *is_fragmented = 0; 467 return (char*)pkt + strlen(http_methods[i]) - 1; 468 } 469 /* Try to find HTTP method in a second part of fragmented packet */ 470 if ((http_frag == 1 || http_frag == 2) && 471 memcmp(pkt, http_methods[i] + http_frag, 472 strlen(http_methods[i]) - http_frag) == 0 473 ) 474 { 475 if (is_fragmented) 476 *is_fragmented = 1; 477 return (char*)pkt + strlen(http_methods[i]) - http_frag - 1; 478 } 479 } 480 return NULL; 481 } 482 483 /** Fragment and send the packet. 484 * 485 * This function cuts off the end of the packet (step=0) or 486 * the beginning of the packet (step=1) with fragment_size bytes. 487 */ 488 static void send_native_fragment(HANDLE w_filter, WINDIVERT_ADDRESS addr, 489 char *packet, UINT packetLen, PVOID packet_data, 490 UINT packet_dataLen, int packet_v4, int packet_v6, 491 PWINDIVERT_IPHDR ppIpHdr, PWINDIVERT_IPV6HDR ppIpV6Hdr, 492 PWINDIVERT_TCPHDR ppTcpHdr, 493 unsigned int fragment_size, int step) { 494 char packet_bak[MAX_PACKET_SIZE]; 495 memcpy(packet_bak, packet, packetLen); 496 UINT orig_packetLen = packetLen; 497 498 if (fragment_size >= packet_dataLen) { 499 if (step == 1) 500 fragment_size = 0; 501 else 502 return; 503 } 504 505 if (step == 0) { 506 if (packet_v4) 507 ppIpHdr->Length = htons( 508 ntohs(ppIpHdr->Length) - 509 packet_dataLen + fragment_size 510 ); 511 else if (packet_v6) 512 ppIpV6Hdr->Length = htons( 513 ntohs(ppIpV6Hdr->Length) - 514 packet_dataLen + fragment_size 515 ); 516 //printf("step0 (%d:%d), pp:%d, was:%d, now:%d\n", 517 // packet_v4, packet_v6, ntohs(ppIpHdr->Length), 518 // packetLen, packetLen - packet_dataLen + fragment_size); 519 packetLen = packetLen - packet_dataLen + fragment_size; 520 } 521 522 else if (step == 1) { 523 if (packet_v4) 524 ppIpHdr->Length = htons( 525 ntohs(ppIpHdr->Length) - fragment_size 526 ); 527 else if (packet_v6) 528 ppIpV6Hdr->Length = htons( 529 ntohs(ppIpV6Hdr->Length) - fragment_size 530 ); 531 //printf("step1 (%d:%d), pp:%d, was:%d, now:%d\n", packet_v4, packet_v6, ntohs(ppIpHdr->Length), 532 // packetLen, packetLen - fragment_size); 533 memmove(packet_data, 534 (char*)packet_data + fragment_size, 535 packet_dataLen - fragment_size); 536 packetLen -= fragment_size; 537 538 ppTcpHdr->SeqNum = htonl(ntohl(ppTcpHdr->SeqNum) + fragment_size); 539 } 540 541 addr.IPChecksum = 0; 542 addr.TCPChecksum = 0; 543 544 WinDivertHelperCalcChecksums( 545 packet, packetLen, &addr, 0 546 ); 547 WinDivertSend( 548 w_filter, packet, 549 packetLen, 550 NULL, &addr 551 ); 552 memcpy(packet, packet_bak, orig_packetLen); 553 //printf("Sent native fragment of %d size (step%d)\n", packetLen, step); 554 } 555 556 int main(int argc, char *argv[]) { 557 static enum packet_type_e { 558 unknown, 559 ipv4_tcp, ipv4_tcp_data, ipv4_udp_data, 560 ipv6_tcp, ipv6_tcp_data, ipv6_udp_data 561 } packet_type; 562 int i, should_reinject, should_recalc_checksum = 0; 563 int sni_ok = 0; 564 int opt; 565 int packet_v4, packet_v6; 566 HANDLE w_filter = NULL; 567 WINDIVERT_ADDRESS addr; 568 char packet[MAX_PACKET_SIZE]; 569 PVOID packet_data; 570 UINT packetLen; 571 UINT packet_dataLen; 572 PWINDIVERT_IPHDR ppIpHdr; 573 PWINDIVERT_IPV6HDR ppIpV6Hdr; 574 PWINDIVERT_TCPHDR ppTcpHdr; 575 PWINDIVERT_UDPHDR ppUdpHdr; 576 conntrack_info_t dns_conn_info; 577 tcp_conntrack_info_t tcp_conn_info; 578 579 int do_passivedpi = 0, do_fragment_http = 0, 580 do_fragment_http_persistent = 0, 581 do_fragment_http_persistent_nowait = 0, 582 do_fragment_https = 0, do_host = 0, 583 do_host_removespace = 0, do_additional_space = 0, 584 do_http_allports = 0, 585 do_host_mixedcase = 0, 586 do_dnsv4_redirect = 0, do_dnsv6_redirect = 0, 587 do_dns_verb = 0, do_tcp_verb = 0, do_blacklist = 0, 588 do_allow_no_sni = 0, 589 do_fragment_by_sni = 0, 590 do_fake_packet = 0, 591 do_auto_ttl = 0, 592 do_wrong_chksum = 0, 593 do_wrong_seq = 0, 594 do_native_frag = 0, do_reverse_frag = 0; 595 unsigned int http_fragment_size = 0; 596 unsigned int https_fragment_size = 0; 597 unsigned int current_fragment_size = 0; 598 unsigned short max_payload_size = 0; 599 BYTE should_send_fake = 0; 600 BYTE ttl_of_fake_packet = 0; 601 BYTE ttl_min_nhops = 0; 602 BYTE auto_ttl_1 = 0; 603 BYTE auto_ttl_2 = 0; 604 BYTE auto_ttl_max = 0; 605 uint32_t dnsv4_addr = 0; 606 struct in6_addr dnsv6_addr = {0}; 607 struct in6_addr dns_temp_addr = {0}; 608 uint16_t dnsv4_port = htons(53); 609 uint16_t dnsv6_port = htons(53); 610 char *host_addr, *useragent_addr, *method_addr; 611 unsigned int host_len, useragent_len; 612 int http_req_fragmented; 613 614 char *hdr_name_addr = NULL, *hdr_value_addr = NULL; 615 unsigned int hdr_value_len; 616 617 // Make sure to search DLLs only in safe path, not in current working dir. 618 SetDllDirectory(""); 619 SetSearchPathMode(BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE | BASE_SEARCH_PATH_PERMANENT); 620 621 if (!running_from_service) { 622 running_from_service = 1; 623 if (service_register(argc, argv)) { 624 /* We've been called as a service. Register service 625 * and exit this thread. main() would be called from 626 * service.c next time. 627 * 628 * Note that if service_register() succeedes it does 629 * not return until the service is stopped. 630 * That is why we should set running_from_service 631 * before calling service_register and unset it 632 * afterwards. 633 */ 634 return 0; 635 } 636 running_from_service = 0; 637 } 638 639 if (filter_string == NULL) 640 filter_string = strdup(FILTER_STRING_TEMPLATE); 641 if (filter_passive_string == NULL) 642 filter_passive_string = strdup(FILTER_PASSIVE_STRING_TEMPLATE); 643 644 printf( 645 "GoodbyeDPI " GOODBYEDPI_VERSION 646 ": Passive DPI blocker and Active DPI circumvention utility\n" 647 "https://github.com/ValdikSS/GoodbyeDPI\n\n" 648 ); 649 650 if (argc == 1) { 651 /* enable mode -5 by default */ 652 do_fragment_http = do_fragment_https = 1; 653 do_reverse_frag = do_native_frag = 1; 654 http_fragment_size = https_fragment_size = 2; 655 do_fragment_http_persistent = do_fragment_http_persistent_nowait = 1; 656 do_fake_packet = 1; 657 do_auto_ttl = 1; 658 max_payload_size = 1200; 659 } 660 661 while ((opt = getopt_long(argc, argv, "123456prsaf:e:mwk:n", long_options, NULL)) != -1) { 662 switch (opt) { 663 case '1': 664 do_passivedpi = do_host = do_host_removespace \ 665 = do_fragment_http = do_fragment_https \ 666 = do_fragment_http_persistent \ 667 = do_fragment_http_persistent_nowait = 1; 668 break; 669 case '2': 670 do_passivedpi = do_host = do_host_removespace \ 671 = do_fragment_http = do_fragment_https \ 672 = do_fragment_http_persistent \ 673 = do_fragment_http_persistent_nowait = 1; 674 https_fragment_size = 40u; 675 break; 676 case '3': 677 do_passivedpi = do_host = do_host_removespace \ 678 = do_fragment_https = 1; 679 https_fragment_size = 40u; 680 break; 681 case '4': 682 do_passivedpi = do_host = do_host_removespace = 1; 683 break; 684 case '5': 685 do_fragment_http = do_fragment_https = 1; 686 do_reverse_frag = do_native_frag = 1; 687 http_fragment_size = https_fragment_size = 2; 688 do_fragment_http_persistent = do_fragment_http_persistent_nowait = 1; 689 do_fake_packet = 1; 690 do_auto_ttl = 1; 691 max_payload_size = 1200; 692 break; 693 case '6': 694 do_fragment_http = do_fragment_https = 1; 695 do_reverse_frag = do_native_frag = 1; 696 http_fragment_size = https_fragment_size = 2; 697 do_fragment_http_persistent = do_fragment_http_persistent_nowait = 1; 698 do_fake_packet = 1; 699 do_wrong_seq = 1; 700 max_payload_size = 1200; 701 break; 702 case 'p': 703 do_passivedpi = 1; 704 break; 705 case 'r': 706 do_host = 1; 707 break; 708 case 's': 709 do_host_removespace = 1; 710 break; 711 case 'a': 712 do_additional_space = 1; 713 do_host_removespace = 1; 714 break; 715 case 'm': 716 do_host_mixedcase = 1; 717 break; 718 case 'f': 719 do_fragment_http = 1; 720 SET_HTTP_FRAGMENT_SIZE_OPTION(atousi(optarg, "Fragment size should be in range [0 - 0xFFFF]\n")); 721 break; 722 case 'k': 723 do_fragment_http_persistent = 1; 724 do_native_frag = 1; 725 SET_HTTP_FRAGMENT_SIZE_OPTION(atousi(optarg, "Fragment size should be in range [0 - 0xFFFF]\n")); 726 break; 727 case 'n': 728 do_fragment_http_persistent = 1; 729 do_fragment_http_persistent_nowait = 1; 730 do_native_frag = 1; 731 break; 732 case 'e': 733 do_fragment_https = 1; 734 https_fragment_size = atousi(optarg, "Fragment size should be in range [0 - 65535]\n"); 735 break; 736 case 'w': 737 do_http_allports = 1; 738 break; 739 case 'z': // --port 740 /* i is used as a temporary variable here */ 741 i = atoi(optarg); 742 if (i <= 0 || i > 65535) { 743 printf("Port parameter error!\n"); 744 exit(EXIT_FAILURE); 745 } 746 if (i != 80 && i != 443) 747 add_filter_str(IPPROTO_TCP, i); 748 i = 0; 749 break; 750 case 'i': // --ip-id 751 /* i is used as a temporary variable here */ 752 i = atousi(optarg, "IP ID parameter error!\n"); 753 add_ip_id_str(i); 754 i = 0; 755 break; 756 case 'd': // --dns-addr 757 if ((inet_pton(AF_INET, optarg, dns_temp_addr.s6_addr) == 1) && 758 !do_dnsv4_redirect) 759 { 760 do_dnsv4_redirect = 1; 761 if (inet_pton(AF_INET, optarg, &dnsv4_addr) != 1) { 762 puts("DNS address parameter error!"); 763 exit(EXIT_FAILURE); 764 } 765 add_filter_str(IPPROTO_UDP, 53); 766 flush_dns_cache(); 767 break; 768 } 769 puts("DNS address parameter error!"); 770 exit(EXIT_FAILURE); 771 break; 772 case '!': // --dnsv6-addr 773 if ((inet_pton(AF_INET6, optarg, dns_temp_addr.s6_addr) == 1) && 774 !do_dnsv6_redirect) 775 { 776 do_dnsv6_redirect = 1; 777 if (inet_pton(AF_INET6, optarg, dnsv6_addr.s6_addr) != 1) { 778 puts("DNS address parameter error!"); 779 exit(EXIT_FAILURE); 780 } 781 add_filter_str(IPPROTO_UDP, 53); 782 flush_dns_cache(); 783 break; 784 } 785 puts("DNS address parameter error!"); 786 exit(EXIT_FAILURE); 787 break; 788 case 'g': // --dns-port 789 if (!do_dnsv4_redirect) { 790 puts("--dns-port should be used with --dns-addr!\n" 791 "Make sure you use --dns-addr and pass it before " 792 "--dns-port"); 793 exit(EXIT_FAILURE); 794 } 795 dnsv4_port = atousi(optarg, "DNS port parameter error!"); 796 if (dnsv4_port != 53) { 797 add_filter_str(IPPROTO_UDP, dnsv4_port); 798 } 799 dnsv4_port = htons(dnsv4_port); 800 break; 801 case '@': // --dnsv6-port 802 if (!do_dnsv6_redirect) { 803 puts("--dnsv6-port should be used with --dnsv6-addr!\n" 804 "Make sure you use --dnsv6-addr and pass it before " 805 "--dnsv6-port"); 806 exit(EXIT_FAILURE); 807 } 808 dnsv6_port = atousi(optarg, "DNS port parameter error!"); 809 if (dnsv6_port != 53) { 810 add_filter_str(IPPROTO_UDP, dnsv6_port); 811 } 812 dnsv6_port = htons(dnsv6_port); 813 break; 814 case 'v': 815 do_dns_verb = 1; 816 do_tcp_verb = 1; 817 break; 818 case 'b': // --blacklist 819 do_blacklist = 1; 820 if (!blackwhitelist_load_list(optarg)) { 821 printf("Can't load blacklist from file!\n"); 822 exit(EXIT_FAILURE); 823 } 824 break; 825 case ']': // --allow-no-sni 826 do_allow_no_sni = 1; 827 break; 828 case '>': // --frag-by-sni 829 do_fragment_by_sni = 1; 830 break; 831 case '$': // --set-ttl 832 do_auto_ttl = auto_ttl_1 = auto_ttl_2 = auto_ttl_max = 0; 833 do_fake_packet = 1; 834 ttl_of_fake_packet = atoub(optarg, "Set TTL parameter error!"); 835 break; 836 case '[': // --min-ttl 837 do_fake_packet = 1; 838 ttl_min_nhops = atoub(optarg, "Set Minimum TTL number of hops parameter error!"); 839 break; 840 case '+': // --auto-ttl 841 do_fake_packet = 1; 842 do_auto_ttl = 1; 843 844 if (!optarg && argv[optind] && argv[optind][0] != '-') 845 optarg = argv[optind]; 846 847 if (optarg) { 848 char *autottl_copy = strdup(optarg); 849 if (strchr(autottl_copy, '-')) { 850 // token "-" found, start X-Y parser 851 char *autottl_current = strtok(autottl_copy, "-"); 852 auto_ttl_1 = atoub(autottl_current, "Set Auto TTL parameter error!"); 853 autottl_current = strtok(NULL, "-"); 854 if (!autottl_current) { 855 puts("Set Auto TTL parameter error!"); 856 exit(EXIT_FAILURE); 857 } 858 auto_ttl_2 = atoub(autottl_current, "Set Auto TTL parameter error!"); 859 autottl_current = strtok(NULL, "-"); 860 if (!autottl_current) { 861 puts("Set Auto TTL parameter error!"); 862 exit(EXIT_FAILURE); 863 } 864 auto_ttl_max = atoub(autottl_current, "Set Auto TTL parameter error!"); 865 } 866 else { 867 // single digit parser 868 auto_ttl_2 = atoub(optarg, "Set Auto TTL parameter error!"); 869 auto_ttl_1 = auto_ttl_2; 870 } 871 free(autottl_copy); 872 } 873 break; 874 case '%': // --wrong-chksum 875 do_fake_packet = 1; 876 do_wrong_chksum = 1; 877 break; 878 case ')': // --wrong-seq 879 do_fake_packet = 1; 880 do_wrong_seq = 1; 881 break; 882 case '*': // --native-frag 883 do_native_frag = 1; 884 do_fragment_http_persistent = 1; 885 do_fragment_http_persistent_nowait = 1; 886 break; 887 case '(': // --reverse-frag 888 do_reverse_frag = 1; 889 do_native_frag = 1; 890 do_fragment_http_persistent = 1; 891 do_fragment_http_persistent_nowait = 1; 892 break; 893 case '|': // --max-payload 894 if (!optarg && argv[optind] && argv[optind][0] != '-') 895 optarg = argv[optind]; 896 if (optarg) 897 max_payload_size = atousi(optarg, "Max payload size parameter error!"); 898 else 899 max_payload_size = 1200; 900 break; 901 default: 902 puts("Usage: goodbyedpi.exe [OPTION...]\n" 903 " -p block passive DPI\n" 904 " -r replace Host with hoSt\n" 905 " -s remove space between host header and its value\n" 906 " -a additional space between Method and Request-URI (enables -s, may break sites)\n" 907 " -m mix Host header case (test.com -> tEsT.cOm)\n" 908 " -f <value> set HTTP fragmentation to value\n" 909 " -k <value> enable HTTP persistent (keep-alive) fragmentation and set it to value\n" 910 " -n do not wait for first segment ACK when -k is enabled\n" 911 " -e <value> set HTTPS fragmentation to value\n" 912 " -w try to find and parse HTTP traffic on all processed ports (not only on port 80)\n" 913 " --port <value> additional TCP port to perform fragmentation on (and HTTP tricks with -w)\n" 914 " --ip-id <value> handle additional IP ID (decimal, drop redirects and TCP RSTs with this ID).\n" 915 " --dns-addr <value> redirect UDPv4 DNS requests to the supplied IPv4 address (experimental)\n" 916 " --dns-port <value> redirect UDPv4 DNS requests to the supplied port (53 by default)\n" 917 " --dnsv6-addr <value> redirect UDPv6 DNS requests to the supplied IPv6 address (experimental)\n" 918 " --dnsv6-port <value> redirect UDPv6 DNS requests to the supplied port (53 by default)\n" 919 " --dns-verb print verbose DNS redirection messages\n" 920 " --blacklist <txtfile> perform circumvention tricks only to host names and subdomains from\n" 921 " supplied text file (HTTP Host/TLS SNI).\n" 922 " This option can be supplied multiple times.\n" 923 " --allow-no-sni perform circumvention if TLS SNI can't be detected with --blacklist enabled.\n" 924 " --frag-by-sni if SNI is detected in TLS packet, fragment the packet right before SNI value.\n" 925 " --set-ttl <value> activate Fake Request Mode and send it with supplied TTL value.\n" 926 " DANGEROUS! May break websites in unexpected ways. Use with care (or --blacklist).\n" 927 " --auto-ttl [a1-a2-m] activate Fake Request Mode, automatically detect TTL and decrease\n" 928 " it based on a distance. If the distance is shorter than a2, TTL is decreased\n" 929 " by a2. If it's longer, (a1; a2) scale is used with the distance as a weight.\n" 930 " If the resulting TTL is more than m(ax), set it to m.\n" 931 " Default (if set): --auto-ttl 1-4-10. Also sets --min-ttl 3.\n" 932 " DANGEROUS! May break websites in unexpected ways. Use with care (or --blacklist).\n" 933 " --min-ttl <value> minimum TTL distance (128/64 - TTL) for which to send Fake Request\n" 934 " in --set-ttl and --auto-ttl modes.\n" 935 " --wrong-chksum activate Fake Request Mode and send it with incorrect TCP checksum.\n" 936 " May not work in a VM or with some routers, but is safer than set-ttl.\n" 937 " Could be combined with --set-ttl\n" 938 " --wrong-seq activate Fake Request Mode and send it with TCP SEQ/ACK in the past.\n" 939 " --native-frag fragment (split) the packets by sending them in smaller packets, without\n" 940 " shrinking the Window Size. Works faster (does not slow down the connection)\n" 941 " and better.\n" 942 " --reverse-frag fragment (split) the packets just as --native-frag, but send them in the\n" 943 " reversed order. Works with the websites which could not handle segmented\n" 944 " HTTPS TLS ClientHello (because they receive the TCP flow \"combined\").\n" 945 " --max-payload [value] packets with TCP payload data more than [value] won't be processed.\n" 946 " Use this option to reduce CPU usage by skipping huge amount of data\n" 947 " (like file transfers) in already established sessions.\n" 948 " May skip some huge HTTP requests from being processed.\n" 949 " Default (if set): --max-payload 1200.\n" 950 "\n"); 951 puts("LEGACY modesets:\n" 952 " -1 -p -r -s -f 2 -k 2 -n -e 2 (most compatible mode)\n" 953 " -2 -p -r -s -f 2 -k 2 -n -e 40 (better speed for HTTPS yet still compatible)\n" 954 " -3 -p -r -s -e 40 (better speed for HTTP and HTTPS)\n" 955 " -4 -p -r -s (best speed)" 956 "\n" 957 "Modern modesets (more stable, more compatible, faster):\n" 958 " -5 -f 2 -e 2 --auto-ttl --reverse-frag --max-payload (this is the default)\n" 959 " -6 -f 2 -e 2 --wrong-seq --reverse-frag --max-payload\n"); 960 exit(EXIT_FAILURE); 961 } 962 } 963 964 if (!http_fragment_size) 965 http_fragment_size = 2; 966 if (!https_fragment_size) 967 https_fragment_size = 2; 968 if (!auto_ttl_1) 969 auto_ttl_1 = 1; 970 if (!auto_ttl_2) 971 auto_ttl_2 = 4; 972 if (do_auto_ttl) { 973 if (!ttl_min_nhops) 974 ttl_min_nhops = 3; 975 if (!auto_ttl_max) 976 auto_ttl_max = 10; 977 } 978 979 printf("Block passive: %d\n" /* 1 */ 980 "Fragment HTTP: %u\n" /* 2 */ 981 "Fragment persistent HTTP: %u\n" /* 3 */ 982 "Fragment HTTPS: %u\n" /* 4 */ 983 "Fragment by SNI: %u\n" /* 5 */ 984 "Native fragmentation (splitting): %d\n" /* 6 */ 985 "Fragments sending in reverse: %d\n" /* 7 */ 986 "hoSt: %d\n" /* 8 */ 987 "Host no space: %d\n" /* 9 */ 988 "Additional space: %d\n" /* 10 */ 989 "Mix Host: %d\n" /* 11 */ 990 "HTTP AllPorts: %d\n" /* 12 */ 991 "HTTP Persistent Nowait: %d\n" /* 13 */ 992 "DNS redirect: %d\n" /* 14 */ 993 "DNSv6 redirect: %d\n" /* 15 */ 994 "Allow missing SNI: %d\n" /* 16 */ 995 "Fake requests, TTL: %s (fixed: %hu, auto: %hu-%hu-%hu, min distance: %hu)\n" /* 17 */ 996 "Fake requests, wrong checksum: %d\n" /* 18 */ 997 "Fake requests, wrong SEQ/ACK: %d\n" /* 19 */ 998 "Max payload size: %hu\n", /* 20 */ 999 do_passivedpi, /* 1 */ 1000 (do_fragment_http ? http_fragment_size : 0), /* 2 */ 1001 (do_fragment_http_persistent ? http_fragment_size : 0),/* 3 */ 1002 (do_fragment_https ? https_fragment_size : 0), /* 4 */ 1003 do_fragment_by_sni, /* 5 */ 1004 do_native_frag, /* 6 */ 1005 do_reverse_frag, /* 7 */ 1006 do_host, /* 8 */ 1007 do_host_removespace, /* 9 */ 1008 do_additional_space, /* 10 */ 1009 do_host_mixedcase, /* 11 */ 1010 do_http_allports, /* 12 */ 1011 do_fragment_http_persistent_nowait, /* 13 */ 1012 do_dnsv4_redirect, /* 14 */ 1013 do_dnsv6_redirect, /* 15 */ 1014 do_allow_no_sni, /* 16 */ 1015 do_auto_ttl ? "auto" : (do_fake_packet ? "fixed" : "disabled"), /* 17 */ 1016 ttl_of_fake_packet, do_auto_ttl ? auto_ttl_1 : 0, do_auto_ttl ? auto_ttl_2 : 0, 1017 do_auto_ttl ? auto_ttl_max : 0, ttl_min_nhops, 1018 do_wrong_chksum, /* 18 */ 1019 do_wrong_seq, /* 19 */ 1020 max_payload_size /* 20 */ 1021 ); 1022 1023 if (do_fragment_http && http_fragment_size > 2 && !do_native_frag) { 1024 puts("\nWARNING: HTTP fragmentation values > 2 are not fully compatible " 1025 "with other options. Please use values <= 2 or disable HTTP fragmentation " 1026 "completely."); 1027 } 1028 1029 if (do_native_frag && !(do_fragment_http || do_fragment_https)) { 1030 puts("\nERROR: Native fragmentation is enabled but fragment sizes are not set.\n" 1031 "Fragmentation has no effect."); 1032 die(); 1033 } 1034 1035 if (max_payload_size) 1036 add_maxpayloadsize_str(max_payload_size); 1037 finalize_filter_strings(); 1038 puts("\nOpening filter"); 1039 filter_num = 0; 1040 1041 if (do_passivedpi) { 1042 /* IPv4 only filter for inbound RST packets with ID [0x0; 0xF] */ 1043 filters[filter_num] = init( 1044 filter_passive_string, 1045 WINDIVERT_FLAG_DROP); 1046 if (filters[filter_num] == NULL) 1047 die(); 1048 filter_num++; 1049 } 1050 1051 /* 1052 * IPv4 & IPv6 filter for inbound HTTP redirection packets and 1053 * active DPI circumvention 1054 */ 1055 filters[filter_num] = init(filter_string, 0); 1056 1057 w_filter = filters[filter_num]; 1058 filter_num++; 1059 1060 for (i = 0; i < filter_num; i++) { 1061 if (filters[i] == NULL) 1062 die(); 1063 } 1064 1065 printf("Filter activated, GoodbyeDPI is now running!\n"); 1066 signal(SIGINT, sigint_handler); 1067 1068 while (1) { 1069 if (WinDivertRecv(w_filter, packet, sizeof(packet), &packetLen, &addr)) { 1070 debug("Got %s packet, len=%d!\n", addr.Outbound ? "outbound" : "inbound", 1071 packetLen); 1072 should_reinject = 1; 1073 should_recalc_checksum = 0; 1074 sni_ok = 0; 1075 1076 ppIpHdr = (PWINDIVERT_IPHDR)NULL; 1077 ppIpV6Hdr = (PWINDIVERT_IPV6HDR)NULL; 1078 ppTcpHdr = (PWINDIVERT_TCPHDR)NULL; 1079 ppUdpHdr = (PWINDIVERT_UDPHDR)NULL; 1080 packet_v4 = packet_v6 = 0; 1081 packet_type = unknown; 1082 1083 // Parse network packet and set it's type 1084 if (WinDivertHelperParsePacket(packet, packetLen, &ppIpHdr, 1085 &ppIpV6Hdr, NULL, NULL, NULL, &ppTcpHdr, &ppUdpHdr, &packet_data, &packet_dataLen, 1086 NULL, NULL)) 1087 { 1088 if (ppIpHdr) { 1089 packet_v4 = 1; 1090 if (ppTcpHdr) { 1091 packet_type = ipv4_tcp; 1092 if (packet_data) { 1093 packet_type = ipv4_tcp_data; 1094 } 1095 } 1096 else if (ppUdpHdr && packet_data) { 1097 packet_type = ipv4_udp_data; 1098 } 1099 } 1100 1101 else if (ppIpV6Hdr) { 1102 packet_v6 = 1; 1103 if (ppTcpHdr) { 1104 packet_type = ipv6_tcp; 1105 if (packet_data) { 1106 packet_type = ipv6_tcp_data; 1107 } 1108 } 1109 else if (ppUdpHdr && packet_data) { 1110 packet_type = ipv6_udp_data; 1111 } 1112 } 1113 } 1114 1115 debug("packet_type: %d, packet_v4: %d, packet_v6: %d\n", packet_type, packet_v4, packet_v6); 1116 1117 if (packet_type == ipv4_tcp_data || packet_type == ipv6_tcp_data) { 1118 //printf("Got parsed packet, len=%d!\n", packet_dataLen); 1119 /* Got a TCP packet WITH DATA */ 1120 1121 /* Handle INBOUND packet with data and find HTTP REDIRECT in there */ 1122 if (!addr.Outbound && packet_dataLen > 16) { 1123 /* If INBOUND packet with DATA (tcp.Ack) */ 1124 1125 /* Drop packets from filter with HTTP 30x Redirect */ 1126 if (do_passivedpi && is_passivedpi_redirect(packet_data, packet_dataLen)) { 1127 if (packet_v4) { 1128 //printf("Dropping HTTP Redirect packet!\n"); 1129 should_reinject = 0; 1130 } 1131 else if (packet_v6 && WINDIVERT_IPV6HDR_GET_FLOWLABEL(ppIpV6Hdr) == 0x0) { 1132 /* Contrary to IPv4 where we get only packets with IP ID 0x0-0xF, 1133 * for IPv6 we got all the incoming data packets since we can't 1134 * filter them in a driver. 1135 * 1136 * Handle only IPv6 Flow Label == 0x0 for now 1137 */ 1138 //printf("Dropping HTTP Redirect packet!\n"); 1139 should_reinject = 0; 1140 } 1141 } 1142 } 1143 /* Handle OUTBOUND packet on port 443, search for something that resembles 1144 * TLS handshake, send fake request. 1145 */ 1146 else if (addr.Outbound && 1147 ((do_fragment_https ? packet_dataLen == https_fragment_size : 0) || 1148 packet_dataLen > 16) && 1149 ppTcpHdr->DstPort != htons(80) && 1150 (do_fake_packet || do_native_frag) 1151 ) 1152 { 1153 /** 1154 * In case of Window Size fragmentation=2, we'll receive only 2 byte packet. 1155 * But if the packet is more than 2 bytes, check ClientHello byte. 1156 */ 1157 if ((packet_dataLen == 2 && memcmp(packet_data, "\x16\x03", 2) == 0) || 1158 (packet_dataLen >= 3 && ( memcmp(packet_data, "\x16\x03\x01", 3) == 0 || memcmp(packet_data, "\x16\x03\x03", 3) == 0 ))) 1159 { 1160 if (do_blacklist || do_fragment_by_sni) { 1161 sni_ok = extract_sni(packet_data, packet_dataLen, 1162 &host_addr, &host_len); 1163 } 1164 if ( 1165 (do_blacklist && sni_ok && 1166 blackwhitelist_check_hostname(host_addr, host_len) 1167 ) || 1168 (do_blacklist && !sni_ok && do_allow_no_sni) || 1169 (!do_blacklist) 1170 ) 1171 { 1172 #ifdef DEBUG 1173 char lsni[HOST_MAXLEN + 1] = {0}; 1174 extract_sni(packet_data, packet_dataLen, 1175 &host_addr, &host_len); 1176 memcpy(lsni, host_addr, host_len); 1177 printf("Blocked HTTPS website SNI: %s\n", lsni); 1178 #endif 1179 if (do_fake_packet) { 1180 TCP_HANDLE_OUTGOING_FAKE_PACKET(send_fake_https_request); 1181 } 1182 if (do_native_frag) { 1183 // Signal for native fragmentation code handler 1184 should_recalc_checksum = 1; 1185 } 1186 } 1187 } 1188 } 1189 /* Handle OUTBOUND packet on port 80, search for Host header */ 1190 else if (addr.Outbound && 1191 packet_dataLen > 16 && 1192 (do_http_allports ? 1 : (ppTcpHdr->DstPort == htons(80))) && 1193 find_http_method_end(packet_data, 1194 (do_fragment_http ? http_fragment_size : 0u), 1195 &http_req_fragmented) && 1196 (do_host || do_host_removespace || 1197 do_host_mixedcase || do_fragment_http_persistent || 1198 do_fake_packet)) 1199 { 1200 1201 /* Find Host header */ 1202 if (find_header_and_get_info(packet_data, packet_dataLen, 1203 http_host_find, &hdr_name_addr, &hdr_value_addr, &hdr_value_len) && 1204 hdr_value_len > 0 && hdr_value_len <= HOST_MAXLEN && 1205 (do_blacklist ? blackwhitelist_check_hostname(hdr_value_addr, hdr_value_len) : 1)) 1206 { 1207 host_addr = hdr_value_addr; 1208 host_len = hdr_value_len; 1209 #ifdef DEBUG 1210 char lhost[HOST_MAXLEN + 1] = {0}; 1211 memcpy(lhost, host_addr, host_len); 1212 printf("Blocked HTTP website Host: %s\n", lhost); 1213 #endif 1214 1215 if (do_native_frag) { 1216 // Signal for native fragmentation code handler 1217 should_recalc_checksum = 1; 1218 } 1219 1220 if (do_fake_packet) { 1221 TCP_HANDLE_OUTGOING_FAKE_PACKET(send_fake_http_request); 1222 } 1223 1224 if (do_host_mixedcase) { 1225 mix_case(host_addr, host_len); 1226 should_recalc_checksum = 1; 1227 } 1228 1229 if (do_host) { 1230 /* Replace "Host: " with "hoSt: " */ 1231 memcpy(hdr_name_addr, http_host_replace, strlen(http_host_replace)); 1232 should_recalc_checksum = 1; 1233 //printf("Replaced Host header!\n"); 1234 } 1235 1236 /* If removing space between host header and its value 1237 * and adding additional space between Method and Request-URI */ 1238 if (do_additional_space && do_host_removespace) { 1239 /* End of "Host:" without trailing space */ 1240 method_addr = find_http_method_end(packet_data, 1241 (do_fragment_http ? http_fragment_size : 0), 1242 NULL); 1243 1244 if (method_addr) { 1245 memmove(method_addr + 1, method_addr, 1246 (size_t)(host_addr - method_addr - 1)); 1247 should_recalc_checksum = 1; 1248 } 1249 } 1250 /* If just removing space between host header and its value */ 1251 else if (do_host_removespace) { 1252 if (find_header_and_get_info(packet_data, packet_dataLen, 1253 http_useragent_find, &hdr_name_addr, 1254 &hdr_value_addr, &hdr_value_len)) 1255 { 1256 useragent_addr = hdr_value_addr; 1257 useragent_len = hdr_value_len; 1258 1259 /* We move Host header value by one byte to the left and then 1260 * "insert" stolen space to the end of User-Agent value because 1261 * some web servers are not tolerant to additional space in the 1262 * end of Host header. 1263 * 1264 * Nothing is done if User-Agent header is missing. 1265 */ 1266 if (useragent_addr && useragent_len > 0) { 1267 /* useragent_addr is in the beginning of User-Agent value */ 1268 1269 if (useragent_addr > host_addr) { 1270 /* Move one byte to the LEFT from "Host:" 1271 * to the end of User-Agent 1272 */ 1273 memmove(host_addr - 1, host_addr, 1274 (size_t)(useragent_addr + useragent_len - host_addr)); 1275 host_addr -= 1; 1276 /* Put space in the end of User-Agent header */ 1277 *(char*)((unsigned char*)useragent_addr + useragent_len - 1) = ' '; 1278 should_recalc_checksum = 1; 1279 //printf("Replaced Host header!\n"); 1280 } 1281 else { 1282 /* User-Agent goes BEFORE Host header */ 1283 1284 /* Move one byte to the RIGHT from the end of User-Agent 1285 * to the "Host:" 1286 */ 1287 memmove(useragent_addr + useragent_len + 1, 1288 useragent_addr + useragent_len, 1289 (size_t)(host_addr - 1 - (useragent_addr + useragent_len))); 1290 /* Put space in the end of User-Agent header */ 1291 *(char*)((unsigned char*)useragent_addr + useragent_len) = ' '; 1292 should_recalc_checksum = 1; 1293 //printf("Replaced Host header!\n"); 1294 } 1295 } /* if (host_len <= HOST_MAXLEN && useragent_addr) */ 1296 } /* if (find_header_and_get_info http_useragent) */ 1297 } /* else if (do_host_removespace) */ 1298 } /* if (find_header_and_get_info http_host) */ 1299 } /* Handle OUTBOUND packet with data */ 1300 1301 /* 1302 * should_recalc_checksum mean we have detected a packet to handle and 1303 * modified it in some way. 1304 * Handle native fragmentation here, incl. sending the packet. 1305 */ 1306 if (should_reinject && should_recalc_checksum && do_native_frag) 1307 { 1308 current_fragment_size = 0; 1309 if (do_fragment_http && ppTcpHdr->DstPort == htons(80)) { 1310 current_fragment_size = http_fragment_size; 1311 } 1312 else if (do_fragment_https && ppTcpHdr->DstPort != htons(80)) { 1313 if (do_fragment_by_sni && sni_ok) { 1314 current_fragment_size = (void*)host_addr - packet_data; 1315 } else { 1316 current_fragment_size = https_fragment_size; 1317 } 1318 } 1319 1320 if (current_fragment_size) { 1321 send_native_fragment(w_filter, addr, packet, packetLen, packet_data, 1322 packet_dataLen,packet_v4, packet_v6, 1323 ppIpHdr, ppIpV6Hdr, ppTcpHdr, 1324 current_fragment_size, do_reverse_frag); 1325 1326 send_native_fragment(w_filter, addr, packet, packetLen, packet_data, 1327 packet_dataLen,packet_v4, packet_v6, 1328 ppIpHdr, ppIpV6Hdr, ppTcpHdr, 1329 current_fragment_size, !do_reverse_frag); 1330 continue; 1331 } 1332 } 1333 } /* Handle TCP packet with data */ 1334 1335 /* Else if we got TCP packet without data */ 1336 else if (packet_type == ipv4_tcp || packet_type == ipv6_tcp) { 1337 /* If we got INBOUND SYN+ACK packet */ 1338 if (!addr.Outbound && 1339 ppTcpHdr->Syn == 1 && ppTcpHdr->Ack == 1) { 1340 //printf("Changing Window Size!\n"); 1341 /* 1342 * Window Size is changed even if do_fragment_http_persistent 1343 * is enabled as there could be non-HTTP data on port 80 1344 */ 1345 1346 if (do_fake_packet && (do_auto_ttl || ttl_min_nhops)) { 1347 if (!((packet_v4 && tcp_handle_incoming(&ppIpHdr->SrcAddr, &ppIpHdr->DstAddr, 1348 ppTcpHdr->SrcPort, ppTcpHdr->DstPort, 1349 0, ppIpHdr->TTL)) 1350 || 1351 (packet_v6 && tcp_handle_incoming((uint32_t*)&ppIpV6Hdr->SrcAddr, 1352 (uint32_t*)&ppIpV6Hdr->DstAddr, 1353 ppTcpHdr->SrcPort, ppTcpHdr->DstPort, 1354 1, ppIpV6Hdr->HopLimit)))) 1355 { 1356 if (do_tcp_verb) 1357 puts("[TCP WARN] Can't add TCP connection record."); 1358 } 1359 } 1360 1361 if (!do_native_frag) { 1362 if (do_fragment_http && ppTcpHdr->SrcPort == htons(80)) { 1363 change_window_size(ppTcpHdr, http_fragment_size); 1364 should_recalc_checksum = 1; 1365 } 1366 else if (do_fragment_https && ppTcpHdr->SrcPort != htons(80)) { 1367 change_window_size(ppTcpHdr, https_fragment_size); 1368 should_recalc_checksum = 1; 1369 } 1370 } 1371 } 1372 } 1373 1374 /* Else if we got UDP packet with data */ 1375 else if ((do_dnsv4_redirect && (packet_type == ipv4_udp_data)) || 1376 (do_dnsv6_redirect && (packet_type == ipv6_udp_data))) 1377 { 1378 if (!addr.Outbound) { 1379 if ((packet_v4 && dns_handle_incoming(&ppIpHdr->DstAddr, ppUdpHdr->DstPort, 1380 packet_data, packet_dataLen, 1381 &dns_conn_info, 0)) 1382 || 1383 (packet_v6 && dns_handle_incoming(ppIpV6Hdr->DstAddr, ppUdpHdr->DstPort, 1384 packet_data, packet_dataLen, 1385 &dns_conn_info, 1))) 1386 { 1387 /* Changing source IP and port to the values 1388 * from DNS conntrack */ 1389 if (packet_v4) 1390 ppIpHdr->SrcAddr = dns_conn_info.dstip[0]; 1391 else if (packet_v6) 1392 ipv6_copy_addr(ppIpV6Hdr->SrcAddr, dns_conn_info.dstip); 1393 ppUdpHdr->DstPort = dns_conn_info.srcport; 1394 ppUdpHdr->SrcPort = dns_conn_info.dstport; 1395 should_recalc_checksum = 1; 1396 } 1397 else { 1398 if (dns_is_dns_packet(packet_data, packet_dataLen, 0)) 1399 should_reinject = 0; 1400 1401 if (do_dns_verb && !should_reinject) { 1402 printf("[DNS] Error handling incoming packet: srcport = %hu, dstport = %hu\n", 1403 ntohs(ppUdpHdr->SrcPort), ntohs(ppUdpHdr->DstPort)); 1404 } 1405 } 1406 } 1407 1408 else if (addr.Outbound) { 1409 if ((packet_v4 && dns_handle_outgoing(&ppIpHdr->SrcAddr, ppUdpHdr->SrcPort, 1410 &ppIpHdr->DstAddr, ppUdpHdr->DstPort, 1411 packet_data, packet_dataLen, 0)) 1412 || 1413 (packet_v6 && dns_handle_outgoing(ppIpV6Hdr->SrcAddr, ppUdpHdr->SrcPort, 1414 ppIpV6Hdr->DstAddr, ppUdpHdr->DstPort, 1415 packet_data, packet_dataLen, 1))) 1416 { 1417 /* Changing destination IP and port to the values 1418 * from configuration */ 1419 if (packet_v4) { 1420 ppIpHdr->DstAddr = dnsv4_addr; 1421 ppUdpHdr->DstPort = dnsv4_port; 1422 } 1423 else if (packet_v6) { 1424 ipv6_copy_addr(ppIpV6Hdr->DstAddr, (uint32_t*)dnsv6_addr.s6_addr); 1425 ppUdpHdr->DstPort = dnsv6_port; 1426 } 1427 should_recalc_checksum = 1; 1428 } 1429 else { 1430 if (dns_is_dns_packet(packet_data, packet_dataLen, 1)) 1431 should_reinject = 0; 1432 1433 if (do_dns_verb && !should_reinject) { 1434 printf("[DNS] Error handling outgoing packet: srcport = %hu, dstport = %hu\n", 1435 ntohs(ppUdpHdr->SrcPort), ntohs(ppUdpHdr->DstPort)); 1436 } 1437 } 1438 } 1439 } 1440 1441 if (should_reinject) { 1442 //printf("Re-injecting!\n"); 1443 if (should_recalc_checksum) { 1444 WinDivertHelperCalcChecksums(packet, packetLen, &addr, (UINT64)0LL); 1445 } 1446 WinDivertSend(w_filter, packet, packetLen, NULL, &addr); 1447 } 1448 } 1449 else { 1450 // error, ignore 1451 if (!exiting) 1452 printf("Error receiving packet!\n"); 1453 break; 1454 } 1455 } 1456 }