From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: passt.top; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=HymylLJO; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by passt.top (Postfix) with ESMTPS id 012A35A0265 for ; Wed, 01 Jul 2026 02:07:31 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1782864450; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=mdf1U4YvDLV1HtSRTBkbG/Gx1J+StvcWuoowFkAlKss=; b=HymylLJOl3lTx7vvLNVEEj2lHWA2oo6X2RhIOFLphyOfcRTflvuR6HO6numO2HduDWw6KV OGACmkOLZWxmu8FowzWMp9OdAGwqUD6G+N8J/GFsb83Y3iqeN3IhfH+omuhZ/alobal6uI z6SuCCuOXKbLUgYyskuzK/9AMRnqGzk= Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-218-8emyikClM2uuVVIoZiQ2aA-1; Tue, 30 Jun 2026 20:07:29 -0400 X-MC-Unique: 8emyikClM2uuVVIoZiQ2aA-1 X-Mimecast-MFC-AGG-ID: 8emyikClM2uuVVIoZiQ2aA_1782864448 Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-46fd6d94a8dso13780f8f.2 for ; Tue, 30 Jun 2026 17:07:29 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782864448; x=1783469248; h=date:content-transfer-encoding:mime-version:organization:references :in-reply-to:message-id:subject:cc:to:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=mdf1U4YvDLV1HtSRTBkbG/Gx1J+StvcWuoowFkAlKss=; b=mRkyxkn6PQ6P0nkUO7R7hyvbCYWhZ88rCYR0emfKNeWxBLaOVwtvK5PWaP0xX0EiSv CS7MFuh1Q2vHqwqjC/OhHlZRW7URIjTVX44H+wjRVpw/yk67zGgT+9tC6P70H5lTdnF9 8CzBIuM0qoox6kmbPn/ZXFuB7STcNHaHUsocyAlPBOd9lxvIjs2wWn4biBoBzrh7rEt+ hqcFJHlGsaOBogQXHPMsTnB88y41IBdePJ8S6qroOPj5UQKGo5iXEwzBoy0Htp7qAwXQ +Ew4DVu3Jjgvre1Mpqjobch2qvWADx7Xf9dKtMshW1C36VR4U9RDKEQ8CcI5NS0evV0G zYxA== X-Gm-Message-State: AOJu0YzjJeZH8meR8FRwBprHELn2Vf6jlM5toGGP2B41VHtaDjgHR5o5 qiC5++6WeI5fpsYvBIrrChObyGRrNylR72RBYpITWTBkwMOD/hR4+qAfOQPYqdBoLn9/cq+XDUr u2L3Fu9vclbTvF+2owdru01VtF5nEZLF76dYY9fS06vr0nk88cjVNlQ== X-Gm-Gg: AfdE7cmiqQXsdRWCN/0mbgSmpr1Flbp4A7mU7xMPIiCkyWa+/E7evq0x9zQBMOm7hQk B6WNed1yF/tdQWBD6tajHQRv34jE0aDsMj5oj31oZsU+PlBGaBV81r3/NvObOEcCQ7ZJDltkNcp Wha3nymNqsTXiXCU8lkyTd3EXuYInj26m2Njc38bsTjFbaP0X4RTRlb+vGofj1XXMpVTvbQeCJZ Vu5Ri12Z0dJHK7hQzndXGeTili5ckLbjv9uoJQ1MHImMEA3P5PRrDUc4jKLUwByd32jqRM/1xU/ hwdJBhZu4YMGiP2/S3G6GWUf0bk2fVFzH+a91e3lXmaHN6VDBWh0QdJZGmvM2N2qo7ErhaRsNtR vmi7OlPGl+Z63/IR0rMq3AR2f8dspFQ3uyHo57qs= X-Received: by 2002:a5d:5c8a:0:b0:475:f0f0:9f01 with SMTP id ffacd0b85a97d-4765b22d451mr4104385f8f.56.1782864447753; Tue, 30 Jun 2026 17:07:27 -0700 (PDT) X-Received: by 2002:a5d:5c8a:0:b0:475:f0f0:9f01 with SMTP id ffacd0b85a97d-4765b22d451mr4104337f8f.56.1782864447156; Tue, 30 Jun 2026 17:07:27 -0700 (PDT) Received: from maya.myfinge.rs (ifcgrfdd.trafficplex.cloud. [176.103.220.4]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-47567979eafsm11697703f8f.34.2026.06.30.17.07.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 30 Jun 2026 17:07:26 -0700 (PDT) From: Stefano Brivio To: David Gibson Subject: Re: [PATCH 08/12] parse: Add helpers for parsing IP addresses Message-ID: <20260701020725.024edf81@elisabeth> In-Reply-To: <20260626071003.3472194-9-david@gibson.dropbear.id.au> References: <20260626071003.3472194-1-david@gibson.dropbear.id.au> <20260626071003.3472194-9-david@gibson.dropbear.id.au> Organization: Red Hat X-Mailer: Claws Mail 4.2.0 (GTK 3.24.49; x86_64-pc-linux-gnu) MIME-Version: 1.0 Date: Wed, 01 Jul 2026 02:07:26 +0200 (CEST) X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: Ad9YzI2J3nYpfHyhG4WFHtRIHm1J1KIBxX-RGPMZnCU_1782864448 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Message-ID-Hash: YCK3MUD7JXXKGS2WWWLYBZ2B2R7JZOQC X-Message-ID-Hash: YCK3MUD7JXXKGS2WWWLYBZ2B2R7JZOQC X-MailFrom: sbrivio@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: passt-dev@passt.top, Jon Maloy X-Mailman-Version: 3.3.8 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: On Fri, 26 Jun 2026 17:09:59 +1000 David Gibson wrote: > parse_ipv[46]() are wrappers around inet_pton() that are more > convenient for use when the IP is part of a longer string, rather than > the entire string. parse_inany() replaces inany_pton() which again > will become more convenient for strings including IPs that aren't just > an IP. > > For now we only have some simple and sometimes awkward use cases, > we'll replace these with more natural uses in future. > > Cc: Jon Maloy > > Signed-off-by: David Gibson > --- > Makefile | 1 + > conf.c | 6 ++-- > fwd_rule.c | 21 ++++--------- > inany.c | 24 ++------------ > inany.h | 1 - > parse.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ > parse.h | 4 +++ > 7 files changed, 109 insertions(+), 39 deletions(-) > > diff --git a/Makefile b/Makefile > index 85d279c0..e2b22ddf 100644 > --- a/Makefile > +++ b/Makefile > @@ -227,4 +227,5 @@ pesto.cppcheck: CPPCHECK_FLAGS += --suppress=unusedFunction:inany.c > pesto.cppcheck: CPPCHECK_FLAGS += --suppress=unusedFunction:ip.h > pesto.cppcheck: CPPCHECK_FLAGS += --suppress=unusedFunction:serialise.c > pesto.cppcheck: CPPCHECK_FLAGS += --suppress=staticFunction:fwd_rule.c > +pesto.cppcheck: CPPCHECK_FLAGS += --suppress=staticFunction:parse.c > pesto.cppcheck: $(PESTO_SRCS) $(PESTO_HEADERS) seccomp_pesto.h > diff --git a/conf.c b/conf.c > index bd357117..2d1895d4 100644 > --- a/conf.c > +++ b/conf.c > @@ -357,7 +357,7 @@ static uint8_t conf_ip4_prefix(const char *arg) > struct in_addr mask; > unsigned long len; > > - if (inet_pton(AF_INET, arg, &mask)) { > + if (parse_ipv4(&p, &mask) && parse_eoi(p)) { > in_addr_t hmask = ntohl(mask.s_addr); > len = __builtin_popcount(hmask); > if ((hmask << len) == 0) > @@ -1577,7 +1577,9 @@ void conf(struct ctx *c, int argc, char **argv) > if (addr_has_prefix_len && prefix_len_from_opt) > die("Redundant prefix length specification"); > > - if (!addr_has_prefix_len && !inany_pton(optarg, &addr)) > + p = optarg; > + if (!addr_has_prefix_len && > + !(parse_inany(&p, &addr) && parse_eoi(p))) parse_port_range() reports error if the input isn't NULL-terminated, but these new functions don't, and in all the usages at least introduced in this patch, you always need to couple that with a && parse_eoi(p) (or && !*p). Is there a reason for this difference? > die("Invalid address: %s", optarg); > > if (prefix_len_from_opt && inany_v4(&addr)) > diff --git a/fwd_rule.c b/fwd_rule.c > index 0b85b17e..6d7ec2c5 100644 > --- a/fwd_rule.c > +++ b/fwd_rule.c > @@ -595,6 +595,8 @@ void fwd_rule_parse(char optname, bool del, const char *optarg, > strncpy(buf, optarg, sizeof(buf) - 1); > > if ((spec = strchr(buf, '/'))) { > + const char *p = buf; > + > *spec = 0; > spec++; > > @@ -616,22 +618,11 @@ void fwd_rule_parse(char optname, bool del, const char *optarg, > } > } > > - if (ifname == buf + 1) { /* Interface without address */ > + if (ifname == buf + 1 || /* Interface without address */ > + !strcmp(buf, "*")) /* Explicit wildcard address */ > addr = NULL; > - } else { > - char *p = buf; > - > - /* Allow square brackets for IPv4 too for convenience */ > - if (*p == '[' && p[strlen(p) - 1] == ']') { > - p[strlen(p) - 1] = '\0'; > - p++; > - } > - > - if (strcmp(p, "*") == 0) > - addr = NULL; > - else if (!inany_pton(p, &addr_buf)) > - die("Bad forwarding address '%s'", p); > - } > + else if (!parse_inany(&p, &addr_buf) && parse_eoi(p)) > + die("Bad forwarding address '%s'", buf); > } else { > spec = buf; > > diff --git a/inany.c b/inany.c > index 23faf3ff..154f08b5 100644 > --- a/inany.c > +++ b/inany.c > @@ -27,6 +27,7 @@ > #include "ip.h" > #include "inany.h" > #include "fwd.h" > +#include "parse.h" > > const union inany_addr inany_loopback4 = INANY_INIT4(IN4ADDR_LOOPBACK_INIT); > const union inany_addr inany_any4 = INANY_INIT4(IN4ADDR_ANY_INIT); > @@ -70,26 +71,6 @@ const char *inany_ntop(const union inany_addr *src, char *dst, socklen_t size) > return inet_ntop(AF_INET6, &src->a6, dst, size); > } > > -/** inany_pton - Parse an IPv[46] address from text format > - * @src: IPv[46] address > - * @dst: output buffer, filled with parsed address > - * > - * Return: on success, 1, if no parseable address is found, 0 > - */ > -int inany_pton(const char *src, union inany_addr *dst) > -{ > - if (inet_pton(AF_INET, src, &dst->v4mapped.a4)) { > - memset(&dst->v4mapped.zero, 0, sizeof(dst->v4mapped.zero)); > - memset(&dst->v4mapped.one, 0xff, sizeof(dst->v4mapped.one)); > - return 1; > - } > - > - if (inet_pton(AF_INET6, src, &dst->a6)) > - return 1; > - > - return 0; > -} > - > /** > * inany_prefix_pton() - Parse an IPv[46] address with prefix length > * @src: IPv[46] address and prefix length string in CIDR format > @@ -104,6 +85,7 @@ int inany_prefix_pton(const char *src, union inany_addr *dst, > char astr[INANY_ADDRSTRLEN] = { 0 }; > size_t alen = strcspn(src, "/"); > const char *pstr = &src[alen + 1]; > + const char *p = astr; > unsigned long plen; > char *end; > > @@ -129,7 +111,7 @@ int inany_prefix_pton(const char *src, union inany_addr *dst, > return 1; > } > > - if (inany_pton(astr, dst)) { > + if (parse_inany(&p, dst) && parse_eoi(p)) { > if (plen > 32) > return 0; > *prefix_len = plen + 96; > diff --git a/inany.h b/inany.h > index 6bf3ecaa..93d98368 100644 > --- a/inany.h > +++ b/inany.h > @@ -303,7 +303,6 @@ static inline int inany_from_sockaddr(union inany_addr *dst, in_port_t *port, > > bool inany_matches(const union inany_addr *a, const union inany_addr *b); > const char *inany_ntop(const union inany_addr *src, char *dst, socklen_t size); > -int inany_pton(const char *src, union inany_addr *dst); > int inany_prefix_pton(const char *src, union inany_addr *dst, > uint8_t *prefix_len); > > diff --git a/parse.c b/parse.c > index bd091fde..0349c5dc 100644 > --- a/parse.c > +++ b/parse.c > @@ -16,9 +16,12 @@ > #include > #include > #include > +#include > +#include > > #include "common.h" > #include "parse.h" > +#include "inany.h" > > /** > * DOC: Theory of Operation > @@ -110,3 +113,91 @@ bool parse_port_range(const char **cursor, struct port_range *range) > *cursor = p; > return true; > } > + > +/** > + * parse_ipv4() - Parse an IPv4 address from a string > + * @abuf: On success, updated with parsed address > + */ > +bool parse_ipv4(const char **cursor, struct in_addr *abuf) > +{ > + /* Brackets are not typical on IPv4, but allow for consistency */ > + const char *p = *cursor; > + bool bracket = parse_literal(&p, "["); > + char buf[INET_ADDRSTRLEN]; > + struct in_addr addr; > + size_t len; > + > + if (bracket) > + len = strcspn(p, "]"); > + else > + len = strspn(p, "0123456789."); > + > + if (len >= sizeof(buf)) > + return false; > + memcpy(buf, p, len); > + buf[len] = '\0'; > + p += len; > + > + if (!inet_pton(AF_INET, buf, &addr)) > + return false; > + > + if (bracket && !parse_literal(&p, "]")) > + return false; > + > + *cursor = p; > + *abuf = addr; > + return true; > +} > + > +/** > + * parse_ipv6() - Parse an IPv6 address from a string > + * @abuf: On success, updated with parsed address > + */ > +static bool parse_ipv6(const char **cursor, struct in6_addr *abuf) > +{ > + const char *p = *cursor; > + bool bracket = parse_literal(&p, "["); > + char buf[INET6_ADDRSTRLEN]; > + struct in6_addr addr; > + size_t len; > + > + if (bracket) > + len = strcspn(p, "]"); > + else > + len = strspn(p, "0123456789aAbBcCdDeEfF:."); > + > + if (len >= sizeof(buf)) > + return false; > + memcpy(buf, p, len); > + buf[len] = '\0'; > + p += len; > + > + if (!inet_pton(AF_INET6, buf, &addr)) > + return false; > + > + if (bracket && !parse_literal(&p, "]")) > + return false; > + > + *cursor = p; > + *abuf = addr; > + return true; > +} > + > +/** > + * parse_inany() - Parse an IPv4 or IPv6 address from a string > + * @addr: On success, updated with parsed address > + */ > +bool parse_inany(const char **cursor, union inany_addr *addr) > +{ > + struct in_addr a4; > + > + if (parse_ipv6(cursor, &addr->a6)) > + return true; > + > + if (parse_ipv4(cursor, &a4)) { > + *addr = inany_from_v4(a4); > + return true; > + } > + > + return false; > +} > diff --git a/parse.h b/parse.h > index 155b3995..2820a065 100644 > --- a/parse.h > +++ b/parse.h > @@ -9,6 +9,8 @@ > #include > #include > > +union inany_addr; > + > /** > * port_range() - Represents a non-empty range of ports > * @first: First port number in the range > @@ -24,5 +26,7 @@ bool parse_literal(const char **cursor, const char *lit); > bool parse_eoi(const char *cursor); > bool parse_unsigned(const char **cursor, int base, unsigned long *valp); > bool parse_port_range(const char **cursor, struct port_range *range); > +bool parse_ipv4(const char **cursor, struct in_addr *abuf); > +bool parse_inany(const char **cursor, union inany_addr *addr); > > #endif /* _PARSE_H */ -- Stefano