]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
xshared: Prefer xtables_chain_protos lookup over getprotoent
authorPhil Sutter <phil@nwl.cc>
Tue, 1 Mar 2022 22:05:29 +0000 (23:05 +0100)
committerPhil Sutter <phil@nwl.cc>
Thu, 10 Mar 2022 16:38:31 +0000 (17:38 +0100)
When dumping a large ruleset, common protocol matches such as for TCP
port number significantly slow down rule printing due to repeated calls
for getprotobynumber(). The latter does not involve any caching, so
/etc/protocols is consulted over and over again.

As a simple countermeasure, make functions converting between proto
number and name prefer the built-in list of "well-known" protocols. This
is not a perfect solution, repeated rules for protocol names libxtables
does not cache (e.g. igmp or dccp) will still be slow. Implementing
getprotoent() result caching could solve this.

As a side-effect, explicit check for pseudo-protocol "all" may be
dropped as it is contained in the built-in list and therefore immutable.

Also update xtables_chain_protos entries a bit to align with typical
/etc/protocols contents. The testsuite assumes those names, so the
preferred ones prior to this patch are indeed uncommon nowadays.

Signed-off-by: Phil Sutter <phil@nwl.cc>
Acked-by: Florian Westphal <fw@strlen.de>
iptables/xshared.c
libxtables/xtables.c

index 50a1d48a55ebe777de95a907d63461d2aa518390..43321d3b5358ca337fefb2a3b4255902724b2164 100644 (file)
@@ -53,16 +53,16 @@ proto_to_name(uint16_t proto, int nolookup)
 {
        unsigned int i;
 
+       for (i = 0; xtables_chain_protos[i].name != NULL; ++i)
+               if (xtables_chain_protos[i].num == proto)
+                       return xtables_chain_protos[i].name;
+
        if (proto && !nolookup) {
                struct protoent *pent = getprotobynumber(proto);
                if (pent)
                        return pent->p_name;
        }
 
-       for (i = 0; xtables_chain_protos[i].name != NULL; ++i)
-               if (xtables_chain_protos[i].num == proto)
-                       return xtables_chain_protos[i].name;
-
        return NULL;
 }
 
index 87424d045466be61214c5e739a1ebbdcdfac8aeb..094cbd87ec1edecbbbe4152fd6c6cfc2436e6338 100644 (file)
@@ -2101,10 +2101,11 @@ const struct xtables_pprot xtables_chain_protos[] = {
        {"udp",       IPPROTO_UDP},
        {"udplite",   IPPROTO_UDPLITE},
        {"icmp",      IPPROTO_ICMP},
-       {"icmpv6",    IPPROTO_ICMPV6},
        {"ipv6-icmp", IPPROTO_ICMPV6},
+       {"icmpv6",    IPPROTO_ICMPV6},
        {"esp",       IPPROTO_ESP},
        {"ah",        IPPROTO_AH},
+       {"mobility-header", IPPROTO_MH},
        {"ipv6-mh",   IPPROTO_MH},
        {"mh",        IPPROTO_MH},
        {"all",       0},
@@ -2120,23 +2121,15 @@ xtables_parse_protocol(const char *s)
        if (xtables_strtoui(s, NULL, &proto, 0, UINT8_MAX))
                return proto;
 
-       /* first deal with the special case of 'all' to prevent
-        * people from being able to redefine 'all' in nsswitch
-        * and/or provoke expensive [not working] ldap/nis/...
-        * lookups */
-       if (strcmp(s, "all") == 0)
-               return 0;
+       for (i = 0; xtables_chain_protos[i].name != NULL; ++i) {
+               if (strcmp(s, xtables_chain_protos[i].name) == 0)
+                       return xtables_chain_protos[i].num;
+       }
 
        pent = getprotobyname(s);
        if (pent != NULL)
                return pent->p_proto;
 
-       for (i = 0; i < ARRAY_SIZE(xtables_chain_protos); ++i) {
-               if (xtables_chain_protos[i].name == NULL)
-                       continue;
-               if (strcmp(s, xtables_chain_protos[i].name) == 0)
-                       return xtables_chain_protos[i].num;
-       }
        xt_params->exit_err(PARAMETER_PROBLEM,
                "unknown protocol \"%s\" specified", s);
        return -1;