Browse Source

nfqws: tls mod set sni

pull/1319/head
bol-van 1 day ago
parent
commit
6b0bc7a96b
  1. 1
      docs/changes.txt
  2. 3
      docs/readme.en.md
  3. 5
      docs/readme.md
  4. 5
      nfq/desync.c
  5. 170
      nfq/nfqws.c
  6. 38
      nfq/params.c
  7. 6
      nfq/params.h

1
docs/changes.txt

@ -476,3 +476,4 @@ v70.6
nfqws: detect Discord Voice IP discovery packets
nfqws: detect STUN message packets
nfqws: change SNI to specified value tls mod : --dpi-desync-fake-tls-mod sni=<sni>

3
docs/readme.en.md

@ -174,7 +174,7 @@ nfqws takes the following parameters:
--dpi-desync-any-protocol=0|1 ; 0(default)=desync only http and tls 1=desync any nonempty data packet
--dpi-desync-fake-http=<filename>|0xHEX ; file containing fake http request
--dpi-desync-fake-tls=<filename>|0xHEX ; file containing fake TLS ClientHello (for https)
--dpi-desync-fake-tls-mod=mod[,mod] ; comma separated list of TLS fake mods. available mods : none,rnd,rndsni,dupsid,padencap
--dpi-desync-fake-tls-mod=mod[,mod] ; comma separated list of TLS fake mods. available mods : none,rnd,rndsni,sni=<sni>,dupsid,padencap
--dpi-desync-fake-unknown=<filename>|0xHEX ; file containing unknown protocol fake payload
--dpi-desync-fake-syndata=<filename>|0xHEX ; file containing SYN data payload
--dpi-desync-fake-quic=<filename>|0xHEX ; file containing fake QUIC Initial
@ -285,6 +285,7 @@ It's possible to use TLS Client Hello with any fingerprint and any SNI.
* `rnd`. Randomize `random` and `session id` fields. Applied on every request.
* `rndsni`. Randomize SNI. If SNI >=7 symbols random SLD is applied with known TLD. Otherwise filled with random symbols. Applied only once at startup.
* `dupsid`. Copy `session ID` from original TLS Client Hello. Takes precedence over `rnd`. Applied on every request.
* `sni=<sni>`. Set specified SNI value. Changes TLS fake length, fixes lengths in TLS structure. Applied once at startup before `rndsni`.
* `padencap`. Padding extension is extended by original TLS Client Hello size (including multi packet variation with kyber). Padding extension is added to the end if not present, otherwise it must be the last extension. All lengths are increased. Fake size is not changed. Can be useful if DPI does not analyze sequence numbers properly. Applied on every request.
By default if custom fake is not defined `rnd,rndsni,dupsid` mods are applied. If defined - `none`.

5
docs/readme.md

@ -1,4 +1,4 @@
# zapret v70.5
# zapret v70.6
# ВНИМАНИЕ, остерегайтесь мошенников
@ -196,7 +196,7 @@ dvtws, собираемый из тех же исходников (см. [док
--dpi-desync-any-protocol=0|1 ; 0(default)=работать только по http request и tls clienthello 1=по всем непустым пакетам данных
--dpi-desync-fake-http=<filename>|0xHEX ; файл, содержащий фейковый http запрос для dpi-desync=fake, на замену стандартному www.iana.org
--dpi-desync-fake-tls=<filename>|0xHEX ; файл, содержащий фейковый tls clienthello для dpi-desync=fake, на замену стандартному
--dpi-desync-fake-tls-mod=mod[,mod] ; список через запятую режимов runtime модификации фейков : none,rnd,rndsni,dupsid,padencap
--dpi-desync-fake-tls-mod=mod[,mod] ; список через запятую режимов runtime модификации фейков : none,rnd,rndsni,sni=<sni>,dupsid,padencap
--dpi-desync-fake-unknown=<filename>|0xHEX ; файл, содержащий фейковый пейлоад неизвестного протокола для dpi-desync=fake, на замену стандартным нулям 256 байт
--dpi-desync-fake-syndata=<filename>|0xHEX ; файл, содержащий фейковый пейлоад пакета SYN для режима десинхронизации syndata
--dpi-desync-fake-quic=<filename>|0xHEX ; файл, содержащий фейковый QUIC Initial
@ -340,6 +340,7 @@ dvtws, собираемый из тех же исходников (см. [док
* `rnd`. Рандомизировать поля `random` и `session id`. Выполняется на каждый запрос.
* `dupsid`. Копировать `session ID` из передаваемого TLS Client Hello. Имеет приоритет над `rnd`. Выполняется на каждый запрос.
* `rndsni`. Рандомизировать SNI. Если SNI >=7 символов, применяется случайный домен 2 уровня с известным TLD, иначе заполняется случайными символами без точки. Выполняется один раз при старте.
* `sni=<sni>`. Заменить sni на указанное значение. Макс длина SNI - 63 байта. Общая длина TLS фейка и длины в структуре TLS Client Hello меняются. Выполняется один раз при старте. Если сочетается с `rndsni`, выполняется до него.
* `padencap`. Расширяется padding extension на размер передаваемого TLS Client Hello (включая многопакетный вариант с kyber). Если padding отсутствует, он добавляется в конец. Если присутствует - требуется, чтобы padding шел последним extension. Правятся все длины, чтобы создать видимость включения передаваемого TLS Client Hello в padding extension. Размер фейка не изменяется. Расчет идет на DPI, который не анализирует sequence numbers должным образом. Выполняется на каждый запрос.
По умолчанию если не задан собственный фейк для TLS используются модификации `rnd,rndsni,dupsid`. Если фейк задан, используется `none`.

5
nfq/desync.c

@ -609,7 +609,7 @@ 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, 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)
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)
{
bool b=false;
if (modcache) // it's filled only if it's TLS
@ -630,6 +630,7 @@ static bool runtime_tls_mod(int fake_n,const struct fake_tls_mod_cache *modcache
phton16(fake_mod+modcache->extlen_offset,(uint16_t)sz_ext);
phton16(fake_mod+modcache->padlen_offset,(uint16_t)sz_pad);
b=true;
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)
@ -638,6 +639,7 @@ static bool runtime_tls_mod(int fake_n,const struct fake_tls_mod_cache *modcache
fill_random_bytes(fake_mod+11,32); // random
fill_random_bytes(fake_mod+44,fake_mod[43]); // session id
b=true;
DLOG("fake[%d] applied rnd tls mod\n", fake_n);
}
if (fake_tls_mod & FAKE_TLS_MOD_DUP_SID)
{
@ -650,6 +652,7 @@ static bool runtime_tls_mod(int fake_n,const struct fake_tls_mod_cache *modcache
if (!b) memcpy(fake_mod,fake_data,fake_data_size);
memcpy(fake_mod+44,payload+44,fake_mod[43]); // session id
b=true;
DLOG("fake[%d] applied dupsid tls mod\n", fake_n);
}
}
}

170
nfq/nfqws.c

@ -950,35 +950,57 @@ static bool parse_ip_list(char *opt, ipset *pp)
return true;
}
static bool parse_tlsmod_list(char *opt, uint8_t *mod)
static bool parse_tlsmod_list(char *opt, uint32_t *mod, char *sni, size_t sni_buf_len)
{
char *e,*p,c;
char *e,*e2,*p,c,c2;
*mod &= FAKE_TLS_MOD_SAVE_MASK;
*mod |= FAKE_TLS_MOD_SET;
for (p=opt ; p ; )
{
if ((e = strchr(p,',')))
for (e2=p ; *e2 && *e2!=',' && *e2!='=' ; e2++);
if ((e = strchr(e2,',')))
{
c=*e;
*e=0;
}
if (*e2=='=')
{
c2=*e2;
*e2=0;
}
else
e2=NULL;
if (!strcmp(p,"rnd"))
*mod |= FAKE_TLS_MOD_RND;
else if (!strcmp(p,"rndsni"))
*mod |= FAKE_TLS_MOD_RND_SNI;
else if (!strcmp(p,"sni"))
{
*mod |= FAKE_TLS_MOD_SNI;
if (!e2 || !e2[1] || e2[1]==',') goto err;
strncpy(sni,e2+1,sni_buf_len-1);
sni[sni_buf_len-1]=0;
}
else if (!strcmp(p,"padencap"))
*mod |= FAKE_TLS_MOD_PADENCAP;
else if (!strcmp(p,"dupsid"))
*mod |= FAKE_TLS_MOD_DUP_SID;
else if (strcmp(p,"none"))
return false;
goto err;
if (e2) *e2=c2;
if (e) *e++=c;
p = e;
}
return true;
err:
if (e2) *e2=c2;
if (e) *e++=c;
return false;
}
@ -1012,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, 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)
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)
{
const uint8_t *ext;
size_t extlen, slen;
size_t extlen;
modcache->extlen_offset = modcache->padlen_offset = 0;
if (fake_tls_mod & FAKE_TLS_MOD_PADENCAP)
if (fake_tls_mod & (FAKE_TLS_MOD_PADENCAP|FAKE_TLS_MOD_SNI))
{
if (!TLSFindExtLen(fake_tls,*fake_tls_size,&modcache->extlen_offset))
{
@ -1026,6 +1048,84 @@ static bool onetime_tls_mod_blob(int profile_n, int fake_n, uint8_t fake_tls_mod
return false;
}
DLOG("profile %d fake[%d] tls extensions length offset : %zu\n", profile_n, fake_n, modcache->extlen_offset);
size_t slen;
if (!TLSFindExt(fake_tls,*fake_tls_size,0,&ext,&extlen,false))
{
DLOG_ERR("profile %d fake[%d] sni mod is set but tls fake does not have SNI\n", profile_n, fake_n);
return false;
}
uint8_t *sniext = fake_tls + (ext - fake_tls);
if (!TLSAdvanceToHostInSNI(&ext,&extlen,&slen))
{
DLOG_ERR("profile %d fake[%d] sni set but tls fake has invalid SNI structure\n", profile_n, fake_n);
return false;
}
uint8_t *sni = fake_tls + (ext - fake_tls);
if (fake_tls_mod & FAKE_TLS_MOD_SNI)
{
size_t slen_new = strlen(fake_tls_sni);
ssize_t slen_delta = slen_new-slen;
if (slen_delta)
{
if ((*fake_tls_size+slen_delta)>fake_tls_buf_size)
{
DLOG_ERR("profile %d fake[%d] not enough space for new SNI\n", profile_n, fake_n);
return false;
}
memmove(sni+slen_new,sni+slen,fake_tls+*fake_tls_size-(sni+slen));
phton16(fake_tls+3,(uint16_t)(pntoh16(fake_tls+3)+slen_delta));
phton24(fake_tls+6,(uint32_t)(pntoh24(fake_tls+6)+slen_delta));
phton16(fake_tls+modcache->extlen_offset,(uint16_t)(pntoh16(fake_tls+modcache->extlen_offset)+slen_delta));
phton16(sniext-2,(uint16_t)(pntoh16(sniext-2)+slen_delta));
phton16(sniext,(uint16_t)(pntoh16(sniext)+slen_delta));
phton16(sni-2,(uint16_t)(pntoh16(sni-2)+slen_delta));
*fake_tls_size+=slen_delta;
}
DLOG_ERR("profile %d fake[%d] change sni to %s size_delta=%zd\n", profile_n, fake_n, fake_tls_sni,slen_delta);
memcpy(sni,fake_tls_sni,slen_new);
slen = slen_new;
}
if (fake_tls_mod & FAKE_TLS_MOD_RND_SNI)
{
if (!slen)
{
DLOG_ERR("profile %d fake[%d] rndsni set but tls fake has zero sized SNI\n", profile_n, fake_n);
return false;
}
char *s1=NULL, *s2=NULL;
if (params.debug)
{
if ((s1 = malloc(slen+1)))
{
memcpy(s1,sni,slen); s1[slen]=0;
}
}
fill_random_az(sni,1);
if (slen>=7) // domain name in SNI must be at least 3 chars long to enable xxx.tls randomization
{
fill_random_az09(sni+1,slen-5);
sni[slen-4] = '.';
memcpy(sni+slen-3,tld[random()%(sizeof(tld)/sizeof(*tld))],3);
}
else
fill_random_az09(sni+1,slen-1);
if (params.debug)
{
if (s1 && (s2 = malloc(slen+1)))
{
memcpy(s2,sni,slen); s2[slen]=0;
DLOG("profile %d fake[%d] generated random SNI : %s -> %s\n",profile_n,fake_n,s1,s2);
}
free(s1); free(s2);
}
}
}
if (fake_tls_mod & FAKE_TLS_MOD_PADENCAP)
{
if (TLSFindExt(fake_tls,*fake_tls_size,21,&ext,&extlen,false))
{
if ((ext-fake_tls+extlen)!=*fake_tls_size)
@ -1054,54 +1154,6 @@ static bool onetime_tls_mod_blob(int profile_n, int fake_n, uint8_t fake_tls_mod
DLOG("profile %d fake[%d] tls padding is absent. added. padding length offset %zu\n", profile_n, fake_n, modcache->padlen_offset);
}
}
if (fake_tls_mod & FAKE_TLS_MOD_RND_SNI)
{
if (!TLSFindExt(fake_tls,*fake_tls_size,0,&ext,&extlen,false))
{
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 fake[%d] rndsni set but tls fake has invalid SNI structure\n", profile_n, fake_n);
return false;
}
if (!slen)
{
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 = fake_tls + (ext - fake_tls);
char *s1=NULL, *s2=NULL;
if (params.debug)
{
if ((s1 = malloc(slen+1)))
{
memcpy(s1,sni,slen); s1[slen]=0;
}
}
fill_random_az(sni,1);
if (slen>=7) // domain name in SNI must be at least 3 chars long to enable xxx.tls randomization
{
fill_random_az09(sni+1,slen-5);
sni[slen-4] = '.';
memcpy(sni+slen-3,tld[random()%(sizeof(tld)/sizeof(*tld))],3);
}
else
fill_random_az09(sni+1,slen-1);
if (params.debug)
{
if (s1 && (s2 = malloc(slen+1)))
{
memcpy(s2,sni,slen); s2[slen]=0;
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)
@ -1130,7 +1182,7 @@ static bool onetime_tls_mod(struct desync_profile *dp)
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))
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))
return false;
}
if (!bMod)
@ -1378,7 +1430,7 @@ static void exithelp(void)
" --dpi-desync-any-protocol=0|1\t\t\t; 0(default)=desync only http and tls 1=desync any nonempty data packet\n"
" --dpi-desync-fake-http=<filename>|0xHEX\t; file containing fake http request\n"
" --dpi-desync-fake-tls=<filename>|0xHEX\t\t; file containing fake TLS ClientHello (for https)\n"
" --dpi-desync-fake-tls-mod=mod[,mod]\t\t; comma separated list of TLS fake mods. available mods : none,rnd,rndsni,dupsid,padencap\n"
" --dpi-desync-fake-tls-mod=mod[,mod]\t\t; comma separated list of TLS fake mods. available mods : none,rnd,rndsni,sni=<sni>,dupsid,padencap\n"
" --dpi-desync-fake-unknown=<filename>|0xHEX\t; file containing unknown protocol fake payload\n"
" --dpi-desync-fake-syndata=<filename>|0xHEX\t; file containing SYN data payload\n"
" --dpi-desync-fake-quic=<filename>|0xHEX\t; file containing fake QUIC Initial\n"
@ -2051,11 +2103,11 @@ 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);
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;
break;
case 40: /* dpi-desync-fake-tls-mod */
if (!parse_tlsmod_list(optarg,&dp->fake_tls_mod))
if (!parse_tlsmod_list(optarg,&dp->fake_tls_mod,dp->fake_tls_sni,sizeof(dp->fake_tls_sni)))
{
DLOG_ERR("Invalid tls mod : %s\n",optarg);
exit_clean(1);

38
nfq/params.c

@ -206,7 +206,7 @@ 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))
if (!blob_collection_add_blob(&dp->fake_tls,fake_tls_clienthello_default,sizeof(fake_tls_clienthello_default),4+sizeof(dp->fake_tls_sni)))
return false;
}
if (blob_collection_empty(&dp->fake_unknown))
@ -222,35 +222,15 @@ bool dp_fake_defaults(struct desync_profile *dp)
memset(item->data,0,item->size);
item->data[0] = 0x40;
}
if (blob_collection_empty(&dp->fake_wg))
struct blob_collection_head **fake,*fakes_z64[] = {&dp->fake_wg, &dp->fake_dht, &dp->fake_discord, &dp->fake_stun, &dp->fake_unknown_udp,NULL};
for(fake=fakes_z64;*fake;fake++)
{
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_discord))
{
if (!(item=blob_collection_add_blob(&dp->fake_discord,NULL,64,0)))
return false;
memset(item->data,0,item->size);
}
if (blob_collection_empty(&dp->fake_stun))
{
if (!(item=blob_collection_add_blob(&dp->fake_stun,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);
if (blob_collection_empty(*fake))
{
if (!(item=blob_collection_add_blob(*fake,NULL,64,0)))
return false;
memset(item->data,0,item->size);
}
}
return true;
}

6
nfq/params.h

@ -44,7 +44,8 @@
#define FAKE_TLS_MOD_RND 0x10
#define FAKE_TLS_MOD_DUP_SID 0x20
#define FAKE_TLS_MOD_RND_SNI 0x40
#define FAKE_TLS_MOD_PADENCAP 0x80
#define FAKE_TLS_MOD_SNI 0x80
#define FAKE_TLS_MOD_PADENCAP 0x100
#define FAKE_MAX_TCP 1460
#define FAKE_MAX_UDP 1472
@ -87,7 +88,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;
uint8_t fake_tls_mod;
uint32_t fake_tls_mod;
char fake_tls_sni[64];
int udplen_increment;

Loading…
Cancel
Save