Home | History | Annotate | Line # | Download | only in isc
sockaddr.c revision 1.1.1.11
      1       1.1  christos /*	$NetBSD: sockaddr.c,v 1.1.1.11 2024/09/22 00:06:13 christos Exp $	*/
      2       1.1  christos 
      3       1.1  christos /*
      4       1.1  christos  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5       1.1  christos  *
      6   1.1.1.9  christos  * SPDX-License-Identifier: MPL-2.0
      7   1.1.1.9  christos  *
      8       1.1  christos  * This Source Code Form is subject to the terms of the Mozilla Public
      9       1.1  christos  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10   1.1.1.8  christos  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11       1.1  christos  *
     12       1.1  christos  * See the COPYRIGHT file distributed with this work for additional
     13       1.1  christos  * information regarding copyright ownership.
     14       1.1  christos  */
     15       1.1  christos 
     16       1.1  christos /*! \file */
     17       1.1  christos 
     18   1.1.1.2  christos #include <stdbool.h>
     19       1.1  christos #include <stdio.h>
     20       1.1  christos 
     21       1.1  christos #include <isc/buffer.h>
     22       1.1  christos #include <isc/hash.h>
     23       1.1  christos #include <isc/netaddr.h>
     24       1.1  christos #include <isc/print.h>
     25       1.1  christos #include <isc/region.h>
     26       1.1  christos #include <isc/sockaddr.h>
     27       1.1  christos #include <isc/string.h>
     28       1.1  christos #include <isc/util.h>
     29       1.1  christos 
     30   1.1.1.2  christos bool
     31       1.1  christos isc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
     32   1.1.1.7  christos 	return (isc_sockaddr_compare(a, b,
     33   1.1.1.7  christos 				     ISC_SOCKADDR_CMPADDR |
     34   1.1.1.7  christos 					     ISC_SOCKADDR_CMPPORT |
     35   1.1.1.7  christos 					     ISC_SOCKADDR_CMPSCOPE));
     36       1.1  christos }
     37       1.1  christos 
     38   1.1.1.2  christos bool
     39       1.1  christos isc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
     40   1.1.1.7  christos 	return (isc_sockaddr_compare(
     41   1.1.1.7  christos 		a, b, ISC_SOCKADDR_CMPADDR | ISC_SOCKADDR_CMPSCOPE));
     42       1.1  christos }
     43       1.1  christos 
     44   1.1.1.2  christos bool
     45       1.1  christos isc_sockaddr_compare(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
     46   1.1.1.7  christos 		     unsigned int flags) {
     47       1.1  christos 	REQUIRE(a != NULL && b != NULL);
     48       1.1  christos 
     49   1.1.1.7  christos 	if (a->length != b->length) {
     50   1.1.1.2  christos 		return (false);
     51   1.1.1.7  christos 	}
     52       1.1  christos 
     53       1.1  christos 	/*
     54       1.1  christos 	 * We don't just memcmp because the sin_zero field isn't always
     55       1.1  christos 	 * zero.
     56       1.1  christos 	 */
     57       1.1  christos 
     58   1.1.1.7  christos 	if (a->type.sa.sa_family != b->type.sa.sa_family) {
     59   1.1.1.2  christos 		return (false);
     60   1.1.1.7  christos 	}
     61       1.1  christos 	switch (a->type.sa.sa_family) {
     62       1.1  christos 	case AF_INET:
     63       1.1  christos 		if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
     64       1.1  christos 		    memcmp(&a->type.sin.sin_addr, &b->type.sin.sin_addr,
     65       1.1  christos 			   sizeof(a->type.sin.sin_addr)) != 0)
     66   1.1.1.7  christos 		{
     67   1.1.1.2  christos 			return (false);
     68   1.1.1.7  christos 		}
     69       1.1  christos 		if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
     70       1.1  christos 		    a->type.sin.sin_port != b->type.sin.sin_port)
     71   1.1.1.7  christos 		{
     72   1.1.1.2  christos 			return (false);
     73   1.1.1.7  christos 		}
     74       1.1  christos 		break;
     75       1.1  christos 	case AF_INET6:
     76       1.1  christos 		if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
     77       1.1  christos 		    memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr,
     78       1.1  christos 			   sizeof(a->type.sin6.sin6_addr)) != 0)
     79   1.1.1.7  christos 		{
     80   1.1.1.2  christos 			return (false);
     81   1.1.1.7  christos 		}
     82       1.1  christos 		/*
     83       1.1  christos 		 * If ISC_SOCKADDR_CMPSCOPEZERO is set then don't return
     84   1.1.1.2  christos 		 * false if one of the scopes in zero.
     85       1.1  christos 		 */
     86       1.1  christos 		if ((flags & ISC_SOCKADDR_CMPSCOPE) != 0 &&
     87       1.1  christos 		    a->type.sin6.sin6_scope_id != b->type.sin6.sin6_scope_id &&
     88       1.1  christos 		    ((flags & ISC_SOCKADDR_CMPSCOPEZERO) == 0 ||
     89   1.1.1.7  christos 		     (a->type.sin6.sin6_scope_id != 0 &&
     90   1.1.1.7  christos 		      b->type.sin6.sin6_scope_id != 0)))
     91   1.1.1.7  christos 		{
     92   1.1.1.2  christos 			return (false);
     93   1.1.1.7  christos 		}
     94       1.1  christos 		if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
     95       1.1  christos 		    a->type.sin6.sin6_port != b->type.sin6.sin6_port)
     96   1.1.1.7  christos 		{
     97   1.1.1.2  christos 			return (false);
     98   1.1.1.7  christos 		}
     99       1.1  christos 		break;
    100       1.1  christos 	default:
    101   1.1.1.7  christos 		if (memcmp(&a->type, &b->type, a->length) != 0) {
    102   1.1.1.2  christos 			return (false);
    103   1.1.1.7  christos 		}
    104       1.1  christos 	}
    105   1.1.1.2  christos 	return (true);
    106       1.1  christos }
    107       1.1  christos 
    108   1.1.1.2  christos bool
    109       1.1  christos isc_sockaddr_eqaddrprefix(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
    110   1.1.1.7  christos 			  unsigned int prefixlen) {
    111       1.1  christos 	isc_netaddr_t na, nb;
    112       1.1  christos 	isc_netaddr_fromsockaddr(&na, a);
    113       1.1  christos 	isc_netaddr_fromsockaddr(&nb, b);
    114       1.1  christos 	return (isc_netaddr_eqprefix(&na, &nb, prefixlen));
    115       1.1  christos }
    116       1.1  christos 
    117       1.1  christos isc_result_t
    118       1.1  christos isc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target) {
    119       1.1  christos 	isc_result_t result;
    120       1.1  christos 	isc_netaddr_t netaddr;
    121       1.1  christos 	char pbuf[sizeof("65000")];
    122       1.1  christos 	unsigned int plen;
    123       1.1  christos 	isc_region_t avail;
    124       1.1  christos 
    125       1.1  christos 	REQUIRE(sockaddr != NULL);
    126       1.1  christos 
    127       1.1  christos 	/*
    128       1.1  christos 	 * Do the port first, giving us the opportunity to check for
    129       1.1  christos 	 * unsupported address families before calling
    130       1.1  christos 	 * isc_netaddr_fromsockaddr().
    131       1.1  christos 	 */
    132       1.1  christos 	switch (sockaddr->type.sa.sa_family) {
    133       1.1  christos 	case AF_INET:
    134   1.1.1.7  christos 		snprintf(pbuf, sizeof(pbuf), "%u",
    135   1.1.1.7  christos 			 ntohs(sockaddr->type.sin.sin_port));
    136       1.1  christos 		break;
    137       1.1  christos 	case AF_INET6:
    138   1.1.1.7  christos 		snprintf(pbuf, sizeof(pbuf), "%u",
    139   1.1.1.7  christos 			 ntohs(sockaddr->type.sin6.sin6_port));
    140       1.1  christos 		break;
    141       1.1  christos 	case AF_UNIX:
    142       1.1  christos 		plen = strlen(sockaddr->type.sunix.sun_path);
    143   1.1.1.7  christos 		if (plen >= isc_buffer_availablelength(target)) {
    144       1.1  christos 			return (ISC_R_NOSPACE);
    145   1.1.1.7  christos 		}
    146       1.1  christos 
    147   1.1.1.8  christos 		isc_buffer_putmem(
    148   1.1.1.8  christos 			target,
    149   1.1.1.8  christos 			(const unsigned char *)sockaddr->type.sunix.sun_path,
    150   1.1.1.8  christos 			plen);
    151       1.1  christos 
    152       1.1  christos 		/*
    153       1.1  christos 		 * Null terminate after used region.
    154       1.1  christos 		 */
    155       1.1  christos 		isc_buffer_availableregion(target, &avail);
    156       1.1  christos 		INSIST(avail.length >= 1);
    157       1.1  christos 		avail.base[0] = '\0';
    158       1.1  christos 
    159       1.1  christos 		return (ISC_R_SUCCESS);
    160       1.1  christos 	default:
    161       1.1  christos 		return (ISC_R_FAILURE);
    162       1.1  christos 	}
    163       1.1  christos 
    164       1.1  christos 	plen = strlen(pbuf);
    165       1.1  christos 	INSIST(plen < sizeof(pbuf));
    166       1.1  christos 
    167       1.1  christos 	isc_netaddr_fromsockaddr(&netaddr, sockaddr);
    168       1.1  christos 	result = isc_netaddr_totext(&netaddr, target);
    169   1.1.1.7  christos 	if (result != ISC_R_SUCCESS) {
    170       1.1  christos 		return (result);
    171   1.1.1.7  christos 	}
    172       1.1  christos 
    173   1.1.1.7  christos 	if (1 + plen + 1 > isc_buffer_availablelength(target)) {
    174       1.1  christos 		return (ISC_R_NOSPACE);
    175   1.1.1.7  christos 	}
    176       1.1  christos 
    177       1.1  christos 	isc_buffer_putmem(target, (const unsigned char *)"#", 1);
    178       1.1  christos 	isc_buffer_putmem(target, (const unsigned char *)pbuf, plen);
    179       1.1  christos 
    180       1.1  christos 	/*
    181       1.1  christos 	 * Null terminate after used region.
    182       1.1  christos 	 */
    183       1.1  christos 	isc_buffer_availableregion(target, &avail);
    184       1.1  christos 	INSIST(avail.length >= 1);
    185       1.1  christos 	avail.base[0] = '\0';
    186       1.1  christos 
    187       1.1  christos 	return (ISC_R_SUCCESS);
    188       1.1  christos }
    189       1.1  christos 
    190       1.1  christos void
    191       1.1  christos isc_sockaddr_format(const isc_sockaddr_t *sa, char *array, unsigned int size) {
    192       1.1  christos 	isc_result_t result;
    193       1.1  christos 	isc_buffer_t buf;
    194       1.1  christos 
    195   1.1.1.7  christos 	if (size == 0U) {
    196       1.1  christos 		return;
    197   1.1.1.7  christos 	}
    198       1.1  christos 
    199       1.1  christos 	isc_buffer_init(&buf, array, size);
    200       1.1  christos 	result = isc_sockaddr_totext(sa, &buf);
    201       1.1  christos 	if (result != ISC_R_SUCCESS) {
    202       1.1  christos 		/*
    203       1.1  christos 		 * The message is the same as in netaddr.c.
    204       1.1  christos 		 */
    205   1.1.1.7  christos 		snprintf(array, size, "<unknown address, family %u>",
    206       1.1  christos 			 sa->type.sa.sa_family);
    207       1.1  christos 		array[size - 1] = '\0';
    208       1.1  christos 	}
    209       1.1  christos }
    210       1.1  christos 
    211       1.1  christos unsigned int
    212   1.1.1.2  christos isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, bool address_only) {
    213       1.1  christos 	unsigned int length = 0;
    214       1.1  christos 	const unsigned char *s = NULL;
    215       1.1  christos 	unsigned int h = 0;
    216       1.1  christos 	unsigned int p = 0;
    217       1.1  christos 	const struct in6_addr *in6;
    218       1.1  christos 
    219       1.1  christos 	REQUIRE(sockaddr != NULL);
    220       1.1  christos 
    221       1.1  christos 	switch (sockaddr->type.sa.sa_family) {
    222       1.1  christos 	case AF_INET:
    223       1.1  christos 		s = (const unsigned char *)&sockaddr->type.sin.sin_addr;
    224       1.1  christos 		p = ntohs(sockaddr->type.sin.sin_port);
    225       1.1  christos 		length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
    226       1.1  christos 		break;
    227       1.1  christos 	case AF_INET6:
    228       1.1  christos 		in6 = &sockaddr->type.sin6.sin6_addr;
    229       1.1  christos 		s = (const unsigned char *)in6;
    230       1.1  christos 		if (IN6_IS_ADDR_V4MAPPED(in6)) {
    231       1.1  christos 			s += 12;
    232       1.1  christos 			length = sizeof(sockaddr->type.sin.sin_addr.s_addr);
    233   1.1.1.7  christos 		} else {
    234       1.1  christos 			length = sizeof(sockaddr->type.sin6.sin6_addr);
    235   1.1.1.7  christos 		}
    236       1.1  christos 		p = ntohs(sockaddr->type.sin6.sin6_port);
    237       1.1  christos 		break;
    238       1.1  christos 	default:
    239  1.1.1.10  christos 		UNEXPECTED_ERROR("unknown address family: %d",
    240   1.1.1.3  christos 				 (int)sockaddr->type.sa.sa_family);
    241       1.1  christos 		s = (const unsigned char *)&sockaddr->type;
    242       1.1  christos 		length = sockaddr->length;
    243       1.1  christos 		p = 0;
    244       1.1  christos 	}
    245       1.1  christos 
    246   1.1.1.4  christos 	uint8_t buf[sizeof(struct sockaddr_storage) + sizeof(p)];
    247   1.1.1.4  christos 	memmove(buf, s, length);
    248   1.1.1.4  christos 	if (!address_only) {
    249   1.1.1.4  christos 		memmove(buf + length, &p, sizeof(p));
    250   1.1.1.4  christos 		h = isc_hash_function(buf, length + sizeof(p), true);
    251   1.1.1.4  christos 	} else {
    252   1.1.1.4  christos 		h = isc_hash_function(buf, length, true);
    253   1.1.1.4  christos 	}
    254       1.1  christos 
    255       1.1  christos 	return (h);
    256       1.1  christos }
    257       1.1  christos 
    258       1.1  christos void
    259   1.1.1.7  christos isc_sockaddr_any(isc_sockaddr_t *sockaddr) {
    260       1.1  christos 	memset(sockaddr, 0, sizeof(*sockaddr));
    261       1.1  christos 	sockaddr->type.sin.sin_family = AF_INET;
    262       1.1  christos 	sockaddr->type.sin.sin_addr.s_addr = INADDR_ANY;
    263       1.1  christos 	sockaddr->type.sin.sin_port = 0;
    264       1.1  christos 	sockaddr->length = sizeof(sockaddr->type.sin);
    265       1.1  christos 	ISC_LINK_INIT(sockaddr, link);
    266       1.1  christos }
    267       1.1  christos 
    268       1.1  christos void
    269   1.1.1.7  christos isc_sockaddr_any6(isc_sockaddr_t *sockaddr) {
    270       1.1  christos 	memset(sockaddr, 0, sizeof(*sockaddr));
    271       1.1  christos 	sockaddr->type.sin6.sin6_family = AF_INET6;
    272       1.1  christos 	sockaddr->type.sin6.sin6_addr = in6addr_any;
    273       1.1  christos 	sockaddr->type.sin6.sin6_port = 0;
    274       1.1  christos 	sockaddr->length = sizeof(sockaddr->type.sin6);
    275       1.1  christos 	ISC_LINK_INIT(sockaddr, link);
    276       1.1  christos }
    277       1.1  christos 
    278       1.1  christos void
    279       1.1  christos isc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
    280   1.1.1.7  christos 		    in_port_t port) {
    281       1.1  christos 	memset(sockaddr, 0, sizeof(*sockaddr));
    282       1.1  christos 	sockaddr->type.sin.sin_family = AF_INET;
    283       1.1  christos 	sockaddr->type.sin.sin_addr = *ina;
    284       1.1  christos 	sockaddr->type.sin.sin_port = htons(port);
    285       1.1  christos 	sockaddr->length = sizeof(sockaddr->type.sin);
    286       1.1  christos 	ISC_LINK_INIT(sockaddr, link);
    287       1.1  christos }
    288       1.1  christos 
    289       1.1  christos void
    290       1.1  christos isc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int pf) {
    291   1.1.1.7  christos 	switch (pf) {
    292   1.1.1.7  christos 	case AF_INET:
    293   1.1.1.7  christos 		isc_sockaddr_any(sockaddr);
    294   1.1.1.7  christos 		break;
    295   1.1.1.7  christos 	case AF_INET6:
    296   1.1.1.7  christos 		isc_sockaddr_any6(sockaddr);
    297   1.1.1.7  christos 		break;
    298   1.1.1.7  christos 	default:
    299   1.1.1.9  christos 		UNREACHABLE();
    300   1.1.1.7  christos 	}
    301       1.1  christos }
    302       1.1  christos 
    303       1.1  christos void
    304       1.1  christos isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6,
    305   1.1.1.7  christos 		     in_port_t port) {
    306       1.1  christos 	memset(sockaddr, 0, sizeof(*sockaddr));
    307       1.1  christos 	sockaddr->type.sin6.sin6_family = AF_INET6;
    308       1.1  christos 	sockaddr->type.sin6.sin6_addr = *ina6;
    309       1.1  christos 	sockaddr->type.sin6.sin6_port = htons(port);
    310       1.1  christos 	sockaddr->length = sizeof(sockaddr->type.sin6);
    311       1.1  christos 	ISC_LINK_INIT(sockaddr, link);
    312       1.1  christos }
    313       1.1  christos 
    314       1.1  christos void
    315       1.1  christos isc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
    316   1.1.1.7  christos 		      in_port_t port) {
    317       1.1  christos 	memset(sockaddr, 0, sizeof(*sockaddr));
    318       1.1  christos 	sockaddr->type.sin6.sin6_family = AF_INET6;
    319       1.1  christos 	sockaddr->type.sin6.sin6_addr.s6_addr[10] = 0xff;
    320       1.1  christos 	sockaddr->type.sin6.sin6_addr.s6_addr[11] = 0xff;
    321       1.1  christos 	memmove(&sockaddr->type.sin6.sin6_addr.s6_addr[12], ina, 4);
    322       1.1  christos 	sockaddr->type.sin6.sin6_port = htons(port);
    323       1.1  christos 	sockaddr->length = sizeof(sockaddr->type.sin6);
    324       1.1  christos 	ISC_LINK_INIT(sockaddr, link);
    325       1.1  christos }
    326       1.1  christos 
    327       1.1  christos int
    328       1.1  christos isc_sockaddr_pf(const isc_sockaddr_t *sockaddr) {
    329       1.1  christos 	/*
    330       1.1  christos 	 * Get the protocol family of 'sockaddr'.
    331       1.1  christos 	 */
    332       1.1  christos 
    333       1.1  christos #if (AF_INET == PF_INET && AF_INET6 == PF_INET6)
    334       1.1  christos 	/*
    335       1.1  christos 	 * Assume that PF_xxx == AF_xxx for all AF and PF.
    336       1.1  christos 	 */
    337       1.1  christos 	return (sockaddr->type.sa.sa_family);
    338   1.1.1.7  christos #else  /* if (AF_INET == PF_INET && AF_INET6 == PF_INET6) */
    339       1.1  christos 	switch (sockaddr->type.sa.sa_family) {
    340       1.1  christos 	case AF_INET:
    341       1.1  christos 		return (PF_INET);
    342       1.1  christos 	case AF_INET6:
    343       1.1  christos 		return (PF_INET6);
    344       1.1  christos 	default:
    345  1.1.1.10  christos 		FATAL_ERROR("unknown address family: %d",
    346       1.1  christos 			    (int)sockaddr->type.sa.sa_family);
    347       1.1  christos 	}
    348   1.1.1.7  christos #endif /* if (AF_INET == PF_INET && AF_INET6 == PF_INET6) */
    349       1.1  christos }
    350       1.1  christos 
    351       1.1  christos void
    352       1.1  christos isc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na,
    353   1.1.1.7  christos 			 in_port_t port) {
    354       1.1  christos 	memset(sockaddr, 0, sizeof(*sockaddr));
    355       1.1  christos 	sockaddr->type.sin.sin_family = na->family;
    356       1.1  christos 	switch (na->family) {
    357       1.1  christos 	case AF_INET:
    358       1.1  christos 		sockaddr->length = sizeof(sockaddr->type.sin);
    359       1.1  christos 		sockaddr->type.sin.sin_addr = na->type.in;
    360       1.1  christos 		sockaddr->type.sin.sin_port = htons(port);
    361       1.1  christos 		break;
    362       1.1  christos 	case AF_INET6:
    363       1.1  christos 		sockaddr->length = sizeof(sockaddr->type.sin6);
    364       1.1  christos 		memmove(&sockaddr->type.sin6.sin6_addr, &na->type.in6, 16);
    365       1.1  christos 		sockaddr->type.sin6.sin6_scope_id = isc_netaddr_getzone(na);
    366       1.1  christos 		sockaddr->type.sin6.sin6_port = htons(port);
    367       1.1  christos 		break;
    368       1.1  christos 	default:
    369   1.1.1.9  christos 		UNREACHABLE();
    370       1.1  christos 	}
    371       1.1  christos 	ISC_LINK_INIT(sockaddr, link);
    372       1.1  christos }
    373       1.1  christos 
    374       1.1  christos void
    375       1.1  christos isc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port) {
    376       1.1  christos 	switch (sockaddr->type.sa.sa_family) {
    377       1.1  christos 	case AF_INET:
    378       1.1  christos 		sockaddr->type.sin.sin_port = htons(port);
    379       1.1  christos 		break;
    380       1.1  christos 	case AF_INET6:
    381       1.1  christos 		sockaddr->type.sin6.sin6_port = htons(port);
    382       1.1  christos 		break;
    383       1.1  christos 	default:
    384  1.1.1.10  christos 		FATAL_ERROR("unknown address family: %d",
    385       1.1  christos 			    (int)sockaddr->type.sa.sa_family);
    386       1.1  christos 	}
    387       1.1  christos }
    388       1.1  christos 
    389       1.1  christos in_port_t
    390       1.1  christos isc_sockaddr_getport(const isc_sockaddr_t *sockaddr) {
    391       1.1  christos 	in_port_t port = 0;
    392       1.1  christos 
    393       1.1  christos 	switch (sockaddr->type.sa.sa_family) {
    394       1.1  christos 	case AF_INET:
    395       1.1  christos 		port = ntohs(sockaddr->type.sin.sin_port);
    396       1.1  christos 		break;
    397       1.1  christos 	case AF_INET6:
    398       1.1  christos 		port = ntohs(sockaddr->type.sin6.sin6_port);
    399       1.1  christos 		break;
    400       1.1  christos 	default:
    401  1.1.1.10  christos 		FATAL_ERROR("unknown address family: %d",
    402       1.1  christos 			    (int)sockaddr->type.sa.sa_family);
    403       1.1  christos 	}
    404       1.1  christos 
    405       1.1  christos 	return (port);
    406       1.1  christos }
    407       1.1  christos 
    408   1.1.1.2  christos bool
    409       1.1  christos isc_sockaddr_ismulticast(const isc_sockaddr_t *sockaddr) {
    410       1.1  christos 	isc_netaddr_t netaddr;
    411       1.1  christos 
    412       1.1  christos 	if (sockaddr->type.sa.sa_family == AF_INET ||
    413   1.1.1.7  christos 	    sockaddr->type.sa.sa_family == AF_INET6)
    414   1.1.1.7  christos 	{
    415       1.1  christos 		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
    416       1.1  christos 		return (isc_netaddr_ismulticast(&netaddr));
    417       1.1  christos 	}
    418   1.1.1.2  christos 	return (false);
    419       1.1  christos }
    420       1.1  christos 
    421   1.1.1.2  christos bool
    422       1.1  christos isc_sockaddr_isexperimental(const isc_sockaddr_t *sockaddr) {
    423       1.1  christos 	isc_netaddr_t netaddr;
    424       1.1  christos 
    425       1.1  christos 	if (sockaddr->type.sa.sa_family == AF_INET) {
    426       1.1  christos 		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
    427       1.1  christos 		return (isc_netaddr_isexperimental(&netaddr));
    428       1.1  christos 	}
    429   1.1.1.2  christos 	return (false);
    430       1.1  christos }
    431       1.1  christos 
    432   1.1.1.2  christos bool
    433       1.1  christos isc_sockaddr_issitelocal(const isc_sockaddr_t *sockaddr) {
    434       1.1  christos 	isc_netaddr_t netaddr;
    435       1.1  christos 
    436       1.1  christos 	if (sockaddr->type.sa.sa_family == AF_INET6) {
    437       1.1  christos 		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
    438       1.1  christos 		return (isc_netaddr_issitelocal(&netaddr));
    439       1.1  christos 	}
    440   1.1.1.2  christos 	return (false);
    441       1.1  christos }
    442       1.1  christos 
    443   1.1.1.2  christos bool
    444       1.1  christos isc_sockaddr_islinklocal(const isc_sockaddr_t *sockaddr) {
    445       1.1  christos 	isc_netaddr_t netaddr;
    446       1.1  christos 
    447       1.1  christos 	if (sockaddr->type.sa.sa_family == AF_INET6) {
    448       1.1  christos 		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
    449       1.1  christos 		return (isc_netaddr_islinklocal(&netaddr));
    450       1.1  christos 	}
    451   1.1.1.2  christos 	return (false);
    452       1.1  christos }
    453       1.1  christos 
    454   1.1.1.2  christos bool
    455       1.1  christos isc_sockaddr_isnetzero(const isc_sockaddr_t *sockaddr) {
    456       1.1  christos 	isc_netaddr_t netaddr;
    457       1.1  christos 
    458       1.1  christos 	if (sockaddr->type.sa.sa_family == AF_INET) {
    459       1.1  christos 		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
    460       1.1  christos 		return (isc_netaddr_isnetzero(&netaddr));
    461       1.1  christos 	}
    462   1.1.1.2  christos 	return (false);
    463       1.1  christos }
    464       1.1  christos 
    465       1.1  christos isc_result_t
    466       1.1  christos isc_sockaddr_frompath(isc_sockaddr_t *sockaddr, const char *path) {
    467   1.1.1.7  christos 	if (strlen(path) >= sizeof(sockaddr->type.sunix.sun_path)) {
    468       1.1  christos 		return (ISC_R_NOSPACE);
    469   1.1.1.7  christos 	}
    470       1.1  christos 	memset(sockaddr, 0, sizeof(*sockaddr));
    471       1.1  christos 	sockaddr->length = sizeof(sockaddr->type.sunix);
    472       1.1  christos 	sockaddr->type.sunix.sun_family = AF_UNIX;
    473       1.1  christos 	strlcpy(sockaddr->type.sunix.sun_path, path,
    474       1.1  christos 		sizeof(sockaddr->type.sunix.sun_path));
    475       1.1  christos 	return (ISC_R_SUCCESS);
    476   1.1.1.7  christos }
    477   1.1.1.7  christos 
    478   1.1.1.7  christos isc_result_t
    479   1.1.1.7  christos isc_sockaddr_fromsockaddr(isc_sockaddr_t *isa, const struct sockaddr *sa) {
    480   1.1.1.7  christos 	unsigned int length = 0;
    481   1.1.1.7  christos 
    482   1.1.1.7  christos 	switch (sa->sa_family) {
    483   1.1.1.7  christos 	case AF_INET:
    484   1.1.1.7  christos 		length = sizeof(isa->type.sin);
    485   1.1.1.7  christos 		break;
    486   1.1.1.7  christos 	case AF_INET6:
    487   1.1.1.7  christos 		length = sizeof(isa->type.sin6);
    488   1.1.1.7  christos 		break;
    489   1.1.1.7  christos 	case AF_UNIX:
    490   1.1.1.7  christos 		length = sizeof(isa->type.sunix);
    491   1.1.1.7  christos 		break;
    492   1.1.1.7  christos 	default:
    493   1.1.1.7  christos 		return (ISC_R_NOTIMPLEMENTED);
    494   1.1.1.7  christos 	}
    495   1.1.1.7  christos 
    496   1.1.1.7  christos 	memset(isa, 0, sizeof(isc_sockaddr_t));
    497   1.1.1.8  christos 	memmove(isa, sa, length);
    498   1.1.1.7  christos 	isa->length = length;
    499   1.1.1.7  christos 
    500   1.1.1.7  christos 	return (ISC_R_SUCCESS);
    501       1.1  christos }
    502  1.1.1.11  christos 
    503  1.1.1.11  christos bool
    504  1.1.1.11  christos isc_sockaddr_disabled(const isc_sockaddr_t *sockaddr) {
    505  1.1.1.11  christos 	if ((sockaddr->type.sa.sa_family == AF_INET &&
    506  1.1.1.11  christos 	     isc_net_probeipv4() == ISC_R_DISABLED) ||
    507  1.1.1.11  christos 	    (sockaddr->type.sa.sa_family == AF_INET6 &&
    508  1.1.1.11  christos 	     isc_net_probeipv6() == ISC_R_DISABLED))
    509  1.1.1.11  christos 	{
    510  1.1.1.11  christos 		return (true);
    511  1.1.1.11  christos 	}
    512  1.1.1.11  christos 	return (false);
    513  1.1.1.11  christos }
    514