diff --git a/docs/changes.txt b/docs/changes.txt index e1809c34..3e40f1de 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -508,5 +508,6 @@ v71.1 nfqws,tpws: much faster ipset implementation. move from hash to avl tree nfqws,tpws: check list files accessibility with dropped privs in --dry-run mode nfqws,tpws: --debug=android for NDK builds +nfqws: --filter-ssid (linux-only) install_easy: stop if running embedded release on traditional linux system (some files missing) install_bin: add "read elf" arch detection method diff --git a/docs/compile/build_howto_unix.txt b/docs/compile/build_howto_unix.txt index 8ede080c..ae85c3c7 100644 --- a/docs/compile/build_howto_unix.txt +++ b/docs/compile/build_howto_unix.txt @@ -1,6 +1,6 @@ debian,ubuntu : -apt install make gcc zlib1g-dev libcap-dev libnetfilter-queue-dev libsystemd-dev +apt install make gcc zlib1g-dev libcap-dev libnetfilter-queue-dev libmnl-dev libsystemd-dev make -C /opt/zapret systemd FreeBSD : diff --git a/nfq/Makefile b/nfq/Makefile index 927b0eb5..f3681011 100644 --- a/nfq/Makefile +++ b/nfq/Makefile @@ -4,7 +4,7 @@ CFLAGS_SYSTEMD = -DUSE_SYSTEMD CFLAGS_BSD = -Wno-address-of-packed-member CFLAGS_CYGWIN = -Wno-address-of-packed-member -static LDFLAGS_ANDROID = -llog -LIBS_LINUX = -lnetfilter_queue -lnfnetlink -lz +LIBS_LINUX = -lz -lnetfilter_queue -lnfnetlink -lmnl LIBS_SYSTEMD = -lsystemd LIBS_BSD = -lz LIBS_CYGWIN = -lz -Lwindows/windivert -Iwindows -lwlanapi -lole32 -loleaut32 diff --git a/nfq/darkmagic.c b/nfq/darkmagic.c index fad80092..fc4fd883 100644 --- a/nfq/darkmagic.c +++ b/nfq/darkmagic.c @@ -29,6 +29,13 @@ #endif +#ifdef __linux__ +#include +#include +#include +#include +#endif + uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment) { return htonl(ntohl(netorder_value)+cpuorder_increment); @@ -1832,6 +1839,239 @@ bool rawsend_queue(struct rawpacket_tailhead *q) } + +#if defined(HAS_FILTER_SSID) && defined(__linux__) + +// linux-specific wlan retrieval implementation + +typedef void netlink_prepare_nlh_cb_t(struct nlmsghdr *nlh); + +static bool netlink_genl_simple_transact(struct mnl_socket* nl, uint16_t type, uint16_t flags, uint8_t cmd, uint8_t version, netlink_prepare_nlh_cb_t cb_prepare_nlh, mnl_cb_t cb_data, void *data) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + struct genlmsghdr *genl; + ssize_t rd; + + nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = type; + nlh->nlmsg_flags = flags; + + genl = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr)); + genl->cmd = cmd; + genl->version = version; + + if (cb_prepare_nlh) cb_prepare_nlh(nlh); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) + { + DLOG_PERROR("mnl_socket_sendto"); + return false; + } + + while ((rd=mnl_socket_recvfrom(nl, buf, sizeof(buf))) > 0) + { + switch(mnl_cb_run(buf, rd, 0, 0, cb_data, data)) + { + case MNL_CB_STOP: + return true; + case MNL_CB_OK: + break; + default: + return false; + } + } + + return false; +} + +static void wlan_id_prepare(struct nlmsghdr *nlh) +{ + mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, "nl80211"); +} +static int wlan_id_attr_cb(const struct nlattr *attr, void *data) +{ + if (mnl_attr_type_valid(attr, CTRL_ATTR_MAX) < 0) + { + DLOG_PERROR("mnl_attr_type_valid"); + return MNL_CB_ERROR; + } + + switch(mnl_attr_get_type(attr)) + { + case CTRL_ATTR_FAMILY_ID: + if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0) + { + DLOG_PERROR("mnl_attr_validate(family_id)"); + return MNL_CB_ERROR; + } + *((uint16_t*)data) = mnl_attr_get_u16(attr); + break; + } + return MNL_CB_OK; +} +static int wlan_id_cb(const struct nlmsghdr *nlh, void *data) +{ + return mnl_attr_parse(nlh, sizeof(struct genlmsghdr), wlan_id_attr_cb, data); +} +static uint16_t wlan_get_family_id(struct mnl_socket* nl) +{ + uint16_t id; + return netlink_genl_simple_transact(nl, GENL_ID_CTRL, NLM_F_REQUEST | NLM_F_ACK, CTRL_CMD_GETFAMILY, 1, wlan_id_prepare, wlan_id_cb, &id) ? id : 0; +} + +static int wlan_info_attr_cb(const struct nlattr *attr, void *data) +{ + struct wlan_interface *wlan = (struct wlan_interface *)data; + switch(mnl_attr_get_type(attr)) + { + case NL80211_ATTR_IFINDEX: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) + { + DLOG_PERROR("mnl_attr_validate(ifindex)"); + return MNL_CB_ERROR; + } + wlan->ifindex = mnl_attr_get_u32(attr); + break; + case NL80211_ATTR_SSID: + if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) + { + DLOG_PERROR("mnl_attr_validate(ssid)"); + return MNL_CB_ERROR; + } + snprintf(wlan->ssid,sizeof(wlan->ssid),"%s",mnl_attr_get_str(attr)); + break; + case NL80211_ATTR_IFNAME: + if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) + { + DLOG_PERROR("mnl_attr_validate(ifname)"); + return MNL_CB_ERROR; + } + snprintf(wlan->ifname,sizeof(wlan->ifname),"%s",mnl_attr_get_str(attr)); + break; + } + return MNL_CB_OK; +} +static int wlan_info_cb(const struct nlmsghdr *nlh, void *data) +{ + int ret; + struct wlan_interface_collection *wc = (struct wlan_interface_collection*)data; + if (wc->count>=WLAN_INTERFACE_MAX) return MNL_CB_OK; + memset(wc->wlan+wc->count,0,sizeof(wc->wlan[0])); + ret = mnl_attr_parse(nlh, sizeof(struct genlmsghdr), wlan_info_attr_cb, wc->wlan+wc->count); + if (ret>=0 && *wc->wlan[wc->count].ssid && *wc->wlan[wc->count].ifname && wc->wlan[wc->count].ifindex) + wc->count++; + return ret; +} +static bool wlan_info(struct mnl_socket* nl, uint16_t wlan_family_id, struct wlan_interface_collection* w) +{ + return netlink_genl_simple_transact(nl, wlan_family_id, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP, NL80211_CMD_GET_INTERFACE, 0, NULL, wlan_info_cb, w); +} + +static bool wlan_init80211(struct mnl_socket** nl) +{ + if (!(*nl = mnl_socket_open(NETLINK_GENERIC))) + { + DLOG_PERROR("mnl_socket_open"); + return false; + } + if (mnl_socket_bind(*nl, 0, MNL_SOCKET_AUTOPID)) + { + DLOG_PERROR("mnl_socket_bind"); + return false; + } + return true; +} + +static void wlan_deinit80211(struct mnl_socket** nl) +{ + if (*nl) + { + mnl_socket_close(*nl); + *nl = NULL; + } +} + +static time_t wlan_info_last = 0; +static bool wlan_info_rate_limited(struct mnl_socket* nl, uint16_t wlan_family_id, struct wlan_interface_collection* w) +{ + bool bres = true; + time_t now = time(NULL); + + // do not purge too often to save resources + if (wlan_info_last != now) + { + bres = wlan_info(nl,wlan_family_id,w); + wlan_info_last = now; + } + return bres; +} + +static struct mnl_socket* nl_wifi = NULL; +static uint16_t id_nl80211; +struct wlan_interface_collection wlans = { .count = 0 }; + +void wlan_info_deinit(void) +{ + wlan_deinit80211(&nl_wifi); +} +bool wlan_info_init(void) +{ + wlan_info_deinit(); + + if (!wlan_init80211(&nl_wifi)) return false; + if (!(id_nl80211 = wlan_get_family_id(nl_wifi))) + { + wlan_info_deinit(); + return false; + } + return true; +} +bool wlan_info_get(void) +{ + return wlan_info(nl_wifi, id_nl80211, &wlans); +} +bool wlan_info_get_rate_limited(void) +{ + return wlan_info_rate_limited(nl_wifi, id_nl80211, &wlans); +} + +#endif + + +#ifdef HAS_FILTER_SSID +const char *wlan_ifname2ssid(const struct wlan_interface_collection *w, const char *ifname) +{ + int i; + if (ifname) + { + for (i=0;icount;i++) + if (!strcmp(w->wlan[i].ifname,ifname)) + return w->wlan[i].ssid; + } + return NULL; +} +const char *wlan_ifidx2ssid(const struct wlan_interface_collection *w,int ifidx) +{ + int i; + for (i=0;icount;i++) + if (w->wlan[i].ifindex == ifidx) + return w->wlan[i].ssid; + return NULL; +} +const char *wlan_ssid_search_ifname(const char *ifname) +{ + return wlan_ifname2ssid(&wlans,ifname); +} +const char *wlan_ssid_search_ifidx(int ifidx) +{ + return wlan_ifidx2ssid(&wlans,ifidx); +} + +#endif + + + uint8_t hop_count_guess(uint8_t ttl) { // 18.65.168.125 ( cloudfront ) 255 diff --git a/nfq/darkmagic.h b/nfq/darkmagic.h index a1f9ebb2..3f9eaa8e 100644 --- a/nfq/darkmagic.h +++ b/nfq/darkmagic.h @@ -1,5 +1,6 @@ #pragma once +#include "nfqws.h" #include "checksum.h" #include "packet_queue.h" #include "pools.h" @@ -272,3 +273,29 @@ void verdict_udp_csum_fix(uint8_t verdict, struct udphdr *udphdr, size_t transpo void dbgprint_socket_buffers(int fd); bool set_socket_buffers(int fd, int rcvbuf, int sndbuf); + + +#ifdef HAS_FILTER_SSID + +struct wlan_interface +{ + int ifindex; + char ifname[IFNAMSIZ], ssid[33]; +}; +#define WLAN_INTERFACE_MAX 16 +struct wlan_interface_collection +{ + int count; + struct wlan_interface wlan[WLAN_INTERFACE_MAX]; +}; + +extern struct wlan_interface_collection wlans; + +void wlan_info_deinit(void); +bool wlan_info_init(void); +bool wlan_info_get(void); +bool wlan_info_get_rate_limited(void); +const char *wlan_ssid_search_ifname(const char *ifname); +const char *wlan_ssid_search_ifidx(int ifidx); + +#endif diff --git a/nfq/desync.c b/nfq/desync.c index 3e0c362e..7c994ab7 100644 --- a/nfq/desync.c +++ b/nfq/desync.c @@ -223,7 +223,7 @@ enum dpi_desync_mode desync_mode_from_string(const char *s) static bool dp_match( struct desync_profile *dp, - uint8_t l3proto, const struct sockaddr *dest, const char *hostname, t_l7proto l7proto, + uint8_t l3proto, const struct sockaddr *dest, const char *hostname, t_l7proto l7proto, const char *ssid, bool *bCheckDone, bool *bCheckResult, bool *bExcluded) { bool bHostlistsEmpty; @@ -241,6 +241,11 @@ static bool dp_match( if (dp->filter_l7 && !l7_proto_match(l7proto, dp->filter_l7)) // L7 filter does not match return false; +#ifdef HAS_FILTER_SSID + if (!LIST_EMPTY(&dp->filter_ssid) && !strlist_search(&dp->filter_ssid,ssid)) + return false; +#endif + bHostlistsEmpty = PROFILE_HOSTLISTS_EMPTY(dp); if (!dp->hostlist_auto && !hostname && !bHostlistsEmpty) // avoid cpu consuming ipset check. profile cannot win if regular hostlists are present without auto hostlist and hostname is unknown. @@ -271,7 +276,7 @@ static bool dp_match( } static struct desync_profile *dp_find( struct desync_profile_list_head *head, - uint8_t l3proto, const struct sockaddr *dest, const char *hostname, t_l7proto l7proto, + uint8_t l3proto, const struct sockaddr *dest, const char *hostname, t_l7proto l7proto, const char *ssid, bool *bCheckDone, bool *bCheckResult, bool *bExcluded) { struct desync_profile_list *dpl; @@ -279,12 +284,12 @@ static struct desync_profile *dp_find( { char ip_port[48]; ntop46_port(dest, ip_port,sizeof(ip_port)); - DLOG("desync profile search for %s target=%s l7proto=%s hostname='%s'\n", proto_name(l3proto), ip_port, l7proto_str(l7proto), hostname ? hostname : ""); + DLOG("desync profile search for %s target=%s l7proto=%s ssid='%s' hostname='%s'\n", proto_name(l3proto), ip_port, l7proto_str(l7proto), ssid ? ssid : "", hostname ? hostname : ""); } if (bCheckDone) *bCheckDone = false; LIST_FOREACH(dpl, head, next) { - if (dp_match(&dpl->dp,l3proto,dest,hostname,l7proto,bCheckDone,bCheckResult,bExcluded)) + if (dp_match(&dpl->dp,l3proto,dest,hostname,l7proto,ssid,bCheckDone,bCheckResult,bExcluded)) { DLOG("desync profile %d matches\n",dpl->dp.n); return &dpl->dp; @@ -1107,6 +1112,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint bool bSack,DF; uint16_t nmss; char host[256]; + const char *ifname = NULL, *ssid = NULL; uint32_t desync_fwmark = fwmark | params.desync_fwmark; extract_endpoints(dis->ip, dis->ip6, dis->tcp, NULL, &src, &dst); @@ -1122,6 +1128,11 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint if (!ConntrackPoolDoubleSearch(¶ms.conntrack, dis->ip, dis->ip6, dis->tcp, NULL, &ctrack_replay, &bReverse) || bReverse) return verdict; + ifname = bReverse ? ifin : ifout; +#ifdef HAS_FILTER_SSID + ssid = wlan_ssid_search_ifname(ifname); + if (ssid) DLOG("found ssid for %s : %s\n",ifname,ssid); +#endif dp = ctrack_replay->dp; if (dp) DLOG("using cached desync profile %d\n",dp->n); @@ -1133,7 +1144,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint if (!(ctrack_replay->hostname = strdup(host))) DLOG_ERR("strdup(host): out of memory\n"); } - dp = ctrack_replay->dp = dp_find(¶ms.desync_profiles, IPPROTO_TCP, (struct sockaddr *)&dst, ctrack_replay->hostname, ctrack_replay->l7proto, NULL, NULL, NULL); + dp = ctrack_replay->dp = dp_find(¶ms.desync_profiles, IPPROTO_TCP, (struct sockaddr *)&dst, ctrack_replay->hostname, ctrack_replay->l7proto, ssid, NULL, NULL, NULL); ctrack_replay->dp_search_complete = true; } if (!dp) @@ -1155,6 +1166,11 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint ctrack_replay = ctrack; } } + ifname = bReverse ? ifin : ifout; +#ifdef HAS_FILTER_SSID + ssid = wlan_ssid_search_ifname(ifname); + if (ssid) DLOG("found ssid for %s : %s\n",ifname,ssid); +#endif if (dp) DLOG("using cached desync profile %d\n",dp->n); else if (!ctrack || !ctrack->dp_search_complete) @@ -1170,7 +1186,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint DLOG_ERR("strdup(host): out of memory\n"); } } - dp = dp_find(¶ms.desync_profiles, IPPROTO_TCP, (struct sockaddr *)&dst, hostname, ctrack ? ctrack->l7proto : UNKNOWN, NULL, NULL, NULL); + dp = dp_find(¶ms.desync_profiles, IPPROTO_TCP, (struct sockaddr *)&dst, hostname, ctrack ? ctrack->l7proto : UNKNOWN, ssid, NULL, NULL, NULL); if (ctrack) { ctrack->dp = dp; @@ -1574,7 +1590,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint dp = dp_find(¶ms.desync_profiles, IPPROTO_TCP, (struct sockaddr *)&dst, ctrack_replay ? ctrack_replay->hostname : bHaveHost ? host : NULL, - ctrack_replay ? ctrack_replay->l7proto : l7proto, + ctrack_replay ? ctrack_replay->l7proto : l7proto, ssid, &bCheckDone, &bCheckResult, &bCheckExcluded); if (ctrack_replay) { @@ -2368,6 +2384,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint bool DF; char host[256]; t_l7proto l7proto = UNKNOWN; + const char *ifname = NULL, *ssid = NULL; extract_endpoints(dis->ip, dis->ip6, NULL, dis->udp, &src, &dst); @@ -2379,6 +2396,12 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint if (!ConntrackPoolDoubleSearch(¶ms.conntrack, dis->ip, dis->ip6, NULL, dis->udp, &ctrack_replay, &bReverse) || bReverse) return verdict; + ifname = bReverse ? ifin : ifout; +#ifdef HAS_FILTER_SSID + ssid = wlan_ssid_search_ifname(ifname); + if (ssid) DLOG("found ssid for %s : %s\n",ifname,ssid); +#endif + dp = ctrack_replay->dp; if (dp) DLOG("using cached desync profile %d\n",dp->n); @@ -2390,7 +2413,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint if (!(ctrack_replay->hostname = strdup(host))) DLOG_ERR("strdup(host): out of memory\n"); } - dp = ctrack_replay->dp = dp_find(¶ms.desync_profiles, IPPROTO_UDP, (struct sockaddr *)&dst, ctrack_replay->hostname, ctrack_replay->l7proto, NULL, NULL, NULL); + dp = ctrack_replay->dp = dp_find(¶ms.desync_profiles, IPPROTO_UDP, (struct sockaddr *)&dst, ctrack_replay->hostname, ctrack_replay->l7proto, ssid, NULL, NULL, NULL); ctrack_replay->dp_search_complete = true; } if (!dp) @@ -2415,6 +2438,11 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint ctrack_replay = ctrack; } } + ifname = bReverse ? ifin : ifout; +#ifdef HAS_FILTER_SSID + ssid = wlan_ssid_search_ifname(ifname); + if (ssid) DLOG("found ssid for %s : %s\n",ifname,ssid); +#endif if (dp) DLOG("using cached desync profile %d\n",dp->n); else if (!ctrack || !ctrack->dp_search_complete) @@ -2430,7 +2458,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint DLOG_ERR("strdup(host): out of memory\n"); } } - dp = dp_find(¶ms.desync_profiles, IPPROTO_UDP, (struct sockaddr *)&dst, hostname, ctrack ? ctrack->l7proto : UNKNOWN, NULL, NULL, NULL); + dp = dp_find(¶ms.desync_profiles, IPPROTO_UDP, (struct sockaddr *)&dst, hostname, ctrack ? ctrack->l7proto : UNKNOWN, ssid, NULL, NULL, NULL); if (ctrack) { ctrack->dp = dp; @@ -2703,7 +2731,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint dp = dp_find(¶ms.desync_profiles, IPPROTO_UDP, (struct sockaddr *)&dst, ctrack_replay ? ctrack_replay->hostname : bHaveHost ? host : NULL, - ctrack_replay ? ctrack_replay->l7proto : l7proto, + ctrack_replay ? ctrack_replay->l7proto : l7proto, ssid, &bCheckDone, &bCheckResult, &bCheckExcluded); if (ctrack_replay) { diff --git a/nfq/nfqws.c b/nfq/nfqws.c index 87add017..a3180cad 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -306,6 +306,12 @@ static int nfq_main(void) if (!nfq_init(&h,&qh)) goto err; + if (params.filter_ssid_present && !wlan_info_init()) + { + DLOG_ERR("cannot initialize wlan info capture\n"); + goto err; + } + if (params.daemon) daemonize(); sec_harden(); @@ -330,6 +336,9 @@ static int nfq_main(void) while ((rd = recv(fd, buf, sizeof(buf), 0)) >= 0) { ReloadCheck(); + if (params.filter_ssid_present) + if (!wlan_info_get_rate_limited()) + DLOG_ERR("cannot get wlan info\n"); if (rd) { int r = nfq_handle_packet(h, (char *)buf, (int)rd); @@ -346,9 +355,12 @@ static int nfq_main(void) } while(e==ENOBUFS); nfq_deinit(&h,&qh); + wlan_info_deinit(); return 0; err: if (Fpid) fclose(Fpid); + nfq_deinit(&h,&qh); + wlan_info_deinit(); return 1; } @@ -1127,6 +1139,20 @@ static bool parse_fooling(char *opt, unsigned int *fooling_mode) return true; } +static bool parse_strlist(char *opt, struct str_list_head *list) +{ + char *e,*p = optarg; + while (p) + { + e = strchr(p,','); + if (e) *e++=0; + if (*p && !strlist_add(list, p)) + return false; + p = e; + } + return true; +} + static void split_compat(struct desync_profile *dp) { if (!dp->split_count) @@ -1532,6 +1558,9 @@ static void exithelp(void) " --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|discord|stun|unknown] ; L6-L7 protocol filter. multiple comma separated values allowed.\n" +#ifdef HAS_FILTER_SSID + " --filter-ssid=ssid1[,ssid2,ssid3,...]\t\t; per profile wifi SSID filter\n" +#endif " --ipset=\t\t\t\t; ipset include filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)\n" " --ipset-ip=\t\t\t\t; comma separated fixed subnet list\n" " --ipset-exclude=\t\t\t; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)\n" @@ -1805,6 +1834,9 @@ enum opt_indices { IDX_FILTER_TCP, IDX_FILTER_UDP, IDX_FILTER_L7, +#ifdef HAS_FILTER_SSID + IDX_FILTER_SSID, +#endif IDX_IPSET, IDX_IPSET_IP, IDX_IPSET_EXCLUDE, @@ -1926,6 +1958,9 @@ static const struct option long_options[] = { [IDX_FILTER_TCP] = {"filter-tcp", required_argument, 0, 0}, [IDX_FILTER_UDP] = {"filter-udp", required_argument, 0, 0}, [IDX_FILTER_L7] = {"filter-l7", required_argument, 0, 0}, +#ifdef HAS_FILTER_SSID + [IDX_FILTER_SSID] = {"filter-ssid", required_argument, 0, 0}, +#endif [IDX_IPSET] = {"ipset", required_argument, 0, 0}, [IDX_IPSET_IP] = {"ipset-ip", required_argument, 0, 0}, [IDX_IPSET_EXCLUDE] = {"ipset-exclude", required_argument, 0, 0}, @@ -2810,6 +2845,16 @@ int main(int argc, char **argv) exit_clean(1); } break; +#ifdef HAS_FILTER_SSID + case IDX_FILTER_SSID: + if (!parse_strlist(optarg,&dp->filter_ssid)) + { + DLOG_ERR("strlist_add failed\n"); + exit_clean(1); + } + params.filter_ssid_present = true; + break; +#endif case IDX_IPSET: if (bSkip) break; if (!RegisterIpset(dp, false, optarg)) @@ -2914,38 +2959,18 @@ int main(int argc, char **argv) break; case IDX_SSID_FILTER: hash_ssid_filter=hash_jen(optarg,strlen(optarg)); + if (!parse_strlist(optarg,¶ms.ssid_filter)) { - char *e,*p = optarg; - while (p) - { - e = strchr(p,','); - if (e) *e++=0; - if (*p && !strlist_add(¶ms.ssid_filter, p)) - { - DLOG_ERR("strlist_add failed\n"); - exit_clean(1); - } - p = e; - - } + DLOG_ERR("strlist_add failed\n"); + exit_clean(1); } break; case IDX_NLM_FILTER: hash_nlm_filter=hash_jen(optarg,strlen(optarg)); + if (!parse_strlist(optarg,¶ms.nlm_filter)) { - char *e,*p = optarg; - while (p) - { - e = strchr(p,','); - if (e) *e++=0; - if (*p && !strlist_add(¶ms.nlm_filter, p)) - { - DLOG_ERR("strlist_add failed\n"); - exit_clean(1); - } - p = e; - - } + DLOG_ERR("strlist_add failed\n"); + exit_clean(1); } break; case IDX_NLM_LIST: diff --git a/nfq/nfqws.h b/nfq/nfqws.h index 86aa8829..745f6951 100644 --- a/nfq/nfqws.h +++ b/nfq/nfqws.h @@ -2,6 +2,10 @@ #include +#ifdef __linux__ +#define HAS_FILTER_SSID 1 +#endif + #ifdef __CYGWIN__ extern bool bQuit; #endif diff --git a/nfq/params.c b/nfq/params.c index 9081cdb5..25b6ea6b 100644 --- a/nfq/params.c +++ b/nfq/params.c @@ -42,6 +42,7 @@ int DLOG_FILENAME(const char *filename, const char *format, va_list args) r=-1; return r; } + typedef void (*f_log_function)(int priority, const char *line); static char log_buf[1024]; @@ -301,6 +302,9 @@ static void dp_clear_dynamic(struct desync_profile *dp) ipset_collection_destroy(&dp->ips_collection_exclude); port_filters_destroy(&dp->pf_tcp); port_filters_destroy(&dp->pf_udp); +#ifdef HAS_FILTER_SSID + strlist_destroy(&dp->filter_ssid); +#endif HostFailPoolDestroy(&dp->hostlist_auto_fail_counters); struct blob_collection_head **fake,*fakes[] = {&dp->fake_http, &dp->fake_tls, &dp->fake_unknown, &dp->fake_unknown_udp, &dp->fake_quic, &dp->fake_wg, &dp->fake_dht, &dp->fake_discord, &dp->fake_stun, NULL}; for(fake=fakes;*fake;fake++) blob_collection_destroy(*fake); diff --git a/nfq/params.h b/nfq/params.h index 9d714d4e..1e108c08 100644 --- a/nfq/params.h +++ b/nfq/params.h @@ -1,5 +1,6 @@ #pragma once +#include "nfqws.h" #include "pools.h" #include "conntrack.h" #include "desync.h" @@ -135,6 +136,13 @@ struct desync_profile struct port_filters_head pf_tcp,pf_udp; uint32_t filter_l7; // L7_PROTO_* bits +#ifdef HAS_FILTER_SSID + // per profile ssid filter + // annot use global filter because it's not possible to bind multiple instances to a single queue + // it's possible to run multiple winws instances on the same windivert filter, but it's not the case for linux + struct str_list_head filter_ssid; +#endif + // list of pointers to ipsets struct ipset_collection_head ips_collection, ips_collection_exclude; @@ -209,7 +217,12 @@ struct params_s t_conntrack conntrack; bool ctrack_disable; - bool autottl_present,cache_hostname; + bool autottl_present; +#ifdef HAS_FILTER_SSID + bool filter_ssid_present; +#endif + + bool cache_hostname; unsigned int ipcache_lifetime; ip_cache ipcache; }; diff --git a/nfq/pools.c b/nfq/pools.c index 2ec4cee9..aa698ffa 100644 --- a/nfq/pools.c +++ b/nfq/pools.c @@ -159,6 +159,19 @@ void strlist_destroy(struct str_list_head *head) strlist_entry_destroy(entry); } } +bool strlist_search(const struct str_list_head *head, const char *str) +{ + struct str_list *entry; + if (str) + { + LIST_FOREACH(entry, head, next) + { + if (!strcmp(entry->str, str)) + return true; + } + } + return false; +} diff --git a/nfq/pools.h b/nfq/pools.h index 5adaf7f6..5018ecd1 100644 --- a/nfq/pools.h +++ b/nfq/pools.h @@ -34,6 +34,11 @@ struct str_list { }; LIST_HEAD(str_list_head, str_list); +bool strlist_add(struct str_list_head *head, const char *filename); +void strlist_destroy(struct str_list_head *head); +bool strlist_search(const struct str_list_head *head, const char *str); + + typedef struct hostfail_pool { char *str; /* key */ int counter; /* value */ @@ -49,10 +54,6 @@ void HostFailPoolPurge(hostfail_pool **pp); void HostFailPoolPurgeRateLimited(hostfail_pool **pp); void HostFailPoolDump(hostfail_pool *p); -bool strlist_add(struct str_list_head *head, const char *filename); -void strlist_destroy(struct str_list_head *head); - - struct hostlist_file { char *filename;