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@xxxxxx> --- iptables/xshared.c | 8 ++++---- libxtables/xtables.c | 19 ++++++------------- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/iptables/xshared.c b/iptables/xshared.c index 50a1d48a55ebe..43321d3b5358c 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -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; } diff --git a/libxtables/xtables.c b/libxtables/xtables.c index 87424d045466b..094cbd87ec1ed 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -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; -- 2.34.1