Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144453121
D52629.id162438.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
28 KB
Referenced Files
None
Subscribers
None
D52629.id162438.diff
View Options
diff --git a/lib/libc/inet/inet_net_ntop.c b/lib/libc/inet/inet_net_ntop.c
--- a/lib/libc/inet/inet_net_ntop.c
+++ b/lib/libc/inet/inet_net_ntop.c
@@ -1,20 +1,23 @@
-/*-
- * SPDX-License-Identifier: ISC
+/* $OpenBSD: inet_net_ntop.c,v 1.9 2019/07/03 03:24:04 deraadt Exp $ */
+
+/*
+ * Copyright (c) 2012 by Gilles Chehade <gilles@openbsd.org>
+ * Copyright (c) 1996 by Internet Software Consortium.
*
- * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
- * Copyright (c) 1996,1999 by Internet Software Consortium.
+ * SPDX-License-Identifier: ISC
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
- * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
*/
#include "port_before.h"
@@ -31,18 +34,10 @@
#include "port_after.h"
-#ifdef SPRINTF_CHAR
-# define SPRINTF(x) strlen(sprintf/**/x)
-#else
-# define SPRINTF(x) ((size_t)sprintf x)
-#endif
-
-static char * inet_net_ntop_ipv4(const u_char *src, int bits, char *dst,
- size_t size);
-static char * inet_net_ntop_ipv6(const u_char *src, int bits, char *dst,
- size_t size);
+static char *inet_net_ntop_ipv4(const u_char *, int, char *, size_t);
+static char *inet_net_ntop_ipv6(const u_char *, int, char *, size_t);
-/*%
+/*
* char *
* inet_net_ntop(af, src, bits, dst, size)
* convert network number from network to presentation format.
@@ -66,7 +61,7 @@
}
}
-/*%
+/*
* static char *
* inet_net_ntop_ipv4(src, bits, dst, size)
* convert IPv4 network number from network to presentation format.
@@ -75,7 +70,7 @@
* pointer to dst, or NULL if an error occurred (check errno).
* note:
* network byte order assumed. this means 192.5.5.240/28 has
- * 0b11110000 in its fourth octet.
+ * 0x11110000 in its fourth octet.
* author:
* Paul Vixie (ISC), July 1996
*/
@@ -83,53 +78,63 @@
inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
{
char *odst = dst;
- char *t;
u_int m;
int b;
+ char *ep;
+ int advance;
+
+ ep = dst + size;
+ if (ep <= dst)
+ goto emsgsize;
if (bits < 0 || bits > 32) {
errno = EINVAL;
return (NULL);
}
-
if (bits == 0) {
- if (size < sizeof "0")
+ if (ep - dst < sizeof "0")
goto emsgsize;
*dst++ = '0';
- size--;
*dst = '\0';
}
/* Format whole octets. */
for (b = bits / 8; b > 0; b--) {
- if (size <= sizeof "255.")
+ if (ep - dst < sizeof "255.")
+ goto emsgsize;
+ advance = snprintf(dst, ep - dst, "%u", *src++);
+ if (advance <= 0 || advance >= ep - dst)
goto emsgsize;
- t = dst;
- dst += SPRINTF((dst, "%u", *src++));
+ dst += advance;
if (b > 1) {
+ if (dst + 1 >= ep)
+ goto emsgsize;
*dst++ = '.';
*dst = '\0';
}
- size -= (size_t)(dst - t);
}
/* Format partial octet. */
b = bits % 8;
if (b > 0) {
- if (size <= sizeof ".255")
+ if (ep - dst < sizeof ".255")
goto emsgsize;
- t = dst;
if (dst != odst)
*dst++ = '.';
m = ((1 << b) - 1) << (8 - b);
- dst += SPRINTF((dst, "%u", *src & m));
- size -= (size_t)(dst - t);
+ advance = snprintf(dst, ep - dst, "%u", *src & m);
+ if (advance <= 0 || advance >= ep - dst)
+ goto emsgsize;
+ dst += advance;
}
/* Format CIDR /width. */
- if (size <= sizeof "/32")
+ if (ep - dst < sizeof "/32")
+ goto emsgsize;
+ advance = snprintf(dst, ep - dst, "/%u", bits);
+ if (advance <= 0 || advance >= ep - dst)
goto emsgsize;
- dst += SPRINTF((dst, "/%u", bits));
+ dst += advance;
return (odst);
emsgsize:
@@ -137,132 +142,27 @@
return (NULL);
}
-/*%
- * static char *
- * inet_net_ntop_ipv6(src, bits, fakebits, dst, size)
- * convert IPv6 network number from network to presentation format.
- * generates CIDR style result always. Picks the shortest representation
- * unless the IP is really IPv4.
- * always prints specified number of bits (bits).
- * return:
- * pointer to dst, or NULL if an error occurred (check errno).
- * note:
- * network byte order assumed. this means 192.5.5.240/28 has
- * 0b11110000 in its fourth octet.
- * author:
- * Vadim Kogan (UCB), June 2001
- * Original version (IPv4) by Paul Vixie (ISC), July 1996
- */
-
static char *
-inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) {
- u_int m;
- int b;
- int p;
- int zero_s, zero_l, tmp_zero_s, tmp_zero_l;
- int i;
- int is_ipv4 = 0;
- unsigned char inbuf[16];
- char outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
- char *cp;
- int words;
- u_char *s;
+inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size)
+{
+ int ret;
+ char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255:255:255:255/128")];
if (bits < 0 || bits > 128) {
errno = EINVAL;
return (NULL);
}
- cp = outbuf;
-
- if (bits == 0) {
- *cp++ = ':';
- *cp++ = ':';
- *cp = '\0';
- } else {
- /* Copy src to private buffer. Zero host part. */
- p = (bits + 7) / 8;
- memcpy(inbuf, src, p);
- memset(inbuf + p, 0, 16 - p);
- b = bits % 8;
- if (b != 0) {
- m = ~0 << (8 - b);
- inbuf[p-1] &= m;
- }
-
- s = inbuf;
-
- /* how many words need to be displayed in output */
- words = (bits + 15) / 16;
- if (words == 1)
- words = 2;
-
- /* Find the longest substring of zero's */
- zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0;
- for (i = 0; i < (words * 2); i += 2) {
- if ((s[i] | s[i+1]) == 0) {
- if (tmp_zero_l == 0)
- tmp_zero_s = i / 2;
- tmp_zero_l++;
- } else {
- if (tmp_zero_l && zero_l < tmp_zero_l) {
- zero_s = tmp_zero_s;
- zero_l = tmp_zero_l;
- tmp_zero_l = 0;
- }
- }
- }
-
- if (tmp_zero_l && zero_l < tmp_zero_l) {
- zero_s = tmp_zero_s;
- zero_l = tmp_zero_l;
- }
-
- if (zero_l != words && zero_s == 0 && ((zero_l == 6) ||
- ((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) ||
- ((zero_l == 7 && s[14] != 0 && s[15] != 1)))))
- is_ipv4 = 1;
-
- /* Format whole words. */
- for (p = 0; p < words; p++) {
- if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l) {
- /* Time to skip some zeros */
- if (p == zero_s)
- *cp++ = ':';
- if (p == words - 1)
- *cp++ = ':';
- s++;
- s++;
- continue;
- }
+ if (inet_ntop(AF_INET6, src, buf, size) == NULL)
+ return (NULL);
- if (is_ipv4 && p > 5 ) {
- *cp++ = (p == 6) ? ':' : '.';
- cp += SPRINTF((cp, "%u", *s++));
- /* we can potentially drop the last octet */
- if (p != 7 || bits > 120) {
- *cp++ = '.';
- cp += SPRINTF((cp, "%u", *s++));
- }
- } else {
- if (cp != outbuf)
- *cp++ = ':';
- cp += SPRINTF((cp, "%x", *s * 256 + s[1]));
- s += 2;
- }
- }
+ ret = snprintf(dst, size, "%s/%d", buf, bits);
+ if (ret < 0 || ret >= size) {
+ errno = EMSGSIZE;
+ return (NULL);
}
- /* Format CIDR /width. */
- sprintf(cp, "/%u", bits);
- if (strlen(outbuf) + 1 > size)
- goto emsgsize;
- strcpy(dst, outbuf);
return (dst);
-
-emsgsize:
- errno = EMSGSIZE;
- return (NULL);
}
/*
@@ -271,5 +171,3 @@
*/
#undef inet_net_ntop
__weak_reference(__inet_net_ntop, inet_net_ntop);
-
-/*! \file */
diff --git a/lib/libc/inet/inet_net_pton.c b/lib/libc/inet/inet_net_pton.c
--- a/lib/libc/inet/inet_net_pton.c
+++ b/lib/libc/inet/inet_net_pton.c
@@ -1,20 +1,23 @@
-/*-
- * SPDX-License-Identifier: ISC
+/* $OpenBSD: inet_net_pton.c,v 1.14 2022/12/27 17:10:06 jmc Exp $ */
+
+/*
+ * Copyright (c) 2012 by Gilles Chehade <gilles@openbsd.org>
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
*
- * Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
- * Copyright (C) 1996, 1998, 1999, 2001, 2003 Internet Software Consortium.
+ * SPDX-License-Identifier: ISC
*
- * Permission to use, copy, modify, and/or distribute this software for any
+ * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
- * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
*/
#include "port_before.h"
@@ -22,7 +25,6 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
-#include <arpa/nameser.h>
#include <arpa/inet.h>
#include <assert.h>
@@ -34,13 +36,37 @@
#include "port_after.h"
-#ifdef SPRINTF_CHAR
-# define SPRINTF(x) strlen(sprintf/**/x)
-#else
-# define SPRINTF(x) ((size_t)sprintf x)
-#endif
+static int inet_net_pton_ipv4(const char *, u_char *, size_t);
+static int inet_net_pton_ipv6(const char *, u_char *, size_t);
-/*%
+/*
+ * static int
+ * inet_net_pton(af, src, dst, size)
+ * convert network number from presentation to network format.
+ * accepts hex octets, hex strings, decimal octets, and /CIDR.
+ * "size" is in bytes and describes "dst".
+ * return:
+ * number of bits, either imputed classfully or specified with /CIDR,
+ * or -1 if some failure occurred (check errno). ENOENT means it was
+ * not a valid network specification.
+ * author:
+ * Paul Vixie (ISC), June 1996
+ */
+int
+inet_net_pton(int af, const char *src, void *dst, size_t size)
+{
+ switch (af) {
+ case AF_INET:
+ return (inet_net_pton_ipv4(src, dst, size));
+ case AF_INET6:
+ return (inet_net_pton_ipv6(src, dst, size));
+ default:
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+}
+
+/*
* static int
* inet_net_pton_ipv4(src, dst, size)
* convert IPv4 network number from presentation to network format.
@@ -52,27 +78,29 @@
* not an IPv4 network specification.
* note:
* network byte order assumed. this means 192.5.5.240/28 has
- * 0b11110000 in its fourth octet.
+ * 0x11110000 in its fourth octet.
* author:
* Paul Vixie (ISC), June 1996
*/
static int
-inet_net_pton_ipv4(const char *src, u_char *dst, size_t size) {
- static const char xdigits[] = "0123456789abcdef";
- static const char digits[] = "0123456789";
- int n, ch, tmp = 0, dirty, bits;
+inet_net_pton_ipv4(const char *src, u_char *dst, size_t size)
+{
+ static const char
+ xdigits[] = "0123456789abcdef",
+ digits[] = "0123456789";
+ int n, ch, tmp, dirty, bits;
const u_char *odst = dst;
- ch = *src++;
+ ch = (unsigned char)*src++;
if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
- && isascii((unsigned char)(src[1]))
- && isxdigit((unsigned char)(src[1]))) {
+ && isascii((unsigned char)src[1]) && isxdigit((unsigned char)src[1])) {
/* Hexadecimal: Eat nybble string. */
- if (size <= 0U)
+ if (size == 0)
goto emsgsize;
- dirty = 0;
- src++; /*%< skip x or X. */
- while ((ch = *src++) != '\0' && isascii(ch) && isxdigit(ch)) {
+ tmp = 0, dirty = 0;
+ src++; /* skip x or X. */
+ while ((ch = (unsigned char)*src++) != '\0' &&
+ isascii(ch) && isxdigit(ch)) {
if (isupper(ch))
ch = tolower(ch);
n = strchr(xdigits, ch) - xdigits;
@@ -82,14 +110,14 @@
else
tmp = (tmp << 4) | n;
if (++dirty == 2) {
- if (size-- <= 0U)
+ if (size-- == 0)
goto emsgsize;
*dst++ = (u_char) tmp;
dirty = 0;
}
}
- if (dirty) { /*%< Odd trailing nybble? */
- if (size-- <= 0U)
+ if (dirty) { /* Odd trailing nybble? */
+ if (size-- == 0)
goto emsgsize;
*dst++ = (u_char) (tmp << 4);
}
@@ -104,16 +132,16 @@
tmp += n;
if (tmp > 255)
goto enoent;
- } while ((ch = *src++) != '\0' &&
+ } while ((ch = (unsigned char)*src++) != '\0' &&
isascii(ch) && isdigit(ch));
- if (size-- <= 0U)
+ if (size-- == 0)
goto emsgsize;
*dst++ = (u_char) tmp;
if (ch == '\0' || ch == '/')
break;
if (ch != '.')
goto enoent;
- ch = *src++;
+ ch = (unsigned char)*src++;
if (!isascii(ch) || !isdigit(ch))
goto enoent;
}
@@ -121,10 +149,10 @@
goto enoent;
bits = -1;
- if (ch == '/' && isascii((unsigned char)(src[0])) &&
- isdigit((unsigned char)(src[0])) && dst > odst) {
+ if (ch == '/' && isascii((unsigned char)src[0]) &&
+ isdigit((unsigned char)src[0]) && dst > odst) {
/* CIDR width specifier. Nothing can follow it. */
- ch = *src++; /*%< Skip over the /. */
+ ch = (unsigned char)*src++; /* Skip over the /. */
bits = 0;
do {
n = strchr(digits, ch) - digits;
@@ -132,8 +160,9 @@
bits *= 10;
bits += n;
if (bits > 32)
- goto enoent;
- } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch));
+ goto emsgsize;
+ } while ((ch = (unsigned char)*src++) != '\0' &&
+ isascii(ch) && isdigit(ch));
if (ch != '\0')
goto enoent;
}
@@ -147,29 +176,23 @@
goto enoent;
/* If no CIDR spec was given, infer width from net class. */
if (bits == -1) {
- if (*odst >= 240) /*%< Class E */
+ if (*odst >= 240) /* Class E */
bits = 32;
- else if (*odst >= 224) /*%< Class D */
- bits = 8;
- else if (*odst >= 192) /*%< Class C */
+ else if (*odst >= 224) /* Class D */
+ bits = 4;
+ else if (*odst >= 192) /* Class C */
bits = 24;
- else if (*odst >= 128) /*%< Class B */
+ else if (*odst >= 128) /* Class B */
bits = 16;
- else /*%< Class A */
+ else /* Class A */
bits = 8;
/* If imputed mask is narrower than specified octets, widen. */
if (bits < ((dst - odst) * 8))
bits = (dst - odst) * 8;
- /*
- * If there are no additional bits specified for a class D
- * address adjust bits to 4.
- */
- if (bits == 8 && *odst == 224)
- bits = 4;
}
/* Extend network to cover the actual mask. */
while (bits > ((dst - odst) * 8)) {
- if (size-- <= 0U)
+ if (size-- == 0)
goto emsgsize;
*dst++ = '\0';
}
@@ -184,222 +207,48 @@
return (-1);
}
-static int
-getbits(const char *src, int *bitsp) {
- static const char digits[] = "0123456789";
- int n;
- int val;
- char ch;
-
- val = 0;
- n = 0;
- while ((ch = *src++) != '\0') {
- const char *pch;
-
- pch = strchr(digits, ch);
- if (pch != NULL) {
- if (n++ != 0 && val == 0) /*%< no leading zeros */
- return (0);
- val *= 10;
- val += (pch - digits);
- if (val > 128) /*%< range */
- return (0);
- continue;
- }
- return (0);
- }
- if (n == 0)
- return (0);
- *bitsp = val;
- return (1);
-}
static int
-getv4(const char *src, u_char *dst, int *bitsp) {
- static const char digits[] = "0123456789";
- u_char *odst = dst;
- int n;
- u_int val;
- char ch;
-
- val = 0;
- n = 0;
- while ((ch = *src++) != '\0') {
- const char *pch;
+inet_net_pton_ipv6(const char *src, u_char *dst, size_t size)
+{
+ struct in6_addr in6;
+ int ret;
+ int bits;
+ size_t bytes;
+ char buf[INET6_ADDRSTRLEN + sizeof("/128")];
+ char *sep;
+ const char *errstr;
- pch = strchr(digits, ch);
- if (pch != NULL) {
- if (n++ != 0 && val == 0) /*%< no leading zeros */
- return (0);
- val *= 10;
- val += (pch - digits);
- if (val > 255) /*%< range */
- return (0);
- continue;
- }
- if (ch == '.' || ch == '/') {
- if (dst - odst > 3) /*%< too many octets? */
- return (0);
- *dst++ = val;
- if (ch == '/')
- return (getbits(src, bitsp));
- val = 0;
- n = 0;
- continue;
- }
- return (0);
+ if (strlcpy(buf, src, sizeof buf) >= sizeof buf) {
+ errno = EMSGSIZE;
+ return (-1);
}
- if (n == 0)
- return (0);
- if (dst - odst > 3) /*%< too many octets? */
- return (0);
- *dst++ = val;
- return (1);
-}
-static int
-inet_net_pton_ipv6(const char *src, u_char *dst, size_t size) {
- static const char xdigits_l[] = "0123456789abcdef",
- xdigits_u[] = "0123456789ABCDEF";
- u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
- const char *xdigits, *curtok;
- int ch, saw_xdigit;
- u_int val;
- int digits;
- int bits;
- size_t bytes;
- int words;
- int ipv4;
+ sep = strchr(buf, '/');
+ if (sep != NULL)
+ *sep++ = '\0';
- memset((tp = tmp), '\0', NS_IN6ADDRSZ);
- endp = tp + NS_IN6ADDRSZ;
- colonp = NULL;
- /* Leading :: requires some special handling. */
- if (*src == ':')
- if (*++src != ':')
- goto enoent;
- curtok = src;
- saw_xdigit = 0;
- val = 0;
- digits = 0;
- bits = -1;
- ipv4 = 0;
- while ((ch = *src++) != '\0') {
- const char *pch;
+ ret = inet_pton(AF_INET6, buf, &in6);
+ if (ret != 1)
+ return (-1);
- if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
- pch = strchr((xdigits = xdigits_u), ch);
- if (pch != NULL) {
- val <<= 4;
- val |= (pch - xdigits);
- if (++digits > 4)
- goto enoent;
- saw_xdigit = 1;
- continue;
- }
- if (ch == ':') {
- curtok = src;
- if (!saw_xdigit) {
- if (colonp)
- goto enoent;
- colonp = tp;
- continue;
- } else if (*src == '\0')
- goto enoent;
- if (tp + NS_INT16SZ > endp)
- return (0);
- *tp++ = (u_char) (val >> 8) & 0xff;
- *tp++ = (u_char) val & 0xff;
- saw_xdigit = 0;
- digits = 0;
- val = 0;
- continue;
- }
- if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
- getv4(curtok, tp, &bits) > 0) {
- tp += NS_INADDRSZ;
- saw_xdigit = 0;
- ipv4 = 1;
- break; /*%< '\\0' was seen by inet_pton4(). */
- }
- if (ch == '/' && getbits(src, &bits) > 0)
- break;
- goto enoent;
- }
- if (saw_xdigit) {
- if (tp + NS_INT16SZ > endp)
- goto enoent;
- *tp++ = (u_char) (val >> 8) & 0xff;
- *tp++ = (u_char) val & 0xff;
- }
- if (bits == -1)
+ if (sep == NULL)
bits = 128;
-
- words = (bits + 15) / 16;
- if (words < 2)
- words = 2;
- if (ipv4)
- words = 8;
- endp = tmp + 2 * words;
-
- if (colonp != NULL) {
- /*
- * Since some memmove()'s erroneously fail to handle
- * overlapping regions, we'll do the shift by hand.
- */
- const int n = tp - colonp;
- int i;
-
- if (tp == endp)
- goto enoent;
- for (i = 1; i <= n; i++) {
- endp[- i] = colonp[n - i];
- colonp[n - i] = 0;
+ else {
+ bits = strtonum(sep, 0, 128, &errstr);
+ if (errstr) {
+ errno = EINVAL;
+ return (-1);
}
- tp = endp;
}
- if (tp != endp)
- goto enoent;
bytes = (bits + 7) / 8;
- if (bytes > size)
- goto emsgsize;
- memcpy(dst, tmp, bytes);
- return (bits);
-
- enoent:
- errno = ENOENT;
- return (-1);
-
- emsgsize:
- errno = EMSGSIZE;
- return (-1);
-}
-
-/*%
- * int
- * inet_net_pton(af, src, dst, size)
- * convert network number from presentation to network format.
- * accepts hex octets, hex strings, decimal octets, and /CIDR.
- * "size" is in bytes and describes "dst".
- * return:
- * number of bits, either imputed classfully or specified with /CIDR,
- * or -1 if some failure occurred (check errno). ENOENT means it was
- * not a valid network specification.
- * author:
- * Paul Vixie (ISC), June 1996
- */
-int
-inet_net_pton(int af, const char *src, void *dst, size_t size) {
- switch (af) {
- case AF_INET:
- return (inet_net_pton_ipv4(src, dst, size));
- case AF_INET6:
- return (inet_net_pton_ipv6(src, dst, size));
- default:
- errno = EAFNOSUPPORT;
+ if (bytes > size) {
+ errno = EMSGSIZE;
return (-1);
}
+ memcpy(dst, &in6.s6_addr, bytes);
+ return (bits);
}
/*
@@ -408,5 +257,3 @@
*/
#undef inet_net_pton
__weak_reference(__inet_net_pton, inet_net_pton);
-
-/*! \file */
diff --git a/lib/libc/tests/net/Makefile b/lib/libc/tests/net/Makefile
--- a/lib/libc/tests/net/Makefile
+++ b/lib/libc/tests/net/Makefile
@@ -4,8 +4,10 @@
ATF_TESTS_C+= eui64_aton_test
ATF_TESTS_C+= eui64_ntoa_test
ATF_TESTS_CXX+= link_addr_test
+ATF_TESTS_CXX+= inet_net_test
CXXSTD.link_addr_test= c++20
+CXXSTD.inet_net_test= c++20
CFLAGS+= -I${.CURDIR}
diff --git a/lib/libc/tests/net/inet_net_test.cc b/lib/libc/tests/net/inet_net_test.cc
new file mode 100644
--- /dev/null
+++ b/lib/libc/tests/net/inet_net_test.cc
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2025 Lexi Winter
+ *
+ * SPDX-License-Identifier: ISC
+ */
+
+/*
+ * Tests for inet_net_pton() and inet_net_ntop().
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ranges>
+#include <string>
+#include <vector>
+
+#include <atf-c++.hpp>
+
+using namespace std::literals;
+
+/*
+ * inet_net_ntop() and inet_net_pton() for IPv4.
+ */
+ATF_TEST_CASE_WITHOUT_HEAD(inet_net_inet4)
+ATF_TEST_CASE_BODY(inet_net_inet4)
+{
+ /*
+ * Define a list of addresses we want to check. Each address is passed
+ * to inet_net_pton() to convert it to a in_addr, then we convert the
+ * in_addr back to a string and compare it with the expected value. We
+ * want to test over-long prefixes here (such as 10.0.0.1/8), so we also
+ * specify what the result is * expected to be.
+ */
+
+ struct test_addr {
+ std::string input;
+ unsigned bits;
+ std::string output;
+ };
+
+ auto test_addrs = std::vector<test_addr>{
+ // Simple prefixes that fall on octet boundaries.
+ { "10.0.0.0/8", 8, "10/8" },
+ { "10.1.0.0/16", 16, "10.1/16" },
+ { "10.1.2.0/24", 24, "10.1.2/24" },
+ { "10.1.2.3/32", 32, "10.1.2.3/32" },
+
+ // Simple prefixes with the short-form address.
+ { "10/8", 8, "10/8" },
+ { "10.1/16", 16, "10.1/16" },
+ { "10.1.2/24", 24, "10.1.2/24" },
+
+ // A prefix that doesn't fall on an octet boundary.
+ { "10.1.64/18", 18, "10.1.64/18" },
+ };
+
+ for (auto const &addr: test_addrs) {
+ /*
+ * Convert the input string to an in_addr + bits, and make
+ * sure the result produces the number of bits we expected.
+ */
+
+ auto in = in_addr{};
+ errno = 0;
+ auto bits = inet_net_pton(AF_INET, addr.input.c_str(),
+ &in, sizeof(in));
+ ATF_REQUIRE(bits != -1);
+ ATF_REQUIRE_EQ(bits, addr.bits);
+
+ /*
+ * Convert the in_addr back to a string
+ */
+
+ /*
+ * XXX: Should there be a constant for the size of the result
+ * buffer? For now, use ADDRSTRLEN + 3 ("/32") + 1 (NUL).
+ *
+ * Fill the buffer with 'Z', so we can check the result was
+ * properly terminated.
+ */
+ auto strbuf = std::vector<char>(INET_ADDRSTRLEN + 4 + 1, 'Z');
+ auto ret = inet_net_ntop(AF_INET, &in, bits,
+ strbuf.data(), strbuf.size());
+ ATF_REQUIRE(ret != NULL);
+ ATF_REQUIRE_EQ(ret, strbuf.data());
+
+ /* Make sure the result was NUL-terminated and find the NUL */
+ ATF_REQUIRE(strbuf.size() >= 1);
+ auto end = std::ranges::find(strbuf, '\0');
+ ATF_REQUIRE(end != strbuf.end());
+
+ /*
+ * Check the result matches what we expect. Use a temporary
+ * string here instead of std::ranges::equal because this
+ * means ATF can print the mismatch.
+ */
+ auto str = std::string(std::ranges::begin(strbuf), end);
+ ATF_REQUIRE_EQ(str, addr.output);
+ }
+}
+
+/*
+ * inet_net_ntop() and inet_net_pton() for IPv6.
+ */
+ATF_TEST_CASE_WITHOUT_HEAD(inet_net_inet6)
+ATF_TEST_CASE_BODY(inet_net_inet6)
+{
+ /*
+ * Define a list of addresses we want to check. Each address is
+ * passed to inet_net_pton() to convert it to a in6_addr, then we
+ * convert the in6_addr back to a string and compare it with the
+ * expected value. We want to test over-long prefixes here (such
+ * as 2001:db8::1/32), so we also specify what the result is
+ * expected to be.
+ */
+
+ struct test_addr {
+ std::string input;
+ unsigned bits;
+ std::string output;
+ };
+
+ auto test_addrs = std::vector<test_addr>{
+ // A prefix with a trailing ::
+ { "2001:db8::/32", 32, "2001:db8::/32" },
+
+ // A prefix with a leading ::. Note that the output is
+ // different from the input because inet_ntop() renders
+ // this prefix with an IPv4 suffix for legacy reasons.
+ { "::ffff:0:0/96", 96, "::ffff:0.0.0.0/96" },
+
+ // The same prefix but with the IPv4 legacy form as input.
+ { "::ffff:0.0.0.0/96", 96, "::ffff:0.0.0.0/96" },
+
+ // A prefix with an infix ::.
+ { "2001:db8::1/128", 128, "2001:db8::1/128" },
+
+ // A prefix with bits set which are outside the prefix;
+ // these should be silently ignored.
+ { "2001:db8:1:1:1:1:1:1/32", 32, "2001:db8::/32" },
+
+ // As above but with infix ::.
+ { "2001:db8::1/32", 32, "2001:db8::/32" },
+
+ // A prefix with only ::, commonly used to represent the
+ // entire address space.
+ { "::/0", 0, "::/0" },
+
+ // A single address with no ::.
+ { "2001:db8:1:1:1:1:1:1/128", 128, "2001:db8:1:1:1:1:1:1/128" },
+
+ // A prefix with no ::.
+ { "2001:db8:1:1:0:0:0:0/64", 64, "2001:db8:1:1::/64" },
+
+ // A prefix which isn't on a 16-bit boundary.
+ { "2001:db8:c000::/56", 56, "2001:db8:c000::/56" },
+
+ // A prefix which isn't on a nibble boundary.
+ { "2001:db8:c100::/57", 57, "2001:db8:c100::/57" },
+
+ // An address without a prefix length, which should be treated
+ // as a /128.
+ { "2001:db8::", 128, "2001:db8::/128" },
+ { "2001:db8::1", 128, "2001:db8::1/128" },
+
+ // Test vectors provided in PR bin/289198.
+ { "fe80::1/64", 64, "fe80::/64" },
+ { "fe80::f000:74ff:fe54:bed2/64",
+ 64, "fe80::/64" },
+ { "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/64",
+ 64, "ffff:ffff:ffff:ffff::/64" },
+ { "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 128,
+ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" },
+ };
+
+ for (auto const &addr: test_addrs) {
+ /*
+ * Convert the input string to an in6_addr + bits, and make
+ * sure the result produces the number of bits we expected.
+ */
+
+ auto in6 = in6_addr{};
+ errno = 0;
+ auto bits = inet_net_pton(AF_INET6, addr.input.c_str(),
+ &in6, sizeof(in6));
+ ATF_REQUIRE(bits != -1);
+ ATF_REQUIRE_EQ(bits, addr.bits);
+
+ /*
+ * Convert the in6_addr back to a string
+ */
+
+ /*
+ * XXX: Should there be a constant for the size of the result
+ * buffer? For now, use ADDRSTRLEN + 4 ("/128") + 1 (NUL).
+ *
+ * Fill the buffer with 'Z', so we can check the result was
+ * properly terminated.
+ */
+ auto strbuf = std::vector<char>(INET6_ADDRSTRLEN + 4 + 1, 'Z');
+ auto ret = inet_net_ntop(AF_INET6, &in6, bits,
+ strbuf.data(), strbuf.size());
+ ATF_REQUIRE(ret != NULL);
+ ATF_REQUIRE_EQ(ret, strbuf.data());
+
+ /* Make sure the result was NUL-terminated and find the NUL */
+ ATF_REQUIRE(strbuf.size() >= 1);
+ auto end = std::ranges::find(strbuf, '\0');
+ ATF_REQUIRE(end != strbuf.end());
+
+ /*
+ * Check the result matches what we expect. Use a temporary
+ * string here instead of std::ranges::equal because this
+ * means ATF can print the mismatch.
+ */
+ auto str = std::string(std::ranges::begin(strbuf), end);
+ ATF_REQUIRE_EQ(str, addr.output);
+ }
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(inet_net_pton_invalid)
+ATF_TEST_CASE_BODY(inet_net_pton_invalid)
+{
+ auto ret = int{};
+ auto addr4 = in_addr{};
+ auto str4 = "10.0.0.0"s;
+ auto addr6 = in6_addr{};
+ auto str6 = "2001:db8::"s;
+
+ /* Passing an address which is too short should be an error */
+ ret = inet_net_pton(AF_INET6, str6.c_str(), &addr6, sizeof(addr6) - 1);
+ ATF_REQUIRE_EQ(ret, -1);
+
+ ret = inet_net_pton(AF_INET, str4.c_str(), &addr4, sizeof(addr4) - 1);
+ ATF_REQUIRE_EQ(ret, -1);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(inet_net_ntop_invalid)
+ATF_TEST_CASE_BODY(inet_net_ntop_invalid)
+{
+ auto addr4 = in_addr{};
+ auto addr6 = in6_addr{};
+ auto strbuf = std::vector<char>(INET6_ADDRSTRLEN + 4 + 1);
+
+ /*
+ * Passing a buffer which is too small should not overrun the buffer.
+ * Test this by initialising the buffer to 'Z', and only providing
+ * part of it to the function.
+ */
+
+ std::ranges::fill(strbuf, 'Z');
+ auto ret = inet_net_ntop(AF_INET6, &addr6, 128, strbuf.data(), 1);
+ ATF_REQUIRE_EQ(ret, NULL);
+ ATF_REQUIRE_EQ(strbuf[2], 'Z');
+
+ std::ranges::fill(strbuf, 'Z');
+ ret = inet_net_ntop(AF_INET, &addr4, 32, strbuf.data(), 1);
+ ATF_REQUIRE_EQ(ret, NULL);
+ ATF_REQUIRE_EQ(strbuf[2], 'Z');
+}
+
+ATF_INIT_TEST_CASES(tcs)
+{
+ ATF_ADD_TEST_CASE(tcs, inet_net_inet4);
+ ATF_ADD_TEST_CASE(tcs, inet_net_inet6);
+ ATF_ADD_TEST_CASE(tcs, inet_net_pton_invalid);
+ ATF_ADD_TEST_CASE(tcs, inet_net_ntop_invalid);
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Feb 9, 12:42 PM (7 h, 58 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28580480
Default Alt Text
D52629.id162438.diff (28 KB)
Attached To
Mode
D52629: libc: Import OpenBSD's inet_net_{ntop,pton}
Attached
Detach File
Event Timeline
Log In to Comment