xref: /openbsd/usr.bin/dig/lib/isc/sockaddr.c (revision 4cfece93)
1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14  * PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /* $Id: sockaddr.c,v 1.7 2020/02/25 05:00:43 jsg Exp $ */
18 
19 /*! \file */
20 
21 #include <stdio.h>
22 
23 #include <isc/buffer.h>
24 #include <isc/netaddr.h>
25 
26 #include <isc/region.h>
27 #include <isc/sockaddr.h>
28 #include <string.h>
29 #include <isc/util.h>
30 
31 isc_boolean_t
32 isc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
33 	return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
34 					   ISC_SOCKADDR_CMPPORT|
35 					   ISC_SOCKADDR_CMPSCOPE));
36 }
37 
38 isc_boolean_t
39 isc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b) {
40 	return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR|
41 					   ISC_SOCKADDR_CMPSCOPE));
42 }
43 
44 isc_boolean_t
45 isc_sockaddr_compare(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
46 		     unsigned int flags)
47 {
48 	REQUIRE(a != NULL && b != NULL);
49 
50 	if (a->length != b->length)
51 		return (ISC_FALSE);
52 
53 	/*
54 	 * We don't just memcmp because the sin_zero field isn't always
55 	 * zero.
56 	 */
57 
58 	if (a->type.sa.sa_family != b->type.sa.sa_family)
59 		return (ISC_FALSE);
60 	switch (a->type.sa.sa_family) {
61 	case AF_INET:
62 		if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
63 		    memcmp(&a->type.sin.sin_addr, &b->type.sin.sin_addr,
64 			   sizeof(a->type.sin.sin_addr)) != 0)
65 			return (ISC_FALSE);
66 		if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
67 		    a->type.sin.sin_port != b->type.sin.sin_port)
68 			return (ISC_FALSE);
69 		break;
70 	case AF_INET6:
71 		if ((flags & ISC_SOCKADDR_CMPADDR) != 0 &&
72 		    memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr,
73 			   sizeof(a->type.sin6.sin6_addr)) != 0)
74 			return (ISC_FALSE);
75 		/*
76 		 * If ISC_SOCKADDR_CMPSCOPEZERO is set then don't return
77 		 * ISC_FALSE if one of the scopes in zero.
78 		 */
79 		if ((flags & ISC_SOCKADDR_CMPSCOPE) != 0 &&
80 		    a->type.sin6.sin6_scope_id != b->type.sin6.sin6_scope_id &&
81 		    ((flags & ISC_SOCKADDR_CMPSCOPEZERO) == 0 ||
82 		      (a->type.sin6.sin6_scope_id != 0 &&
83 		       b->type.sin6.sin6_scope_id != 0)))
84 			return (ISC_FALSE);
85 		if ((flags & ISC_SOCKADDR_CMPPORT) != 0 &&
86 		    a->type.sin6.sin6_port != b->type.sin6.sin6_port)
87 			return (ISC_FALSE);
88 		break;
89 	default:
90 		if (memcmp(&a->type, &b->type, a->length) != 0)
91 			return (ISC_FALSE);
92 	}
93 	return (ISC_TRUE);
94 }
95 
96 isc_result_t
97 isc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target) {
98 	isc_result_t result;
99 	isc_netaddr_t netaddr;
100 	char pbuf[sizeof("65000")];
101 	unsigned int plen;
102 	isc_region_t avail;
103 
104 	REQUIRE(sockaddr != NULL);
105 
106 	/*
107 	 * Do the port first, giving us the opportunity to check for
108 	 * unsupported address families before calling
109 	 * isc_netaddr_fromsockaddr().
110 	 */
111 	switch (sockaddr->type.sa.sa_family) {
112 	case AF_INET:
113 		snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin.sin_port));
114 		break;
115 	case AF_INET6:
116 		snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin6.sin6_port));
117 		break;
118 	default:
119 		return (ISC_R_FAILURE);
120 	}
121 
122 	plen = strlen(pbuf);
123 	INSIST(plen < sizeof(pbuf));
124 
125 	isc_netaddr_fromsockaddr(&netaddr, sockaddr);
126 	result = isc_netaddr_totext(&netaddr, target);
127 	if (result != ISC_R_SUCCESS)
128 		return (result);
129 
130 	if (1 + plen + 1 > isc_buffer_availablelength(target))
131 		return (ISC_R_NOSPACE);
132 
133 	isc_buffer_putmem(target, (const unsigned char *)"#", 1);
134 	isc_buffer_putmem(target, (const unsigned char *)pbuf, plen);
135 
136 	/*
137 	 * Null terminate after used region.
138 	 */
139 	isc_buffer_availableregion(target, &avail);
140 	INSIST(avail.length >= 1);
141 	avail.base[0] = '\0';
142 
143 	return (ISC_R_SUCCESS);
144 }
145 
146 void
147 isc_sockaddr_format(const isc_sockaddr_t *sa, char *array, unsigned int size) {
148 	isc_result_t result;
149 	isc_buffer_t buf;
150 
151 	if (size == 0U)
152 		return;
153 
154 	isc_buffer_init(&buf, array, size);
155 	result = isc_sockaddr_totext(sa, &buf);
156 	if (result != ISC_R_SUCCESS) {
157 		/*
158 		 * The message is the same as in netaddr.c.
159 		 */
160 		snprintf(array, size, "<unknown address, family %u>",
161 			 sa->type.sa.sa_family);
162 		array[size - 1] = '\0';
163 	}
164 }
165 
166 void
167 isc_sockaddr_any(isc_sockaddr_t *sockaddr)
168 {
169 	memset(sockaddr, 0, sizeof(*sockaddr));
170 	sockaddr->type.sin.sin_family = AF_INET;
171 	sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
172 	sockaddr->type.sin.sin_addr.s_addr = INADDR_ANY;
173 	sockaddr->type.sin.sin_port = 0;
174 	sockaddr->length = sizeof(sockaddr->type.sin);
175 	ISC_LINK_INIT(sockaddr, link);
176 }
177 
178 void
179 isc_sockaddr_any6(isc_sockaddr_t *sockaddr)
180 {
181 	memset(sockaddr, 0, sizeof(*sockaddr));
182 	sockaddr->type.sin6.sin6_family = AF_INET6;
183 	sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
184 	sockaddr->type.sin6.sin6_addr = in6addr_any;
185 	sockaddr->type.sin6.sin6_port = 0;
186 	sockaddr->length = sizeof(sockaddr->type.sin6);
187 	ISC_LINK_INIT(sockaddr, link);
188 }
189 
190 void
191 isc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina,
192 		    in_port_t port)
193 {
194 	memset(sockaddr, 0, sizeof(*sockaddr));
195 	sockaddr->type.sin.sin_family = AF_INET;
196 	sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin);
197 	sockaddr->type.sin.sin_addr = *ina;
198 	sockaddr->type.sin.sin_port = htons(port);
199 	sockaddr->length = sizeof(sockaddr->type.sin);
200 	ISC_LINK_INIT(sockaddr, link);
201 }
202 
203 void
204 isc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int pf) {
205      switch (pf) {
206      case AF_INET:
207 	     isc_sockaddr_any(sockaddr);
208 	     break;
209      case AF_INET6:
210 	     isc_sockaddr_any6(sockaddr);
211 	     break;
212      default:
213 	     INSIST(0);
214      }
215 }
216 
217 void
218 isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6,
219 		     in_port_t port)
220 {
221 	memset(sockaddr, 0, sizeof(*sockaddr));
222 	sockaddr->type.sin6.sin6_family = AF_INET6;
223 	sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6);
224 	sockaddr->type.sin6.sin6_addr = *ina6;
225 	sockaddr->type.sin6.sin6_port = htons(port);
226 	sockaddr->length = sizeof(sockaddr->type.sin6);
227 	ISC_LINK_INIT(sockaddr, link);
228 }
229 
230 int
231 isc_sockaddr_pf(const isc_sockaddr_t *sockaddr) {
232 
233 	/*
234 	 * Get the protocol family of 'sockaddr'.
235 	 */
236 
237 	return (sockaddr->type.sa.sa_family);
238 }
239 
240 in_port_t
241 isc_sockaddr_getport(const isc_sockaddr_t *sockaddr) {
242 	in_port_t port = 0;
243 
244 	switch (sockaddr->type.sa.sa_family) {
245 	case AF_INET:
246 		port = ntohs(sockaddr->type.sin.sin_port);
247 		break;
248 	case AF_INET6:
249 		port = ntohs(sockaddr->type.sin6.sin6_port);
250 		break;
251 	default:
252 		FATAL_ERROR(__FILE__, __LINE__,
253 			    "unknown address family: %d",
254 			    (int)sockaddr->type.sa.sa_family);
255 	}
256 
257 	return (port);
258 }
259 
260 isc_boolean_t
261 isc_sockaddr_ismulticast(const isc_sockaddr_t *sockaddr) {
262 	isc_netaddr_t netaddr;
263 
264 	if (sockaddr->type.sa.sa_family == AF_INET ||
265 	    sockaddr->type.sa.sa_family == AF_INET6) {
266 		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
267 		return (isc_netaddr_ismulticast(&netaddr));
268 	}
269 	return (ISC_FALSE);
270 }
271 
272 isc_boolean_t
273 isc_sockaddr_issitelocal(const isc_sockaddr_t *sockaddr) {
274 	isc_netaddr_t netaddr;
275 
276 	if (sockaddr->type.sa.sa_family == AF_INET6) {
277 		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
278 		return (isc_netaddr_issitelocal(&netaddr));
279 	}
280 	return (ISC_FALSE);
281 }
282 
283 isc_boolean_t
284 isc_sockaddr_islinklocal(const isc_sockaddr_t *sockaddr) {
285 	isc_netaddr_t netaddr;
286 
287 	if (sockaddr->type.sa.sa_family == AF_INET6) {
288 		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
289 		return (isc_netaddr_islinklocal(&netaddr));
290 	}
291 	return (ISC_FALSE);
292 }
293