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=IYB/eSdo; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by passt.top (Postfix) with ESMTPS id D49515A0262 for ; Wed, 01 Jul 2026 02:11:58 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1782864717; 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=W/iPwiJSyJyJB1VKmhOrrfoLUa81Y39JLE+FpBRFfqY=; b=IYB/eSdoxqhrAdfM613ZtS4zF2UIbgHF9RmAaojlxEaYgeQf+QZ323EW0cIpVQz4XTXC0K VZduYxywqfM+/fWTTaY6KXYfw/tsV3APgWWgdVboZfPctZAkd30OKJN28O3AFvuywRSQxA 2kM7nJwwccJ+1UIz/yjEc0B4kFrSUm4= Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-377-YI7AytCgPm6pjz0e_DqKPw-1; Tue, 30 Jun 2026 20:11:56 -0400 X-MC-Unique: YI7AytCgPm6pjz0e_DqKPw-1 X-Mimecast-MFC-AGG-ID: YI7AytCgPm6pjz0e_DqKPw_1782864715 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-493b786d550so677945e9.0 for ; Tue, 30 Jun 2026 17:11:55 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782864715; x=1783469515; 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=W/iPwiJSyJyJB1VKmhOrrfoLUa81Y39JLE+FpBRFfqY=; b=M4ek4Xl2jWMwjdNLFcQUKpfN5Qcj0kuMRxrBmCrvng/t9N/YdVBoxOxykKQiDP/1Ua useh5Xb4YAdwKkYHS7M7O8hC1k7D2Ex5Zth8x4+fDKGerUm3xzWEm9yG0f/tG9feBwzi aaHmkv2vMs5Oq6Q4FLD3c5vrokE2z6GfiWinzrBAG1RCD3XdzrBd96HMsrad74SsZ9f/ QH9JO3c6h1epRV61mR7Fx6gQmk2pFJ0zrh81OEFKegErW69qKqBdq7D+0VI5HpnHwu3/ oup9Ympyewh0E2fjKwIIKpurs2xd2P9si0Wunv7JVvsnLwLfnY8hj2/I6yzQ6LXU0rCs 2iaA== X-Gm-Message-State: AOJu0YyPtlG01pMqmd244CPPukpx9EAQULMZgc+aoJdClfXfo6djM53T f+X5rZngQcV538ut4dm3G2QKgXqaAIp2T4aQH3DdyYBkjJMPOclZ+7WKF9dtj2dZ2CXiTz1lhJt 41yaqU+umFy8kq2zxnTcjWGTwEXnIuaIQnzRszLNgmQG45mClAxK+Iw== X-Gm-Gg: AfdE7cmQhtdqbsSKDj1fQ/RAM2kOt6ghozIetnvxCim/b4QEk+yomHytYvSbYTknFT3 6db74qDHDp7VqQEwIsI6rIqlH8s+lLVKW5rMT1mLi6B7j3/o4rci1sl08fYPR0HcNxeJLLg9uKI ZuWFMFd/wKUq5BWAY5jPE470UiNK/JjwNGOJaxdvGokrAnJeVThjbn+UNzVRh1/9RmAE1OGjpx6 /BhW64OaRza8949F3kGh6ACaZWuBdLs+KNGwTWHi3sMNEU7Jf7eNqHHgksgbxobVAAd6YagmJO3 SVdAWNlDr5fm0MqQloW7YHBh2+VTkJGkxiI4+GVgKGpKsD7JWQdEs/vshG6yDJRmgFKWXwdpbXt +Dv5qoNUMSapTQvMDF0mpjA== X-Received: by 2002:a05:600c:638e:b0:493:be36:94b3 with SMTP id 5b1f17b1804b1-493be42d391mr27776685e9.13.1782864714721; Tue, 30 Jun 2026 17:11:54 -0700 (PDT) X-Received: by 2002:a05:600c:638e:b0:493:be36:94b3 with SMTP id 5b1f17b1804b1-493be42d391mr27776305e9.13.1782864714290; Tue, 30 Jun 2026 17:11:54 -0700 (PDT) Received: from maya.myfinge.rs (ifcgrfdd.trafficplex.cloud. [2a10:fc81:a806:d6a9::1]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-47567a6f0ddsm11335809f8f.37.2026.06.30.17.11.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 30 Jun 2026 17:11:53 -0700 (PDT) From: Stefano Brivio To: David Gibson Subject: [RESEND #2] Re: [PATCH 08/12] parse: Add helpers for parsing IP addresses Message-ID: <20260701021152.600ca7b0@elisabeth> In-Reply-To: <20260701020725.024edf81@elisabeth> References: <20260626071003.3472194-1-david@gibson.dropbear.id.au> <20260626071003.3472194-9-david@gibson.dropbear.id.au> <20260701020725.024edf81@elisabeth> 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:11:52 +0200 (CEST) X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 0qADULZja5aZTqF66jLWVa0G_LJUkW1QD56GfFwuvbo_1782864715 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Message-ID-Hash: DXSHVXW5VUTPKTPCQCZSK7E7VG57OFGO X-Message-ID-Hash: DXSHVXW5VUTPKTPCQCZSK7E7VG57OFGO 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: *Actually* resending to jmaloy@redhat.com, the original email had: On Wed, 1 Jul 2026 02:07:25 +0200 Stefano Brivio wrote: > 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 ...jamloy@redhat.com instead. > > > > 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