From 2452a529eb32e41707d0dd3aee11e0e2cce59feb Mon Sep 17 00:00:00 2001 From: bol-van Date: Tue, 29 Oct 2024 17:41:59 +0300 Subject: [PATCH] nfqws: comma separated values in --filter-tcp, --filter-udp --- nfq/desync.c | 2 +- nfq/helpers.c | 5 +++++ nfq/nfqws.c | 48 +++++++++++++++++++++++++++++++++++------------- nfq/params.c | 5 +++++ nfq/params.h | 2 +- nfq/pools.c | 39 +++++++++++++++++++++++++++++++++++++++ nfq/pools.h | 11 +++++++++++ 7 files changed, 97 insertions(+), 15 deletions(-) diff --git a/nfq/desync.c b/nfq/desync.c index c782300..a028093 100644 --- a/nfq/desync.c +++ b/nfq/desync.c @@ -158,7 +158,7 @@ static bool dp_match( if ((dest->sa_family==AF_INET && !dp->filter_ipv4) || (dest->sa_family==AF_INET6 && !dp->filter_ipv6)) // L3 filter does not match return false; - if ((l3proto==IPPROTO_TCP && !pf_in_range(saport(dest), &dp->pf_tcp)) || (l3proto==IPPROTO_UDP && !pf_in_range(saport(dest), &dp->pf_udp))) + if ((l3proto==IPPROTO_TCP && !port_filters_in_range(&dp->pf_tcp,saport(dest))) || (l3proto==IPPROTO_UDP && !port_filters_in_range(&dp->pf_udp,saport(dest)))) // L4 filter does not match return false; if (dp->filter_l7 && !l7_proto_match(l7proto, dp->filter_l7)) diff --git a/nfq/helpers.c b/nfq/helpers.c index dc0c840..7e5087c 100644 --- a/nfq/helpers.c +++ b/nfq/helpers.c @@ -333,6 +333,11 @@ bool pf_parse(const char *s, port_filter *pf) char c; if (!s) return false; + if (*s=='*' && s[1]==0) + { + pf->from=1; pf->to=0xFFFF; + return true; + } if (*s=='~') { pf->neg=true; diff --git a/nfq/nfqws.c b/nfq/nfqws.c index 9320cec..39699bd 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -669,6 +669,26 @@ static bool parse_l7_list(char *opt, uint32_t *l7) return true; } +static bool parse_pf_list(char *opt, struct port_filters_head *pfl) +{ + char *e,*p,c; + port_filter pf; + + for (p=opt ; p ; ) + { + if ((e = strchr(p,','))) + { + c=*e; + *e=0; + } + + if (!pf_parse(p,&pf) || !port_filter_add(pfl,&pf)) return false; + + if (e) *e++=c; + p = e; + } + return true; +} static bool wf_make_l3(char *opt, bool *ipv4, bool *ipv6) { @@ -853,8 +873,8 @@ static void exithelp(void) "\nMULTI-STRATEGY:\n" " --new\t\t\t\t\t\t; begin new strategy\n" " --filter-l3=ipv4|ipv6\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.\n" - " --filter-udp=[~]port1[-port2]\t\t\t; UDP port filter. ~ means negation. setting udp and not setting tcp filter denies tcp.\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" " --ipset=\t\t\t\t; ipset include filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)\n" " --ipset-exclude=\t\t\t; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)\n" @@ -1612,22 +1632,24 @@ int main(int argc, char **argv) } break; case 54: /* filter-tcp */ - if (!pf_parse(optarg,&dp->pf_tcp)) - { - DLOG_ERR("Invalid port filter : %s\n",optarg); - exit_clean(1); - } - // deny udp if not set - if (pf_is_empty(&dp->pf_udp)) dp->pf_udp.neg=true; - break; - case 55: /* filter-udp */ - if (!pf_parse(optarg,&dp->pf_udp)) + if (!parse_pf_list(optarg,&dp->pf_tcp)) { DLOG_ERR("Invalid port filter : %s\n",optarg); exit_clean(1); } // deny tcp if not set - if (pf_is_empty(&dp->pf_tcp)) dp->pf_tcp.neg=true; + if (!port_filters_deny_if_empty(&dp->pf_udp)) + exit_clean(1); + break; + case 55: /* filter-udp */ + if (!parse_pf_list(optarg,&dp->pf_udp)) + { + DLOG_ERR("Invalid port filter : %s\n",optarg); + exit_clean(1); + } + // deny tcp if not set + if (!port_filters_deny_if_empty(&dp->pf_tcp)) + exit_clean(1); break; case 56: /* filter-l7 */ if (!parse_l7_list(optarg,&dp->filter_l7)) diff --git a/nfq/params.c b/nfq/params.c index 3eb7dd3..dec576b 100644 --- a/nfq/params.c +++ b/nfq/params.c @@ -164,6 +164,9 @@ struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head) LIST_INIT(&entry->dp.hl_collection_exclude); LIST_INIT(&entry->dp.ips_collection); LIST_INIT(&entry->dp.ips_collection_exclude); + LIST_INIT(&entry->dp.pf_tcp); + LIST_INIT(&entry->dp.pf_udp); + memcpy(entry->dp.hostspell, "host", 4); // default hostspell entry->dp.desync_skip_nosni = true; entry->dp.desync_split_pos = 2; @@ -211,6 +214,8 @@ static void dp_entry_destroy(struct desync_profile_list *entry) hostlist_collection_destroy(&entry->dp.hl_collection_exclude); ipset_collection_destroy(&entry->dp.ips_collection); ipset_collection_destroy(&entry->dp.ips_collection_exclude); + port_filters_destroy(&entry->dp.pf_tcp); + port_filters_destroy(&entry->dp.pf_udp); HostFailPoolDestroy(&entry->dp.hostlist_auto_fail_counters); free(entry); } diff --git a/nfq/params.h b/nfq/params.h index f741d20..187be1e 100644 --- a/nfq/params.h +++ b/nfq/params.h @@ -65,7 +65,7 @@ struct desync_profile int udplen_increment; bool filter_ipv4,filter_ipv6; - port_filter pf_tcp,pf_udp; + struct port_filters_head pf_tcp,pf_udp; uint32_t filter_l7; // L7_PROTO_* bits // list of pointers to ipsets diff --git a/nfq/pools.c b/nfq/pools.c index 9df09f4..81a7b80 100644 --- a/nfq/pools.c +++ b/nfq/pools.c @@ -448,3 +448,42 @@ bool ipset_collection_is_empty(const struct ipset_collection_head *head) } return true; } + + +bool port_filter_add(struct port_filters_head *head, const port_filter *pf) +{ + struct port_filter_item *entry = malloc(sizeof(struct port_filter_item)); + if (entry) + { + entry->pf = *pf; + LIST_INSERT_HEAD(head, entry, next); + } + return entry; +} +void port_filters_destroy(struct port_filters_head *head) +{ + struct port_filter_item *entry; + while ((entry = LIST_FIRST(head))) + { + LIST_REMOVE(entry, next); + free(entry); + } +} +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; + LIST_FOREACH(item, head, next) + { + if (pf_in_range(port, &item->pf)) + return true; + } + return false; +} +bool port_filters_deny_if_empty(struct port_filters_head *head) +{ + port_filter pf; + if (LIST_FIRST(head)) return true; + return pf_parse("0",&pf) && port_filter_add(head,&pf); +} diff --git a/nfq/pools.h b/nfq/pools.h index 1fd361c..cd37bdd 100644 --- a/nfq/pools.h +++ b/nfq/pools.h @@ -130,3 +130,14 @@ struct ipset_item * ipset_collection_add(struct ipset_collection_head *head, str 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); + + +struct port_filter_item { + port_filter pf; + LIST_ENTRY(port_filter_item) next; +}; +LIST_HEAD(port_filters_head, port_filter_item); +bool port_filter_add(struct port_filters_head *head, const port_filter *pf); +void port_filters_destroy(struct port_filters_head *head); +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);