From 6387315c0be7e602c6a0d9bb00bcfe3f3cdde03d Mon Sep 17 00:00:00 2001 From: bol-van Date: Fri, 21 Mar 2025 17:12:36 +0300 Subject: [PATCH] nfqws: multiple fakes --- nfq/desync.c | 204 +++++++++++++++++++++++++++++++-------------------- nfq/nfqws.c | 167 ++++++++++++++++++++++++++--------------- nfq/params.c | 63 +++++++++++++--- nfq/params.h | 19 +++-- nfq/pools.c | 61 +++++++++++++++ nfq/pools.h | 14 ++++ 6 files changed, 375 insertions(+), 153 deletions(-) diff --git a/nfq/desync.c b/nfq/desync.c index 4a7b330..0ede44c 100644 --- a/nfq/desync.c +++ b/nfq/desync.c @@ -606,45 +606,48 @@ static uint16_t IP4_IP_ID_FIX(const struct ip *ip) // fake_mod buffer must at least sizeof(desync_profile->fake_tls) // size does not change // return : true - altered, false - not altered -static bool runtime_tls_mod(const struct desync_profile *dp, uint8_t *fake_mod, const uint8_t *payload, size_t payload_len) +static bool runtime_tls_mod(int fake_n,const struct fake_tls_mod_cache *modcache, uint8_t fake_tls_mod, const uint8_t *fake_data, size_t fake_data_size, const uint8_t *payload, size_t payload_len, uint8_t *fake_mod) { bool b=false; - if (dp->fake_tls_mod & FAKE_TLS_MOD_PADENCAP) + if (IsTLSClientHello(fake_data,fake_data_size,false)) { - size_t sz_rec = pntoh16(dp->fake_tls+3) + payload_len; - size_t sz_handshake = pntoh24(dp->fake_tls+6) + payload_len; - size_t sz_ext = pntoh16(dp->fake_tls+dp->fake_tls_extlen_offset) + payload_len; - size_t sz_pad = pntoh16(dp->fake_tls+dp->fake_tls_padlen_offset) + payload_len; - if ((sz_rec & ~0xFFFF) || (sz_handshake & ~0xFFFFFF) || (sz_ext & ~0xFFFF) || (sz_pad & ~0xFFFF)) - DLOG("cannot apply padencap tls mod. length overflow.\n"); - else + if (fake_tls_mod & FAKE_TLS_MOD_PADENCAP) { - memcpy(fake_mod,dp->fake_tls,dp->fake_tls_size); - phton16(fake_mod+3,(uint16_t)sz_rec); - phton24(fake_mod+6,(uint32_t)sz_handshake); - phton16(fake_mod+dp->fake_tls_extlen_offset,(uint16_t)sz_ext); - phton16(fake_mod+dp->fake_tls_padlen_offset,(uint16_t)sz_pad); + size_t sz_rec = pntoh16(fake_data+3) + payload_len; + size_t sz_handshake = pntoh24(fake_data+6) + payload_len; + size_t sz_ext = pntoh16(fake_data+modcache->extlen_offset) + payload_len; + size_t sz_pad = pntoh16(fake_data+modcache->padlen_offset) + payload_len; + if ((sz_rec & ~0xFFFF) || (sz_handshake & ~0xFFFFFF) || (sz_ext & ~0xFFFF) || (sz_pad & ~0xFFFF)) + DLOG("fake[%d] cannot apply padencap tls mod. length overflow.\n", fake_n); + else + { + memcpy(fake_mod,fake_data,fake_data_size); + phton16(fake_mod+3,(uint16_t)sz_rec); + phton24(fake_mod+6,(uint32_t)sz_handshake); + phton16(fake_mod+modcache->extlen_offset,(uint16_t)sz_ext); + phton16(fake_mod+modcache->padlen_offset,(uint16_t)sz_pad); + b=true; + } + } + if (fake_tls_mod & FAKE_TLS_MOD_RND) + { + if (!b) memcpy(fake_mod,fake_data,fake_data_size); + fill_random_bytes(fake_mod+11,32); // random + fill_random_bytes(fake_mod+44,fake_mod[43]); // session id b=true; } - } - if (dp->fake_tls_mod & FAKE_TLS_MOD_RND) - { - if (!b) memcpy(fake_mod,dp->fake_tls,dp->fake_tls_size); - fill_random_bytes(fake_mod+11,32); // random - fill_random_bytes(fake_mod+44,fake_mod[43]); // session id - b=true; - } - if (dp->fake_tls_mod & FAKE_TLS_MOD_DUP_SID) - { - if (dp->fake_tls[43]!=payload[43]) - DLOG("cannot apply dupsid tls mod. fake and orig session id length mismatch.\n"); - else if (payload_len<(44+payload[43])) - DLOG("cannot apply dupsid tls mod. data payload is not valid.\n"); - else + if (fake_tls_mod & FAKE_TLS_MOD_DUP_SID) { - if (!b) memcpy(fake_mod,dp->fake_tls,dp->fake_tls_size); - memcpy(fake_mod+44,payload+44,fake_mod[43]); // session id - b=true; + if (fake_data[43]!=payload[43]) + DLOG("fake[%d] cannot apply dupsid tls mod. fake and orig session id length mismatch.\n",fake_n); + else if (payload_len<(44+payload[43])) + DLOG("fake[%d] cannot apply dupsid tls mod. data payload is not valid.\n",fake_n); + else + { + if (!b) memcpy(fake_mod,fake_data,fake_data_size); + memcpy(fake_mod+44,payload+44,fake_mod[43]); // session id + b=true; + } } } return b; @@ -880,8 +883,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint if (!(dis->tcp->th_flags & TH_SYN) && dis->len_payload) { - const uint8_t *fake; - size_t fake_size; + struct blob_collection_head *fake; + char host[256]; bool bHaveHost=false; uint8_t *p, *phost=NULL; @@ -893,7 +896,6 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint int i; uint16_t ip_id; t_l7proto l7proto = UNKNOWN; - uint8_t fake_mod[sizeof(dp->fake_tls)]; if (replay) { @@ -1183,16 +1185,13 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint switch(l7proto) { case HTTP: - fake = dp->fake_http; - fake_size = dp->fake_http_size; + fake = &dp->fake_http; break; case TLS: - fake = runtime_tls_mod(dp,fake_mod,rdata_payload,rlen_payload) ? fake_mod : dp->fake_tls; - fake_size = dp->fake_tls_size; + fake = &dp->fake_tls; break; default: - fake = dp->fake_unknown; - fake_size = dp->fake_unknown_size; + fake = &dp->fake_unknown; break; } if (dp->desync_mode==DESYNC_MULTISPLIT || dp->desync_mode==DESYNC_MULTIDISORDER || dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER) @@ -1273,13 +1272,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint else seqovl_pos = 0; - // we do not need reasm buffer anymore - reasm_orig_cancel(ctrack); - rdata_payload=NULL; - uint32_t fooling_orig = FOOL_NONE; bool bFake = false; - pkt1_len = sizeof(pkt1); switch(dp->desync_mode) { case DESYNC_FAKE_KNOWN: @@ -1291,28 +1285,69 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint } case DESYNC_FAKE: if (reasm_offset) break; - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, - ttl_fake,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), - dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, - fake, fake_size, pkt1, &pkt1_len)) + { - return verdict; + struct blob_item *fake_item; + uint8_t *fake_data; + uint8_t fake_data_buf[FAKE_MAX_TCP]; + int n=0; + + ip_id = IP4_IP_ID_FIX(dis->ip); + + LIST_FOREACH(fake_item, fake, next) + { + n++; + switch(l7proto) + { + case TLS: + if ((fake_item->size <= sizeof(fake_data_buf)) && + runtime_tls_mod(n,(struct fake_tls_mod_cache *)fake_item->extra, dp->fake_tls_mod, fake_item->data, fake_item->size, rdata_payload, rlen_payload, fake_data_buf)) + { + fake_data = fake_data_buf; + break; + } + default: + fake_data = fake_item->data; + } + pkt1_len = sizeof(pkt1); + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, + ttl_fake,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), + dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, + fake_data, fake_item->size, pkt1, &pkt1_len)) + { + reasm_orig_cancel(ctrack); + return verdict; + } + DLOG("sending fake[%d] : ", n); + hexdump_limited_dlog(fake_data,fake_item->size,PKTDATA_MAXDUMP); DLOG("\n"); + if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) + { + reasm_orig_cancel(ctrack); + return verdict; + } + ip_id=IP4_IP_ID_NEXT(ip_id); + } } - DLOG("sending fake : "); - hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n"); bFake = true; break; case DESYNC_RST: case DESYNC_RSTACK: if (reasm_offset) break; + pkt1_len = sizeof(pkt1); if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (dp->desync_mode==DESYNC_RSTACK ? TH_ACK:0), dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, ttl_fake,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, NULL, 0, pkt1, &pkt1_len)) { + reasm_orig_cancel(ctrack); return verdict; } DLOG("sending fake RST/RSTACK\n"); + if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) + { + reasm_orig_cancel(ctrack); + return verdict; + } bFake = true; break; case DESYNC_HOPBYHOP: @@ -1323,8 +1358,11 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint (!split_pos && (dp->desync_mode2==DESYNC_FAKEDSPLIT || dp->desync_mode2==DESYNC_FAKEDDISORDER)) || (!multisplit_count && (dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER)))) { + reasm_orig_cancel(ctrack); + + pkt1_len = sizeof(pkt1); if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, - ttl_orig,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), + ttl_orig,0,0,IP6_FLOW(dis->ip6), fooling_orig,0,0, dis->data_payload, dis->len_payload, pkt1, &pkt1_len)) { @@ -1341,11 +1379,9 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint break; } - if (bFake) - { - if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return verdict; - } + // we do not need reasm buffer anymore + reasm_orig_cancel(ctrack); + rdata_payload=NULL; enum dpi_desync_mode desync_mode = dp->desync_mode2==DESYNC_NONE ? dp->desync_mode : dp->desync_mode2; switch(desync_mode) @@ -1875,8 +1911,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint if (dis->len_payload) { - const uint8_t *fake; - size_t fake_size; + struct blob_collection_head *fake; char host[256]; bool bHaveHost=false; uint16_t ip_id; @@ -2110,20 +2145,16 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint switch(l7proto) { case QUIC: - fake = dp->fake_quic; - fake_size = dp->fake_quic_size; + fake = &dp->fake_quic; break; case WIREGUARD: - fake = dp->fake_wg; - fake_size = dp->fake_wg_size; + fake = &dp->fake_wg; break; case DHT: - fake = dp->fake_dht; - fake_size = dp->fake_dht_size; + fake = &dp->fake_dht; break; default: - fake = dp->fake_unknown_udp; - fake_size = dp->fake_unknown_udp_size; + fake = &dp->fake_unknown_udp; break; } @@ -2140,7 +2171,6 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint } bool bFake = false; - pkt1_len = sizeof(pkt1); switch(dp->desync_mode) { case DESYNC_FAKE_KNOWN: @@ -2150,12 +2180,30 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint break; } case DESYNC_FAKE: - if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_fake, IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), dp->desync_fooling_mode, NULL, 0, 0, fake, fake_size, pkt1, &pkt1_len)) - return verdict; - DLOG("sending fake : "); - hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n"); - if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return verdict; + { + struct blob_item *fake_item; + int n=0; + + ip_id = IP4_IP_ID_FIX(dis->ip); + + LIST_FOREACH(fake_item, fake, next) + { + n++; + pkt1_len = sizeof(pkt1); + if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, + ttl_fake, IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6), + dp->desync_fooling_mode, NULL, 0, 0, + fake_item->data, fake_item->size, pkt1, &pkt1_len)) + { + return verdict; + } + DLOG("sending fake[%d] : ", n); + hexdump_limited_dlog(fake_item->data,fake_item->size,PKTDATA_MAXDUMP); DLOG("\n"); + if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) + return verdict; + ip_id=IP4_IP_ID_NEXT(ip_id); + } + } bFake = true; break; case DESYNC_HOPBYHOP: @@ -2164,9 +2212,9 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint fooling_orig = (dp->desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (dp->desync_mode==DESYNC_DESTOPT) ? FOOL_DESTOPT : FOOL_IPFRAG1; if (dis->ip6 && (dp->desync_mode2==DESYNC_NONE || !desync_valid_second_stage_udp(dp->desync_mode2))) { + pkt1_len = sizeof(pkt1); if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, - ttl_orig,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), - fooling_orig,NULL,0,0, + ttl_orig,0,0,IP6_FLOW(dis->ip6),fooling_orig,NULL,0,0, dis->data_payload, dis->len_payload, pkt1, &pkt1_len)) { return verdict; diff --git a/nfq/nfqws.c b/nfq/nfqws.c index b469fe1..c3b3403 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -1007,74 +1007,67 @@ static void SplitDebug(void) } static const char * tld[]={"com","org","net","edu","gov","biz"}; -static void onetime_tls_mod(struct desync_profile *dp) + +static bool onetime_tls_mod_blob(int profile_n, int fake_n, uint8_t fake_tls_mod, uint8_t *fake_tls, size_t *fake_tls_size, size_t fake_tls_buf_size, struct fake_tls_mod_cache *modcache) { const uint8_t *ext; size_t extlen, slen; - if (dp->n && !(dp->fake_tls_mod & (FAKE_TLS_MOD_SET|FAKE_TLS_MOD_CUSTOM_FAKE))) - dp->fake_tls_mod |= FAKE_TLS_MOD_RND|FAKE_TLS_MOD_RND_SNI|FAKE_TLS_MOD_DUP_SID; // old behavior compat + dup_sid - if (!(dp->fake_tls_mod & ~FAKE_TLS_MOD_SAVE_MASK)) - return; // nothing to do - if (!IsTLSClientHello(dp->fake_tls,dp->fake_tls_size,false) || (dp->fake_tls_size<(44+dp->fake_tls[43]))) // has session id ? + modcache->extlen_offset = modcache->padlen_offset = 0; + if (fake_tls_mod & FAKE_TLS_MOD_PADENCAP) { - DLOG_ERR("profile %d tls mod set but tls fake structure invalid\n", dp->n); - exit_clean(1); - } - if (dp->fake_tls_mod & FAKE_TLS_MOD_PADENCAP) - { - if (!TLSFindExtLen(dp->fake_tls,dp->fake_tls_size,&dp->fake_tls_extlen_offset)) + if (!TLSFindExtLen(fake_tls,*fake_tls_size,&modcache->extlen_offset)) { - DLOG_ERR("profile %d padencap set but tls fake structure invalid\n", dp->n); - exit_clean(1); + DLOG_ERR("profile %d fake[%d] padencap set but tls fake structure invalid\n", profile_n, fake_n); + return false; } - DLOG("profile %d fake tls extensions length offset : %zu\n", dp->n, dp->fake_tls_extlen_offset); - if (TLSFindExt(dp->fake_tls,dp->fake_tls_size,21,&ext,&extlen,false)) + DLOG("profile %d fake[%d] tls extensions length offset : %zu\n", profile_n, fake_n, modcache->extlen_offset); + if (TLSFindExt(fake_tls,*fake_tls_size,21,&ext,&extlen,false)) { - if ((ext-dp->fake_tls+extlen)!=dp->fake_tls_size) + if ((ext-fake_tls+extlen)!=*fake_tls_size) { - DLOG_ERR("profile %d fake tls padding ext is present but it's not at the end. padding ext offset %zu, padding ext size %zu, fake size %zu\n", dp->n, ext-dp->fake_tls, extlen, dp->fake_tls_size); - exit_clean(1); + DLOG_ERR("profile %d fake[%d] tls padding ext is present but it's not at the end. padding ext offset %zu, padding ext size %zu, fake size %zu\n", profile_n, fake_n, ext-fake_tls, extlen, *fake_tls_size); + return false; } - dp->fake_tls_padlen_offset = ext-dp->fake_tls-2; - DLOG("profile %d fake tls padding ext is present, padding length offset %zu\n", dp->n, dp->fake_tls_padlen_offset); + modcache->padlen_offset = ext-fake_tls-2; + DLOG("profile %d fake[%d] tls padding ext is present, padding length offset %zu\n", profile_n, fake_n, modcache->padlen_offset); } else { - if ((dp->fake_tls_size+4)>sizeof(dp->fake_tls)) + if ((*fake_tls_size+4)>fake_tls_buf_size) { - DLOG_ERR("profile %d fake tls padding is absent and there's not space to add it\n", dp->n); - exit_clean(1); + DLOG_ERR("profile %d fake[%d] tls padding is absent and there's no space to add it\n", profile_n, fake_n); + return false; } - phton16(dp->fake_tls+dp->fake_tls_size,21); - dp->fake_tls_size+=2; - dp->fake_tls_padlen_offset=dp->fake_tls_size; - phton16(dp->fake_tls+dp->fake_tls_size,0); - dp->fake_tls_size+=2; - phton16(dp->fake_tls+dp->fake_tls_extlen_offset,pntoh16(dp->fake_tls+dp->fake_tls_extlen_offset)+4); - phton16(dp->fake_tls+3,pntoh16(dp->fake_tls+3)+4); // increase tls record len - phton24(dp->fake_tls+6,pntoh24(dp->fake_tls+6)+4); // increase tls handshake len - DLOG("profile %d fake tls padding is absent. added. padding ledgth offset %zu\n", dp->n, dp->fake_tls_padlen_offset); + phton16(fake_tls+*fake_tls_size,21); + *fake_tls_size+=2; + modcache->padlen_offset=*fake_tls_size; + phton16(fake_tls+*fake_tls_size,0); + *fake_tls_size+=2; + phton16(fake_tls+modcache->extlen_offset,pntoh16(fake_tls+modcache->extlen_offset)+4); + phton16(fake_tls+3,pntoh16(fake_tls+3)+4); // increase tls record len + phton24(fake_tls+6,pntoh24(fake_tls+6)+4); // increase tls handshake len + DLOG("profile %d fake[%d] tls padding is absent. added. padding length offset %zu\n", profile_n, fake_n, modcache->padlen_offset); } } - if (dp->fake_tls_mod & FAKE_TLS_MOD_RND_SNI) + if (fake_tls_mod & FAKE_TLS_MOD_RND_SNI) { - if (!TLSFindExt(dp->fake_tls,dp->fake_tls_size,0,&ext,&extlen,false)) + if (!TLSFindExt(fake_tls,*fake_tls_size,0,&ext,&extlen,false)) { - DLOG_ERR("profile %d rndsni set but tls fake does not have SNI\n", dp->n); - exit_clean(1); + DLOG_ERR("profile %d fake[%d] rndsni set but tls fake does not have SNI\n", profile_n, fake_n); + return false; } if (!TLSAdvanceToHostInSNI(&ext,&extlen,&slen)) { - DLOG_ERR("profile %d rndsni set but tls fake has invalid SNI structure\n", dp->n); - exit_clean(1); + DLOG_ERR("profile %d fake[%d] rndsni set but tls fake has invalid SNI structure\n", profile_n, fake_n); + return false; } if (!slen) { - DLOG_ERR("profile %d rndsni set but tls fake has zero sized SNI\n", dp->n); - exit_clean(1); + DLOG_ERR("profile %d fake[%d] rndsni set but tls fake has zero sized SNI\n", profile_n, fake_n); + return false; } - uint8_t *sni = dp->fake_tls + (ext - dp->fake_tls); + uint8_t *sni = fake_tls + (ext - fake_tls); char *s1=NULL, *s2=NULL; if (params.debug) @@ -1100,11 +1093,66 @@ static void onetime_tls_mod(struct desync_profile *dp) if (s1 && (s2 = malloc(slen+1))) { memcpy(s2,sni,slen); s2[slen]=0; - DLOG("profile %d generated random SNI : %s -> %s\n",dp->n,s1,s2); + DLOG("profile %d fake[%d] generated random SNI : %s -> %s\n",profile_n,fake_n,s1,s2); } free(s1); free(s2); } } + return true; +} +static bool onetime_tls_mod(struct desync_profile *dp) +{ + if (dp->n && !(dp->fake_tls_mod & (FAKE_TLS_MOD_SET|FAKE_TLS_MOD_CUSTOM_FAKE))) + dp->fake_tls_mod |= FAKE_TLS_MOD_RND|FAKE_TLS_MOD_RND_SNI|FAKE_TLS_MOD_DUP_SID; // old behavior compat + dup_sid + if (!(dp->fake_tls_mod & ~FAKE_TLS_MOD_SAVE_MASK)) + return true; // nothing to do + + struct blob_item *fake_tls; + int n=0; + bool bMod=false; + + LIST_FOREACH(fake_tls, &dp->fake_tls, next) + { + ++n; + if (!IsTLSClientHello(fake_tls->data,fake_tls->size,false) || (fake_tls->size < (44+fake_tls->data[43]))) // has session id ? + { + DLOG_ERR("profile %d fake[%d] tls mod set but tls fake structure invalid. mod skipped.\n", dp->n, n); + continue; + + } + bMod = true; + if (!fake_tls->extra) + { + fake_tls->extra = malloc(sizeof(struct fake_tls_mod_cache)); + if (!fake_tls->extra) return false; + } + if (!onetime_tls_mod_blob(dp->n,n,dp->fake_tls_mod,fake_tls->data,&fake_tls->size,fake_tls->size_buf,(struct fake_tls_mod_cache*)fake_tls->extra)) + return false; + } + if (!bMod) + DLOG_ERR("profile %d tls fake list does not have any valid TLS ClientHello\n", dp->n); + return bMod; +} + +static void load_blob_to_collection(const char *filename, struct blob_collection_head *blobs, size_t max_size, size_t size_reserve) +{ + struct blob_item *blob = blob_collection_add(blobs); + uint8_t *p; + if (!blob || (!(blob->data = malloc(max_size+size_reserve)))) + { + DLOG_ERR("out of memory\n"); + exit_clean(1); + } + blob->size = max_size; + load_file_or_exit(filename,blob->data,&blob->size); + p = realloc(blob->data,blob->size+size_reserve); + if (!p) + { + DLOG_ERR("out of memory\n"); + exit_clean(1); + } + blob->data = p; + blob->size_buf = blob->size+size_reserve; } @@ -1992,13 +2040,10 @@ int main(int argc, char **argv) dp->desync_any_proto = !optarg || atoi(optarg); break; case 38: /* dpi-desync-fake-http */ - dp->fake_http_size = sizeof(dp->fake_http); - load_file_or_exit(optarg,dp->fake_http,&dp->fake_http_size); + load_blob_to_collection(optarg, &dp->fake_http, FAKE_MAX_TCP,0); break; case 39: /* dpi-desync-fake-tls */ - dp->fake_tls_size = sizeof(dp->fake_tls); - load_file_or_exit(optarg,dp->fake_tls,&dp->fake_tls_size); - dp->fake_tls_mod |= FAKE_TLS_MOD_CUSTOM_FAKE; + load_blob_to_collection(optarg, &dp->fake_tls, FAKE_MAX_TCP,4); break; case 40: /* dpi-desync-fake-tls-mod */ if (!parse_tlsmod_list(optarg,&dp->fake_tls_mod)) @@ -2008,28 +2053,23 @@ int main(int argc, char **argv) } break; case 41: /* dpi-desync-fake-unknown */ - dp->fake_unknown_size = sizeof(dp->fake_unknown); - load_file_or_exit(optarg,dp->fake_unknown,&dp->fake_unknown_size); + load_blob_to_collection(optarg, &dp->fake_unknown, FAKE_MAX_TCP, 0); break; case 42: /* dpi-desync-fake-syndata */ dp->fake_syndata_size = sizeof(dp->fake_syndata); load_file_or_exit(optarg,dp->fake_syndata,&dp->fake_syndata_size); break; case 43: /* dpi-desync-fake-quic */ - dp->fake_quic_size = sizeof(dp->fake_quic); - load_file_or_exit(optarg,dp->fake_quic,&dp->fake_quic_size); + load_blob_to_collection(optarg, &dp->fake_quic, FAKE_MAX_UDP, 0); break; case 44: /* dpi-desync-fake-wireguard */ - dp->fake_wg_size = sizeof(dp->fake_wg); - load_file_or_exit(optarg,dp->fake_wg,&dp->fake_wg_size); + load_blob_to_collection(optarg, &dp->fake_wg, FAKE_MAX_UDP, 0); break; case 45: /* dpi-desync-fake-dht */ - dp->fake_dht_size = sizeof(dp->fake_dht); - load_file_or_exit(optarg,dp->fake_dht,&dp->fake_dht_size); + load_blob_to_collection(optarg, &dp->fake_dht, FAKE_MAX_UDP, 0); break; case 46: /* dpi-desync-fake-unknown-udp */ - dp->fake_unknown_udp_size = sizeof(dp->fake_unknown_udp); - load_file_or_exit(optarg,dp->fake_unknown_udp,&dp->fake_unknown_udp_size); + load_blob_to_collection(optarg, &dp->fake_unknown_udp, FAKE_MAX_UDP, 0); break; case 47: /* dpi-desync-udplen-increment */ if (sscanf(optarg,"%d",&dp->udplen_increment)<1 || dp->udplen_increment>0x7FFF || dp->udplen_increment<-0x8000) @@ -2475,7 +2515,16 @@ int main(int argc, char **argv) if (AUTOTTL_ENABLED(dp->desync_autottl6)) DLOG("profile %d autottl ipv6 %u:%u-%u\n",dp->n,dp->desync_autottl6.delta,dp->desync_autottl6.min,dp->desync_autottl6.max); split_compat(dp); - onetime_tls_mod(dp); + if (!dp_fake_defaults(dp)) + { + DLOG_ERR("could not fill fake defaults\n"); + exit_clean(1); + } + if (!onetime_tls_mod(dp)) + { + DLOG_ERR("could not mod tls\n"); + exit_clean(1); + } #ifndef __CYGWIN__ if (params.droproot && dp->hostlist_auto && chown(dp->hostlist_auto->filename, params.uid, -1)) DLOG_ERR("could not chown %s. auto hostlist file may not be writable after privilege drop\n", dp->hostlist_auto->filename); diff --git a/nfq/params.c b/nfq/params.c index 2d6590e..6d50d58 100644 --- a/nfq/params.c +++ b/nfq/params.c @@ -184,18 +184,8 @@ void dp_init(struct desync_profile *dp) dp->desync_ipfrag_pos_udp = IPFRAG_UDP_DEFAULT; dp->desync_ipfrag_pos_tcp = IPFRAG_TCP_DEFAULT; dp->desync_repeats = 1; - dp->fake_tls_size = sizeof(fake_tls_clienthello_default); - memcpy(dp->fake_tls,fake_tls_clienthello_default,dp->fake_tls_size); dp->fake_tls_mod = 0; - dp->fake_http_size = strlen(fake_http_request_default); - memcpy(dp->fake_http,fake_http_request_default,dp->fake_http_size); - dp->fake_quic_size = 620; // must be 601+ for TSPU hack - dp->fake_quic[0] = 0x40; // russian TSPU QUIC short header fake - dp->fake_wg_size = 64; - dp->fake_dht_size = 64; - dp->fake_unknown_size = 256; dp->fake_syndata_size = 16; - dp->fake_unknown_udp_size = 64; dp->wscale=-1; // default - dont change scale factor (client) dp->desync_ttl6 = 0xFF; // unused dp->desync_badseq_increment = BADSEQ_INCREMENT_DEFAULT; @@ -207,11 +197,55 @@ void dp_init(struct desync_profile *dp) dp->hostlist_auto_retrans_threshold = HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT; dp->filter_ipv4 = dp->filter_ipv6 = true; } +bool dp_fake_defaults(struct desync_profile *dp) +{ + struct blob_item *item; + if (blob_collection_empty(&dp->fake_http)) + if (!blob_collection_add_blob(&dp->fake_http,fake_http_request_default,strlen(fake_http_request_default),0)) + return false; + if (blob_collection_empty(&dp->fake_tls)) + { + if (!blob_collection_add_blob(&dp->fake_tls,fake_tls_clienthello_default,sizeof(fake_tls_clienthello_default),4)) + return false; + } + if (blob_collection_empty(&dp->fake_unknown)) + { + if (!(item=blob_collection_add_blob(&dp->fake_unknown,NULL,256,0))) + return false; + memset(item->data,0,item->size); + } + if (blob_collection_empty(&dp->fake_quic)) + { + if (!(item=blob_collection_add_blob(&dp->fake_quic,NULL,620,0))) + return false; + memset(item->data,0,item->size); + item->data[0] = 0x40; + } + if (blob_collection_empty(&dp->fake_wg)) + { + if (!(item=blob_collection_add_blob(&dp->fake_wg,NULL,64,0))) + return false; + memset(item->data,0,item->size); + } + if (blob_collection_empty(&dp->fake_dht)) + { + if (!(item=blob_collection_add_blob(&dp->fake_dht,NULL,64,0))) + return false; + memset(item->data,0,item->size); + } + if (blob_collection_empty(&dp->fake_unknown_udp)) + { + if (!(item=blob_collection_add_blob(&dp->fake_unknown_udp,NULL,64,0))) + return false; + memset(item->data,0,item->size); + } + return true; +} struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head) { struct desync_profile_list *entry = calloc(1,sizeof(struct desync_profile_list)); if (!entry) return NULL; - + dp_init(&entry->dp); // add to the tail @@ -234,6 +268,13 @@ static void dp_clear_dynamic(struct desync_profile *dp) ipset_collection_destroy(&dp->ips_collection_exclude); port_filters_destroy(&dp->pf_tcp); port_filters_destroy(&dp->pf_udp); + blob_collection_destroy(&dp->fake_http); + blob_collection_destroy(&dp->fake_tls); + blob_collection_destroy(&dp->fake_unknown); + blob_collection_destroy(&dp->fake_unknown_udp); + blob_collection_destroy(&dp->fake_quic); + blob_collection_destroy(&dp->fake_wg); + blob_collection_destroy(&dp->fake_dht); HostFailPoolDestroy(&dp->hostlist_auto_fail_counters); } void dp_clear(struct desync_profile *dp) diff --git a/nfq/params.h b/nfq/params.h index 1d74a23..877473e 100644 --- a/nfq/params.h +++ b/nfq/params.h @@ -46,8 +46,16 @@ #define FAKE_TLS_MOD_RND_SNI 0x40 #define FAKE_TLS_MOD_PADENCAP 0x80 +#define FAKE_MAX_TCP 1460 +#define FAKE_MAX_UDP 1472 + enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG }; +struct fake_tls_mod_cache +{ + size_t extlen_offset, padlen_offset; +}; + struct desync_profile { int n; // number of the profile @@ -74,12 +82,12 @@ struct desync_profile autottl desync_autottl, desync_autottl6; uint32_t desync_fooling_mode; uint32_t desync_badseq_increment, desync_badseq_ack_increment; - uint8_t fake_http[1460],fake_unknown[1460],fake_syndata[1460],seqovl_pattern[1460],fsplit_pattern[1460]; - uint8_t fake_unknown_udp[1472],udplen_pattern[1472],fake_quic[1472],fake_wg[1472],fake_dht[1472]; - size_t fake_http_size,fake_quic_size,fake_wg_size,fake_dht_size,fake_unknown_size,fake_syndata_size,fake_unknown_udp_size; - uint8_t fake_tls[1460],fake_tls_mod; - size_t fake_tls_size, fake_tls_extlen_offset, fake_tls_padlen_offset; + struct blob_collection_head fake_http,fake_tls,fake_unknown,fake_unknown_udp,fake_quic,fake_wg,fake_dht; + uint8_t fake_syndata[FAKE_MAX_TCP],seqovl_pattern[FAKE_MAX_TCP],fsplit_pattern[FAKE_MAX_TCP],udplen_pattern[FAKE_MAX_UDP]; + size_t fake_syndata_size; + + uint8_t fake_tls_mod; int udplen_increment; @@ -113,6 +121,7 @@ void dp_entry_destroy(struct desync_profile_list *entry); void dp_list_destroy(struct desync_profile_list_head *head); bool dp_list_have_autohostlist(struct desync_profile_list_head *head); void dp_init(struct desync_profile *dp); +bool dp_fake_defaults(struct desync_profile *dp); void dp_clear(struct desync_profile *dp); struct params_s diff --git a/nfq/pools.c b/nfq/pools.c index aca4024..767d8e7 100644 --- a/nfq/pools.c +++ b/nfq/pools.c @@ -517,3 +517,64 @@ bool port_filters_deny_if_empty(struct port_filters_head *head) if (LIST_FIRST(head)) return true; return pf_parse("0",&pf) && port_filter_add(head,&pf); } + + + +struct blob_item *blob_collection_add(struct blob_collection_head *head) +{ + struct blob_item *entry = calloc(1,sizeof(struct blob_item)); + if (entry) + { + // insert to the end + struct blob_item *itemc,*iteml=LIST_FIRST(head); + if (iteml) + { + while ((itemc=LIST_NEXT(iteml,next))) iteml = itemc; + LIST_INSERT_AFTER(iteml, entry, next); + } + else + LIST_INSERT_HEAD(head, entry, next); + } + return entry; +} +struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, const void *data, size_t size, size_t size_reserve) +{ + struct blob_item *entry = calloc(1,sizeof(struct blob_item)); + if (!entry) return NULL; + if (!(entry->data = malloc(size+size_reserve))) + { + free(entry); + return NULL; + } + if (data) memcpy(entry->data,data,size); + entry->size = size; + entry->size_buf = size+size_reserve; + + // insert to the end + struct blob_item *itemc,*iteml=LIST_FIRST(head); + if (iteml) + { + while ((itemc=LIST_NEXT(iteml,next))) iteml = itemc; + LIST_INSERT_AFTER(iteml, entry, next); + } + else + LIST_INSERT_HEAD(head, entry, next); + + return entry; +} + +void blob_collection_destroy(struct blob_collection_head *head) +{ + struct blob_item *entry; + while ((entry = LIST_FIRST(head))) + { + LIST_REMOVE(entry, next); + free(entry->extra); + free(entry->data); + free(entry); + } +} +bool blob_collection_empty(const struct blob_collection_head *head) +{ + return !LIST_FIRST(head); +} diff --git a/nfq/pools.h b/nfq/pools.h index 32190c1..fc17db7 100644 --- a/nfq/pools.h +++ b/nfq/pools.h @@ -146,3 +146,17 @@ bool port_filter_add(struct port_filters_head *head, const port_filter *pf); void port_filters_destroy(struct port_filters_head *head); bool port_filters_in_range(const struct port_filters_head *head, uint16_t port); bool port_filters_deny_if_empty(struct port_filters_head *head); + + +struct blob_item { + uint8_t *data; // main data blob + size_t size; // main data blob size + size_t size_buf;// main data blob allocated size + void *extra; // any data without size + LIST_ENTRY(blob_item) next; +}; +LIST_HEAD(blob_collection_head, blob_item); +struct blob_item *blob_collection_add(struct blob_collection_head *head); +struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, const void *data, size_t size, size_t size_reserve); +void blob_collection_destroy(struct blob_collection_head *head); +bool blob_collection_empty(const struct blob_collection_head *head);