From 929df3f09427181407d3364a01e855451013efba Mon Sep 17 00:00:00 2001 From: bol-van Date: Sun, 6 Apr 2025 11:29:58 +0300 Subject: [PATCH] nfqws: support different tls mods for every tls fake --- docs/readme.en.md | 8 ++++-- docs/readme.md | 11 ++++++-- nfq/desync.c | 10 ++++---- nfq/nfqws.c | 64 +++++++++++++++++++++++++++-------------------- nfq/params.c | 6 +++-- nfq/params.h | 9 +++++-- nfq/pools.c | 1 + nfq/pools.h | 1 + 8 files changed, 70 insertions(+), 40 deletions(-) diff --git a/docs/readme.en.md b/docs/readme.en.md index 12f9b22..57d60a5 100644 --- a/docs/readme.en.md +++ b/docs/readme.en.md @@ -291,9 +291,13 @@ It's possible to use TLS Client Hello with any fingerprint and any SNI. By default if custom fake is not defined `rnd,rndsni,dupsid` mods are applied. If defined - `none`. This behaviour is compatible with previous versions with addition of `dupsid`. -If TLS mod is enabled and there're multiple TLS fakes, all valid TLS Client Hello fakes are modified. -If there's no TLS Client Hello program exits with error. +If multiple TLS fakes are present each one takes the last mod. +If a mod is specified after fake it replaces previous mod. +This way it's possible to use different mods for every TLS fake. +If a mod is set to non-TLS fake it causes error. Use `--dpi-desync-fake-tls-mod=none'. + +Example : `--dpi-desync-fake-tls=iana_org.bin --dpi-desync-fake-tls-mod=rndsni --dpi-desync-fake-tls=0xaabbccdd --dpi-desync-fake-tls-mod=none' ### TCP segmentation diff --git a/docs/readme.md b/docs/readme.md index 3e16259..4cb5743 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -346,8 +346,15 @@ dvtws, собираемый из тех же исходников (см. [док По умолчанию если не задан собственный фейк для TLS используются модификации `rnd,rndsni,dupsid`. Если фейк задан, используется `none`. Это соответствует поведению программы более старых версий с добавлением функции `dupsid`. -Если задан режим модификации и имеется множество TLS фейков, модифицируются все фейки, являющиеся TLS Client Hello. -Если нет ни одного TLS Client Hello фейка, программа завершается с ошибкой. +Если задан режим модификации и имеется множество TLS фейков, к каждому из них применяется последний режим модификации. +Если режим модификации задан после фейка, то он замещает предыдущий режим. +Таким образом можно использовать разные режимы модификации для разных фейков. +При невозможности модифицировать фейк на этапе запуска программа завершается с ошибкой. + +Если сначала идет TLS фейк, для него задан режим однократной модификации, затем идет не TLS фейк, то будет ошибка. +Нужно использовать `--dpi-desync-fake-tls-mod=none'. + +Пример : `--dpi-desync-fake-tls=iana_org.bin --dpi-desync-fake-tls-mod=rndsni --dpi-desync-fake-tls=0xaabbccdd --dpi-desync-fake-tls-mod=none' ### TCP СЕГМЕНТАЦИЯ diff --git a/nfq/desync.c b/nfq/desync.c index ccc17b8..d2636ce 100644 --- a/nfq/desync.c +++ b/nfq/desync.c @@ -623,12 +623,12 @@ 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(int fake_n,const struct fake_tls_mod_cache *modcache, uint32_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) +static bool runtime_tls_mod(int fake_n,const struct fake_tls_mod_cache *modcache, const struct fake_tls_mod *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 (modcache) // it's filled only if it's TLS { - if (fake_tls_mod & FAKE_TLS_MOD_PADENCAP) + if (tls_mod->mod & FAKE_TLS_MOD_PADENCAP) { size_t sz_rec = pntoh16(fake_data+3) + payload_len; size_t sz_handshake = pntoh24(fake_data+6) + payload_len; @@ -647,7 +647,7 @@ static bool runtime_tls_mod(int fake_n,const struct fake_tls_mod_cache *modcache DLOG("fake[%d] applied padencap tls mod. sizes increased by %zu bytes.\n", fake_n, payload_len); } } - if (fake_tls_mod & FAKE_TLS_MOD_RND) + if (tls_mod->mod & FAKE_TLS_MOD_RND) { if (!b) memcpy(fake_mod,fake_data,fake_data_size); fill_random_bytes(fake_mod+11,32); // random @@ -655,7 +655,7 @@ static bool runtime_tls_mod(int fake_n,const struct fake_tls_mod_cache *modcache b=true; DLOG("fake[%d] applied rnd tls mod\n", fake_n); } - if (fake_tls_mod & FAKE_TLS_MOD_DUP_SID) + if (tls_mod->mod & FAKE_TLS_MOD_DUP_SID) { if (fake_data[43]!=payload[43]) DLOG("fake[%d] cannot apply dupsid tls mod. fake and orig session id length mismatch.\n",fake_n); @@ -1321,7 +1321,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint { 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)) + runtime_tls_mod(n,(struct fake_tls_mod_cache *)fake_item->extra,(struct fake_tls_mod *)fake_item->extra2, fake_item->data, fake_item->size, rdata_payload, rlen_payload, fake_data_buf)) { fake_data = fake_data_buf; break; diff --git a/nfq/nfqws.c b/nfq/nfqws.c index aea52d7..4c71fe3 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -1034,13 +1034,13 @@ static void SplitDebug(void) static const char * tld[]={"com","org","net","edu","gov","biz"}; -static bool onetime_tls_mod_blob(int profile_n, int fake_n, uint32_t fake_tls_mod, const char *fake_tls_sni, uint8_t *fake_tls, size_t *fake_tls_size, size_t fake_tls_buf_size, struct fake_tls_mod_cache *modcache) +static bool onetime_tls_mod_blob(int profile_n, int fake_n, const struct fake_tls_mod *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; modcache->extlen_offset = modcache->padlen_offset = 0; - if (fake_tls_mod & (FAKE_TLS_MOD_RND_SNI|FAKE_TLS_MOD_SNI|FAKE_TLS_MOD_PADENCAP)) + if (tls_mod->mod & (FAKE_TLS_MOD_RND_SNI|FAKE_TLS_MOD_SNI|FAKE_TLS_MOD_PADENCAP)) { if (!TLSFindExtLen(fake_tls,*fake_tls_size,&modcache->extlen_offset)) { @@ -1048,7 +1048,7 @@ static bool onetime_tls_mod_blob(int profile_n, int fake_n, uint32_t fake_tls_mo return false; } DLOG("profile %d fake[%d] tls extensions length offset : %zu\n", profile_n, fake_n, modcache->extlen_offset); - if (fake_tls_mod & (FAKE_TLS_MOD_RND_SNI|FAKE_TLS_MOD_SNI)) + if (tls_mod->mod & (FAKE_TLS_MOD_RND_SNI|FAKE_TLS_MOD_SNI)) { size_t slen; if (!TLSFindExt(fake_tls,*fake_tls_size,0,&ext,&extlen,false)) @@ -1063,9 +1063,9 @@ static bool onetime_tls_mod_blob(int profile_n, int fake_n, uint32_t fake_tls_mo return false; } uint8_t *sni = fake_tls + (ext - fake_tls); - if (fake_tls_mod & FAKE_TLS_MOD_SNI) + if (tls_mod->mod & FAKE_TLS_MOD_SNI) { - size_t slen_new = strlen(fake_tls_sni); + size_t slen_new = strlen(tls_mod->sni); ssize_t slen_delta = slen_new-slen; char *s1=NULL; if (params.debug) @@ -1093,12 +1093,12 @@ static bool onetime_tls_mod_blob(int profile_n, int fake_n, uint32_t fake_tls_mo *fake_tls_size+=slen_delta; slen = slen_new; } - DLOG("profile %d fake[%d] change SNI : %s => %s size_delta=%zd\n", profile_n, fake_n, s1, fake_tls_sni, slen_delta); + DLOG("profile %d fake[%d] change SNI : %s => %s size_delta=%zd\n", profile_n, fake_n, s1, tls_mod->sni, slen_delta); free(s1); - memcpy(sni,fake_tls_sni,slen_new); + memcpy(sni,tls_mod->sni,slen_new); } - if (fake_tls_mod & FAKE_TLS_MOD_RND_SNI) + if (tls_mod->mod & FAKE_TLS_MOD_RND_SNI) { if (!slen) { @@ -1136,7 +1136,7 @@ static bool onetime_tls_mod_blob(int profile_n, int fake_n, uint32_t fake_tls_mo } } } - if (fake_tls_mod & FAKE_TLS_MOD_PADENCAP) + if (tls_mod->mod & FAKE_TLS_MOD_PADENCAP) { if (TLSFindExt(fake_tls,*fake_tls_size,21,&ext,&extlen,false)) { @@ -1171,39 +1171,37 @@ static bool onetime_tls_mod_blob(int profile_n, int fake_n, uint32_t fake_tls_mo } 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; + struct fake_tls_mod *tls_mod; 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("profile %d fake[%d] tls mod set but tls fake structure invalid. mod skipped.\n", dp->n, n); + tls_mod = (struct fake_tls_mod *)fake_tls->extra2; + if (!tls_mod) continue; + if (dp->n && !(tls_mod->mod & (FAKE_TLS_MOD_SET|FAKE_TLS_MOD_CUSTOM_FAKE))) + tls_mod->mod |= FAKE_TLS_MOD_RND|FAKE_TLS_MOD_RND_SNI|FAKE_TLS_MOD_DUP_SID; // old behavior compat + dup_sid + if (!(tls_mod->mod & ~FAKE_TLS_MOD_SAVE_MASK)) continue; + if (!IsTLSClientHello(fake_tls->data,fake_tls->size,false) || (fake_tls->size < (44+fake_tls->data[43]))) // has session id ? + { + DLOG("profile %d fake[%d] tls mod set but tls fake structure invalid.\n", dp->n, n); + return false; } - 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,dp->fake_tls_sni,fake_tls->data,&fake_tls->size,fake_tls->size_buf,(struct fake_tls_mod_cache*)fake_tls->extra)) + if (!onetime_tls_mod_blob(dp->n,n,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; + return true; } -static void load_blob_to_collection(const char *filename, struct blob_collection_head *blobs, size_t max_size, size_t size_reserve) +static struct blob_item *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; @@ -1222,6 +1220,7 @@ static void load_blob_to_collection(const char *filename, struct blob_collection } blob->data = p; blob->size_buf = blob->size+size_reserve; + return blob; } @@ -2116,15 +2115,26 @@ int main(int argc, char **argv) load_blob_to_collection(optarg, &dp->fake_http, FAKE_MAX_TCP,0); break; case 39: /* dpi-desync-fake-tls */ - load_blob_to_collection(optarg, &dp->fake_tls, FAKE_MAX_TCP,4+sizeof(dp->fake_tls_sni)); - dp->fake_tls_mod |= FAKE_TLS_MOD_CUSTOM_FAKE; + { + dp->tls_fake_last = load_blob_to_collection(optarg, &dp->fake_tls, FAKE_MAX_TCP,4+sizeof(dp->tls_mod_last.sni)); + if (!(dp->tls_fake_last->extra2 = malloc(sizeof(struct fake_tls_mod)))) + { + DLOG_ERR("out of memory\n"); + exit_clean(1); + } + struct fake_tls_mod *tls_mod = (struct fake_tls_mod*)dp->tls_fake_last->extra2; + *tls_mod = dp->tls_mod_last; + tls_mod->mod |= FAKE_TLS_MOD_CUSTOM_FAKE; + } break; case 40: /* dpi-desync-fake-tls-mod */ - if (!parse_tlsmod_list(optarg,&dp->fake_tls_mod,dp->fake_tls_sni,sizeof(dp->fake_tls_sni))) + if (!parse_tlsmod_list(optarg,&dp->tls_mod_last.mod,dp->tls_mod_last.sni,sizeof(dp->tls_mod_last.sni))) { DLOG_ERR("Invalid tls mod : %s\n",optarg); exit_clean(1); } + if (dp->tls_fake_last) + *(struct fake_tls_mod*)dp->tls_fake_last->extra2 = dp->tls_mod_last; break; case 41: /* dpi-desync-fake-unknown */ load_blob_to_collection(optarg, &dp->fake_unknown, FAKE_MAX_TCP, 0); diff --git a/nfq/params.c b/nfq/params.c index 88bdac5..d862b6e 100644 --- a/nfq/params.c +++ b/nfq/params.c @@ -185,7 +185,6 @@ 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_mod = 0; dp->fake_syndata_size = 16; dp->wscale=-1; // default - dont change scale factor (client) dp->desync_ttl6 = 0xFF; // unused @@ -206,8 +205,11 @@ bool dp_fake_defaults(struct desync_profile *dp) 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+sizeof(dp->fake_tls_sni))) + if (!(item=blob_collection_add_blob(&dp->fake_tls,fake_tls_clienthello_default,sizeof(fake_tls_clienthello_default),4+sizeof(((struct fake_tls_mod*)0)->sni)))) return false; + if (!(item->extra2 = malloc(sizeof(struct fake_tls_mod)))) + return false; + *(struct fake_tls_mod*)item->extra2 = dp->tls_mod_last; } if (blob_collection_empty(&dp->fake_unknown)) { diff --git a/nfq/params.h b/nfq/params.h index 9545991..015059a 100644 --- a/nfq/params.h +++ b/nfq/params.h @@ -56,6 +56,11 @@ struct fake_tls_mod_cache { size_t extlen_offset, padlen_offset; }; +struct fake_tls_mod +{ + char sni[64]; + uint32_t mod; +}; struct desync_profile { @@ -88,8 +93,8 @@ struct desync_profile 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; - uint32_t fake_tls_mod; - char fake_tls_sni[64]; + struct fake_tls_mod tls_mod_last; + struct blob_item *tls_fake_last; int udplen_increment; diff --git a/nfq/pools.c b/nfq/pools.c index 767d8e7..c4ac8fe 100644 --- a/nfq/pools.c +++ b/nfq/pools.c @@ -570,6 +570,7 @@ void blob_collection_destroy(struct blob_collection_head *head) { LIST_REMOVE(entry, next); free(entry->extra); + free(entry->extra2); free(entry->data); free(entry); } diff --git a/nfq/pools.h b/nfq/pools.h index fc17db7..034ccb2 100644 --- a/nfq/pools.h +++ b/nfq/pools.h @@ -153,6 +153,7 @@ struct blob_item { size_t size; // main data blob size size_t size_buf;// main data blob allocated size void *extra; // any data without size + void *extra2; // any data without size LIST_ENTRY(blob_item) next; }; LIST_HEAD(blob_collection_head, blob_item);