xref: /openbsd-src/usr.bin/ssh/addr.c (revision 632d59bf82ef1c5ae20fd4a1838ec4a541a50a00)
1*632d59bfSdjm /* $OpenBSD: addr.c,v 1.9 2024/10/18 04:30:09 djm Exp $ */
24b59ce38Sdtucker 
34b59ce38Sdtucker /*
44b59ce38Sdtucker  * Copyright (c) 2004-2008 Damien Miller <djm@mindrot.org>
54b59ce38Sdtucker  *
64b59ce38Sdtucker  * Permission to use, copy, modify, and distribute this software for any
74b59ce38Sdtucker  * purpose with or without fee is hereby granted, provided that the above
84b59ce38Sdtucker  * copyright notice and this permission notice appear in all copies.
94b59ce38Sdtucker  *
104b59ce38Sdtucker  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
114b59ce38Sdtucker  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
124b59ce38Sdtucker  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
134b59ce38Sdtucker  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
144b59ce38Sdtucker  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
154b59ce38Sdtucker  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
164b59ce38Sdtucker  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
174b59ce38Sdtucker  */
184b59ce38Sdtucker 
194b59ce38Sdtucker #include <sys/types.h>
204b59ce38Sdtucker #include <sys/socket.h>
214b59ce38Sdtucker #include <netinet/in.h>
224b59ce38Sdtucker #include <arpa/inet.h>
234b59ce38Sdtucker 
244b59ce38Sdtucker #include <netdb.h>
254b59ce38Sdtucker #include <string.h>
264b59ce38Sdtucker #include <stdlib.h>
274b59ce38Sdtucker #include <stdio.h>
28dc987674Sderaadt #include <limits.h>
294b59ce38Sdtucker 
304b59ce38Sdtucker #include "addr.h"
314b59ce38Sdtucker 
324b59ce38Sdtucker #define _SA(x)	((struct sockaddr *)(x))
334b59ce38Sdtucker 
34*632d59bfSdjm static int
354b59ce38Sdtucker addr_unicast_masklen(int af)
364b59ce38Sdtucker {
374b59ce38Sdtucker 	switch (af) {
384b59ce38Sdtucker 	case AF_INET:
394b59ce38Sdtucker 		return 32;
404b59ce38Sdtucker 	case AF_INET6:
414b59ce38Sdtucker 		return 128;
424b59ce38Sdtucker 	default:
434b59ce38Sdtucker 		return -1;
444b59ce38Sdtucker 	}
454b59ce38Sdtucker }
464b59ce38Sdtucker 
474b59ce38Sdtucker static inline int
484b59ce38Sdtucker masklen_valid(int af, u_int masklen)
494b59ce38Sdtucker {
504b59ce38Sdtucker 	switch (af) {
514b59ce38Sdtucker 	case AF_INET:
524b59ce38Sdtucker 		return masklen <= 32 ? 0 : -1;
534b59ce38Sdtucker 	case AF_INET6:
544b59ce38Sdtucker 		return masklen <= 128 ? 0 : -1;
554b59ce38Sdtucker 	default:
564b59ce38Sdtucker 		return -1;
574b59ce38Sdtucker 	}
584b59ce38Sdtucker }
594b59ce38Sdtucker 
60*632d59bfSdjm static int
614b59ce38Sdtucker addr_xaddr_to_sa(const struct xaddr *xa, struct sockaddr *sa, socklen_t *len,
624b59ce38Sdtucker     u_int16_t port)
634b59ce38Sdtucker {
644b59ce38Sdtucker 	struct sockaddr_in *in4 = (struct sockaddr_in *)sa;
654b59ce38Sdtucker 	struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa;
664b59ce38Sdtucker 
674b59ce38Sdtucker 	if (xa == NULL || sa == NULL || len == NULL)
684b59ce38Sdtucker 		return -1;
694b59ce38Sdtucker 
704b59ce38Sdtucker 	switch (xa->af) {
714b59ce38Sdtucker 	case AF_INET:
724b59ce38Sdtucker 		if (*len < sizeof(*in4))
734b59ce38Sdtucker 			return -1;
744b59ce38Sdtucker 		memset(sa, '\0', sizeof(*in4));
754b59ce38Sdtucker 		*len = sizeof(*in4);
764b59ce38Sdtucker #ifdef SOCK_HAS_LEN
774b59ce38Sdtucker 		in4->sin_len = sizeof(*in4);
784b59ce38Sdtucker #endif
794b59ce38Sdtucker 		in4->sin_family = AF_INET;
804b59ce38Sdtucker 		in4->sin_port = htons(port);
814b59ce38Sdtucker 		memcpy(&in4->sin_addr, &xa->v4, sizeof(in4->sin_addr));
824b59ce38Sdtucker 		break;
834b59ce38Sdtucker 	case AF_INET6:
844b59ce38Sdtucker 		if (*len < sizeof(*in6))
854b59ce38Sdtucker 			return -1;
864b59ce38Sdtucker 		memset(sa, '\0', sizeof(*in6));
874b59ce38Sdtucker 		*len = sizeof(*in6);
884b59ce38Sdtucker #ifdef SOCK_HAS_LEN
894b59ce38Sdtucker 		in6->sin6_len = sizeof(*in6);
904b59ce38Sdtucker #endif
914b59ce38Sdtucker 		in6->sin6_family = AF_INET6;
924b59ce38Sdtucker 		in6->sin6_port = htons(port);
934b59ce38Sdtucker 		memcpy(&in6->sin6_addr, &xa->v6, sizeof(in6->sin6_addr));
944b59ce38Sdtucker 		in6->sin6_scope_id = xa->scope_id;
954b59ce38Sdtucker 		break;
964b59ce38Sdtucker 	default:
974b59ce38Sdtucker 		return -1;
984b59ce38Sdtucker 	}
994b59ce38Sdtucker 	return 0;
1004b59ce38Sdtucker }
1014b59ce38Sdtucker 
1024b59ce38Sdtucker /*
1034b59ce38Sdtucker  * Convert struct sockaddr to struct xaddr
1044b59ce38Sdtucker  * Returns 0 on success, -1 on failure.
1054b59ce38Sdtucker  */
1064b59ce38Sdtucker int
1074b59ce38Sdtucker addr_sa_to_xaddr(struct sockaddr *sa, socklen_t slen, struct xaddr *xa)
1084b59ce38Sdtucker {
1094b59ce38Sdtucker 	struct sockaddr_in *in4 = (struct sockaddr_in *)sa;
1104b59ce38Sdtucker 	struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa;
1114b59ce38Sdtucker 
1124b59ce38Sdtucker 	memset(xa, '\0', sizeof(*xa));
1134b59ce38Sdtucker 
1144b59ce38Sdtucker 	switch (sa->sa_family) {
1154b59ce38Sdtucker 	case AF_INET:
1164b59ce38Sdtucker 		if (slen < (socklen_t)sizeof(*in4))
1174b59ce38Sdtucker 			return -1;
1184b59ce38Sdtucker 		xa->af = AF_INET;
1194b59ce38Sdtucker 		memcpy(&xa->v4, &in4->sin_addr, sizeof(xa->v4));
1204b59ce38Sdtucker 		break;
1214b59ce38Sdtucker 	case AF_INET6:
1224b59ce38Sdtucker 		if (slen < (socklen_t)sizeof(*in6))
1234b59ce38Sdtucker 			return -1;
1244b59ce38Sdtucker 		xa->af = AF_INET6;
1254b59ce38Sdtucker 		memcpy(&xa->v6, &in6->sin6_addr, sizeof(xa->v6));
1264b59ce38Sdtucker #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
1274b59ce38Sdtucker 		xa->scope_id = in6->sin6_scope_id;
1284b59ce38Sdtucker #endif
1294b59ce38Sdtucker 		break;
1304b59ce38Sdtucker 	default:
1314b59ce38Sdtucker 		return -1;
1324b59ce38Sdtucker 	}
1334b59ce38Sdtucker 
1344b59ce38Sdtucker 	return 0;
1354b59ce38Sdtucker }
1364b59ce38Sdtucker 
137*632d59bfSdjm static int
1384b59ce38Sdtucker addr_invert(struct xaddr *n)
1394b59ce38Sdtucker {
1404b59ce38Sdtucker 	int i;
1414b59ce38Sdtucker 
1424b59ce38Sdtucker 	if (n == NULL)
1434b59ce38Sdtucker 		return -1;
1444b59ce38Sdtucker 
1454b59ce38Sdtucker 	switch (n->af) {
1464b59ce38Sdtucker 	case AF_INET:
1474b59ce38Sdtucker 		n->v4.s_addr = ~n->v4.s_addr;
1484b59ce38Sdtucker 		return 0;
1494b59ce38Sdtucker 	case AF_INET6:
1504b59ce38Sdtucker 		for (i = 0; i < 4; i++)
1514b59ce38Sdtucker 			n->addr32[i] = ~n->addr32[i];
1524b59ce38Sdtucker 		return 0;
1534b59ce38Sdtucker 	default:
1544b59ce38Sdtucker 		return -1;
1554b59ce38Sdtucker 	}
1564b59ce38Sdtucker }
1574b59ce38Sdtucker 
1584b59ce38Sdtucker /*
1594b59ce38Sdtucker  * Calculate a netmask of length 'l' for address family 'af' and
1604b59ce38Sdtucker  * store it in 'n'.
1614b59ce38Sdtucker  * Returns 0 on success, -1 on failure.
1624b59ce38Sdtucker  */
1634b59ce38Sdtucker int
1644b59ce38Sdtucker addr_netmask(int af, u_int l, struct xaddr *n)
1654b59ce38Sdtucker {
1664b59ce38Sdtucker 	int i;
1674b59ce38Sdtucker 
1684b59ce38Sdtucker 	if (masklen_valid(af, l) != 0 || n == NULL)
1694b59ce38Sdtucker 		return -1;
1704b59ce38Sdtucker 
1714b59ce38Sdtucker 	memset(n, '\0', sizeof(*n));
1724b59ce38Sdtucker 	switch (af) {
1734b59ce38Sdtucker 	case AF_INET:
1744b59ce38Sdtucker 		n->af = AF_INET;
1754b59ce38Sdtucker 		if (l == 0)
1764b59ce38Sdtucker 			return 0;
1774b59ce38Sdtucker 		n->v4.s_addr = htonl((0xffffffff << (32 - l)) & 0xffffffff);
1784b59ce38Sdtucker 		return 0;
1794b59ce38Sdtucker 	case AF_INET6:
1804b59ce38Sdtucker 		n->af = AF_INET6;
1814b59ce38Sdtucker 		for (i = 0; i < 4 && l >= 32; i++, l -= 32)
1824b59ce38Sdtucker 			n->addr32[i] = 0xffffffffU;
1834b59ce38Sdtucker 		if (i < 4 && l != 0)
1844b59ce38Sdtucker 			n->addr32[i] = htonl((0xffffffff << (32 - l)) &
1854b59ce38Sdtucker 			    0xffffffff);
1864b59ce38Sdtucker 		return 0;
1874b59ce38Sdtucker 	default:
1884b59ce38Sdtucker 		return -1;
1894b59ce38Sdtucker 	}
1904b59ce38Sdtucker }
1914b59ce38Sdtucker 
192*632d59bfSdjm static int
1934b59ce38Sdtucker addr_hostmask(int af, u_int l, struct xaddr *n)
1944b59ce38Sdtucker {
1954b59ce38Sdtucker 	if (addr_netmask(af, l, n) == -1 || addr_invert(n) == -1)
1964b59ce38Sdtucker 		return -1;
1974b59ce38Sdtucker 	return 0;
1984b59ce38Sdtucker }
1994b59ce38Sdtucker 
2004b59ce38Sdtucker /*
2014b59ce38Sdtucker  * Perform logical AND of addresses 'a' and 'b', storing result in 'dst'.
2024b59ce38Sdtucker  * Returns 0 on success, -1 on failure.
2034b59ce38Sdtucker  */
2044b59ce38Sdtucker int
2054b59ce38Sdtucker addr_and(struct xaddr *dst, const struct xaddr *a, const struct xaddr *b)
2064b59ce38Sdtucker {
2074b59ce38Sdtucker 	int i;
2084b59ce38Sdtucker 
2094b59ce38Sdtucker 	if (dst == NULL || a == NULL || b == NULL || a->af != b->af)
2104b59ce38Sdtucker 		return -1;
2114b59ce38Sdtucker 
2124b59ce38Sdtucker 	memcpy(dst, a, sizeof(*dst));
2134b59ce38Sdtucker 	switch (a->af) {
2144b59ce38Sdtucker 	case AF_INET:
2154b59ce38Sdtucker 		dst->v4.s_addr &= b->v4.s_addr;
2164b59ce38Sdtucker 		return 0;
2174b59ce38Sdtucker 	case AF_INET6:
2184b59ce38Sdtucker 		dst->scope_id = a->scope_id;
2194b59ce38Sdtucker 		for (i = 0; i < 4; i++)
2204b59ce38Sdtucker 			dst->addr32[i] &= b->addr32[i];
2214b59ce38Sdtucker 		return 0;
2224b59ce38Sdtucker 	default:
2234b59ce38Sdtucker 		return -1;
2244b59ce38Sdtucker 	}
2254b59ce38Sdtucker }
2264b59ce38Sdtucker 
227*632d59bfSdjm static int
228ba77ede9Sdjm addr_or(struct xaddr *dst, const struct xaddr *a, const struct xaddr *b)
229ba77ede9Sdjm {
230ba77ede9Sdjm 	int i;
231ba77ede9Sdjm 
232ba77ede9Sdjm 	if (dst == NULL || a == NULL || b == NULL || a->af != b->af)
233ba77ede9Sdjm 		return (-1);
234ba77ede9Sdjm 
235ba77ede9Sdjm 	memcpy(dst, a, sizeof(*dst));
236ba77ede9Sdjm 	switch (a->af) {
237ba77ede9Sdjm 	case AF_INET:
238ba77ede9Sdjm 		dst->v4.s_addr |= b->v4.s_addr;
239ba77ede9Sdjm 		return (0);
240ba77ede9Sdjm 	case AF_INET6:
241ba77ede9Sdjm 		for (i = 0; i < 4; i++)
242ba77ede9Sdjm 			dst->addr32[i] |= b->addr32[i];
243ba77ede9Sdjm 		return (0);
244ba77ede9Sdjm 	default:
245ba77ede9Sdjm 		return (-1);
246ba77ede9Sdjm 	}
247ba77ede9Sdjm }
248ba77ede9Sdjm 
249ba77ede9Sdjm int
2504b59ce38Sdtucker addr_cmp(const struct xaddr *a, const struct xaddr *b)
2514b59ce38Sdtucker {
2524b59ce38Sdtucker 	int i;
2534b59ce38Sdtucker 
2544b59ce38Sdtucker 	if (a->af != b->af)
2554b59ce38Sdtucker 		return (a->af == AF_INET6 ? 1 : -1);
2564b59ce38Sdtucker 
2574b59ce38Sdtucker 	switch (a->af) {
2584b59ce38Sdtucker 	case AF_INET:
2594b59ce38Sdtucker 		/*
2604b59ce38Sdtucker 		 * Can't just subtract here as 255.255.255.255 - 0.0.0.0 is
2614b59ce38Sdtucker 		 * too big to fit into a signed int
2624b59ce38Sdtucker 		 */
2634b59ce38Sdtucker 		if (a->v4.s_addr == b->v4.s_addr)
2644b59ce38Sdtucker 			return 0;
2654b59ce38Sdtucker 		return (ntohl(a->v4.s_addr) > ntohl(b->v4.s_addr) ? 1 : -1);
266d4c3ca28Sdtucker 	case AF_INET6:
2674b59ce38Sdtucker 		/*
2684b59ce38Sdtucker 		 * Do this a byte at a time to avoid the above issue and
2694b59ce38Sdtucker 		 * any endian problems
2704b59ce38Sdtucker 		 */
2714b59ce38Sdtucker 		for (i = 0; i < 16; i++)
2724b59ce38Sdtucker 			if (a->addr8[i] - b->addr8[i] != 0)
2734b59ce38Sdtucker 				return (a->addr8[i] - b->addr8[i]);
2744b59ce38Sdtucker 		if (a->scope_id == b->scope_id)
2754b59ce38Sdtucker 			return (0);
2764b59ce38Sdtucker 		return (a->scope_id > b->scope_id ? 1 : -1);
2774b59ce38Sdtucker 	default:
2784b59ce38Sdtucker 		return (-1);
2794b59ce38Sdtucker 	}
2804b59ce38Sdtucker }
2814b59ce38Sdtucker 
282*632d59bfSdjm static int
2834b59ce38Sdtucker addr_is_all0s(const struct xaddr *a)
2844b59ce38Sdtucker {
2854b59ce38Sdtucker 	int i;
2864b59ce38Sdtucker 
2874b59ce38Sdtucker 	switch (a->af) {
2884b59ce38Sdtucker 	case AF_INET:
2894b59ce38Sdtucker 		return (a->v4.s_addr == 0 ? 0 : -1);
290d4c3ca28Sdtucker 	case AF_INET6:
2914b59ce38Sdtucker 		for (i = 0; i < 4; i++)
2924b59ce38Sdtucker 			if (a->addr32[i] != 0)
2934b59ce38Sdtucker 				return -1;
2944b59ce38Sdtucker 		return 0;
2954b59ce38Sdtucker 	default:
2964b59ce38Sdtucker 		return -1;
2974b59ce38Sdtucker 	}
2984b59ce38Sdtucker }
2994b59ce38Sdtucker 
300ba77ede9Sdjm /* Increment the specified address. Note, does not do overflow checking */
301ba77ede9Sdjm void
302ba77ede9Sdjm addr_increment(struct xaddr *a)
303ba77ede9Sdjm {
304ba77ede9Sdjm 	int i;
305ba77ede9Sdjm 	uint32_t n;
306ba77ede9Sdjm 
307ba77ede9Sdjm 	switch (a->af) {
308ba77ede9Sdjm 	case AF_INET:
309ba77ede9Sdjm 		a->v4.s_addr = htonl(ntohl(a->v4.s_addr) + 1);
310ba77ede9Sdjm 		break;
311ba77ede9Sdjm 	case AF_INET6:
312ba77ede9Sdjm 		for (i = 0; i < 4; i++) {
313ba77ede9Sdjm 			/* Increment with carry */
314ba77ede9Sdjm 			n = ntohl(a->addr32[3 - i]) + 1;
315ba77ede9Sdjm 			a->addr32[3 - i] = htonl(n);
316ba77ede9Sdjm 			if (n != 0)
317ba77ede9Sdjm 				break;
318ba77ede9Sdjm 		}
319ba77ede9Sdjm 		break;
320ba77ede9Sdjm 	}
321ba77ede9Sdjm }
322ba77ede9Sdjm 
3234b59ce38Sdtucker /*
3244b59ce38Sdtucker  * Test whether host portion of address 'a', as determined by 'masklen'
3254b59ce38Sdtucker  * is all zeros.
326584553ebSdtucker  * Returns 0 if host portion of address is all-zeros,
3274b59ce38Sdtucker  * -1 if not all zeros or on failure.
3284b59ce38Sdtucker  */
329*632d59bfSdjm static int
3304b59ce38Sdtucker addr_host_is_all0s(const struct xaddr *a, u_int masklen)
3314b59ce38Sdtucker {
3324b59ce38Sdtucker 	struct xaddr tmp_addr, tmp_mask, tmp_result;
3334b59ce38Sdtucker 
3344b59ce38Sdtucker 	memcpy(&tmp_addr, a, sizeof(tmp_addr));
3354b59ce38Sdtucker 	if (addr_hostmask(a->af, masklen, &tmp_mask) == -1)
3364b59ce38Sdtucker 		return -1;
3374b59ce38Sdtucker 	if (addr_and(&tmp_result, &tmp_addr, &tmp_mask) == -1)
3384b59ce38Sdtucker 		return -1;
3394b59ce38Sdtucker 	return addr_is_all0s(&tmp_result);
3404b59ce38Sdtucker }
3414b59ce38Sdtucker 
342ba77ede9Sdjm #if 0
343*632d59bfSdjm static int
344ba77ede9Sdjm addr_host_to_all0s(struct xaddr *a, u_int masklen)
345ba77ede9Sdjm {
346ba77ede9Sdjm 	struct xaddr tmp_mask;
347ba77ede9Sdjm 
348ba77ede9Sdjm 	if (addr_netmask(a->af, masklen, &tmp_mask) == -1)
349ba77ede9Sdjm 		return (-1);
350ba77ede9Sdjm 	if (addr_and(a, a, &tmp_mask) == -1)
351ba77ede9Sdjm 		return (-1);
352ba77ede9Sdjm 	return (0);
353ba77ede9Sdjm }
354ba77ede9Sdjm #endif
355ba77ede9Sdjm 
356ba77ede9Sdjm int
357ba77ede9Sdjm addr_host_to_all1s(struct xaddr *a, u_int masklen)
358ba77ede9Sdjm {
359ba77ede9Sdjm 	struct xaddr tmp_mask;
360ba77ede9Sdjm 
361ba77ede9Sdjm 	if (addr_hostmask(a->af, masklen, &tmp_mask) == -1)
362ba77ede9Sdjm 		return (-1);
363ba77ede9Sdjm 	if (addr_or(a, a, &tmp_mask) == -1)
364ba77ede9Sdjm 		return (-1);
365ba77ede9Sdjm 	return (0);
366ba77ede9Sdjm }
367ba77ede9Sdjm 
3684b59ce38Sdtucker /*
369584553ebSdtucker  * Parse string address 'p' into 'n'.
3704b59ce38Sdtucker  * Returns 0 on success, -1 on failure.
3714b59ce38Sdtucker  */
3724b59ce38Sdtucker int
3734b59ce38Sdtucker addr_pton(const char *p, struct xaddr *n)
3744b59ce38Sdtucker {
3754b59ce38Sdtucker 	struct addrinfo hints, *ai;
3764b59ce38Sdtucker 
3774b59ce38Sdtucker 	memset(&hints, '\0', sizeof(hints));
3784b59ce38Sdtucker 	hints.ai_flags = AI_NUMERICHOST;
3794b59ce38Sdtucker 
3804b59ce38Sdtucker 	if (p == NULL || getaddrinfo(p, NULL, &hints, &ai) != 0)
3814b59ce38Sdtucker 		return -1;
3824b59ce38Sdtucker 
3832ad7106cSdtucker 	if (ai == NULL)
3844b59ce38Sdtucker 		return -1;
3854b59ce38Sdtucker 
3862ad7106cSdtucker 	if (ai->ai_addr == NULL) {
3872ad7106cSdtucker 		freeaddrinfo(ai);
3882ad7106cSdtucker 		return -1;
3892ad7106cSdtucker 	}
3902ad7106cSdtucker 
3914b59ce38Sdtucker 	if (n != NULL && addr_sa_to_xaddr(ai->ai_addr, ai->ai_addrlen,
3924b59ce38Sdtucker 	    n) == -1) {
3934b59ce38Sdtucker 		freeaddrinfo(ai);
3944b59ce38Sdtucker 		return -1;
3954b59ce38Sdtucker 	}
3964b59ce38Sdtucker 
3974b59ce38Sdtucker 	freeaddrinfo(ai);
3984b59ce38Sdtucker 	return 0;
3994b59ce38Sdtucker }
4004b59ce38Sdtucker 
401*632d59bfSdjm #if 0
402*632d59bfSdjm static int
4034b59ce38Sdtucker addr_sa_pton(const char *h, const char *s, struct sockaddr *sa, socklen_t slen)
4044b59ce38Sdtucker {
4054b59ce38Sdtucker 	struct addrinfo hints, *ai;
4064b59ce38Sdtucker 
4074b59ce38Sdtucker 	memset(&hints, '\0', sizeof(hints));
4084b59ce38Sdtucker 	hints.ai_flags = AI_NUMERICHOST;
4094b59ce38Sdtucker 
4104b59ce38Sdtucker 	if (h == NULL || getaddrinfo(h, s, &hints, &ai) != 0)
4114b59ce38Sdtucker 		return -1;
4124b59ce38Sdtucker 
4132ad7106cSdtucker 	if (ai == NULL)
4144b59ce38Sdtucker 		return -1;
4154b59ce38Sdtucker 
4162ad7106cSdtucker 	if (ai->ai_addr == NULL) {
4172ad7106cSdtucker 		freeaddrinfo(ai);
4184b59ce38Sdtucker 		return -1;
4192ad7106cSdtucker 	}
4202ad7106cSdtucker 
4212ad7106cSdtucker 	if (sa != NULL) {
4222ad7106cSdtucker 		if (slen < ai->ai_addrlen) {
4232ad7106cSdtucker 			freeaddrinfo(ai);
4242ad7106cSdtucker 			return -1;
4252ad7106cSdtucker 		}
4264b59ce38Sdtucker 		memcpy(sa, &ai->ai_addr, ai->ai_addrlen);
4274b59ce38Sdtucker 	}
4284b59ce38Sdtucker 
4294b59ce38Sdtucker 	freeaddrinfo(ai);
4304b59ce38Sdtucker 	return 0;
4314b59ce38Sdtucker }
432*632d59bfSdjm #endif
4334b59ce38Sdtucker 
4344b59ce38Sdtucker int
4354b59ce38Sdtucker addr_ntop(const struct xaddr *n, char *p, size_t len)
4364b59ce38Sdtucker {
4374b59ce38Sdtucker 	struct sockaddr_storage ss;
4384b59ce38Sdtucker 	socklen_t slen = sizeof(ss);
4394b59ce38Sdtucker 
4404b59ce38Sdtucker 	if (addr_xaddr_to_sa(n, _SA(&ss), &slen, 0) == -1)
4414b59ce38Sdtucker 		return -1;
4422ad7106cSdtucker 	if (p == NULL || len == 0)
4434b59ce38Sdtucker 		return -1;
4444b59ce38Sdtucker 	if (getnameinfo(_SA(&ss), slen, p, len, NULL, 0,
445dae09413Sdjm 	    NI_NUMERICHOST) != 0)
4464b59ce38Sdtucker 		return -1;
4474b59ce38Sdtucker 
4484b59ce38Sdtucker 	return 0;
4494b59ce38Sdtucker }
4504b59ce38Sdtucker 
4514b59ce38Sdtucker /*
4524b59ce38Sdtucker  * Parse a CIDR address (x.x.x.x/y or xxxx:yyyy::/z).
4534b59ce38Sdtucker  * Return -1 on parse error, -2 on inconsistency or 0 on success.
4544b59ce38Sdtucker  */
4554b59ce38Sdtucker int
4564b59ce38Sdtucker addr_pton_cidr(const char *p, struct xaddr *n, u_int *l)
4574b59ce38Sdtucker {
4584b59ce38Sdtucker 	struct xaddr tmp;
459dc987674Sderaadt 	u_int masklen = 999;
460dc987674Sderaadt 	char addrbuf[64], *mp;
461dc987674Sderaadt 	const char *errstr;
4624b59ce38Sdtucker 
4634b59ce38Sdtucker 	/* Don't modify argument */
4644b59ce38Sdtucker 	if (p == NULL || strlcpy(addrbuf, p, sizeof(addrbuf)) >= sizeof(addrbuf))
4654b59ce38Sdtucker 		return -1;
4664b59ce38Sdtucker 
4674b59ce38Sdtucker 	if ((mp = strchr(addrbuf, '/')) != NULL) {
4684b59ce38Sdtucker 		*mp = '\0';
4694b59ce38Sdtucker 		mp++;
470dc987674Sderaadt 		masklen = (u_int)strtonum(mp, 0, INT_MAX, &errstr);
471dc987674Sderaadt 		if (errstr)
4724b59ce38Sdtucker 			return -1;
4734b59ce38Sdtucker 	}
4744b59ce38Sdtucker 
4754b59ce38Sdtucker 	if (addr_pton(addrbuf, &tmp) == -1)
4764b59ce38Sdtucker 		return -1;
4774b59ce38Sdtucker 
4784b59ce38Sdtucker 	if (mp == NULL)
4794b59ce38Sdtucker 		masklen = addr_unicast_masklen(tmp.af);
4804b59ce38Sdtucker 	if (masklen_valid(tmp.af, masklen) == -1)
4814b59ce38Sdtucker 		return -2;
4824b59ce38Sdtucker 	if (addr_host_is_all0s(&tmp, masklen) != 0)
4834b59ce38Sdtucker 		return -2;
4844b59ce38Sdtucker 
4854b59ce38Sdtucker 	if (n != NULL)
4864b59ce38Sdtucker 		memcpy(n, &tmp, sizeof(*n));
4874b59ce38Sdtucker 	if (l != NULL)
4884b59ce38Sdtucker 		*l = masklen;
4894b59ce38Sdtucker 
4904b59ce38Sdtucker 	return 0;
4914b59ce38Sdtucker }
4924b59ce38Sdtucker 
4934b59ce38Sdtucker int
4944b59ce38Sdtucker addr_netmatch(const struct xaddr *host, const struct xaddr *net, u_int masklen)
4954b59ce38Sdtucker {
4964b59ce38Sdtucker 	struct xaddr tmp_mask, tmp_result;
4974b59ce38Sdtucker 
4984b59ce38Sdtucker 	if (host->af != net->af)
4994b59ce38Sdtucker 		return -1;
5004b59ce38Sdtucker 
5014b59ce38Sdtucker 	if (addr_netmask(host->af, masklen, &tmp_mask) == -1)
5024b59ce38Sdtucker 		return -1;
5034b59ce38Sdtucker 	if (addr_and(&tmp_result, host, &tmp_mask) == -1)
5044b59ce38Sdtucker 		return -1;
5054b59ce38Sdtucker 	return addr_cmp(&tmp_result, net);
5064b59ce38Sdtucker }
507