Browse Source

nfqws: detect Discord Voice IP Discovery packets

Ivan Trubach 1 day ago
parent
commit
daee265ba3
  1. 4
      docs/changes.txt
  2. 7
      docs/readme.en.md
  3. 6
      docs/readme.md
  4. 9
      nfq/desync.c
  5. 149
      nfq/nfqws.c
  6. 7
      nfq/params.c
  7. 2
      nfq/params.h
  8. 11
      nfq/protocol.c
  9. 4
      nfq/protocol.h

4
docs/changes.txt

@ -471,3 +471,7 @@ v70.5
nfqws: multiple --dpi-desync-fake-xxx
nfqws: support of inter-packet fragmented QUIC CRYPTO
v70.6
nfqws: detect Discord Voice IP discovery packets

7
docs/readme.en.md

@ -180,6 +180,7 @@ nfqws takes the following parameters:
--dpi-desync-fake-quic=<filename>|0xHEX ; file containing fake QUIC Initial
--dpi-desync-fake-wireguard=<filename>|0xHEX ; file containing fake wireguard handshake initiation
--dpi-desync-fake-dht=<filename>|0xHEX ; file containing fake DHT (d1..e)
--dpi-desync-fake-discord=<filename>|0xHEX ; file containing fake Discord voice connection initiation packet (IP Discovery)
--dpi-desync-fake-unknown-udp=<filename>|0xHEX ; file containing unknown udp protocol fake payload
--dpi-desync-udplen-increment=<int> ; increase or decrease udp packet length by N bytes (default 2). negative values decrease length.
--dpi-desync-udplen-pattern=<filename>|0xHEX ; udp tail fill pattern
@ -193,13 +194,13 @@ nfqws takes the following parameters:
--hostlist-auto-fail-threshold=<int> ; how many failed attempts cause hostname to be added to auto hostlist (default : 3)
--hostlist-auto-fail-time=<int> ; all failed attemps must be within these seconds (default : 60)
--hostlist-auto-retrans-threshold=<int> ; how many request retransmissions cause attempt to fail (default : 3)
--hostlist-auto-debug=<logfile> ; debug auto hostlist positives
--hostlist-auto-debug=<logfile> ; debug auto hostlist positives
--new ; begin new strategy (new profile)
--skip ; do not use this profile
--filter-l3=ipv4|ipv6 ; L3 protocol filter. multiple comma separated values allowed.
--filter-tcp=[~]port1[-port2]|* ; TCP port filter. ~ means negation. setting tcp and not setting udp filter denies udp. comma separated list supported.
--filter-udp=[~]port1[-port2]|* ; UDP port filter. ~ means negation. setting udp and not setting tcp filter denies tcp. comma separated list supported.
--filter-l7=[http|tls|quic|wireguard|dht|unknown] ; L6-L7 protocol filter. multiple comma separated values allowed.
--filter-l7=<proto> ; L6-L7 protocol filter. multiple comma separated values allowed. proto: http tls quic wireguard dht discord unknown
--ipset=<filename> ; ipset include filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)
--ipset-ip=<ip_list> ; comma separated fixed subnet list
--ipset-exclude=<filename> ; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)
@ -474,7 +475,7 @@ This option can resist DPIs that track outgoing UDP packet sizes.
Requires that application protocol does not depend on udp payload size.
QUIC initial packets are recognized. Decryption and hostname extraction is supported so `--hostlist` parameter will work.
Wireguard handshake initiation and DHT packets are also recognized.
Wireguard handshake initiation, DHT and [Discord Voice IP Discovery](https://discord.com/developers/docs/topics/voice-connections#ip-discovery) packets are also recognized.
For other protocols desync use `--dpi-desync-any-protocol`.
Conntrack supports udp. `--dpi-desync-cutoff` will work. UDP conntrack timeout can be set in the 4th parameter of `--ctrack-timeouts`.

6
docs/readme.md

@ -201,6 +201,7 @@ dvtws, собираемый из тех же исходников (см. [док
--dpi-desync-fake-syndata=<filename>|0xHEX ; файл, содержащий фейковый пейлоад пакета SYN для режима десинхронизации syndata
--dpi-desync-fake-quic=<filename>|0xHEX ; файл, содержащий фейковый QUIC Initial
--dpi-desync-fake-dht=<filename>|0xHEX ; файл, содержащий фейковый пейлоад DHT протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
--dpi-desync-fake-discord=<filename>|0xHEX ; файл, содержащий фейковый пейлоад Discord протокола нахождения IP адреса для голосовых чатов для dpi-desync=fake, на замену стандартным нулям 64 байт
--dpi-desync-fake-unknown-udp=<filename>|0xHEX ; файл, содержащий фейковый пейлоад неизвестного udp протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
--dpi-desync-udplen-increment=<int> ; насколько увеличивать длину udp пейлоада в режиме udplen
--dpi-desync-udplen-pattern=<filename>|0xHEX ; чем добивать udp пакет в режиме udplen. по умолчанию - нули
@ -226,7 +227,7 @@ dvtws, собираемый из тех же исходников (см. [док
--filter-l3=ipv4|ipv6 ; фильтр версии ip для текущей стратегии
--filter-tcp=[~]port1[-port2]|* ; фильтр портов tcp для текущей стратегии. ~ означает инверсию. установка фильтра tcp и неустановка фильтра udp запрещает udp. поддерживается список через запятую.
--filter-udp=[~]port1[-port2]|* ; фильтр портов udp для текущей стратегии. ~ означает инверсию. установка фильтра udp и неустановка фильтра tcp запрещает tcp. поддерживается список через запятую.
--filter-l7=[http|tls|quic|wireguard|dht|unknown] ; фильтр протокола L6-L7. поддерживается несколько значений через запятую.
--filter-l7=<proto> ; фильтр протокола L6-L7. поддерживается несколько значений через запятую. proto : http tls quic wireguard dht discord unknown
--ipset=<filename> ; включающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
--ipset-ip=<ip_list> ; фиксированный список подсетей через запятую. можно использовать # в начале для комментирования отдельных подсетей.
--ipset-exclude=<filename> ; исключающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
@ -575,7 +576,8 @@ chrome рандомизирует фингерпринт TLS. SNI может о
На текущий момент работает только с DHT.
Поддерживается определение пакетов QUIC Initial с расшифровкой содержимого и имени хоста, то есть параметр
`--hostlist` будет работать.
Определяются пакеты wireguard handshake initiation и DHT (начинается с 'd1', кончается 'e').
Определяются пакеты wireguard handshake initiation, DHT (начинается с 'd1', кончается 'e') и
[Discord Voice IP Discovery](https://discord.com/developers/docs/topics/voice-connections#ip-discovery).
Для десинхронизации других протоколов обязательно указывать `--dpi-desync-any-protocol`.
Реализован conntrack для udp. Можно пользоваться --dpi-desync-cutoff. Таймаут conntrack для udp
можно изменить 4-м параметром в `--ctrack-timeouts`.

9
nfq/desync.c

@ -2079,6 +2079,12 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
l7proto = DHT;
if (ctrack && ctrack->l7proto==UNKNOWN) ctrack->l7proto = l7proto;
}
else if (IsDiscordIpDiscoveryRequest(dis->data_payload,dis->len_payload))
{
DLOG("packet contains Discord Voice IP Discovery...e\n");
l7proto = DISCORD;
if (ctrack && ctrack->l7proto==UNKNOWN) ctrack->l7proto = l7proto;
}
else
{
if (!dp->desync_any_proto)
@ -2191,6 +2197,9 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
case DHT:
fake = &dp->fake_dht;
break;
case DISCORD:
fake = &dp->fake_discord;
break;
default:
fake = &dp->fake_unknown_udp;
break;

149
nfq/nfqws.c

@ -738,6 +738,8 @@ static bool parse_l7_list(char *opt, uint32_t *l7)
*l7 |= L7_PROTO_WIREGUARD;
else if (!strcmp(p,"dht"))
*l7 |= L7_PROTO_DHT;
else if (!strcmp(p,"discord"))
*l7 |= L7_PROTO_DISCORD;
else if (!strcmp(p,"unknown"))
*l7 |= L7_PROTO_UNKNOWN;
else return false;
@ -1321,7 +1323,7 @@ static void exithelp(void)
" --filter-l3=ipv4|ipv6\t\t\t\t; L3 protocol filter. multiple comma separated values allowed.\n"
" --filter-tcp=[~]port1[-port2]|*\t\t; TCP port filter. ~ means negation. setting tcp and not setting udp filter denies udp. comma separated list allowed.\n"
" --filter-udp=[~]port1[-port2]|*\t\t; UDP port filter. ~ means negation. setting udp and not setting tcp filter denies tcp. comma separated list allowed.\n"
" --filter-l7=[http|tls|quic|wireguard|dht|unknown] ; L6-L7 protocol filter. multiple comma separated values allowed.\n"
" --filter-l7=[http|tls|quic|wireguard|dht|discord|unknown] ; L6-L7 protocol filter. multiple comma separated values allowed.\n"
" --ipset=<filename>\t\t\t\t; ipset include filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)\n"
" --ipset-ip=<ip_list>\t\t\t\t; comma separated fixed subnet list\n"
" --ipset-exclude=<filename>\t\t\t; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)\n"
@ -1380,6 +1382,7 @@ static void exithelp(void)
" --dpi-desync-fake-quic=<filename>|0xHEX\t; file containing fake QUIC Initial\n"
" --dpi-desync-fake-wireguard=<filename>|0xHEX\t; file containing fake wireguard handshake initiation\n"
" --dpi-desync-fake-dht=<filename>|0xHEX\t\t; file containing DHT protocol fake payload (d1...e)\n"
" --dpi-desync-fake-discord=<filename>|0xHEX\t\t; file containing Discord protocol fake payload (Voice IP Discovery)\n"
" --dpi-desync-fake-unknown-udp=<filename>|0xHEX\t; file containing unknown udp protocol fake payload\n"
" --dpi-desync-udplen-increment=<int>\t\t; increase or decrease udp packet length by N bytes (default %u). negative values decrease length.\n"
" --dpi-desync-udplen-pattern=<filename>|0xHEX\t; udp tail fill pattern\n"
@ -1604,43 +1607,44 @@ int main(int argc, char **argv)
{"dpi-desync-fake-quic",required_argument,0,0},// optidx=43
{"dpi-desync-fake-wireguard",required_argument,0,0},// optidx=44
{"dpi-desync-fake-dht",required_argument,0,0},// optidx=45
{"dpi-desync-fake-unknown-udp",required_argument,0,0},// optidx=46
{"dpi-desync-udplen-increment",required_argument,0,0},// optidx=47
{"dpi-desync-udplen-pattern",required_argument,0,0},// optidx=48
{"dpi-desync-cutoff",required_argument,0,0},// optidx=49
{"dpi-desync-start",required_argument,0,0},// optidx=50
{"hostlist",required_argument,0,0}, // optidx=51
{"hostlist-domains",required_argument,0,0},// optidx=52
{"hostlist-exclude",required_argument,0,0}, // optidx=53
{"hostlist-exclude-domains",required_argument,0,0},// optidx=54
{"hostlist-auto",required_argument,0,0}, // optidx=55
{"hostlist-auto-fail-threshold",required_argument,0,0}, // optidx=56
{"hostlist-auto-fail-time",required_argument,0,0}, // optidx=57
{"hostlist-auto-retrans-threshold",required_argument,0,0}, // optidx=58
{"hostlist-auto-debug",required_argument,0,0}, // optidx=59
{"new",no_argument,0,0}, // optidx=60
{"skip",no_argument,0,0}, // optidx=61
{"filter-l3",required_argument,0,0}, // optidx=62
{"filter-tcp",required_argument,0,0}, // optidx=63
{"filter-udp",required_argument,0,0}, // optidx=64
{"filter-l7",required_argument,0,0}, // optidx=65
{"ipset",required_argument,0,0}, // optidx=66
{"ipset-ip",required_argument,0,0}, // optidx=67
{"ipset-exclude",required_argument,0,0},// optidx=68
{"ipset-exclude-ip",required_argument,0,0}, // optidx=69
{"dpi-desync-fake-discord",required_argument,0,0},// optidx=46
{"dpi-desync-fake-unknown-udp",required_argument,0,0},// optidx=47
{"dpi-desync-udplen-increment",required_argument,0,0},// optidx=48
{"dpi-desync-udplen-pattern",required_argument,0,0},// optidx=49
{"dpi-desync-cutoff",required_argument,0,0},// optidx=50
{"dpi-desync-start",required_argument,0,0},// optidx=51
{"hostlist",required_argument,0,0}, // optidx=52
{"hostlist-domains",required_argument,0,0},// optidx=53
{"hostlist-exclude",required_argument,0,0}, // optidx=54
{"hostlist-exclude-domains",required_argument,0,0},// optidx=55
{"hostlist-auto",required_argument,0,0}, // optidx=56
{"hostlist-auto-fail-threshold",required_argument,0,0}, // optidx=57
{"hostlist-auto-fail-time",required_argument,0,0}, // optidx=58
{"hostlist-auto-retrans-threshold",required_argument,0,0}, // optidx=59
{"hostlist-auto-debug",required_argument,0,0}, // optidx=60
{"new",no_argument,0,0}, // optidx=61
{"skip",no_argument,0,0}, // optidx=62
{"filter-l3",required_argument,0,0}, // optidx=63
{"filter-tcp",required_argument,0,0}, // optidx=64
{"filter-udp",required_argument,0,0}, // optidx=65
{"filter-l7",required_argument,0,0}, // optidx=66
{"ipset",required_argument,0,0}, // optidx=67
{"ipset-ip",required_argument,0,0}, // optidx=68
{"ipset-exclude",required_argument,0,0},// optidx=69
{"ipset-exclude-ip",required_argument,0,0}, // optidx=70
#ifdef __linux__
{"bind-fix4",no_argument,0,0}, // optidx=70
{"bind-fix6",no_argument,0,0}, // optidx=71
{"bind-fix4",no_argument,0,0}, // optidx=71
{"bind-fix6",no_argument,0,0}, // optidx=72
#elif defined(__CYGWIN__)
{"wf-iface",required_argument,0,0}, // optidx=70
{"wf-l3",required_argument,0,0}, // optidx=71
{"wf-tcp",required_argument,0,0}, // optidx=72
{"wf-udp",required_argument,0,0}, // optidx=73
{"wf-raw",required_argument,0,0}, // optidx=74
{"wf-save",required_argument,0,0}, // optidx=75
{"ssid-filter",required_argument,0,0}, // optidx=76
{"nlm-filter",required_argument,0,0}, // optidx=77
{"nlm-list",optional_argument,0,0}, // optidx=78
{"wf-iface",required_argument,0,0}, // optidx=71
{"wf-l3",required_argument,0,0}, // optidx=72
{"wf-tcp",required_argument,0,0}, // optidx=73
{"wf-udp",required_argument,0,0}, // optidx=74
{"wf-raw",required_argument,0,0}, // optidx=75
{"wf-save",required_argument,0,0}, // optidx=76
{"ssid-filter",required_argument,0,0}, // optidx=77
{"nlm-filter",required_argument,0,0}, // optidx=78
{"nlm-list",optional_argument,0,0}, // optidx=79
#endif
{NULL,0,NULL,0}
};
@ -2069,17 +2073,20 @@ int main(int argc, char **argv)
case 45: /* dpi-desync-fake-dht */
load_blob_to_collection(optarg, &dp->fake_dht, FAKE_MAX_UDP, 0);
break;
case 46: /* dpi-desync-fake-unknown-udp */
case 46: /* dpi-desync-fake-discord */
load_blob_to_collection(optarg, &dp->fake_discord, FAKE_MAX_UDP, 0);
break;
case 47: /* dpi-desync-fake-unknown-udp */
load_blob_to_collection(optarg, &dp->fake_unknown_udp, FAKE_MAX_UDP, 0);
break;
case 47: /* dpi-desync-udplen-increment */
case 48: /* dpi-desync-udplen-increment */
if (sscanf(optarg,"%d",&dp->udplen_increment)<1 || dp->udplen_increment>0x7FFF || dp->udplen_increment<-0x8000)
{
DLOG_ERR("dpi-desync-udplen-increment must be integer within -32768..32767 range\n");
exit_clean(1);
}
break;
case 48: /* dpi-desync-udplen-pattern */
case 49: /* dpi-desync-udplen-pattern */
{
char buf[sizeof(dp->udplen_pattern)];
size_t sz=sizeof(buf);
@ -2087,21 +2094,21 @@ int main(int argc, char **argv)
fill_pattern(dp->udplen_pattern,sizeof(dp->udplen_pattern),buf,sz);
}
break;
case 49: /* desync-cutoff */
case 50: /* desync-cutoff */
if (!parse_cutoff(optarg, &dp->desync_cutoff, &dp->desync_cutoff_mode))
{
DLOG_ERR("invalid desync-cutoff value\n");
exit_clean(1);
}
break;
case 50: /* desync-start */
case 51: /* desync-start */
if (!parse_cutoff(optarg, &dp->desync_start, &dp->desync_start_mode))
{
DLOG_ERR("invalid desync-start value\n");
exit_clean(1);
}
break;
case 51: /* hostlist */
case 52: /* hostlist */
if (bSkip) break;
if (!RegisterHostlist(dp, false, optarg))
{
@ -2109,7 +2116,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 52: /* hostlist-domains */
case 53: /* hostlist-domains */
if (bSkip) break;
if (!anon_hl && !(anon_hl=RegisterHostlist(dp, false, NULL)))
{
@ -2122,7 +2129,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 53: /* hostlist-exclude */
case 54: /* hostlist-exclude */
if (bSkip) break;
if (!RegisterHostlist(dp, true, optarg))
{
@ -2130,7 +2137,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 54: /* hostlist-exclude-domains */
case 55: /* hostlist-exclude-domains */
if (bSkip) break;
if (!anon_hl_exclude && !(anon_hl_exclude=RegisterHostlist(dp, true, NULL)))
{
@ -2143,7 +2150,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 55: /* hostlist-auto */
case 56: /* hostlist-auto */
if (bSkip) break;
if (dp->hostlist_auto)
{
@ -2171,7 +2178,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 56: /* hostlist-auto-fail-threshold */
case 57: /* hostlist-auto-fail-threshold */
dp->hostlist_auto_fail_threshold = (uint8_t)atoi(optarg);
if (dp->hostlist_auto_fail_threshold<1 || dp->hostlist_auto_fail_threshold>20)
{
@ -2179,7 +2186,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 57: /* hostlist-auto-fail-time */
case 58: /* hostlist-auto-fail-time */
dp->hostlist_auto_fail_time = (uint8_t)atoi(optarg);
if (dp->hostlist_auto_fail_time<1)
{
@ -2187,7 +2194,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 58: /* hostlist-auto-retrans-threshold */
case 59: /* hostlist-auto-retrans-threshold */
dp->hostlist_auto_retrans_threshold = (uint8_t)atoi(optarg);
if (dp->hostlist_auto_retrans_threshold<2 || dp->hostlist_auto_retrans_threshold>10)
{
@ -2195,7 +2202,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 59: /* hostlist-auto-debug */
case 60: /* hostlist-auto-debug */
{
FILE *F = fopen(optarg,"a+t");
if (!F)
@ -2209,7 +2216,7 @@ int main(int argc, char **argv)
}
break;
case 60: /* new */
case 61: /* new */
if (bSkip)
{
dp_clear(dp);
@ -2231,18 +2238,18 @@ int main(int argc, char **argv)
anon_hl = anon_hl_exclude = NULL;
anon_ips = anon_ips_exclude = NULL;
break;
case 61: /* skip */
case 62: /* skip */
bSkip = true;
break;
case 62: /* filter-l3 */
case 63: /* filter-l3 */
if (!wf_make_l3(optarg,&dp->filter_ipv4,&dp->filter_ipv6))
{
DLOG_ERR("bad value for --filter-l3\n");
exit_clean(1);
}
break;
case 63: /* filter-tcp */
case 64: /* filter-tcp */
if (!parse_pf_list(optarg,&dp->pf_tcp))
{
DLOG_ERR("Invalid port filter : %s\n",optarg);
@ -2252,7 +2259,7 @@ int main(int argc, char **argv)
if (!port_filters_deny_if_empty(&dp->pf_udp))
exit_clean(1);
break;
case 64: /* filter-udp */
case 65: /* filter-udp */
if (!parse_pf_list(optarg,&dp->pf_udp))
{
DLOG_ERR("Invalid port filter : %s\n",optarg);
@ -2262,14 +2269,14 @@ int main(int argc, char **argv)
if (!port_filters_deny_if_empty(&dp->pf_tcp))
exit_clean(1);
break;
case 65: /* filter-l7 */
case 66: /* filter-l7 */
if (!parse_l7_list(optarg,&dp->filter_l7))
{
DLOG_ERR("Invalid l7 filter : %s\n",optarg);
exit_clean(1);
}
break;
case 66: /* ipset */
case 67: /* ipset */
if (bSkip) break;
if (!RegisterIpset(dp, false, optarg))
{
@ -2277,7 +2284,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 67: /* ipset-ip */
case 68: /* ipset-ip */
if (bSkip) break;
if (!anon_ips && !(anon_ips=RegisterIpset(dp, false, NULL)))
{
@ -2290,7 +2297,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 68: /* ipset-exclude */
case 69: /* ipset-exclude */
if (bSkip) break;
if (!RegisterIpset(dp, true, optarg))
{
@ -2298,7 +2305,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 69: /* ipset-exclude-ip */
case 70: /* ipset-exclude-ip */
if (bSkip) break;
if (!anon_ips_exclude && !(anon_ips_exclude=RegisterIpset(dp, true, NULL)))
{
@ -2314,28 +2321,28 @@ int main(int argc, char **argv)
#ifdef __linux__
case 70: /* bind-fix4 */
case 71: /* bind-fix4 */
params.bind_fix4 = true;
break;
case 71: /* bind-fix6 */
case 72: /* bind-fix6 */
params.bind_fix6 = true;
break;
#elif defined(__CYGWIN__)
case 70: /* wf-iface */
case 71: /* wf-iface */
if (!sscanf(optarg,"%u.%u",&IfIdx,&SubIfIdx))
{
DLOG_ERR("bad value for --wf-iface\n");
exit_clean(1);
}
break;
case 71: /* wf-l3 */
case 72: /* wf-l3 */
if (!wf_make_l3(optarg,&wf_ipv4,&wf_ipv6))
{
DLOG_ERR("bad value for --wf-l3\n");
exit_clean(1);
}
break;
case 72: /* wf-tcp */
case 73: /* wf-tcp */
hash_wf_tcp=hash_jen(optarg,strlen(optarg));
if (!wf_make_pf(optarg,"tcp","SrcPort",wf_pf_tcp_src,sizeof(wf_pf_tcp_src)) ||
!wf_make_pf(optarg,"tcp","DstPort",wf_pf_tcp_dst,sizeof(wf_pf_tcp_dst)))
@ -2344,7 +2351,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 73: /* wf-udp */
case 74: /* wf-udp */
hash_wf_udp=hash_jen(optarg,strlen(optarg));
if (!wf_make_pf(optarg,"udp","SrcPort",wf_pf_udp_src,sizeof(wf_pf_udp_src)) ||
!wf_make_pf(optarg,"udp","DstPort",wf_pf_udp_dst,sizeof(wf_pf_udp_dst)))
@ -2353,7 +2360,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 74: /* wf-raw */
case 75: /* wf-raw */
hash_wf_raw=hash_jen(optarg,strlen(optarg));
if (optarg[0]=='@')
{
@ -2367,11 +2374,11 @@ int main(int argc, char **argv)
windivert_filter[sizeof(windivert_filter) - 1] = '\0';
}
break;
case 75: /* wf-save */
case 76: /* wf-save */
strncpy(wf_save_file, optarg, sizeof(wf_save_file));
wf_save_file[sizeof(wf_save_file) - 1] = '\0';
break;
case 76: /* ssid-filter */
case 77: /* ssid-filter */
hash_ssid_filter=hash_jen(optarg,strlen(optarg));
{
char *e,*p = optarg;
@ -2389,7 +2396,7 @@ int main(int argc, char **argv)
}
}
break;
case 77: /* nlm-filter */
case 78: /* nlm-filter */
hash_nlm_filter=hash_jen(optarg,strlen(optarg));
{
char *e,*p = optarg;
@ -2407,7 +2414,7 @@ int main(int argc, char **argv)
}
}
break;
case 78: /* nlm-list */
case 79: /* nlm-list */
if (!nlm_list(optarg && !strcmp(optarg,"all")))
{
DLOG_ERR("could not get list of NLM networks\n");

7
nfq/params.c

@ -234,6 +234,12 @@ bool dp_fake_defaults(struct desync_profile *dp)
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_unknown_udp))
{
if (!(item=blob_collection_add_blob(&dp->fake_unknown_udp,NULL,64,0)))
@ -276,6 +282,7 @@ static void dp_clear_dynamic(struct desync_profile *dp)
blob_collection_destroy(&dp->fake_quic);
blob_collection_destroy(&dp->fake_wg);
blob_collection_destroy(&dp->fake_dht);
blob_collection_destroy(&dp->fake_discord);
HostFailPoolDestroy(&dp->hostlist_auto_fail_counters);
}
void dp_clear(struct desync_profile *dp)

2
nfq/params.h

@ -83,7 +83,7 @@ struct desync_profile
uint32_t desync_fooling_mode;
uint32_t desync_badseq_increment, desync_badseq_ack_increment;
struct blob_collection_head fake_http,fake_tls,fake_unknown,fake_unknown_udp,fake_quic,fake_wg,fake_dht;
struct blob_collection_head fake_http,fake_tls,fake_unknown,fake_unknown_udp,fake_quic,fake_wg,fake_dht,fake_discord;
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;

11
nfq/protocol.c

@ -35,6 +35,7 @@ const char *l7proto_str(t_l7proto l7)
case QUIC: return "quic";
case WIREGUARD: return "wireguard";
case DHT: return "dht";
case DISCORD: return "discord";
default: return "unknown";
}
}
@ -45,7 +46,8 @@ bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7)
(l7proto==TLS && (filter_l7 & L7_PROTO_TLS)) ||
(l7proto==QUIC && (filter_l7 & L7_PROTO_QUIC)) ||
(l7proto==WIREGUARD && (filter_l7 & L7_PROTO_WIREGUARD)) ||
(l7proto==DHT && (filter_l7 & L7_PROTO_DHT));
(l7proto==DHT && (filter_l7 & L7_PROTO_DHT)) ||
(l7proto==DISCORD && (filter_l7 & L7_PROTO_DISCORD));
}
#define PM_ABS 0
@ -1006,3 +1008,10 @@ bool IsDhtD1(const uint8_t *data, size_t len)
{
return len>=7 && data[0]=='d' && data[1]=='1' && data[len-1]=='e';
}
bool IsDiscordIpDiscoveryRequest(const uint8_t *data, size_t len)
{
return len==74 &&
data[0]==0 && data[1]==1 &&
data[2]==0 && data[3]==70 &&
data[8]==0 && memcmp(&data[8],&data[9],63)==0; // address is not set in requests
}

4
nfq/protocol.h

@ -7,12 +7,13 @@
#include "crypto/aes-gcm.h"
#include "helpers.h"
typedef enum {UNKNOWN=0, HTTP, TLS, QUIC, WIREGUARD, DHT} t_l7proto;
typedef enum {UNKNOWN=0, HTTP, TLS, QUIC, WIREGUARD, DHT, DISCORD} t_l7proto;
#define L7_PROTO_HTTP 0x00000001
#define L7_PROTO_TLS 0x00000002
#define L7_PROTO_QUIC 0x00000004
#define L7_PROTO_WIREGUARD 0x00000008
#define L7_PROTO_DHT 0x00000010
#define L7_PROTO_DISCORD 0x00000020
#define L7_PROTO_UNKNOWN 0x80000000
const char *l7proto_str(t_l7proto l7);
bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7);
@ -72,6 +73,7 @@ bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *hos
bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len);
bool IsDhtD1(const uint8_t *data, size_t len);
bool IsDiscordIpDiscoveryRequest(const uint8_t *data, size_t len);
#define QUIC_MAX_CID_LENGTH 20
typedef struct quic_cid {

Loading…
Cancel
Save