Browse Source

nfqws: detect STUN message packets

Ivan Trubach 1 day ago
parent
commit
b685eea2ec
  1. 3
      docs/readme.en.md
  2. 3
      docs/readme.md
  3. 9
      nfq/desync.c
  4. 147
      nfq/nfqws.c
  5. 7
      nfq/params.c
  6. 2
      nfq/params.h
  7. 12
      nfq/protocol.c
  8. 4
      nfq/protocol.h

3
docs/readme.en.md

@ -181,6 +181,7 @@ nfqws takes the following parameters:
--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-stun=<filename>|0xHEX ; file containing fake STUN message
--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
@ -475,7 +476,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, DHT and [Discord Voice IP Discovery](https://discord.com/developers/docs/topics/voice-connections#ip-discovery) packets are also recognized.
Wireguard handshake initiation, DHT, STUN 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`.

3
docs/readme.md

@ -202,6 +202,7 @@ dvtws, собираемый из тех же исходников (см. [док
--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-stun=<filename>|0xHEX ; файл, содержащий фейковый пейлоад STUN протокола для 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. по умолчанию - нули
@ -576,7 +577,7 @@ chrome рандомизирует фингерпринт TLS. SNI может о
На текущий момент работает только с DHT.
Поддерживается определение пакетов QUIC Initial с расшифровкой содержимого и имени хоста, то есть параметр
`--hostlist` будет работать.
Определяются пакеты wireguard handshake initiation, DHT (начинается с 'd1', кончается 'e') и
Определяются пакеты wireguard handshake initiation, DHT (начинается с 'd1', кончается 'e'), STUN и
[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

9
nfq/desync.c

@ -2085,6 +2085,12 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
l7proto = DISCORD;
if (ctrack && ctrack->l7proto==UNKNOWN) ctrack->l7proto = l7proto;
}
else if (IsStunMessage(dis->data_payload,dis->len_payload))
{
DLOG("packet contains STUN message...e\n");
l7proto = STUN;
if (ctrack && ctrack->l7proto==UNKNOWN) ctrack->l7proto = l7proto;
}
else
{
if (!dp->desync_any_proto)
@ -2200,6 +2206,9 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
case DISCORD:
fake = &dp->fake_discord;
break;
case STUN:
fake = &dp->fake_stun;
break;
default:
fake = &dp->fake_unknown_udp;
break;

147
nfq/nfqws.c

@ -740,6 +740,8 @@ static bool parse_l7_list(char *opt, uint32_t *l7)
*l7 |= L7_PROTO_DHT;
else if (!strcmp(p,"discord"))
*l7 |= L7_PROTO_DISCORD;
else if (!strcmp(p,"stun"))
*l7 |= L7_PROTO_STUN;
else if (!strcmp(p,"unknown"))
*l7 |= L7_PROTO_UNKNOWN;
else return false;
@ -1383,6 +1385,7 @@ static void exithelp(void)
" --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-stun=<filename>|0xHEX\t\t; file containing STUN protocol fake payload\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"
@ -1608,43 +1611,44 @@ int main(int argc, char **argv)
{"dpi-desync-fake-wireguard",required_argument,0,0},// optidx=44
{"dpi-desync-fake-dht",required_argument,0,0},// optidx=45
{"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
{"dpi-desync-fake-stun",required_argument,0,0},// optidx=47
{"dpi-desync-fake-unknown-udp",required_argument,0,0},// optidx=48
{"dpi-desync-udplen-increment",required_argument,0,0},// optidx=49
{"dpi-desync-udplen-pattern",required_argument,0,0},// optidx=50
{"dpi-desync-cutoff",required_argument,0,0},// optidx=51
{"dpi-desync-start",required_argument,0,0},// optidx=52
{"hostlist",required_argument,0,0}, // optidx=53
{"hostlist-domains",required_argument,0,0},// optidx=54
{"hostlist-exclude",required_argument,0,0}, // optidx=55
{"hostlist-exclude-domains",required_argument,0,0},// optidx=56
{"hostlist-auto",required_argument,0,0}, // optidx=57
{"hostlist-auto-fail-threshold",required_argument,0,0}, // optidx=58
{"hostlist-auto-fail-time",required_argument,0,0}, // optidx=59
{"hostlist-auto-retrans-threshold",required_argument,0,0}, // optidx=60
{"hostlist-auto-debug",required_argument,0,0}, // optidx=61
{"new",no_argument,0,0}, // optidx=62
{"skip",no_argument,0,0}, // optidx=63
{"filter-l3",required_argument,0,0}, // optidx=64
{"filter-tcp",required_argument,0,0}, // optidx=65
{"filter-udp",required_argument,0,0}, // optidx=66
{"filter-l7",required_argument,0,0}, // optidx=67
{"ipset",required_argument,0,0}, // optidx=68
{"ipset-ip",required_argument,0,0}, // optidx=69
{"ipset-exclude",required_argument,0,0},// optidx=70
{"ipset-exclude-ip",required_argument,0,0}, // optidx=71
#ifdef __linux__
{"bind-fix4",no_argument,0,0}, // optidx=71
{"bind-fix6",no_argument,0,0}, // optidx=72
{"bind-fix4",no_argument,0,0}, // optidx=72
{"bind-fix6",no_argument,0,0}, // optidx=73
#elif defined(__CYGWIN__)
{"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
{"wf-iface",required_argument,0,0}, // optidx=72
{"wf-l3",required_argument,0,0}, // optidx=73
{"wf-tcp",required_argument,0,0}, // optidx=74
{"wf-udp",required_argument,0,0}, // optidx=75
{"wf-raw",required_argument,0,0}, // optidx=76
{"wf-save",required_argument,0,0}, // optidx=77
{"ssid-filter",required_argument,0,0}, // optidx=78
{"nlm-filter",required_argument,0,0}, // optidx=79
{"nlm-list",optional_argument,0,0}, // optidx=80
#endif
{NULL,0,NULL,0}
};
@ -2076,17 +2080,20 @@ int main(int argc, char **argv)
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 */
case 47: /* dpi-desync-fake-stun */
load_blob_to_collection(optarg, &dp->fake_stun, FAKE_MAX_UDP, 0);
break;
case 48: /* dpi-desync-fake-unknown-udp */
load_blob_to_collection(optarg, &dp->fake_unknown_udp, FAKE_MAX_UDP, 0);
break;
case 48: /* dpi-desync-udplen-increment */
case 49: /* 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 49: /* dpi-desync-udplen-pattern */
case 50: /* dpi-desync-udplen-pattern */
{
char buf[sizeof(dp->udplen_pattern)];
size_t sz=sizeof(buf);
@ -2094,21 +2101,21 @@ int main(int argc, char **argv)
fill_pattern(dp->udplen_pattern,sizeof(dp->udplen_pattern),buf,sz);
}
break;
case 50: /* desync-cutoff */
case 51: /* 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 51: /* desync-start */
case 52: /* 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 52: /* hostlist */
case 53: /* hostlist */
if (bSkip) break;
if (!RegisterHostlist(dp, false, optarg))
{
@ -2116,7 +2123,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 53: /* hostlist-domains */
case 54: /* hostlist-domains */
if (bSkip) break;
if (!anon_hl && !(anon_hl=RegisterHostlist(dp, false, NULL)))
{
@ -2129,7 +2136,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 54: /* hostlist-exclude */
case 55: /* hostlist-exclude */
if (bSkip) break;
if (!RegisterHostlist(dp, true, optarg))
{
@ -2137,7 +2144,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 55: /* hostlist-exclude-domains */
case 56: /* hostlist-exclude-domains */
if (bSkip) break;
if (!anon_hl_exclude && !(anon_hl_exclude=RegisterHostlist(dp, true, NULL)))
{
@ -2150,7 +2157,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 56: /* hostlist-auto */
case 57: /* hostlist-auto */
if (bSkip) break;
if (dp->hostlist_auto)
{
@ -2178,7 +2185,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 57: /* hostlist-auto-fail-threshold */
case 58: /* 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)
{
@ -2186,7 +2193,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 58: /* hostlist-auto-fail-time */
case 59: /* hostlist-auto-fail-time */
dp->hostlist_auto_fail_time = (uint8_t)atoi(optarg);
if (dp->hostlist_auto_fail_time<1)
{
@ -2194,7 +2201,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 59: /* hostlist-auto-retrans-threshold */
case 60: /* 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)
{
@ -2202,7 +2209,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 60: /* hostlist-auto-debug */
case 61: /* hostlist-auto-debug */
{
FILE *F = fopen(optarg,"a+t");
if (!F)
@ -2216,7 +2223,7 @@ int main(int argc, char **argv)
}
break;
case 61: /* new */
case 62: /* new */
if (bSkip)
{
dp_clear(dp);
@ -2238,18 +2245,18 @@ int main(int argc, char **argv)
anon_hl = anon_hl_exclude = NULL;
anon_ips = anon_ips_exclude = NULL;
break;
case 62: /* skip */
case 63: /* skip */
bSkip = true;
break;
case 63: /* filter-l3 */
case 64: /* 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 64: /* filter-tcp */
case 65: /* filter-tcp */
if (!parse_pf_list(optarg,&dp->pf_tcp))
{
DLOG_ERR("Invalid port filter : %s\n",optarg);
@ -2259,7 +2266,7 @@ int main(int argc, char **argv)
if (!port_filters_deny_if_empty(&dp->pf_udp))
exit_clean(1);
break;
case 65: /* filter-udp */
case 66: /* filter-udp */
if (!parse_pf_list(optarg,&dp->pf_udp))
{
DLOG_ERR("Invalid port filter : %s\n",optarg);
@ -2269,14 +2276,14 @@ int main(int argc, char **argv)
if (!port_filters_deny_if_empty(&dp->pf_tcp))
exit_clean(1);
break;
case 66: /* filter-l7 */
case 67: /* filter-l7 */
if (!parse_l7_list(optarg,&dp->filter_l7))
{
DLOG_ERR("Invalid l7 filter : %s\n",optarg);
exit_clean(1);
}
break;
case 67: /* ipset */
case 68: /* ipset */
if (bSkip) break;
if (!RegisterIpset(dp, false, optarg))
{
@ -2284,7 +2291,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 68: /* ipset-ip */
case 69: /* ipset-ip */
if (bSkip) break;
if (!anon_ips && !(anon_ips=RegisterIpset(dp, false, NULL)))
{
@ -2297,7 +2304,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 69: /* ipset-exclude */
case 70: /* ipset-exclude */
if (bSkip) break;
if (!RegisterIpset(dp, true, optarg))
{
@ -2305,7 +2312,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 70: /* ipset-exclude-ip */
case 71: /* ipset-exclude-ip */
if (bSkip) break;
if (!anon_ips_exclude && !(anon_ips_exclude=RegisterIpset(dp, true, NULL)))
{
@ -2321,28 +2328,28 @@ int main(int argc, char **argv)
#ifdef __linux__
case 71: /* bind-fix4 */
case 72: /* bind-fix4 */
params.bind_fix4 = true;
break;
case 72: /* bind-fix6 */
case 73: /* bind-fix6 */
params.bind_fix6 = true;
break;
#elif defined(__CYGWIN__)
case 71: /* wf-iface */
case 72: /* wf-iface */
if (!sscanf(optarg,"%u.%u",&IfIdx,&SubIfIdx))
{
DLOG_ERR("bad value for --wf-iface\n");
exit_clean(1);
}
break;
case 72: /* wf-l3 */
case 73: /* wf-l3 */
if (!wf_make_l3(optarg,&wf_ipv4,&wf_ipv6))
{
DLOG_ERR("bad value for --wf-l3\n");
exit_clean(1);
}
break;
case 73: /* wf-tcp */
case 74: /* 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)))
@ -2351,7 +2358,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 74: /* wf-udp */
case 75: /* 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)))
@ -2360,7 +2367,7 @@ int main(int argc, char **argv)
exit_clean(1);
}
break;
case 75: /* wf-raw */
case 76: /* wf-raw */
hash_wf_raw=hash_jen(optarg,strlen(optarg));
if (optarg[0]=='@')
{
@ -2374,11 +2381,11 @@ int main(int argc, char **argv)
windivert_filter[sizeof(windivert_filter) - 1] = '\0';
}
break;
case 76: /* wf-save */
case 77: /* wf-save */
strncpy(wf_save_file, optarg, sizeof(wf_save_file));
wf_save_file[sizeof(wf_save_file) - 1] = '\0';
break;
case 77: /* ssid-filter */
case 78: /* ssid-filter */
hash_ssid_filter=hash_jen(optarg,strlen(optarg));
{
char *e,*p = optarg;
@ -2396,7 +2403,7 @@ int main(int argc, char **argv)
}
}
break;
case 78: /* nlm-filter */
case 79: /* nlm-filter */
hash_nlm_filter=hash_jen(optarg,strlen(optarg));
{
char *e,*p = optarg;
@ -2414,7 +2421,7 @@ int main(int argc, char **argv)
}
}
break;
case 79: /* nlm-list */
case 80: /* nlm-list */
if (!nlm_list(optarg && !strcmp(optarg,"all")))
{
DLOG_ERR("could not get list of NLM networks\n");

7
nfq/params.c

@ -240,6 +240,12 @@ bool dp_fake_defaults(struct desync_profile *dp)
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)))
@ -283,6 +289,7 @@ static void dp_clear_dynamic(struct desync_profile *dp)
blob_collection_destroy(&dp->fake_wg);
blob_collection_destroy(&dp->fake_dht);
blob_collection_destroy(&dp->fake_discord);
blob_collection_destroy(&dp->fake_stun);
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,fake_discord;
struct blob_collection_head fake_http,fake_tls,fake_unknown,fake_unknown_udp,fake_quic,fake_wg,fake_dht,fake_discord,fake_stun;
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;

12
nfq/protocol.c

@ -36,6 +36,7 @@ const char *l7proto_str(t_l7proto l7)
case WIREGUARD: return "wireguard";
case DHT: return "dht";
case DISCORD: return "discord";
case STUN: return "stun";
default: return "unknown";
}
}
@ -47,7 +48,8 @@ bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7)
(l7proto==QUIC && (filter_l7 & L7_PROTO_QUIC)) ||
(l7proto==WIREGUARD && (filter_l7 & L7_PROTO_WIREGUARD)) ||
(l7proto==DHT && (filter_l7 & L7_PROTO_DHT)) ||
(l7proto==DISCORD && (filter_l7 & L7_PROTO_DISCORD));
(l7proto==DISCORD && (filter_l7 & L7_PROTO_DISCORD)) ||
(l7proto==STUN && (filter_l7 & L7_PROTO_STUN));
}
#define PM_ABS 0
@ -1015,3 +1017,11 @@ bool IsDiscordIpDiscoveryRequest(const uint8_t *data, size_t len)
data[2]==0 && data[3]==70 &&
data[8]==0 && memcmp(&data[8],&data[9],63)==0; // address is not set in requests
}
bool IsStunMessage(const uint8_t *data, size_t len)
{
return len>=20 && // header size
(data[0]&0xC0)==0 && // 2 most significant bits must be zeroes
(data[3]&0b11)==0 && // length must be a multiple of 4
ntohl(*(uint32_t*)(&data[4]))==0x2112A442 && // magic cookie
ntohs(*(uint16_t*)(&data[2]))==len-20;
}

4
nfq/protocol.h

@ -7,13 +7,14 @@
#include "crypto/aes-gcm.h"
#include "helpers.h"
typedef enum {UNKNOWN=0, HTTP, TLS, QUIC, WIREGUARD, DHT, DISCORD} t_l7proto;
typedef enum {UNKNOWN=0, HTTP, TLS, QUIC, WIREGUARD, DHT, DISCORD, STUN} 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_STUN 0x00000030
#define L7_PROTO_UNKNOWN 0x80000000
const char *l7proto_str(t_l7proto l7);
bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7);
@ -74,6 +75,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);
bool IsStunMessage(const uint8_t *data, size_t len);
#define QUIC_MAX_CID_LENGTH 20
typedef struct quic_cid {

Loading…
Cancel
Save