nfqws: support different tls mods for every tls fake

This commit is contained in:
bol-van 2025-04-06 11:29:58 +03:00
parent 7272b243cb
commit 929df3f094
8 changed files with 70 additions and 40 deletions

View File

@ -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

View File

@ -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 СЕГМЕНТАЦИЯ

View File

@ -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;

View File

@ -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);

View File

@ -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))
{

View File

@ -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;

View File

@ -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);
}

View File

@ -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);