diff --git a/binaries/aarch64/nfqws b/binaries/aarch64/nfqws index 5d0aa70..7bd797a 100755 Binary files a/binaries/aarch64/nfqws and b/binaries/aarch64/nfqws differ diff --git a/binaries/arm/nfqws b/binaries/arm/nfqws index 3c21e5c..7413d13 100755 Binary files a/binaries/arm/nfqws and b/binaries/arm/nfqws differ diff --git a/binaries/freebsd-x64/dvtws b/binaries/freebsd-x64/dvtws index 4b03c88..4a9e390 100755 Binary files a/binaries/freebsd-x64/dvtws and b/binaries/freebsd-x64/dvtws differ diff --git a/binaries/mips32r1-lsb/nfqws b/binaries/mips32r1-lsb/nfqws index be3d5fd..928b574 100755 Binary files a/binaries/mips32r1-lsb/nfqws and b/binaries/mips32r1-lsb/nfqws differ diff --git a/binaries/mips32r1-msb/nfqws b/binaries/mips32r1-msb/nfqws index 8670990..b4333c1 100755 Binary files a/binaries/mips32r1-msb/nfqws and b/binaries/mips32r1-msb/nfqws differ diff --git a/binaries/mips64r2-msb/nfqws b/binaries/mips64r2-msb/nfqws index 411484e..7705541 100755 Binary files a/binaries/mips64r2-msb/nfqws and b/binaries/mips64r2-msb/nfqws differ diff --git a/binaries/ppc/nfqws b/binaries/ppc/nfqws index 881a3b8..8bb0547 100755 Binary files a/binaries/ppc/nfqws and b/binaries/ppc/nfqws differ diff --git a/binaries/x86/nfqws b/binaries/x86/nfqws index 20787f2..c13eb66 100755 Binary files a/binaries/x86/nfqws and b/binaries/x86/nfqws differ diff --git a/binaries/x86_64/nfqws b/binaries/x86_64/nfqws index c137993..6e966d7 100755 Binary files a/binaries/x86_64/nfqws and b/binaries/x86_64/nfqws differ diff --git a/nfq/darkmagic.c b/nfq/darkmagic.c index 25267e7..ccc68a1 100644 --- a/nfq/darkmagic.c +++ b/nfq/darkmagic.c @@ -298,10 +298,12 @@ bool prepare_udp_segment4( const struct sockaddr_in *src, const struct sockaddr_in *dst, uint8_t ttl, uint8_t fooling, + uint16_t padlen, const void *data, uint16_t len, uint8_t *buf, size_t *buflen) { - uint16_t ip_payload_len = sizeof(struct udphdr) + len; + uint16_t datalen = len + padlen; + uint16_t ip_payload_len = sizeof(struct udphdr) + datalen; uint16_t pktlen = sizeof(struct ip) + ip_payload_len; if (pktlen>*buflen) return false; @@ -309,10 +311,12 @@ bool prepare_udp_segment4( struct udphdr *udp = (struct udphdr*)(ip+1); uint8_t *payload = (uint8_t*)(udp+1); + fill_iphdr(ip, &src->sin_addr, &dst->sin_addr, pktlen, IPPROTO_UDP, ttl); - fill_udphdr(udp, src->sin_port, dst->sin_port, len); + fill_udphdr(udp, src->sin_port, dst->sin_port, datalen); memcpy(payload,data,len); + memset(payload+len,0,padlen); udp4_fix_checksum(udp,ip_payload_len,&ip->ip_src,&ip->ip_dst); if (fooling & FOOL_BADSUM) udp->uh_sum^=htons(0xBEAF); @@ -323,10 +327,12 @@ bool prepare_udp_segment6( const struct sockaddr_in6 *src, const struct sockaddr_in6 *dst, uint8_t ttl, uint8_t fooling, + uint16_t padlen, const void *data, uint16_t len, uint8_t *buf, size_t *buflen) { - uint16_t transport_payload_len = sizeof(struct udphdr) + len; + uint16_t datalen = len + padlen; + uint16_t transport_payload_len = sizeof(struct udphdr) + datalen; uint16_t ip_payload_len = transport_payload_len + 8*!!((fooling & (FOOL_HOPBYHOP|FOOL_HOPBYHOP2))==FOOL_HOPBYHOP) + 16*!!(fooling & FOOL_HOPBYHOP2) + @@ -384,9 +390,10 @@ bool prepare_udp_segment6( uint8_t *payload = (uint8_t*)(udp+1); fill_ip6hdr(ip6, &src->sin6_addr, &dst->sin6_addr, ip_payload_len, proto, ttl); - fill_udphdr(udp, src->sin6_port, dst->sin6_port, len); + fill_udphdr(udp, src->sin6_port, dst->sin6_port, datalen); memcpy(payload,data,len); + memset(payload+len,0,padlen); udp6_fix_checksum(udp,transport_payload_len,&ip6->ip6_src,&ip6->ip6_dst); if (fooling & FOOL_BADSUM) udp->uh_sum^=htons(0xBEAF); @@ -397,13 +404,14 @@ bool prepare_udp_segment( const struct sockaddr *src, const struct sockaddr *dst, uint8_t ttl, uint8_t fooling, + uint16_t padlen, const void *data, uint16_t len, uint8_t *buf, size_t *buflen) { return (src->sa_family==AF_INET && dst->sa_family==AF_INET) ? - prepare_udp_segment4((struct sockaddr_in *)src,(struct sockaddr_in *)dst,ttl,fooling,data,len,buf,buflen) : + prepare_udp_segment4((struct sockaddr_in *)src,(struct sockaddr_in *)dst,ttl,fooling,padlen,data,len,buf,buflen) : (src->sa_family==AF_INET6 && dst->sa_family==AF_INET6) ? - prepare_udp_segment6((struct sockaddr_in6 *)src,(struct sockaddr_in6 *)dst,ttl,fooling,data,len,buf,buflen) : + prepare_udp_segment6((struct sockaddr_in6 *)src,(struct sockaddr_in6 *)dst,ttl,fooling,padlen,data,len,buf,buflen) : false; } diff --git a/nfq/darkmagic.h b/nfq/darkmagic.h index 34889eb..1f37cfd 100644 --- a/nfq/darkmagic.h +++ b/nfq/darkmagic.h @@ -73,18 +73,21 @@ bool prepare_udp_segment4( const struct sockaddr_in *src, const struct sockaddr_in *dst, uint8_t ttl, uint8_t fooling, + uint16_t padlen, const void *data, uint16_t len, uint8_t *buf, size_t *buflen); bool prepare_udp_segment6( const struct sockaddr_in6 *src, const struct sockaddr_in6 *dst, uint8_t ttl, uint8_t fooling, + uint16_t padlen, const void *data, uint16_t len, uint8_t *buf, size_t *buflen); bool prepare_udp_segment( const struct sockaddr *src, const struct sockaddr *dst, uint8_t ttl, uint8_t fooling, + uint16_t padlen, const void *data, uint16_t len, uint8_t *buf, size_t *buflen); diff --git a/nfq/desync.c b/nfq/desync.c index add328e..d0e84c4 100644 --- a/nfq/desync.c +++ b/nfq/desync.c @@ -67,22 +67,32 @@ bool desync_valid_zero_stage(enum dpi_desync_mode mode) } bool desync_valid_first_stage(enum dpi_desync_mode mode) { - return mode==DESYNC_FAKE || mode==DESYNC_RST || mode==DESYNC_RSTACK || mode==DESYNC_HOPBYHOP || mode==DESYNC_DESTOPT || mode==DESYNC_IPFRAG1; + return mode==DESYNC_FAKE || mode==DESYNC_FAKE_KNOWN || mode==DESYNC_RST || mode==DESYNC_RSTACK || mode==DESYNC_HOPBYHOP || mode==DESYNC_DESTOPT || mode==DESYNC_IPFRAG1; } bool desync_only_first_stage(enum dpi_desync_mode mode) { return false; } bool desync_valid_second_stage(enum dpi_desync_mode mode) +{ + return mode==DESYNC_NONE || mode==DESYNC_DISORDER || mode==DESYNC_DISORDER2 || mode==DESYNC_SPLIT || mode==DESYNC_SPLIT2 || mode==DESYNC_IPFRAG2 || mode==DESYNC_UDPLEN; +} +bool desync_valid_second_stage_tcp(enum dpi_desync_mode mode) { return mode==DESYNC_NONE || mode==DESYNC_DISORDER || mode==DESYNC_DISORDER2 || mode==DESYNC_SPLIT || mode==DESYNC_SPLIT2 || mode==DESYNC_IPFRAG2; } +bool desync_valid_second_stage_udp(enum dpi_desync_mode mode) +{ + return mode==DESYNC_NONE || mode==DESYNC_UDPLEN || mode==DESYNC_IPFRAG2; +} enum dpi_desync_mode desync_mode_from_string(const char *s) { if (!s) return DESYNC_NONE; else if (!strcmp(s,"fake")) return DESYNC_FAKE; + else if (!strcmp(s,"fakeknown")) + return DESYNC_FAKE_KNOWN; else if (!strcmp(s,"rst")) return DESYNC_RST; else if (!strcmp(s,"rstack")) @@ -105,6 +115,8 @@ enum dpi_desync_mode desync_mode_from_string(const char *s) return DESYNC_DESTOPT; else if (!strcmp(s,"ipfrag1")) return DESYNC_IPFRAG1; + else if (!strcmp(s,"udplen")) + return DESYNC_UDPLEN; return DESYNC_INVALID; } @@ -262,6 +274,7 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s char host[256]; bool bHaveHost=false; bool bIsHttp; + bool bKnownProtocol = false; uint8_t *p, *phost; if ((bIsHttp = IsHttp(data_payload,len_payload))) @@ -277,6 +290,7 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s DLOG("not applying tampering to HTTP without Host:\n") return res; } + bKnownProtocol = true; } else if (IsTLSClientHello(data_payload,len_payload)) { @@ -294,6 +308,7 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s return res; } } + bKnownProtocol = true; } else { @@ -367,6 +382,13 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s b = false; switch(desync_mode) { + case DESYNC_FAKE_KNOWN: + if (!bKnownProtocol) + { + DLOG("not applying fake because of unknown protocol\n"); + desync_mode = params.desync_mode2; + break; + } case DESYNC_FAKE: if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, ttl_fake,params.desync_fooling_mode,params.desync_badseq_increment,params.desync_badseq_ack_increment, @@ -393,7 +415,7 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s case DESYNC_DESTOPT: case DESYNC_IPFRAG1: fooling_orig = (desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (desync_mode==DESYNC_DESTOPT) ? FOOL_DESTOPT : FOOL_IPFRAG1; - if (ip6hdr && params.desync_mode2==DESYNC_NONE) + if (ip6hdr && (params.desync_mode2==DESYNC_NONE || !desync_valid_second_stage_tcp(params.desync_mode2))) { if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, ttl_orig,fooling_orig,0,0, @@ -414,7 +436,7 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s { if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len)) return res; - if (params.desync_mode2==DESYNC_NONE) + if (params.desync_mode2==DESYNC_NONE || !desync_valid_second_stage_tcp(params.desync_mode2)) { if (params.desync_retrans) { @@ -657,6 +679,7 @@ packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, s bool b; char host[256]; bool bHaveHost=false; + bool bKnownProtocol=false; if (IsQUICInitial(data_payload,len_payload)) { @@ -700,6 +723,7 @@ packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, s return res; } } + bKnownProtocol = true; } else { @@ -738,24 +762,32 @@ packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, s pkt1_len = sizeof(pkt1); b = false; - switch(desync_mode) { + case DESYNC_FAKE_KNOWN: + if (!bKnownProtocol) + { + DLOG("not applying fake because of unknown protocol\n"); + desync_mode = params.desync_mode2; + break; + } case DESYNC_FAKE: - if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_fake, params.desync_fooling_mode, fake, fake_size, pkt1, &pkt1_len)) + if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_fake, params.desync_fooling_mode, 0, fake, fake_size, pkt1, &pkt1_len)) return res; DLOG("sending fake request : "); hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n") + if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len)) + return res; b = true; break; case DESYNC_HOPBYHOP: case DESYNC_DESTOPT: case DESYNC_IPFRAG1: fooling_orig = (desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (desync_mode==DESYNC_DESTOPT) ? FOOL_DESTOPT : FOOL_IPFRAG1; - if (ip6hdr && params.desync_mode2==DESYNC_NONE) + if (ip6hdr && (params.desync_mode2==DESYNC_NONE || !desync_valid_second_stage_udp(params.desync_mode2))) { if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, - ttl_orig,fooling_orig, + ttl_orig,fooling_orig,0, data_payload, len_payload, pkt1, &pkt1_len)) { return res; @@ -767,14 +799,13 @@ packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, s return drop; } desync_mode = params.desync_mode2; + break; } if (b) { - if (params.desync_mode2==DESYNC_NONE) + if (params.desync_mode2==DESYNC_NONE || !desync_valid_second_stage_udp(params.desync_mode2)) { - if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len)) - return res; DLOG("reinjecting original packet. len=%zu len_payload=%zu\n", len_pkt, len_payload) #ifdef __FreeBSD__ // FreeBSD tend to pass ipv6 frames with wrong checksum @@ -793,6 +824,14 @@ packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, s switch(desync_mode) { + case DESYNC_UDPLEN: + pkt1_len = sizeof(pkt1); + if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_orig,fooling_orig, params.udplen_increment, data_payload, len_payload, pkt1, &pkt1_len)) + return res; + DLOG("resending original packet with increased by %u length\n", params.udplen_increment); + if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len)) + return res; + return drop; case DESYNC_IPFRAG2: { diff --git a/nfq/desync.h b/nfq/desync.h index b531af0..a7ce2d4 100644 --- a/nfq/desync.h +++ b/nfq/desync.h @@ -22,6 +22,7 @@ enum dpi_desync_mode { DESYNC_NONE=0, DESYNC_INVALID, DESYNC_FAKE, + DESYNC_FAKE_KNOWN, DESYNC_RST, DESYNC_RSTACK, DESYNC_SYNACK, @@ -32,7 +33,8 @@ enum dpi_desync_mode { DESYNC_IPFRAG2, DESYNC_HOPBYHOP, DESYNC_DESTOPT, - DESYNC_IPFRAG1 + DESYNC_IPFRAG1, + DESYNC_UDPLEN }; extern const char *fake_http_request_default; @@ -43,6 +45,8 @@ bool desync_valid_zero_stage(enum dpi_desync_mode mode); bool desync_valid_first_stage(enum dpi_desync_mode mode); bool desync_only_first_stage(enum dpi_desync_mode mode); bool desync_valid_second_stage(enum dpi_desync_mode mode); +bool desync_valid_second_stage_tcp(enum dpi_desync_mode mode); +bool desync_valid_second_stage_udp(enum dpi_desync_mode mode); void desync_init(); packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, struct ip *ip, struct ip6_hdr *ip6hdr, struct tcphdr *tcphdr, size_t len_tcp, uint8_t *data_payload, size_t len_payload); diff --git a/nfq/nfqws.c b/nfq/nfqws.c index 109c58c..1fac593 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -505,7 +505,7 @@ static void exithelp() " --hostspell\t\t\t\t; exact spelling of \"Host\" header. must be 4 chars. default is \"host\"\n" " --hostnospace\t\t\t\t; remove space after Host: and add it to User-Agent: to preserve packet size\n" " --domcase\t\t\t\t; mix domain case : Host: TeSt.cOm\n" - " --dpi-desync=[,][,] ; try to desync dpi state. modes : synack fake rst rstack hopbyhop destopt ipfrag1 disorder disorder2 split split2 ipfrag2\n" + " --dpi-desync=[,][,] ; try to desync dpi state. modes : synack fake fakeknown rst rstack hopbyhop destopt ipfrag1 disorder disorder2 split split2 ipfrag2 udplen\n" #ifdef __linux__ " --dpi-desync-fwmark=\t; override fwmark for desync packet. default = 0x%08X (%u)\n" #elif defined(SO_USER_COOKIE) @@ -530,6 +530,7 @@ static void exithelp() " --dpi-desync-fake-unknown=\t; file containing unknown protocol fake payload\n" " --dpi-desync-fake-quic=\t; file containing fake QUIC Initial\n" " --dpi-desync-fake-unknown-udp= ; file containing unknown udp protocol fake payload\n" + " --dpi-desync-udplen-increment=\t; increase udp packet length by N bytes (default %u)\n" " --dpi-desync-cutoff=[n|d|s]N\t\t; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n" " --hostlist=\t\t\t; apply dpi desync only to the listed hosts (one host per line, subdomains auto apply)\n", CTRACK_T_SYN, CTRACK_T_EST, CTRACK_T_FIN, CTRACK_T_UDP, @@ -539,7 +540,8 @@ static void exithelp() DPI_DESYNC_MAX_FAKE_LEN, DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_UDP_DEFAULT, DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_TCP_DEFAULT, - BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT + BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT, + UDPLEN_INCREMENT_DEFAULT ); exit(1); } @@ -627,6 +629,7 @@ int main(int argc, char **argv) params.desync_badseq_increment = BADSEQ_INCREMENT_DEFAULT; params.desync_badseq_ack_increment = BADSEQ_ACK_INCREMENT_DEFAULT; params.wssize_cutoff_mode = params.desync_cutoff_mode = 'n'; // packet number by default + params.udplen_increment = UDPLEN_INCREMENT_DEFAULT; if (can_drop_root()) // are we root ? { @@ -680,8 +683,9 @@ int main(int argc, char **argv) {"dpi-desync-fake-unknown",required_argument,0,0},// optidx=30 {"dpi-desync-fake-quic",required_argument,0,0},// optidx=31 {"dpi-desync-fake-unknown-udp",required_argument,0,0},// optidx=32 - {"dpi-desync-cutoff",required_argument,0,0},// optidx=33 - {"hostlist",required_argument,0,0}, // optidx=34 + {"dpi-desync-udplen-increment",required_argument,0,0},// optidx=33 + {"dpi-desync-cutoff",required_argument,0,0},// optidx=34 + {"hostlist",required_argument,0,0}, // optidx=35 {NULL,0,NULL,0} }; if (argc < 2) exithelp(); @@ -966,14 +970,17 @@ int main(int argc, char **argv) params.fake_unknown_udp_size = sizeof(params.fake_unknown_udp); load_file_or_exit(optarg,params.fake_unknown_udp,¶ms.fake_unknown_udp_size); break; - case 33: /* desync-cutoff */ + case 33: /* dpi-desync-udplen-increment */ + params.udplen_increment = (uint16_t)atoi(optarg); + break; + case 34: /* desync-cutoff */ if (!parse_cutoff(optarg, ¶ms.desync_cutoff, ¶ms.desync_cutoff_mode)) { fprintf(stderr, "invalid desync-cutoff value\n"); exit_clean(1); } break; - case 34: /* hostlist */ + case 35: /* hostlist */ if (!LoadHostList(¶ms.hostlist, optarg)) exit_clean(1); strncpy(params.hostfile,optarg,sizeof(params.hostfile)); diff --git a/nfq/params.h b/nfq/params.h index f10739a..4882844 100644 --- a/nfq/params.h +++ b/nfq/params.h @@ -23,6 +23,8 @@ #define IPFRAG_UDP_DEFAULT 8 #define IPFRAG_TCP_DEFAULT 32 +#define UDPLEN_INCREMENT_DEFAULT 2 + struct params_s { bool debug; @@ -50,6 +52,7 @@ struct params_s strpool *hostlist; uint8_t fake_http[1432],fake_tls[1432],fake_unknown[1432],fake_unknown_udp[1472],fake_quic[1472]; size_t fake_http_size,fake_tls_size,fake_unknown_size,fake_unknown_udp_size,fake_quic_size; + uint16_t udplen_increment; bool droproot; uid_t uid; gid_t gid;