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