From: Pablo Neira Ayuso <pablo@netfilter.org>
To: Thomas Haller <thaller@redhat.com>
Cc: NetFilter <netfilter-devel@vger.kernel.org>
Subject: Re: [nft PATCH] src: use reentrant getprotobyname_r()/getprotobynumber_r()/getservbyport_r()
Date: Fri, 11 Aug 2023 14:20:19 +0200 [thread overview]
Message-ID: <ZNYng8dQBhk48kj9@calendula> (raw)
In-Reply-To: <20230810123035.3866306-1-thaller@redhat.com>
Hi Thomas,
On Thu, Aug 10, 2023 at 02:30:30PM +0200, Thomas Haller wrote:
> If the reentrant versions of the functions are available, use them so
> that libnftables is thread-safe in this regard.
At netlink sequence tracking is not thread-safe, users hit EILSEQ
errors when multiple threads recycle the same nft_ctx object. Updates
are serialized by mutex per netns, batching is usually the way to go
to amortize the cost of ruleset updates.
Are you planning to have a user of libnftables that is multi-thread?
> Signed-off-by: Thomas Haller <thaller@redhat.com>
> ---
> configure.ac | 4 +++
> include/utils.h | 4 +++
> src/datatype.c | 29 +++++++---------
> src/json.c | 21 ++++++------
> src/rule.c | 6 ++--
> src/utils.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++
> 6 files changed, 123 insertions(+), 31 deletions(-)
>
> diff --git a/configure.ac b/configure.ac
> index b0201ac3528e..42f0dc4cf392 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -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 \
> diff --git a/include/utils.h b/include/utils.h
> index d5073e061033..56f1522e601a 100644
> --- a/include/utils.h
> +++ b/include/utils.h
> @@ -138,4 +138,8 @@ extern char *xstrdup(const char *s);
> extern void xstrunescape(const char *in, char *out);
> extern int round_pow_2(unsigned int value);
>
> +bool nft_getprotobynumber(int number, char *out_name, size_t name_len);
> +bool nft_getprotobyname(const char *name, uint8_t *out_proto);
> +bool nft_getservbyport(int port, const char *proto, char *out_name, size_t name_len);
> +
> #endif /* NFTABLES_UTILS_H */
> diff --git a/src/datatype.c b/src/datatype.c
> index da802a18bccd..5b3d39137f01 100644
> --- a/src/datatype.c
> +++ b/src/datatype.c
> @@ -697,12 +697,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[1024];
> +
> + if (nft_getprotobynumber(mpz_get_uint8(expr->value), name, sizeof(name))) {
> + nft_print(octx, "%s", name);
> return;
> }
> }
> @@ -711,15 +710,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[1024];
> +
> + 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 +726,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 +738,8 @@ static struct error_record *inet_protocol_type_parse(struct parse_ctx *ctx,
>
> proto = i;
> } else {
> - p = getprotobyname(sym->identifier);
> - if (p == NULL)
> + if (!nft_getprotobyname(sym->identifier, &proto))
> return error(&sym->location, "Could not resolve protocol name");
> -
> - proto = p->p_proto;
> }
>
> *res = constant_expr_alloc(&sym->location, &inet_protocol_type,
> @@ -768,12 +763,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[1024];
>
> - 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)
> diff --git a/src/json.c b/src/json.c
> index a119dfc4f1eb..969b44e3004a 100644
> --- a/src/json.c
> +++ b/src/json.c
> @@ -297,10 +297,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[1024];
>
> - if (p)
> - return json_string(p->p_name);
> + if (nft_getprotobynumber(proto, name, sizeof(name)))
> + return json_string(name);
> return json_integer(proto);
> }
>
> @@ -1093,12 +1093,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[1024];
> +
> + if (nft_getprotobynumber(mpz_get_uint8(expr->value), name, sizeof(name)))
> + return json_string(name);
> }
> return integer_type_json(expr, octx);
> }
> @@ -1106,13 +1105,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[1024];
>
> 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/rule.c b/src/rule.c
> index 99c4f0bb8b00..c32c7303a28e 100644
> --- a/src/rule.c
> +++ b/src/rule.c
> @@ -1666,10 +1666,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[1024];
>
> - 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);
> }
> diff --git a/src/utils.c b/src/utils.c
> index a5815018c775..a3cac19c92a0 100644
> --- a/src/utils.c
> +++ b/src/utils.c
> @@ -14,6 +14,7 @@
> #include <stdio.h>
> #include <unistd.h>
> #include <string.h>
> +#include <netdb.h>
>
> #include <nftables.h>
> #include <utils.h>
> @@ -105,3 +106,92 @@ int round_pow_2(unsigned int n)
> {
> return 1UL << fls(n - 1);
> }
> +
> +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[2048];
> + 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;
> +}
> +
> +bool nft_getprotobyname(const char *name, uint8_t *out_proto)
> +{
> + const struct protoent *result;
> +
> +#if HAVE_DECL_GETPROTOBYNAME_R
> + struct protoent result_buf;
> + char buf[2048];
> + 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 false;
> +
> + if (result->p_proto < 0 || result->p_proto > UINT8_MAX)
> + return false;
> + if (out_proto)
> + *out_proto = result->p_proto;
> + return true;
> +}
> +
> +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[2048];
> + 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;
> +}
> --
> 2.41.0
>
next prev parent reply other threads:[~2023-08-11 12:20 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-08-10 12:30 [nft PATCH] src: use reentrant getprotobyname_r()/getprotobynumber_r()/getservbyport_r() Thomas Haller
2023-08-10 21:48 ` Jan Engelhardt
2023-08-11 11:28 ` Thomas Haller
2023-08-11 12:20 ` Pablo Neira Ayuso [this message]
2023-08-11 12:58 ` Thomas Haller
2023-08-16 16:16 ` Pablo Neira Ayuso
2023-08-18 9:18 ` [nft PATCH v2] " Thomas Haller
2023-08-18 9:57 ` Pablo Neira Ayuso
2023-08-18 14:14 ` Thomas Haller
2023-08-18 16:10 ` Pablo Neira Ayuso
2023-08-18 16:23 ` Pablo Neira Ayuso
2023-08-18 17:38 ` Thomas Haller
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ZNYng8dQBhk48kj9@calendula \
--to=pablo@netfilter.org \
--cc=netfilter-devel@vger.kernel.org \
--cc=thaller@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).