Browse Source

Merge pull request #6 from vemneyy/copilot/add-dpi-desync-split-pos-param

Add file-based split list support for `--dpi-desync-split-pos` with per-fake random selection
pull/2093/head
vemneyy 4 months ago
committed by GitHub
parent
commit
deeed587cf
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 5
      docs/readme.en.md
  2. 3
      docs/readme.md
  3. 12
      nfq/desync.c
  4. 50
      nfq/nfqws.c
  5. 1
      nfq/params.h

5
docs/readme.en.md

@ -197,7 +197,7 @@ nfqws takes the following parameters:
--dpi-desync-fooling=<mode>[,<mode>] ; can use multiple comma separated values. modes : none md5sig ts badseq badsum datanoack hopbyhop hopbyhop2 --dpi-desync-fooling=<mode>[,<mode>] ; can use multiple comma separated values. modes : none md5sig ts badseq badsum datanoack hopbyhop hopbyhop2
--dpi-desync-repeats=<N> ; send every desync packet N times --dpi-desync-repeats=<N> ; send every desync packet N times
--dpi-desync-skip-nosni=0|1 ; 1(default)=do not act on ClientHello without SNI (ESNI ?) --dpi-desync-skip-nosni=0|1 ; 1(default)=do not act on ClientHello without SNI (ESNI ?)
--dpi-desync-split-pos=N|-N|marker+N|marker-N ; comma separated list of split positions --dpi-desync-split-pos=N|-N|marker+N|marker-N|@file ; comma separated list of split positions or @file (one position per line)
; markers: method,host,endhost,sld,endsld,midsld,sniext ; markers: method,host,endhost,sld,endsld,midsld,sniext
; full list is only used by multisplit and multidisorder ; full list is only used by multisplit and multidisorder
; fakedsplit/fakeddisorder use first l7-protocol-compatible parameter if present, first abs value otherwise ; fakedsplit/fakeddisorder use first l7-protocol-compatible parameter if present, first abs value otherwise
@ -442,7 +442,8 @@ When splitting all markers are resolved to absolute offsets. If a relative posit
In `multisplit`or `multidisorder` case split is cancelled if no position remained. In `multisplit`or `multidisorder` case split is cancelled if no position remained.
`fakedsplit` и `fakeddisorder` use only one split position. It's searched from the `--dpi-desync-split-pos` list by a special alorightm. `fakedsplit` и `fakeddisorder` use only one split position. It's searched from the `--dpi-desync-split-pos` list by a special algorithm.
If split positions were loaded from `@file`, one position is randomly selected from that file list for each fake packet.
First relative markers are searched. If no suitable found absolute markers are searched. If nothing found position 1 is used. First relative markers are searched. If no suitable found absolute markers are searched. If nothing found position 1 is used.
For example, `--dpi-desync-split-pos=method+2,midsld,5` means `method+2` for http, `midsld` for TLS and 5 for others. For example, `--dpi-desync-split-pos=method+2,midsld,5` means `method+2` for http, `midsld` for TLS and 5 for others.

3
docs/readme.md

@ -230,7 +230,7 @@ dvtws, собираемый из тех же исходников (см. [док
--dpi-desync-fooling=<fooling> ; дополнительные методики как сделать, чтобы фейковый пакет не дошел до сервера. none md5sig badseq badsum datanoack ts hopbyhop hopbyhop2 --dpi-desync-fooling=<fooling> ; дополнительные методики как сделать, чтобы фейковый пакет не дошел до сервера. none md5sig badseq badsum datanoack ts hopbyhop hopbyhop2
--dpi-desync-repeats=<N> ; посылать каждый генерируемый в nfqws пакет N раз (не влияет на остальные пакеты) --dpi-desync-repeats=<N> ; посылать каждый генерируемый в nfqws пакет N раз (не влияет на остальные пакеты)
--dpi-desync-skip-nosni=0|1 ; 1(default)=не применять dpi desync для запросов без hostname в SNI, в частности для ESNI --dpi-desync-skip-nosni=0|1 ; 1(default)=не применять dpi desync для запросов без hostname в SNI, в частности для ESNI
--dpi-desync-split-pos=N|-N|marker+N|marker-N ; список через запятую маркеров для tcp сегментации в режимах split и disorder --dpi-desync-split-pos=N|-N|marker+N|marker-N|@file ; список через запятую маркеров для tcp сегментации или @file (одна позиция в строке)
--dpi-desync-split-seqovl=N|-N|marker+N|marker-N ; единичный маркер, определяющий величину перекрытия sequence в режимах split и disorder. для split поддерживается только положительное число. --dpi-desync-split-seqovl=N|-N|marker+N|marker-N ; единичный маркер, определяющий величину перекрытия sequence в режимах split и disorder. для split поддерживается только положительное число.
--dpi-desync-split-seqovl-pattern=[+ofs]@<filename>|0xHEX ; чем заполнять фейковую часть overlap --dpi-desync-split-seqovl-pattern=[+ofs]@<filename>|0xHEX ; чем заполнять фейковую часть overlap
--dpi-desync-fakedsplit-pattern=[+ofs]@<filename>|0xHEX ; чем заполнять фейки в fakedsplit/fakeddisorder --dpi-desync-fakedsplit-pattern=[+ofs]@<filename>|0xHEX ; чем заполнять фейки в fakedsplit/fakeddisorder
@ -540,6 +540,7 @@ hex строка начинается с "0x". Имя файла можно пи
В вариантах `multisplit` и `multidisorder` если не осталось ни одной позиции, разбиение не происходит. В вариантах `multisplit` и `multidisorder` если не осталось ни одной позиции, разбиение не происходит.
Варианты `fakedsplit` и `fakeddisorder` применяют только одну позицию сплита. Ее поиск среди списка `--dpi-desync-split-pos` осуществляется особым образом. Варианты `fakedsplit` и `fakeddisorder` применяют только одну позицию сплита. Ее поиск среди списка `--dpi-desync-split-pos` осуществляется особым образом.
Если список задан через `@file`, для каждого формируемого фейка позиция выбирается случайно из строк этого файла.
Сначала сверяются все относительные маркеры. Если среди них найден подходящий, применяется он. В противном случае сверяются все абсолютные маркеры. Сначала сверяются все относительные маркеры. Если среди них найден подходящий, применяется он. В противном случае сверяются все абсолютные маркеры.
Если и среди них ничего не найдено, применяется позиция 1. Если и среди них ничего не найдено, применяется позиция 1.

12
nfq/desync.c

@ -1964,8 +1964,18 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
else if (dp->desync_mode == DESYNC_FAKEDSPLIT || dp->desync_mode == DESYNC_FAKEDDISORDER || dp->desync_mode2 == DESYNC_FAKEDSPLIT || dp->desync_mode2 == DESYNC_FAKEDDISORDER) else if (dp->desync_mode == DESYNC_FAKEDSPLIT || dp->desync_mode == DESYNC_FAKEDDISORDER || dp->desync_mode2 == DESYNC_FAKEDSPLIT || dp->desync_mode2 == DESYNC_FAKEDDISORDER)
{ {
multisplit_count = 0; multisplit_count = 0;
split_pos = 0;
if (dp->split_random_count > 0)
{
int n = random() % dp->split_random_count;
for (i = 0, split_pos = 0; i < dp->split_random_count && !split_pos; i++)
{
int k = dp->split_random_start + (n + i) % dp->split_random_count;
split_pos = ResolvePos(rdata_payload, rlen_payload, l7proto, dp->splits + k);
}
}
// first look for non-abs split // first look for non-abs split
for (i = 0, split_pos = 0; i < dp->split_count && !split_pos; i++) for (i = 0; i < dp->split_count && !split_pos; i++)
if (dp->splits[i].marker != PM_ABS) if (dp->splits[i].marker != PM_ABS)
split_pos = ResolvePos(rdata_payload, rlen_payload, l7proto, dp->splits + i); split_pos = ResolvePos(rdata_payload, rlen_payload, l7proto, dp->splits + i);
// second look for abs split // second look for abs split

50
nfq/nfqws.c

@ -1198,6 +1198,42 @@ static bool parse_split_pos_list(char *opt, struct proto_pos *splits, int splits
if (p) return false; // too much splits if (p) return false; // too much splits
return true; return true;
} }
static bool load_split_pos_file(const char *filename, struct proto_pos *splits, int splits_size, int *split_count)
{
FILE *f = fopen(filename, "r");
if (!f)
{
DLOG_PERROR("fopen split-pos file");
return false;
}
char line[256], *p, *trim_pos;
int line_num = 0;
*split_count = 0;
while (fgets(line, sizeof(line), f))
{
line_num++;
if (*split_count >= splits_size)
{
fclose(f);
return false;
}
if ((p = strchr(line, '\n'))) *p = 0;
if ((p = strchr(line, '\r'))) *p = 0;
for (p = line; *p == ' ' || *p == '\t'; p++);
if (!*p || *p == '#') continue;
trim_pos = p + strlen(p) - 1;
while (trim_pos > p && (*trim_pos == ' ' || *trim_pos == '\t')) *trim_pos-- = 0;
if (!parse_split_pos(p, splits + *split_count))
{
DLOG_ERR("split-pos file %s line %d: invalid split pos: %s\n", filename, line_num, p);
fclose(f);
return false;
}
(*split_count)++;
}
fclose(f);
return *split_count > 0;
}
static bool parse_domain_list(char *opt, hostlist_pool **pp) static bool parse_domain_list(char *opt, hostlist_pool **pp)
{ {
@ -2047,7 +2083,7 @@ static void exithelp(void)
" --dpi-desync-fooling=<mode>[,<mode>]\t\t\t; can use multiple comma separated values. modes : none md5sig badseq badsum datanoack ts hopbyhop hopbyhop2\n" " --dpi-desync-fooling=<mode>[,<mode>]\t\t\t; can use multiple comma separated values. modes : none md5sig badseq badsum datanoack ts hopbyhop hopbyhop2\n"
" --dpi-desync-repeats=<N>\t\t\t\t; send every desync packet N times\n" " --dpi-desync-repeats=<N>\t\t\t\t; send every desync packet N times\n"
" --dpi-desync-skip-nosni=0|1\t\t\t\t; 1(default)=do not act on ClientHello without SNI\n" " --dpi-desync-skip-nosni=0|1\t\t\t\t; 1(default)=do not act on ClientHello without SNI\n"
" --dpi-desync-split-pos=N|-N|marker+N|marker-N\t\t; comma separated list of split positions\n" " --dpi-desync-split-pos=N|-N|marker+N|marker-N|@file\t; comma separated list of split positions or file (one position per line)\n"
"\t\t\t\t\t\t\t; markers: method,host,endhost,sld,endsld,midsld,sniext\n" "\t\t\t\t\t\t\t; markers: method,host,endhost,sld,endsld,midsld,sniext\n"
"\t\t\t\t\t\t\t; full list is only used by multisplit and multidisorder\n" "\t\t\t\t\t\t\t; full list is only used by multisplit and multidisorder\n"
"\t\t\t\t\t\t\t; fakedsplit/fakeddisorder use first l7-protocol-compatible parameter if present, first abs value otherwise\n" "\t\t\t\t\t\t\t; fakedsplit/fakeddisorder use first l7-protocol-compatible parameter if present, first abs value otherwise\n"
@ -3037,7 +3073,17 @@ int main(int argc, char **argv)
case IDX_DPI_DESYNC_SPLIT_POS: case IDX_DPI_DESYNC_SPLIT_POS:
{ {
int ct; int ct;
if (!parse_split_pos_list(optarg, dp->splits + dp->split_count, MAX_SPLITS - dp->split_count, &ct)) if (*optarg == '@')
{
if (!load_split_pos_file(optarg + 1, dp->splits + dp->split_count, MAX_SPLITS - dp->split_count, &ct))
{
DLOG_ERR("could not load split pos list from file or too much positions (before parsing - %u, max - %u) : %s\n", dp->split_count, MAX_SPLITS, optarg + 1);
exit_clean(1);
}
if (!dp->split_random_count) dp->split_random_start = dp->split_count;
dp->split_random_count += ct;
}
else if (!parse_split_pos_list(optarg, dp->splits + dp->split_count, MAX_SPLITS - dp->split_count, &ct))
{ {
DLOG_ERR("could not parse split pos list or too much positions (before parsing - %u, max - %u) : %s\n", dp->split_count, MAX_SPLITS, optarg); DLOG_ERR("could not parse split pos list or too much positions (before parsing - %u, max - %u) : %s\n", dp->split_count, MAX_SPLITS, optarg);
exit_clean(1); exit_clean(1);

1
nfq/params.h

@ -131,6 +131,7 @@ struct desync_profile
// multisplit // multisplit
struct proto_pos splits[MAX_SPLITS]; struct proto_pos splits[MAX_SPLITS];
int split_count; int split_count;
int split_random_start, split_random_count;
struct proto_pos seqovl,hostfakesplit_midhost; struct proto_pos seqovl,hostfakesplit_midhost;
char dup_start_mode, dup_cutoff_mode; // n - packets, d - data packets, s - relative sequence char dup_start_mode, dup_cutoff_mode; // n - packets, d - data packets, s - relative sequence

Loading…
Cancel
Save