helpers: make the proto field as a list rather than one option
authorPierre Lebleu <pme.lebleu@gmail.com>
Mon, 7 May 2018 14:17:16 +0000 (16:17 +0200)
committerJohn Crispin <john@phrozen.org>
Mon, 14 May 2018 14:15:02 +0000 (16:15 +0200)
The field proto in the struct fw3_cthelper should be implemented
as a list in order to support multiple protocols.

For example, the helper for SIP should be able to support both
TCP and UDP within only one entry in the config file.

config helper
        option name 'sip'
        option description 'SIP VoIP connection tracking'
        option module 'nf_conntrack_sip'
        option family 'any'
        option proto 'tcpudp'
        option port '5060'

Signed-off-by: Pierre Lebleu <pme.lebleu@gmail.com>
helpers.c
helpers.h
options.h
redirects.c
rules.c

index 8cad0b3459754f08eb7d5cecd028598456472570..36317d2fc42573d9b54c4c24053abeefb0ee55e1 100644 (file)
--- a/helpers.c
+++ b/helpers.c
@@ -25,7 +25,7 @@ const struct fw3_option fw3_cthelper_opts[] = {
        FW3_OPT("module",      string,   cthelper, module),
        FW3_OPT("description", string,   cthelper, description),
        FW3_OPT("family",      family,   cthelper, family),
-       FW3_OPT("proto",       protocol, cthelper, proto),
+       FW3_LIST("proto",      protocol, cthelper, proto),
        FW3_OPT("port",        port,     cthelper, port),
 
        { }
@@ -46,6 +46,23 @@ test_module(struct fw3_cthelper *helper)
        return true;
 }
 
+static bool
+check_cthelper_proto(const struct fw3_cthelper *helper)
+{
+       struct fw3_protocol     *proto;
+
+       if (list_empty(&helper->proto))
+               return false;
+
+       list_for_each_entry(proto, &helper->proto, list)
+       {
+               if (!proto->protocol || proto->any || proto->invert)
+                       return false;
+       }
+
+       return true;
+}
+
 static bool
 check_cthelper(struct fw3_state *state, struct fw3_cthelper *helper, struct uci_element *e)
 {
@@ -57,7 +74,7 @@ check_cthelper(struct fw3_state *state, struct fw3_cthelper *helper, struct uci_
        {
                warn_section("helper", helper, e, "must have a module assigned");
        }
-       else if (!helper->proto.protocol || helper->proto.any || helper->proto.invert)
+       else if (!check_cthelper_proto(helper))
        {
                warn_section("helper", helper, e, "must specify a protocol");
        }
@@ -84,6 +101,7 @@ fw3_alloc_cthelper(struct fw3_state *state)
 
        helper->enabled = true;
        helper->family  = FW3_FAMILY_ANY;
+       INIT_LIST_HEAD(&helper->proto);
 
        list_add_tail(&helper->list, &state->cthelpers);
 
@@ -157,6 +175,20 @@ fw3_lookup_cthelper(struct fw3_state *state, const char *name)
        return NULL;
 }
 
+bool
+fw3_cthelper_check_proto(const struct fw3_cthelper *h, const struct fw3_protocol *proto)
+{
+       struct fw3_protocol     *p;
+
+       list_for_each_entry(p, &h->proto, list)
+       {
+               if (p->protocol == proto->protocol)
+                       return true;
+       }
+
+       return false;
+}
+
 struct fw3_cthelper *
 fw3_lookup_cthelper_by_proto_port(struct fw3_state *state,
                                   struct fw3_protocol *proto,
@@ -178,7 +210,7 @@ fw3_lookup_cthelper_by_proto_port(struct fw3_state *state,
                if (!h->enabled)
                        continue;
 
-               if (h->proto.protocol != proto->protocol)
+               if (!fw3_cthelper_check_proto(h, proto))
                        continue;
 
                if (h->port.set && (!port || !port->set))
@@ -198,11 +230,11 @@ fw3_lookup_cthelper_by_proto_port(struct fw3_state *state,
 
 static void
 print_helper_rule(struct fw3_ipt_handle *handle, struct fw3_cthelper *helper,
-                  struct fw3_zone *zone)
+                  struct fw3_zone *zone, struct fw3_protocol *proto)
 {
        struct fw3_ipt_rule *r;
 
-       r = fw3_ipt_rule_create(handle, &helper->proto, NULL, NULL, NULL, NULL);
+       r = fw3_ipt_rule_create(handle, proto, NULL, NULL, NULL, NULL);
 
        if (helper->description && *helper->description)
                fw3_ipt_rule_comment(r, helper->description);
@@ -215,6 +247,16 @@ print_helper_rule(struct fw3_ipt_handle *handle, struct fw3_cthelper *helper,
        fw3_ipt_rule_replace(r, "zone_%s_helper", zone->name);
 }
 
+static void
+expand_helper_rule(struct fw3_ipt_handle *handle, struct fw3_cthelper *helper,
+                  struct fw3_zone *zone)
+{
+       struct fw3_protocol *proto;
+
+       list_for_each_entry(proto, &helper->proto, list)
+               print_helper_rule(handle, helper, zone, proto);
+}
+
 void
 fw3_print_cthelpers(struct fw3_ipt_handle *handle, struct fw3_state *state,
                     struct fw3_zone *zone)
@@ -249,7 +291,7 @@ fw3_print_cthelpers(struct fw3_ipt_handle *handle, struct fw3_state *state,
                        if (!test_module(helper))
                                continue;
 
-                       print_helper_rule(handle, helper, zone);
+                       expand_helper_rule(handle, helper, zone);
                }
        }
        else
@@ -271,7 +313,7 @@ fw3_print_cthelpers(struct fw3_ipt_handle *handle, struct fw3_state *state,
                                continue;
                        }
 
-                       print_helper_rule(handle, helper, zone);
+                       expand_helper_rule(handle, helper, zone);
                }
        }
 }
index 450428ec73873843e67c3e7a9af348b5a740bfca..e2a99cd86d5b1e078b33be3fe03e583ab1d9d96a 100644 (file)
--- a/helpers.h
+++ b/helpers.h
@@ -41,6 +41,9 @@ void
 fw3_print_cthelpers(struct fw3_ipt_handle *handle, struct fw3_state *state,
                     struct fw3_zone *zone);
 
+bool
+fw3_cthelper_check_proto(const struct fw3_cthelper *h, const struct fw3_protocol *proto);
+
 static inline void fw3_free_cthelper(struct fw3_cthelper *helper)
 {
        list_del(&helper->list);
index 15cd504faef277c120a040f050912653868c7de1..08fecf61e33df60740b3f783bc1c5d917e19684e 100644 (file)
--- a/options.h
+++ b/options.h
@@ -526,7 +526,7 @@ struct fw3_cthelper
        const char *module;
        const char *description;
        enum fw3_family family;
-       struct fw3_protocol proto;
+       struct list_head proto;
        struct fw3_port port;
 };
 
index 660cdd2f3e94875b80499a8094cdb90558201ce6..7f9948cd3bb77a3a83b3553615d5e3ef4d677404 100644 (file)
@@ -576,7 +576,7 @@ print_redirect(struct fw3_ipt_handle *h, struct fw3_state *state,
        case FW3_TABLE_RAW:
                if (redir->target == FW3_FLAG_DNAT && redir->helper.ptr)
                {
-                       if (redir->helper.ptr->proto.protocol != proto->protocol)
+                       if (!fw3_cthelper_check_proto(redir->helper.ptr, proto))
                        {
                                info("     ! Skipping protocol %s since helper '%s' does not support it",
                                     fw3_protoname(proto), redir->helper.ptr->name);
diff --git a/rules.c b/rules.c
index ea66771457511b37b7bc7af3fb8248b16f0906d4..58edcd4562f2d07699b13a3eab3a53a9bc5f9d61 100644 (file)
--- a/rules.c
+++ b/rules.c
@@ -436,7 +436,7 @@ print_rule(struct fw3_ipt_handle *handle, struct fw3_state *state,
        }
 
        if (rule->helper.ptr &&
-           rule->helper.ptr->proto.protocol != proto->protocol)
+           !fw3_cthelper_check_proto(rule->helper.ptr, proto))
        {
                info("     ! Skipping protocol %s since helper '%s' does not support it",
                     fw3_protoname(proto), rule->helper.ptr->name);
@@ -444,7 +444,7 @@ print_rule(struct fw3_ipt_handle *handle, struct fw3_state *state,
        }
 
        if (rule->set_helper.ptr &&
-           rule->set_helper.ptr->proto.protocol != proto->protocol)
+           !fw3_cthelper_check_proto(rule->set_helper.ptr, proto))
        {
                info("     ! Skipping protocol %s since helper '%s' does not support it",
                     fw3_protoname(proto), rule->helper.ptr->name);