]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
nftutils: add and use wrappers for getprotoby{name,number}_r(), getservbyport_r()
authorThomas Haller <thaller@redhat.com>
Fri, 18 Aug 2023 14:08:19 +0000 (16:08 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Sun, 20 Aug 2023 21:48:26 +0000 (23:48 +0200)
We should aim to use the thread-safe variants of getprotoby{name,number}
and getservbyport(). However, they may not be available with other libc,
so it requires a configure check. As that is cumbersome, add wrappers
that do that at one place.

These wrappers are thread-safe, if libc provides the reentrant versions.
Use them.

Signed-off-by: Thomas Haller <thaller@redhat.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
configure.ac
src/Makefile.am
src/datatype.c
src/json.c
src/nftutils.c [new file with mode: 0644]
src/nftutils.h [new file with mode: 0644]
src/rule.c

index b0201ac3528e30bdc2427dccc7303a5c22ad7c7f..42f0dc4cf3920aa0d44cf2ede51e47b371f97b1b 100644 (file)
@@ -108,6 +108,10 @@ AC_DEFINE([HAVE_LIBJANSSON], [1], [Define if you have libjansson])
 ])
 AM_CONDITIONAL([BUILD_JSON], [test "x$with_json" != xno])
 
+AC_CHECK_DECLS([getprotobyname_r, getprotobynumber_r, getservbyport_r], [], [], [[
+#include <netdb.h>
+]])
+
 AC_CONFIG_FILES([                                      \
                Makefile                                \
                libnftables.pc                          \
index ace38bd75a97ec89c7cc2a7afd036d90ea13e9fd..ad22a918c1208b76c466837a015c6681ad2ea21d 100644 (file)
@@ -64,6 +64,8 @@ libnftables_la_SOURCES =                      \
                segtree.c                       \
                gmputil.c                       \
                utils.c                         \
+               nftutils.c                      \
+               nftutils.h                      \
                erec.c                          \
                mnl.c                           \
                iface.c                         \
index da802a18bccd49f92fae5e8ef26f45fdeb77b6e3..381320eaf8422faae6243ac36fe8bc24d3c0dcb1 100644 (file)
@@ -29,6 +29,7 @@
 #include <netlink.h>
 #include <json.h>
 #include <misspell.h>
+#include "nftutils.h"
 
 #include <netinet/ip_icmp.h>
 
@@ -697,12 +698,11 @@ const struct datatype ip6addr_type = {
 static void inet_protocol_type_print(const struct expr *expr,
                                      struct output_ctx *octx)
 {
-       struct protoent *p;
-
        if (!nft_output_numeric_proto(octx)) {
-               p = getprotobynumber(mpz_get_uint8(expr->value));
-               if (p != NULL) {
-                       nft_print(octx, "%s", p->p_name);
+               char name[NFT_PROTONAME_MAXSIZE];
+
+               if (nft_getprotobynumber(mpz_get_uint8(expr->value), name, sizeof(name))) {
+                       nft_print(octx, "%s", name);
                        return;
                }
        }
@@ -711,15 +711,15 @@ static void inet_protocol_type_print(const struct expr *expr,
 
 static void inet_protocol_type_describe(struct output_ctx *octx)
 {
-       struct protoent *p;
        uint8_t protonum;
 
        for (protonum = 0; protonum < UINT8_MAX; protonum++) {
-               p = getprotobynumber(protonum);
-               if (!p)
+               char name[NFT_PROTONAME_MAXSIZE];
+
+               if (!nft_getprotobynumber(protonum, name, sizeof(name)))
                        continue;
 
-               nft_print(octx, "\t%-30s\t%u\n", p->p_name, protonum);
+               nft_print(octx, "\t%-30s\t%u\n", name, protonum);
        }
 }
 
@@ -727,7 +727,6 @@ static struct error_record *inet_protocol_type_parse(struct parse_ctx *ctx,
                                                     const struct expr *sym,
                                                     struct expr **res)
 {
-       struct protoent *p;
        uint8_t proto;
        uintmax_t i;
        char *end;
@@ -740,11 +739,13 @@ static struct error_record *inet_protocol_type_parse(struct parse_ctx *ctx,
 
                proto = i;
        } else {
-               p = getprotobyname(sym->identifier);
-               if (p == NULL)
+               int r;
+
+               r = nft_getprotobyname(sym->identifier);
+               if (r < 0)
                        return error(&sym->location, "Could not resolve protocol name");
 
-               proto = p->p_proto;
+               proto = r;
        }
 
        *res = constant_expr_alloc(&sym->location, &inet_protocol_type,
@@ -768,12 +769,12 @@ const struct datatype inet_protocol_type = {
 static void inet_service_print(const struct expr *expr, struct output_ctx *octx)
 {
        uint16_t port = mpz_get_be16(expr->value);
-       const struct servent *s = getservbyport(port, NULL);
+       char name[NFT_SERVNAME_MAXSIZE];
 
-       if (s == NULL)
+       if (!nft_getservbyport(port, NULL, name, sizeof(name)))
                nft_print(octx, "%hu", ntohs(port));
        else
-               nft_print(octx, "\"%s\"", s->s_name);
+               nft_print(octx, "\"%s\"", name);
 }
 
 void inet_service_type_print(const struct expr *expr, struct output_ctx *octx)
index 366c0edf485dbb792bc030b1facb7565e2056a8f..31dd185666b141a6322ac9e74c44aebb52779d56 100644 (file)
@@ -15,6 +15,7 @@
 #include <netlink.h>
 #include <rule.h>
 #include <rt.h>
+#include "nftutils.h"
 
 #include <netdb.h>
 #include <netinet/icmp6.h>
@@ -298,10 +299,10 @@ static json_t *chain_print_json(const struct chain *chain)
 
 static json_t *proto_name_json(uint8_t proto)
 {
-       const struct protoent *p = getprotobynumber(proto);
+       char name[NFT_PROTONAME_MAXSIZE];
 
-       if (p)
-               return json_string(p->p_name);
+       if (nft_getprotobynumber(proto, name, sizeof(name)))
+               return json_string(name);
        return json_integer(proto);
 }
 
@@ -1094,12 +1095,11 @@ json_t *boolean_type_json(const struct expr *expr, struct output_ctx *octx)
 json_t *inet_protocol_type_json(const struct expr *expr,
                                struct output_ctx *octx)
 {
-       struct protoent *p;
-
        if (!nft_output_numeric_proto(octx)) {
-               p = getprotobynumber(mpz_get_uint8(expr->value));
-               if (p != NULL)
-                       return json_string(p->p_name);
+               char name[NFT_PROTONAME_MAXSIZE];
+
+               if (nft_getprotobynumber(mpz_get_uint8(expr->value), name, sizeof(name)))
+                       return json_string(name);
        }
        return integer_type_json(expr, octx);
 }
@@ -1107,13 +1107,13 @@ json_t *inet_protocol_type_json(const struct expr *expr,
 json_t *inet_service_type_json(const struct expr *expr, struct output_ctx *octx)
 {
        uint16_t port = mpz_get_be16(expr->value);
-       const struct servent *s = NULL;
+       char name[NFT_SERVNAME_MAXSIZE];
 
        if (!nft_output_service(octx) ||
-           (s = getservbyport(port, NULL)) == NULL)
+           !nft_getservbyport(port, NULL, name, sizeof(name)))
                return json_integer(ntohs(port));
 
-       return json_string(s->s_name);
+       return json_string(name);
 }
 
 json_t *mark_type_json(const struct expr *expr, struct output_ctx *octx)
diff --git a/src/nftutils.c b/src/nftutils.c
new file mode 100644 (file)
index 0000000..13f879d
--- /dev/null
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <config.h>
+
+#include "nftutils.h"
+
+#include <netdb.h>
+#include <string.h>
+#include <stdint.h>
+
+/* Buffer size used for getprotobynumber_r() and similar. The manual comments
+ * that a buffer of 1024 should be sufficient "for most applications"(??), so
+ * let's double it.  It still fits reasonably on the stack, so no need to
+ * choose a smaller one. */
+#define NETDB_BUFSIZE 2048
+
+bool nft_getprotobynumber(int proto, char *out_name, size_t name_len)
+{
+       const struct protoent *result;
+
+#if HAVE_DECL_GETPROTOBYNUMBER_R
+       struct protoent result_buf;
+       char buf[NETDB_BUFSIZE];
+       int r;
+
+       r = getprotobynumber_r(proto,
+                              &result_buf,
+                              buf,
+                              sizeof(buf),
+                              (struct protoent **) &result);
+       if (r != 0 || result != &result_buf)
+               result = NULL;
+#else
+       result = getprotobynumber(proto);
+#endif
+
+       if (!result)
+               return false;
+
+       if (strlen(result->p_name) >= name_len)
+               return false;
+       strcpy(out_name, result->p_name);
+       return true;
+}
+
+int nft_getprotobyname(const char *name)
+{
+       const struct protoent *result;
+
+#if HAVE_DECL_GETPROTOBYNAME_R
+       struct protoent result_buf;
+       char buf[NETDB_BUFSIZE];
+       int r;
+
+       r = getprotobyname_r(name,
+                            &result_buf,
+                            buf,
+                            sizeof(buf),
+                            (struct protoent **) &result);
+       if (r != 0 || result != &result_buf)
+               result = NULL;
+#else
+       result = getprotobyname(name);
+#endif
+
+       if (!result)
+               return -1;
+
+       if (result->p_proto < 0 || result->p_proto > UINT8_MAX)
+               return -1;
+       return (uint8_t) result->p_proto;
+}
+
+bool nft_getservbyport(int port, const char *proto, char *out_name, size_t name_len)
+{
+       const struct servent *result;
+
+#if HAVE_DECL_GETSERVBYPORT_R
+       struct servent result_buf;
+       char buf[NETDB_BUFSIZE];
+       int r;
+
+       r = getservbyport_r(port,
+                           proto,
+                           &result_buf,
+                           buf,
+                           sizeof(buf),
+                           (struct servent**) &result);
+       if (r != 0 || result != &result_buf)
+               result = NULL;
+#else
+       result = getservbyport(port, proto);
+#endif
+
+       if (!result)
+               return false;
+
+       if (strlen(result->s_name) >= name_len)
+               return false;
+       strcpy(out_name, result->s_name);
+       return true;
+}
diff --git a/src/nftutils.h b/src/nftutils.h
new file mode 100644 (file)
index 0000000..cb584b9
--- /dev/null
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef NFTUTILS_H
+#define NFTUTILS_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+/* The maximum buffer size for (struct protoent).p_name. It is excessively large,
+ * while still reasonably fitting on the stack. Arbitrarily chosen. */
+#define NFT_PROTONAME_MAXSIZE 1024
+
+bool nft_getprotobynumber(int number, char *out_name, size_t name_len);
+int nft_getprotobyname(const char *name);
+
+/* The maximum buffer size for (struct servent).s_name. It is excessively large,
+ * while still reasonably fitting on the stack. Arbitrarily chosen. */
+#define NFT_SERVNAME_MAXSIZE 1024
+
+bool nft_getservbyport(int port, const char *proto, char *out_name, size_t name_len);
+
+#endif /* NFTUTILS_H */
index 99c4f0bb8b00302afaff871c91abf8f50a38f570..b59fcd3a9fa8d9f6c6b8e2a282cc42d714fc0f3d 100644 (file)
@@ -27,6 +27,7 @@
 #include <cache.h>
 #include <owner.h>
 #include <intervals.h>
+#include "nftutils.h"
 
 #include <libnftnl/common.h>
 #include <libnftnl/ruleset.h>
@@ -1666,10 +1667,10 @@ struct obj *obj_lookup_fuzzy(const char *obj_name,
 
 static void print_proto_name_proto(uint8_t l4, struct output_ctx *octx)
 {
-       const struct protoent *p = getprotobynumber(l4);
+       char name[NFT_PROTONAME_MAXSIZE];
 
-       if (p)
-               nft_print(octx, "%s", p->p_name);
+       if (nft_getprotobynumber(l4, name, sizeof(name)))
+               nft_print(octx, "%s", name);
        else
                nft_print(octx, "%d", l4);
 }