diff --git a/nfq2/conntrack_base.h b/nfq2/conntrack_base.h index 0103782..b18df44 100644 --- a/nfq2/conntrack_base.h +++ b/nfq2/conntrack_base.h @@ -1,5 +1,10 @@ #pragma once +#define CTRACK_T_SYN 60 +#define CTRACK_T_FIN 60 +#define CTRACK_T_EST 300 +#define CTRACK_T_UDP 60 + // SYN - SYN or SYN/ACK received // ESTABLISHED - any except SYN or SYN/ACK received // FIN - FIN or RST received diff --git a/nfq2/desync.c b/nfq2/desync.c index 54eca9b..4f3689f 100644 --- a/nfq2/desync.c +++ b/nfq2/desync.c @@ -1531,6 +1531,7 @@ static uint8_t dpi_desync_udp_packet_play( t_protocol_probe testers[] = { {L7P_DNS_RESPONSE,L7_DNS,IsDNSResponse,false}, {L7P_DHT,L7_DHT,IsDht,false}, + {L7P_STUN,L7_STUN,IsStunMessage,false}, {L7P_WIREGUARD_INITIATION,L7_WIREGUARD,IsWireguardHandshakeInitiation,false}, {L7P_WIREGUARD_RESPONSE,L7_WIREGUARD,IsWireguardHandshakeResponse,false}, {L7P_WIREGUARD_COOKIE,L7_WIREGUARD,IsWireguardHandshakeCookie,false}, @@ -1682,7 +1683,7 @@ static uint8_t dpi_desync_udp_packet_play( t_protocol_probe testers[] = { {L7P_DISCORD_IP_DISCOVERY,L7_DISCORD,IsDiscordIpDiscoveryRequest,false}, - {L7P_STUN_BINDING_REQ,L7_STUN,IsStunBindingRequest,false}, + {L7P_STUN,L7_STUN,IsStunMessage,false}, {L7P_DNS_QUERY,L7_DNS,IsDNSQuery,false}, {L7P_DHT,L7_DHT,IsDht,false}, {L7P_WIREGUARD_INITIATION,L7_WIREGUARD,IsWireguardHandshakeInitiation,false}, diff --git a/nfq2/hostlist.c b/nfq2/hostlist.c index f783b16..7a72be2 100644 --- a/nfq2/hostlist.c +++ b/nfq2/hostlist.c @@ -301,13 +301,34 @@ struct hostlist_file *RegisterHostlist(struct desync_profile *dp, bool bExclude, filename); } +static void HostlistsDebugProfile(const struct desync_profile *dp, const char *entity) +{ + struct hostlist_item *hl_item; + + LIST_FOREACH(hl_item, &dp->hl_collection, next) + if (hl_item->hfile!=dp->hostlist_auto) + { + if (hl_item->hfile->filename) + DLOG("%s %u (%s) include hostlist %s%s\n",entity, dp->n, PROFILE_NAME(dp), hl_item->hfile->filename,hl_item->hfile->hostlist ? "" : " (empty)"); + else + DLOG("%s %u (%s) include fixed hostlist%s\n",entity, dp->n, PROFILE_NAME(dp), hl_item->hfile->hostlist ? "" : " (empty)"); + } + LIST_FOREACH(hl_item, &dp->hl_collection_exclude, next) + { + if (hl_item->hfile->filename) + DLOG("%s %u (%s) exclude hostlist %s%s\n",entity, dp->n,PROFILE_NAME(dp),hl_item->hfile->filename,hl_item->hfile->hostlist ? "" : " (empty)"); + else + DLOG("%s %u (%s) exclude fixed hostlist%s\n",entity, dp->n,PROFILE_NAME(dp),hl_item->hfile->hostlist ? "" : " (empty)"); + } + if (dp->hostlist_auto) + DLOG("%s %u (%s) auto hostlist %s%s\n",entity, dp->n,PROFILE_NAME(dp),dp->hostlist_auto->filename,dp->hostlist_auto->hostlist ? "" : " (empty)"); +} void HostlistsDebug() { if (!params.debug) return; struct hostlist_file *hfile; struct desync_profile_list *dpl; - struct hostlist_item *hl_item; LIST_FOREACH(hfile, ¶ms.hostlists, next) { @@ -319,22 +340,10 @@ void HostlistsDebug() LIST_FOREACH(dpl, ¶ms.desync_profiles, next) { - LIST_FOREACH(hl_item, &dpl->dp.hl_collection, next) - if (hl_item->hfile!=dpl->dp.hostlist_auto) - { - if (hl_item->hfile->filename) - DLOG("profile %u (%s) include hostlist %s%s\n",dpl->dp.n, PROFILE_NAME(&dpl->dp), hl_item->hfile->filename,hl_item->hfile->hostlist ? "" : " (empty)"); - else - DLOG("profile %u (%s) include fixed hostlist%s\n",dpl->dp.n, PROFILE_NAME(&dpl->dp), hl_item->hfile->hostlist ? "" : " (empty)"); - } - LIST_FOREACH(hl_item, &dpl->dp.hl_collection_exclude, next) - { - if (hl_item->hfile->filename) - DLOG("profile %u (%s) exclude hostlist %s%s\n",dpl->dp.n,PROFILE_NAME(&dpl->dp),hl_item->hfile->filename,hl_item->hfile->hostlist ? "" : " (empty)"); - else - DLOG("profile %u (%s) exclude fixed hostlist%s\n",dpl->dp.n,PROFILE_NAME(&dpl->dp),hl_item->hfile->hostlist ? "" : " (empty)"); - } - if (dpl->dp.hostlist_auto) - DLOG("profile %u (%s) auto hostlist %s%s\n",dpl->dp.n,PROFILE_NAME(&dpl->dp),dpl->dp.hostlist_auto->filename,dpl->dp.hostlist_auto->hostlist ? "" : " (empty)"); + HostlistsDebugProfile(&dpl->dp, "profile"); + } + LIST_FOREACH(dpl, ¶ms.desync_templates, next) + { + HostlistsDebugProfile(&dpl->dp, "template"); } } diff --git a/nfq2/ipset.c b/nfq2/ipset.c index 27bbadd..f8fd516 100644 --- a/nfq2/ipset.c +++ b/nfq2/ipset.c @@ -287,13 +287,31 @@ static const char *dbg_ipset_fill(const ipset *ips) else return "empty"; } +void IpsetsDebugProfile(const struct desync_profile *dp, const char *entity) +{ + struct ipset_item *ips_item; + + LIST_FOREACH(ips_item, &dp->ips_collection, next) + { + if (ips_item->hfile->filename) + DLOG("%s %u (%s) include ipset %s (%s)\n",entity,dp->n,PROFILE_NAME(dp),ips_item->hfile->filename,dbg_ipset_fill(&ips_item->hfile->ipset)); + else + DLOG("%s %u (%s) include fixed ipset (%s)\n",entity,dp->n,PROFILE_NAME(dp),dbg_ipset_fill(&ips_item->hfile->ipset)); + } + LIST_FOREACH(ips_item, &dp->ips_collection_exclude, next) + { + if (ips_item->hfile->filename) + DLOG("%s %u (%s) exclude ipset %s (%s)\n",entity,dp->n,PROFILE_NAME(dp),ips_item->hfile->filename,dbg_ipset_fill(&ips_item->hfile->ipset)); + else + DLOG("%s %u (%s) exclude fixed ipset (%s)\n",entity,dp->n,PROFILE_NAME(dp),dbg_ipset_fill(&ips_item->hfile->ipset)); + } +} void IpsetsDebug() { if (!params.debug) return; struct ipset_file *hfile; struct desync_profile_list *dpl; - struct ipset_item *ips_item; LIST_FOREACH(hfile, ¶ms.ipsets, next) { @@ -305,15 +323,10 @@ void IpsetsDebug() LIST_FOREACH(dpl, ¶ms.desync_profiles, next) { - LIST_FOREACH(ips_item, &dpl->dp.ips_collection, next) - if (ips_item->hfile->filename) - DLOG("profile %u (%s) include ipset %s (%s)\n",dpl->dp.n,PROFILE_NAME(&dpl->dp),ips_item->hfile->filename,dbg_ipset_fill(&ips_item->hfile->ipset)); - else - DLOG("profile %u (%s) include fixed ipset (%s)\n",dpl->dp.n,PROFILE_NAME(&dpl->dp),dbg_ipset_fill(&ips_item->hfile->ipset)); - LIST_FOREACH(ips_item, &dpl->dp.ips_collection_exclude, next) - if (ips_item->hfile->filename) - DLOG("profile %u (%s) exclude ipset %s (%s)\n",dpl->dp.n,PROFILE_NAME(&dpl->dp),ips_item->hfile->filename,dbg_ipset_fill(&ips_item->hfile->ipset)); - else - DLOG("profile %u (%s) exclude fixed ipset (%s)\n",dpl->dp.n,PROFILE_NAME(&dpl->dp),dbg_ipset_fill(&ips_item->hfile->ipset)); + IpsetsDebugProfile(&dpl->dp, "profile"); + } + LIST_FOREACH(dpl, ¶ms.desync_templates, next) + { + IpsetsDebugProfile(&dpl->dp, "template"); } } diff --git a/nfq2/lua.c b/nfq2/lua.c index 32e3556..cea9313 100644 --- a/nfq2/lua.c +++ b/nfq2/lua.c @@ -1223,7 +1223,7 @@ void lua_pushf_ctrack(const t_ctrack *ctrack, const t_ctrack_position *pos) LUA_STACK_GUARD_LEAVE(params.L, 0) } -void lua_pushf_args(const struct ptr_list_head *args, int idx_desync) +void lua_pushf_args(const struct str2_list_head *args, int idx_desync) { // var=val - pass val string // var=%val - subst 'val' blob @@ -1233,7 +1233,7 @@ void lua_pushf_args(const struct ptr_list_head *args, int idx_desync) LUA_STACK_GUARD_ENTER(params.L) - struct ptr_list *arg; + struct str2_list *arg; const char *var, *val; idx_desync = lua_absindex(params.L, idx_desync); @@ -1242,8 +1242,8 @@ void lua_pushf_args(const struct ptr_list_head *args, int idx_desync) lua_newtable(params.L); LIST_FOREACH(arg, args, next) { - var = (char*)arg->ptr1; - val = arg->ptr2 ? (char*)arg->ptr2 : ""; + var = arg->str1; + val = arg->str2 ? arg->str2 : ""; if (val[0]=='\\' && (val[1]=='%' || val[1]=='#')) // escape char lua_pushf_str(var, val+1); diff --git a/nfq2/lua.h b/nfq2/lua.h index 974b432..64c74ad 100644 --- a/nfq2/lua.h +++ b/nfq2/lua.h @@ -72,7 +72,7 @@ void lua_pushf_ip6hdr(const struct ip6_hdr *ip6, size_t len); void lua_push_dissect(const struct dissect *dis); void lua_pushf_dissect(const struct dissect *dis); void lua_pushf_ctrack(const t_ctrack *ctrack, const t_ctrack_position *pos); -void lua_pushf_args(const struct ptr_list_head *args, int idx_desync); +void lua_pushf_args(const struct str2_list_head *args, int idx_desync); void lua_pushf_pos(const char *name, const struct packet_pos *pos); void lua_pushf_range(const char *name, const struct packet_range *range); void lua_pushf_global(const char *field, const char *global); diff --git a/nfq2/nfqws.c b/nfq2/nfqws.c index ca9e919..5b2b7dd 100644 --- a/nfq2/nfqws.c +++ b/nfq2/nfqws.c @@ -48,11 +48,6 @@ #define NF_ACCEPT 1 #endif -#define CTRACK_T_SYN 60 -#define CTRACK_T_FIN 60 -#define CTRACK_T_EST 300 -#define CTRACK_T_UDP 60 - #define MAX_CONFIG_FILE_SIZE 16384 struct params_s params; @@ -1007,27 +1002,27 @@ static bool parse_pf_list(char *opt, struct port_filters_head *pfl) return true; } -bool lua_call_param_add(char *opt, struct ptr_list_head *args) +bool lua_call_param_add(char *opt, struct str2_list_head *args) { char c,*p; - struct ptr_list *arg; + struct str2_list *arg; if ((p = strchr(opt,'='))) { c = *p; *p = 0; } - if (!is_identifier(opt) || !(arg=ptrlist_add(args))) + if (!is_identifier(opt) || !(arg=str2list_add(args))) { if (p) *p = c; return false; } - arg->ptr1 = strdup(opt); + arg->str1 = strdup(opt); if (p) { - arg->ptr2 = strdup(p+1); + arg->str2 = strdup(p+1); *p = c; } - return arg->ptr1; + return !!arg->str2; } struct func_list *parse_lua_call(char *opt, struct func_list_head *flist) @@ -1156,21 +1151,21 @@ static void BlobDebug() } } -static void LuaDesyncDebug(struct desync_profile *dp) +static void LuaDesyncDebug(struct desync_profile *dp, const char *entity) { if (params.debug) { struct func_list *func; - struct ptr_list *arg; + struct str2_list *arg; int n,i; LIST_FOREACH(func, &dp->lua_desync, next) { - DLOG("profile %u (%s) lua %s(",dp->n,PROFILE_NAME(dp),func->func); + DLOG("%s %u (%s) lua %s(",entity,dp->n,PROFILE_NAME(dp),func->func); n=0; LIST_FOREACH(arg, &func->args, next) { if (n) DLOG(","); - DLOG(arg->ptr2 ? "%s=\"%s\"" : "%s=\"\"", (char*)arg->ptr1, (char*)arg->ptr2); + DLOG(arg->str2 ? "%s=\"%s\"" : "%s=\"\"", arg->str1, arg->str2); n++; } DLOG(" range_in=%c%u%c%c%u range_out=%c%u%c%c%u payload_type=", @@ -1415,6 +1410,8 @@ static void exithelp(void) " --new\t\t\t\t\t\t\t; begin new profile\n" " --skip\t\t\t\t\t\t\t; do not use this profile\n" " --name\t\t\t\t\t\t\t; set profile name\n" + " --template\t\t\t\t\t\t; use this profile as template (must be named or will be useless)\n" + " --import=\t\t\t\t\t; populate current profile with template data\n" " --filter-l3=ipv4|ipv6\t\t\t\t\t; L3 protocol filter. multiple comma separated values allowed.\n" " --filter-tcp=[~]port1[-port2]|*\t\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\t; UDP port filter. ~ means negation. setting udp and not setting tcp filter denies tcp. comma separated list allowed.\n" @@ -1565,6 +1562,8 @@ enum opt_indices { IDX_NEW, IDX_SKIP, IDX_NAME, + IDX_TEMPLATE, + IDX_IMPORT, IDX_FILTER_L3, IDX_FILTER_TCP, IDX_FILTER_UDP, @@ -1646,6 +1645,8 @@ static const struct option long_options[] = { [IDX_NEW] = {"new", no_argument, 0, 0}, [IDX_SKIP] = {"skip", no_argument, 0, 0}, [IDX_NAME] = {"name", required_argument, 0, 0}, + [IDX_TEMPLATE] = {"template", no_argument, 0, 0}, + [IDX_IMPORT] = {"import", required_argument, 0, 0}, [IDX_FILTER_L3] = {"filter-l3", required_argument, 0, 0}, [IDX_FILTER_TCP] = {"filter-tcp", required_argument, 0, 0}, [IDX_FILTER_UDP] = {"filter-udp", required_argument, 0, 0}, @@ -1684,15 +1685,7 @@ static const struct option long_options[] = { int main(int argc, char **argv) { - if (argc < 2) exithelp(); - - - aes_init_keygen_tables(); // required for aes - set_console_io_buffering(); - set_env_exedir(argv[0]); - #ifdef __CYGWIN__ - prepare_low_appdata(); if (service_run(argc, argv)) { // we were running as service. now exit. @@ -1701,7 +1694,7 @@ int main(int argc, char **argv) #endif int result, v; int option_index = 0; - bool bSkip = false, bDry = false; + bool bSkip = false, bDry = false, bTemplate; struct hostlist_file *anon_hl = NULL, *anon_hl_exclude = NULL; struct ipset_file *anon_ips = NULL, *anon_ips_exclude = NULL; uint64_t payload_type=0; @@ -1713,17 +1706,27 @@ int main(int argc, char **argv) unsigned int hash_wf_tcp_in = 0, hash_wf_udp_in = 0, hash_wf_tcp_out = 0, hash_wf_udp_out = 0, hash_wf_raw = 0, hash_wf_raw_part = 0, hash_ssid_filter = 0, hash_nlm_filter = 0; #endif + if (argc < 2) exithelp(); + srandom(time(NULL)); + aes_init_keygen_tables(); // required for aes mask_from_preflen6_prepare(); + set_env_exedir(argv[0]); + set_console_io_buffering(); +#ifdef __CYGWIN__ + prepare_low_appdata(); +#endif PRINT_VER; - memset(¶ms, 0, sizeof(params)); + init_params(¶ms); + ApplyDefaultBlobs(¶ms.blobs); struct desync_profile_list *dpl; struct desync_profile *dp; - unsigned int desync_profile_count = 0; + unsigned int desync_profile_count = 0, desync_template_count = 0; + bTemplate = false; if (!(dpl = dp_list_add(¶ms.desync_profiles))) { DLOG_ERR("desync_profile_add: out of memory\n"); @@ -1732,39 +1735,6 @@ int main(int argc, char **argv) dp = &dpl->dp; dp->n = ++desync_profile_count; -#ifdef __linux__ - params.qnum = -1; -#elif defined(BSD) - params.port = 0; -#endif - params.desync_fwmark = DPI_DESYNC_FWMARK_DEFAULT; - params.ctrack_t_syn = CTRACK_T_SYN; - params.ctrack_t_est = CTRACK_T_EST; - params.ctrack_t_fin = CTRACK_T_FIN; - params.ctrack_t_udp = CTRACK_T_UDP; - params.ipcache_lifetime = IPCACHE_LIFETIME; - params.lua_gc = LUA_GC_INTERVAL; - - LIST_INIT(¶ms.hostlists); - LIST_INIT(¶ms.ipsets); - LIST_INIT(¶ms.blobs); - LIST_INIT(¶ms.lua_init_scripts); - - ApplyDefaultBlobs(¶ms.blobs); - -#ifdef __CYGWIN__ - LIST_INIT(¶ms.ssid_filter); - LIST_INIT(¶ms.nlm_filter); - LIST_INIT(¶ms.wf_raw_part); -#else - if (can_drop_root()) - { - params.uid = params.gid[0] = 0x7FFFFFFF; // default uid:gid - params.gid_count = 1; - params.droproot = true; - } -#endif - #if !defined( __OpenBSD__) && !defined(__ANDROID__) if (argc >= 2 && (argv[1][0] == '@' || argv[1][0] == '$')) { @@ -2124,19 +2094,35 @@ int main(int argc, char **argv) else { check_dp(dp); + if (bTemplate) + { + if (dp->name && dp_list_search_name(¶ms.desync_templates, dp->name)) + { + DLOG_ERR("template '%s' already present\n", dp->name); + exit_clean(1); + } + dpl->dp.n = ++desync_template_count; + dp_list_move(¶ms.desync_templates, dpl); + } + else + { + desync_profile_count++; + } if (!(dpl = dp_list_add(¶ms.desync_profiles))) { DLOG_ERR("desync_profile_add: out of memory\n"); exit_clean(1); } dp = &dpl->dp; - dp->n = ++desync_profile_count; + dp->n = desync_profile_count; } anon_hl = anon_hl_exclude = NULL; anon_ips = anon_ips_exclude = NULL; payload_type = 0; range_in = PACKET_RANGE_NEVER; range_out = PACKET_RANGE_ALWAYS; + + bTemplate = false; break; case IDX_SKIP: bSkip = true; @@ -2149,6 +2135,25 @@ int main(int argc, char **argv) exit_clean(1); } break; + case IDX_TEMPLATE: + bTemplate = true; + break; + case IDX_IMPORT: + { + struct desync_profile_list *tpl = dp_list_search_name(¶ms.desync_templates, optarg); + if (!tpl) + { + DLOG_ERR("template '%s' not found\n", optarg); + exit_clean(1); + } + if (!dp_list_copy(dp, &tpl->dp)) + { + DLOG_ERR("could not copy template\n"); + exit_clean(1); + } + dp->n = desync_profile_count; + } + break; case IDX_FILTER_L3: if (!wf_make_l3(optarg, &dp->filter_ipv4, &dp->filter_ipv6)) @@ -2411,7 +2416,20 @@ int main(int argc, char **argv) desync_profile_count--; } else + { check_dp(dp); + if (bTemplate) + { + if (dp->name && dp_list_search_name(¶ms.desync_templates, dp->name)) + { + DLOG_ERR("template '%s' already present\n", dp->name); + exit_clean(1); + } + dpl->dp.n = ++desync_template_count; + dp_list_move(¶ms.desync_templates, dpl); + desync_profile_count--; + } + } // do not need args from file anymore #if !defined( __OpenBSD__) && !defined(__ANDROID__) @@ -2441,7 +2459,8 @@ int main(int argc, char **argv) exit_clean(1); } - DLOG_CONDUP("we have %d user defined desync profile(s) and default low priority profile 0\n", desync_profile_count); + DLOG_CONDUP("we have %u user defined desync profile(s) and default low priority profile 0\n", desync_profile_count); + DLOG_CONDUP("we have %u user defined desync template(s)\n", desync_template_count); if (params.writeable_dir_enable) { @@ -2479,7 +2498,12 @@ int main(int argc, char **argv) DLOG_ERR("could not make '%s' accessible. auto hostlist file may not be writable after privilege drop\n", dp->hostlist_auto->filename); } - LuaDesyncDebug(dp); + LuaDesyncDebug(dp,"profile"); + } + LIST_FOREACH(dpl, ¶ms.desync_templates, next) + { + dp = &dpl->dp; + LuaDesyncDebug(dp,"template"); } if (!test_list_files()) @@ -2505,6 +2529,9 @@ int main(int argc, char **argv) BlobDebug(); DLOG("\n"); + // not required anymore. free memory + dp_list_destroy(¶ms.desync_templates); + #ifdef __CYGWIN__ if (!*params.windivert_filter) { diff --git a/nfq2/params.c b/nfq2/params.c index c80cd09..31ea608 100644 --- a/nfq2/params.c +++ b/nfq2/params.c @@ -322,7 +322,7 @@ void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit) } } -void dp_init(struct desync_profile *dp) +void dp_init_dynamic(struct desync_profile *dp) { LIST_INIT(&dp->hl_collection); LIST_INIT(&dp->hl_collection_exclude); @@ -331,31 +331,19 @@ void dp_init(struct desync_profile *dp) LIST_INIT(&dp->pf_tcp); LIST_INIT(&dp->pf_udp); LIST_INIT(&dp->lua_desync); +#ifdef HAS_FILTER_SSID + LIST_INIT(&dp->filter_ssid); +#endif +} +void dp_init(struct desync_profile *dp) +{ + dp_init_dynamic(dp); dp->hostlist_auto_fail_threshold = HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT; dp->hostlist_auto_fail_time = HOSTLIST_AUTO_FAIL_TIME_DEFAULT; dp->hostlist_auto_retrans_threshold = HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT; dp->filter_ipv4 = dp->filter_ipv6 = true; } -struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head) -{ - struct desync_profile_list *entry = calloc(1,sizeof(struct desync_profile_list)); - if (!entry) return NULL; - - dp_init(&entry->dp); - - // add to the tail - struct desync_profile_list *dpn,*dpl=LIST_FIRST(¶ms.desync_profiles); - if (dpl) - { - while ((dpn=LIST_NEXT(dpl,next))) dpl = dpn; - LIST_INSERT_AFTER(dpl, entry, next); - } - else - LIST_INSERT_HEAD(¶ms.desync_profiles, entry, next); - - return entry; -} static void dp_clear_dynamic(struct desync_profile *dp) { hostlist_collection_destroy(&dp->hl_collection); @@ -390,6 +378,66 @@ void dp_list_destroy(struct desync_profile_list_head *head) dp_entry_destroy(entry); } } + +static struct desync_profile_list *desync_profile_entry_alloc() +{ + struct desync_profile_list *entry = calloc(1,sizeof(struct desync_profile_list)); + if (entry) dp_init(&entry->dp); + return entry; +} +struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head) +{ + struct desync_profile_list *entry = desync_profile_entry_alloc(); + if (!entry) return false; + + struct desync_profile_list *tail, *item; + LIST_TAIL(head, tail, item); + LIST_INSERT_TAIL(head, tail, entry, next); + + return entry; +} +bool dp_list_copy(struct desync_profile *to, const struct desync_profile *from) +{ + // clear everything in target + dp_clear(to); + // first copy all simple type values + *to = *from; + // prepare empty dynamic structures + dp_init_dynamic(to); + // copy dynamic structures + to->name = strdup(from->name); + if ( + !to->name || +#ifdef HAS_FILTER_SSID + !strlist_copy(&to->filter_ssid, &from->filter_ssid) || +#endif + !funclist_copy(&to->lua_desync, &from->lua_desync) || + !ipset_collection_copy(&to->ips_collection, &from->ips_collection) || + !ipset_collection_copy(&to->ips_collection_exclude, &from->ips_collection_exclude) || + !hostlist_collection_copy(&to->hl_collection, &from->hl_collection) || + !hostlist_collection_copy(&to->hl_collection_exclude, &from->hl_collection_exclude)) + { + return false; + } + return true; +} +void dp_list_move(struct desync_profile_list_head *target, struct desync_profile_list *dpl) +{ + struct desync_profile_list *tail, *item; + LIST_TAIL(target, tail, item); + LIST_REMOVE(dpl, next); + LIST_INSERT_TAIL(target, tail, dpl, next); +} +struct desync_profile_list *dp_list_search_name(struct desync_profile_list_head *head, const char *name) +{ + struct desync_profile_list *dpl; + if (name) + LIST_FOREACH(dpl, head, next) + if (dpl->dp.name && !strcmp(dpl->dp.name, name)) + return dpl; + return NULL; +} + bool dp_list_have_autohostlist(struct desync_profile_list_head *head) { struct desync_profile_list *dpl; @@ -428,6 +476,7 @@ void cleanup_params(struct params_s *params) ConntrackPoolDestroy(¶ms->conntrack); dp_list_destroy(¶ms->desync_profiles); + dp_list_destroy(¶ms->desync_templates); hostlist_files_destroy(¶ms->hostlists); ipset_files_destroy(¶ms->ipsets); ipcacheDestroy(¶ms->ipcache); @@ -441,3 +490,40 @@ void cleanup_params(struct params_s *params) free(params->user); params->user=NULL; #endif } + +void init_params(struct params_s *params) +{ + memset(params, 0, sizeof(*params)); + +#ifdef __linux__ + params->qnum = -1; +#elif defined(BSD) + params->port = 0; +#endif + params->desync_fwmark = DPI_DESYNC_FWMARK_DEFAULT; + params->ctrack_t_syn = CTRACK_T_SYN; + params->ctrack_t_est = CTRACK_T_EST; + params->ctrack_t_fin = CTRACK_T_FIN; + params->ctrack_t_udp = CTRACK_T_UDP; + params->ipcache_lifetime = IPCACHE_LIFETIME; + params->lua_gc = LUA_GC_INTERVAL; + + LIST_INIT(¶ms->hostlists); + LIST_INIT(¶ms->ipsets); + LIST_INIT(¶ms->blobs); + LIST_INIT(¶ms->lua_init_scripts); + +#ifdef __CYGWIN__ + LIST_INIT(¶ms->ssid_filter); + LIST_INIT(¶ms->nlm_filter); + LIST_INIT(¶ms->wf_raw_part); +#else + if (can_drop_root()) + { + params->uid = params->gid[0] = 0x7FFFFFFF; // default uid:gid + params->gid_count = 1; + params->droproot = true; + } +#endif + +} diff --git a/nfq2/params.h b/nfq2/params.h index 86a7b30..c29e17d 100644 --- a/nfq2/params.h +++ b/nfq2/params.h @@ -6,6 +6,7 @@ #include "desync.h" #include "protocol.h" #include "helpers.h" +#include "sec.h" #include #include @@ -91,6 +92,9 @@ struct desync_profile_list { }; LIST_HEAD(desync_profile_list_head, desync_profile_list); struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head); +void dp_list_move(struct desync_profile_list_head *target, struct desync_profile_list *dpl); +bool dp_list_copy(struct desync_profile *to, const struct desync_profile *from); +struct desync_profile_list *dp_list_search_name(struct desync_profile_list_head *head, const char *name); void dp_entry_destroy(struct desync_profile_list *entry); void dp_list_destroy(struct desync_profile_list_head *head); bool dp_list_have_autohostlist(struct desync_profile_list_head *head); @@ -121,7 +125,7 @@ struct params_s bool bind_fix4,bind_fix6; uint32_t desync_fwmark; // unused in BSD - struct desync_profile_list_head desync_profiles; + struct desync_profile_list_head desync_profiles, desync_templates; #ifdef __CYGWIN__ struct str_list_head ssid_filter,nlm_filter; @@ -172,6 +176,8 @@ struct params_s extern struct params_s params; extern const char *progname; + +void init_params(struct params_s *params); #if !defined( __OpenBSD__) && !defined(__ANDROID__) void cleanup_args(struct params_s *params); #endif diff --git a/nfq2/pools.c b/nfq2/pools.c index a9b382e..331ea01 100644 --- a/nfq2/pools.c +++ b/nfq2/pools.c @@ -155,20 +155,33 @@ bool strlist_add(struct str_list_head *head, const char *str) LIST_INSERT_HEAD(head, entry, next); return true; } +static struct str_list *strlist_entry_copy(const struct str_list *entry) +{ + return strlist_entry_alloc(entry->str); +} +bool strlist_copy(struct str_list_head *to, const struct str_list_head *from) +{ + struct str_list *tail, *item, *entry; + + LIST_TAIL(to, tail, item); + LIST_FOREACH(item, from, next) + { + if (!(entry = strlist_entry_copy(item))) return false; + LIST_INSERT_TAIL(to, tail, entry, next); + tail = tail ? LIST_NEXT(tail, next) : LIST_FIRST(to); + } + return true; +} + bool strlist_add_tail(struct str_list_head *head, const char *str) { struct str_list *entry = strlist_entry_alloc(str); if (!entry) return false; - // add to the tail - struct str_list *strn,*strl=LIST_FIRST(head); - if (strl) - { - while ((strn=LIST_NEXT(strl,next))) strl = strn; - LIST_INSERT_AFTER(strl, entry, next); - } - else - LIST_INSERT_HEAD(head, entry, next); + struct str_list *tail, *item; + LIST_TAIL(head, tail, item); + LIST_INSERT_TAIL(head, tail, entry, next); + return true; } static void strlist_entry_destroy(struct str_list *entry) @@ -200,35 +213,77 @@ bool strlist_search(const struct str_list_head *head, const char *str) } -static struct ptr_list *ptrlist_entry_alloc() +static void str2list_entry_destroy(struct str2_list *entry) { - return (struct ptr_list*)calloc(1,sizeof(struct ptr_list)); + free(entry->str1); + free(entry->str2); + free(entry); +} +void str2list_destroy(struct str2_list_head *head) +{ + struct str2_list *entry; + while ((entry = LIST_FIRST(head))) + { + LIST_REMOVE(entry, next); + str2list_entry_destroy(entry); + } +} +static struct str2_list *str2list_entry_alloc() +{ + return (struct str2_list*)calloc(1,sizeof(struct str2_list)); } -struct ptr_list *ptrlist_add(struct ptr_list_head *head) +struct str2_list *str2list_add(struct str2_list_head *head) { - struct ptr_list *entry = ptrlist_entry_alloc(); + struct str2_list *entry = str2list_entry_alloc(); if (!entry) return NULL; LIST_INSERT_HEAD(head, entry, next); return entry; } -static void ptrlist_entry_destroy(struct ptr_list *entry) +static struct str2_list *str2list_entry_copy(const struct str2_list *entry) { - free(entry->ptr1); - free(entry->ptr2); + struct str2_list *e2 = str2list_entry_alloc(); + if (!e2) return NULL; + e2->str1 = strdup(entry->str1); + e2->str2 = strdup(entry->str2); + if (!e2->str1 || !e2->str2) + { + str2list_entry_destroy(e2); + return false; + } + return e2; +} +bool str2list_copy(struct str2_list_head *to, const struct str2_list_head *from) +{ + struct str2_list *tail, *item, *entry; + + LIST_TAIL(to, tail, item); + LIST_FOREACH(item, from, next) + { + if (!(entry = str2list_entry_copy(item))) return false; + LIST_INSERT_TAIL(to, tail, entry, next); + tail = tail ? LIST_NEXT(tail, next) : LIST_FIRST(to); + } + return true; +} + + + +static void funclist_entry_destroy(struct func_list *entry) +{ + free(entry->func); + str2list_destroy(&entry->args); free(entry); } -void ptrlist_destroy(struct ptr_list_head *head) +void funclist_destroy(struct func_list_head *head) { - struct ptr_list *entry; + struct func_list *entry; while ((entry = LIST_FIRST(head))) { LIST_REMOVE(entry, next); - ptrlist_entry_destroy(entry); + funclist_entry_destroy(entry); } } - - static struct func_list *funclist_entry_alloc(const char *func) { struct func_list *entry = malloc(sizeof(struct func_list)); @@ -250,31 +305,38 @@ struct func_list *funclist_add_tail(struct func_list_head *head, const char *fun struct func_list *entry = funclist_entry_alloc(func); if (!entry) return NULL; - // add to the tail - struct func_list *funcn,*funcl=LIST_FIRST(head); - if (funcl) - { - while ((funcn=LIST_NEXT(funcl,next))) funcl = funcn; - LIST_INSERT_AFTER(funcl, entry, next); - } - else - LIST_INSERT_HEAD(head, entry, next); + struct func_list *tail, *item; + LIST_TAIL(head, tail, item); + LIST_INSERT_TAIL(head, tail, entry, next); + return entry; } -static void funclist_entry_destroy(struct func_list *entry) +static struct func_list *funclist_entry_copy(const struct func_list *entry) { - free(entry->func); - ptrlist_destroy(&entry->args); - free(entry); -} -void funclist_destroy(struct func_list_head *head) -{ - struct func_list *entry; - while ((entry = LIST_FIRST(head))) + struct func_list *e2 = funclist_entry_alloc(entry->func); + if (!e2) return NULL; + e2->payload_type = entry->payload_type; + e2->range_in = entry->range_in; + e2->range_out = entry->range_out; + if (!str2list_copy(&e2->args, &entry->args)) { - LIST_REMOVE(entry, next); - funclist_entry_destroy(entry); + funclist_entry_destroy(e2); + return false; } + return e2; +} +bool funclist_copy(struct func_list_head *to, const struct func_list_head *from) +{ + struct func_list *tail, *item, *entry; + + LIST_TAIL(to, tail, item); + LIST_FOREACH(item, from, next) + { + if (!(entry = funclist_entry_copy(item))) return false; + LIST_INSERT_TAIL(to, tail, entry, next); + tail = tail ? LIST_NEXT(tail, next) : LIST_FIRST(to); + } + return true; } @@ -333,16 +395,36 @@ void hostlist_files_reset_modtime(struct hostlist_files_head *list) FILE_MOD_RESET(&hfile->mod_sig); } -struct hostlist_item *hostlist_collection_add(struct hostlist_collection_head *head, struct hostlist_file *hfile) +static struct hostlist_item *hostlist_collection_entry_alloc(struct hostlist_file *hfile) { struct hostlist_item *entry = malloc(sizeof(struct hostlist_item)); - if (entry) - { - entry->hfile = hfile; - LIST_INSERT_HEAD(head, entry, next); - } + if (entry) entry->hfile = hfile; return entry; } +struct hostlist_item *hostlist_collection_add(struct hostlist_collection_head *head, struct hostlist_file *hfile) +{ + struct hostlist_item *entry = hostlist_collection_entry_alloc(hfile); + if (entry) LIST_INSERT_HEAD(head, entry, next); + return entry; +} +static struct hostlist_item *hostlist_collection_entry_copy(const struct hostlist_item *entry) +{ + return hostlist_collection_entry_alloc(entry->hfile); +} +bool hostlist_collection_copy(struct hostlist_collection_head *to, const struct hostlist_collection_head *from) +{ + struct hostlist_item *tail, *item, *entry; + + LIST_TAIL(to, tail, item); + LIST_FOREACH(item, from, next) + { + if (!(entry = hostlist_collection_entry_copy(item))) return false; + LIST_INSERT_TAIL(to, tail, entry, next); + tail = tail ? LIST_NEXT(tail, next) : LIST_FIRST(to); + } + return true; +} + void hostlist_collection_destroy(struct hostlist_collection_head *head) { struct hostlist_item *entry; @@ -579,16 +661,36 @@ void ipset_files_reset_modtime(struct ipset_files_head *list) FILE_MOD_RESET(&hfile->mod_sig); } -struct ipset_item *ipset_collection_add(struct ipset_collection_head *head, struct ipset_file *hfile) +static struct ipset_item *ipset_collection_entry_alloc(struct ipset_file *hfile) { struct ipset_item *entry = malloc(sizeof(struct ipset_item)); - if (entry) - { - entry->hfile = hfile; - LIST_INSERT_HEAD(head, entry, next); - } + if (entry) entry->hfile = hfile; return entry; } +struct ipset_item *ipset_collection_add(struct ipset_collection_head *head, struct ipset_file *hfile) +{ + struct ipset_item *entry = ipset_collection_entry_alloc(hfile); + if (entry) LIST_INSERT_HEAD(head, entry, next); + return entry; +} +static struct ipset_item *ipset_collection_entry_copy(const struct ipset_item *entry) +{ + return ipset_collection_entry_alloc(entry->hfile); +} +bool ipset_collection_copy(struct ipset_collection_head *to, const struct ipset_collection_head *from) +{ + struct ipset_item *tail, *item, *entry; + + LIST_TAIL(to, tail, item); + LIST_FOREACH(item, from, next) + { + if (!(entry = ipset_collection_entry_copy(item))) return false; + LIST_INSERT_TAIL(to, tail, entry, next); + tail = tail ? LIST_NEXT(tail, next) : LIST_FIRST(to); + } + return true; +} + void ipset_collection_destroy(struct ipset_collection_head *head) { struct ipset_item *entry; @@ -645,7 +747,7 @@ bool port_filters_in_range(const struct port_filters_head *head, uint16_t port) { const struct port_filter_item *item; - if (!LIST_FIRST(head)) return true; + if (LIST_EMPTY(head)) return true; LIST_FOREACH(item, head, next) { if (pf_in_range(port, &item->pf)) @@ -656,7 +758,7 @@ bool port_filters_in_range(const struct port_filters_head *head, uint16_t port) bool port_filters_deny_if_empty(struct port_filters_head *head) { port_filter pf; - if (LIST_FIRST(head)) return true; + if (!LIST_EMPTY(head)) return true; return pf_parse("0",&pf) && port_filter_add(head,&pf); } @@ -667,15 +769,9 @@ struct blob_item *blob_collection_add(struct blob_collection_head *head) struct blob_item *entry = calloc(1,sizeof(struct blob_item)); if (entry) { - // insert to the end - struct blob_item *itemc,*iteml=LIST_FIRST(head); - if (iteml) - { - while ((itemc=LIST_NEXT(iteml,next))) iteml = itemc; - LIST_INSERT_AFTER(iteml, entry, next); - } - else - LIST_INSERT_HEAD(head, entry, next); + struct blob_item *tail, *item; + LIST_TAIL(head, tail, item); + LIST_INSERT_TAIL(head, tail, entry, next); } return entry; } @@ -693,14 +789,9 @@ struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, co entry->size_buf = size+size_reserve; // insert to the end - struct blob_item *itemc,*iteml=LIST_FIRST(head); - if (iteml) - { - while ((itemc=LIST_NEXT(iteml,next))) iteml = itemc; - LIST_INSERT_AFTER(iteml, entry, next); - } - else - LIST_INSERT_HEAD(head, entry, next); + struct blob_item *tail, *item; + LIST_TAIL(head, tail, item); + LIST_INSERT_TAIL(head, tail, entry, next); return entry; } @@ -725,7 +816,7 @@ void blob_collection_destroy(struct blob_collection_head *head) } bool blob_collection_empty(const struct blob_collection_head *head) { - return !LIST_FIRST(head); + return LIST_EMPTY(head); } struct blob_item *blob_collection_search_name(struct blob_collection_head *head, const char *name) { diff --git a/nfq2/pools.h b/nfq2/pools.h index eef397d..4adedce 100644 --- a/nfq2/pools.h +++ b/nfq2/pools.h @@ -17,6 +17,17 @@ #define HOSTLIST_POOL_FLAG_STRICT_MATCH 1 +#define LIST_TAIL(head, tail, temp) {\ + tail=LIST_FIRST(head); \ + if (tail) while ((temp=LIST_NEXT(tail,next))) tail = temp; } + +#define LIST_INSERT_TAIL(head, tail, elm, field) { \ + if (LIST_FIRST(head)) \ + LIST_INSERT_AFTER(tail, elm, field); \ + else \ + LIST_INSERT_HEAD(head, elm, field); } + + typedef struct hostlist_pool { char *str; /* key */ uint32_t flags; /* custom data */ @@ -38,25 +49,28 @@ bool strlist_add(struct str_list_head *head, const char *str); bool strlist_add_tail(struct str_list_head *head, const char *str); void strlist_destroy(struct str_list_head *head); bool strlist_search(const struct str_list_head *head, const char *str); +bool strlist_copy(struct str_list_head *to, const struct str_list_head *from); -struct ptr_list { - void *ptr1,*ptr2; - LIST_ENTRY(ptr_list) next; +struct str2_list { + char *str1,*str2; + LIST_ENTRY(str2_list) next; }; -LIST_HEAD(ptr_list_head, ptr_list); +LIST_HEAD(str2_list_head, str2_list); -struct ptr_list *ptrlist_add(struct ptr_list_head *head); -void ptrlist_destroy(struct ptr_list_head *head); +struct str2_list *str2list_add(struct str2_list_head *head); +bool str2list_copy(struct str2_list_head *to, const struct str2_list_head *from); +void str2list_destroy(struct str2_list_head *head); struct func_list { char *func; uint64_t payload_type; struct packet_range range_in, range_out; - struct ptr_list_head args; + struct str2_list_head args; LIST_ENTRY(func_list) next; }; LIST_HEAD(func_list_head, func_list); struct func_list *funclist_add_tail(struct func_list_head *head, const char *func); +bool funclist_copy(struct func_list_head *to, const struct func_list_head *from); void funclist_destroy(struct func_list_head *head); @@ -96,6 +110,7 @@ struct hostlist_item { LIST_HEAD(hostlist_collection_head, hostlist_item); struct hostlist_item *hostlist_collection_add(struct hostlist_collection_head *head, struct hostlist_file *hfile); void hostlist_collection_destroy(struct hostlist_collection_head *head); +bool hostlist_collection_copy(struct hostlist_collection_head *to, const struct hostlist_collection_head *from); struct hostlist_item *hostlist_collection_search(struct hostlist_collection_head *head, const char *filename); bool hostlist_collection_is_empty(const struct hostlist_collection_head *head); @@ -158,6 +173,7 @@ struct ipset_item { }; LIST_HEAD(ipset_collection_head, ipset_item); struct ipset_item * ipset_collection_add(struct ipset_collection_head *head, struct ipset_file *hfile); +bool ipset_collection_copy(struct ipset_collection_head *to, const struct ipset_collection_head *from); void ipset_collection_destroy(struct ipset_collection_head *head); struct ipset_item *ipset_collection_search(struct ipset_collection_head *head, const char *filename); bool ipset_collection_is_empty(const struct ipset_collection_head *head); diff --git a/nfq2/protocol.c b/nfq2/protocol.c index 6bb2861..e59d9a9 100644 --- a/nfq2/protocol.c +++ b/nfq2/protocol.c @@ -48,7 +48,7 @@ bool l7_proto_match(t_l7proto l7proto, uint64_t filter_l7) static const char *l7payload_name[] = { "all","unknown","empty","known","http_req","http_reply","tls_client_hello","tls_server_hello","quic_initial", "wireguard_initiation","wireguard_response","wireguard_cookie","wireguard_keepalive","wireguard_data", - "dht","discord_ip_discovery","stun_binding_req", + "dht","discord_ip_discovery","stun", "xmpp_stream", "xmpp_starttls", "xmpp_proceed", "xmpp_features", "dns_query", "dns_response", "mtproto_initial"}; @@ -1409,11 +1409,11 @@ bool IsDiscordIpDiscoveryRequest(const uint8_t *data, size_t len) !memcmp(data+8,"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",64); // address is not set in request } -bool IsStunBindingRequest(const uint8_t *data, size_t len) +bool IsStunMessage(const uint8_t *data, size_t len) { return len>=20 && // header size - data[0]==0 && data[1]==1 && - (data[3]&0b11)==0 && // length must be a multiple of 4 + (data[0]&0xC0)==0 && // 2 most significant bits must be zeroes + (data[3]&3)==0 && // length must be a multiple of 4 ntohl(*(uint32_t*)(&data[4]))==0x2112A442 && // magic cookie ntohs(*(uint16_t*)(&data[2]))==len-20; } diff --git a/nfq2/protocol.h b/nfq2/protocol.h index b735551..c6805c1 100644 --- a/nfq2/protocol.h +++ b/nfq2/protocol.h @@ -42,7 +42,7 @@ typedef enum { L7P_WIREGUARD_DATA, L7P_DHT, L7P_DISCORD_IP_DISCOVERY, - L7P_STUN_BINDING_REQ, + L7P_STUN, L7P_XMPP_STREAM, L7P_XMPP_STARTTLS, L7P_XMPP_PROCEED, @@ -153,7 +153,7 @@ bool IsWireguardKeepalive(const uint8_t *data, size_t len); bool IsWireguardData(const uint8_t *data, size_t len); bool IsDht(const uint8_t *data, size_t len); bool IsDiscordIpDiscoveryRequest(const uint8_t *data, size_t len); -bool IsStunBindingRequest(const uint8_t *data, size_t len); +bool IsStunMessage(const uint8_t *data, size_t len); bool IsMTProto(const uint8_t *data, size_t len); #define QUIC_MAX_CID_LENGTH 20