xref: /dragonfly/contrib/dhcpcd/src/sa.c (revision a3f29142)
1 /*
2  * Socket Address handling for dhcpcd
3  * Copyright (c) 2015-2018 Roy Marples <roy@marples.name>
4  * All rights reserved
5 
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/socket.h>
29 #include <sys/types.h>
30 
31 #include <arpa/inet.h>
32 #ifdef AF_LINK
33 #include <net/if_dl.h>
34 #elif AF_PACKET
35 #include <linux/if_packet.h>
36 #endif
37 
38 #include <assert.h>
39 #include <errno.h>
40 #include <stddef.h>
41 #include <stdio.h>
42 #include <stdint.h>
43 #include <string.h>
44 
45 #include "config.h"
46 #include "common.h"
47 #include "sa.h"
48 
49 #ifndef NDEBUG
50 static bool sa_inprefix;
51 #endif
52 
53 socklen_t
54 sa_addroffset(const struct sockaddr *sa)
55 {
56 
57 	assert(sa != NULL);
58 	switch(sa->sa_family) {
59 #ifdef INET
60 	case AF_INET:
61 		return offsetof(struct sockaddr_in, sin_addr) +
62 		       offsetof(struct in_addr, s_addr);
63 #endif /* INET */
64 #ifdef INET6
65 	case AF_INET6:
66 		return offsetof(struct sockaddr_in6, sin6_addr) +
67 		       offsetof(struct in6_addr, s6_addr);
68 #endif /* INET6 */
69 	default:
70 		errno = EAFNOSUPPORT;
71 		return 0;
72 	}
73 }
74 
75 socklen_t
76 sa_addrlen(const struct sockaddr *sa)
77 {
78 #define membersize(type, member) sizeof(((type *)0)->member)
79 	assert(sa != NULL);
80 	switch(sa->sa_family) {
81 #ifdef INET
82 	case AF_INET:
83 		return membersize(struct in_addr, s_addr);
84 #endif /* INET */
85 #ifdef INET6
86 	case AF_INET6:
87 		return membersize(struct in6_addr, s6_addr);
88 #endif /* INET6 */
89 	default:
90 		errno = EAFNOSUPPORT;
91 		return 0;
92 	}
93 }
94 
95 bool
96 sa_is_unspecified(const struct sockaddr *sa)
97 {
98 
99 	assert(sa != NULL);
100 	switch(sa->sa_family) {
101 	case AF_UNSPEC:
102 		return true;
103 #ifdef INET
104 	case AF_INET:
105 		return satocsin(sa)->sin_addr.s_addr == INADDR_ANY;
106 #endif /* INET */
107 #ifdef INET6
108 	case AF_INET6:
109 		return IN6_IS_ADDR_UNSPECIFIED(&satocsin6(sa)->sin6_addr);
110 #endif /* INET6 */
111 	default:
112 		errno = EAFNOSUPPORT;
113 		return false;
114 	}
115 }
116 
117 #ifdef INET6
118 #ifndef IN6MASK128
119 #define IN6MASK128 {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
120 		       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}}
121 #endif
122 static const struct in6_addr in6allones = IN6MASK128;
123 #endif
124 
125 bool
126 sa_is_allones(const struct sockaddr *sa)
127 {
128 
129 	assert(sa != NULL);
130 	switch(sa->sa_family) {
131 	case AF_UNSPEC:
132 		return false;
133 #ifdef INET
134 	case AF_INET:
135 	{
136 		const struct sockaddr_in *sin;
137 
138 		sin = satocsin(sa);
139 		return sin->sin_addr.s_addr == INADDR_BROADCAST;
140 	}
141 #endif /* INET */
142 #ifdef INET6
143 	case AF_INET6:
144 	{
145 		const struct sockaddr_in6 *sin6;
146 
147 		sin6 = satocsin6(sa);
148 		return IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &in6allones);
149 	}
150 #endif /* INET6 */
151 	default:
152 		errno = EAFNOSUPPORT;
153 		return false;
154 	}
155 }
156 
157 bool
158 sa_is_loopback(const struct sockaddr *sa)
159 {
160 
161 	assert(sa != NULL);
162 	switch(sa->sa_family) {
163 	case AF_UNSPEC:
164 		return false;
165 #ifdef INET
166 	case AF_INET:
167 	{
168 		const struct sockaddr_in *sin;
169 
170 		sin = satocsin(sa);
171 		return sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK);
172 	}
173 #endif /* INET */
174 #ifdef INET6
175 	case AF_INET6:
176 	{
177 		const struct sockaddr_in6 *sin6;
178 
179 		sin6 = satocsin6(sa);
180 		return IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr);
181 	}
182 #endif /* INET6 */
183 	default:
184 		errno = EAFNOSUPPORT;
185 		return false;
186 	}
187 }
188 
189 int
190 sa_toprefix(const struct sockaddr *sa)
191 {
192 	int prefix;
193 
194 	assert(sa != NULL);
195 	switch(sa->sa_family) {
196 #ifdef INET
197 	case AF_INET:
198 	{
199 		const struct sockaddr_in *sin;
200 		uint32_t mask;
201 
202 		sin = satocsin(sa);
203 		if (sin->sin_addr.s_addr == INADDR_ANY) {
204 			prefix = 0;
205 			break;
206 		}
207 		mask = ntohl(sin->sin_addr.s_addr);
208 		prefix = 33 - ffs((int)mask);	/* 33 - (1 .. 32) -> 32 .. 1 */
209 		if (prefix < 32) {		/* more than 1 bit in mask */
210 			/* check for non-contig netmask */
211 			if ((mask^(((1U << prefix)-1) << (32 - prefix))) != 0) {
212 				errno = EINVAL;
213 				return -1;	/* noncontig, no pfxlen */
214 			}
215 		}
216 		break;
217 	}
218 #endif
219 #ifdef INET6
220 	case AF_INET6:
221 	{
222 		const struct sockaddr_in6 *sin6;
223 		int x, y;
224 		const uint8_t *lim, *p;
225 
226 		sin6 = satocsin6(sa);
227 		p = (const uint8_t *)sin6->sin6_addr.s6_addr;
228 		lim = p + sizeof(sin6->sin6_addr.s6_addr);
229 		for (x = 0; p < lim; x++, p++) {
230 			if (*p != 0xff)
231 				break;
232 		}
233 		y = 0;
234 		if (p < lim) {
235 			for (y = 0; y < NBBY; y++) {
236 				if ((*p & (0x80 >> y)) == 0)
237 					break;
238 			}
239 		}
240 
241 		/*
242 		 * when the limit pointer is given, do a stricter check on the
243 		 * remaining bits.
244 		 */
245 		if (p < lim) {
246 			if (y != 0 && (*p & (0x00ff >> y)) != 0)
247 				return 0;
248 			for (p = p + 1; p < lim; p++)
249 				if (*p != 0)
250 					return 0;
251 		}
252 
253 		prefix = x * NBBY + y;
254 		break;
255 	}
256 #endif
257 	default:
258 		errno = EAFNOSUPPORT;
259 		return -1;
260 	}
261 
262 #ifndef NDEBUG
263 	/* Ensure the calculation is correct */
264 	if (!sa_inprefix) {
265 		union sa_ss ss;
266 
267 		sa_inprefix = true;
268 		memset(&ss, 0, sizeof(ss));
269 		ss.sa.sa_family = sa->sa_family;
270 		sa_fromprefix(&ss.sa, prefix);
271 		assert(sa_cmp(sa, &ss.sa) == 0);
272 		sa_inprefix = false;
273 	}
274 #endif
275 
276 	return prefix;
277 }
278 
279 int
280 sa_fromprefix(struct sockaddr *sa, int prefix)
281 {
282 	uint8_t *ap;
283 	int max_prefix, bytes, bits, i;
284 
285 	switch (sa->sa_family) {
286 #ifdef INET
287 	case AF_INET:
288 		max_prefix = 32;
289 #ifdef HAVE_SA_LEN
290 		sa->sa_len = sizeof(struct sockaddr_in);
291 #endif
292 		break;
293 #endif
294 #ifdef INET6
295 	case AF_INET6:
296 		max_prefix = 128;
297 #ifdef HAVE_SA_LEN
298 		sa->sa_len = sizeof(struct sockaddr_in6);
299 #endif
300 		break;
301 #endif
302 	default:
303 		errno = EAFNOSUPPORT;
304 		return -1;
305 	}
306 
307 	bytes = prefix / NBBY;
308 	bits = prefix % NBBY;
309 
310 	ap = (uint8_t *)sa + sa_addroffset(sa);
311 	for (i = 0; i < bytes; i++)
312 		*ap++ = 0xff;
313 	if (bits) {
314 		uint8_t a;
315 
316 		a = 0xff;
317 		a  = (uint8_t)(a << (8 - bits));
318 		*ap++ = a;
319 	}
320 	bytes = (max_prefix - prefix) / NBBY;
321 	for (i = 0; i < bytes; i++)
322 		*ap++ = 0x00;
323 
324 #ifndef NDEBUG
325 	/* Ensure the calculation is correct */
326 	if (!sa_inprefix) {
327 		sa_inprefix = true;
328 		assert(sa_toprefix(sa) == prefix);
329 		sa_inprefix = false;
330 	}
331 #endif
332 	return 0;
333 }
334 
335 /* inet_ntop, but for sockaddr. */
336 const char *
337 sa_addrtop(const struct sockaddr *sa, char *buf, socklen_t len)
338 {
339 	const void *addr;
340 
341 	assert(buf != NULL);
342 #ifdef AF_LINK
343 #ifndef CLLADDR
344 #define CLLADDR(sdl) (const void *)((sdl)->sdl_data + (sdl)->sdl_nlen)
345 #endif
346 	if (sa->sa_family == AF_LINK) {
347 		const struct sockaddr_dl *sdl;
348 
349 		sdl = (const void *)sa;
350 		if (sdl->sdl_alen == 0) {
351 			if (snprintf(buf, len, "link#%d", sdl->sdl_index) == -1)
352 				return NULL;
353 			return buf;
354 		}
355 		return hwaddr_ntoa(CLLADDR(sdl), sdl->sdl_alen, buf, len);
356 	}
357 #elif AF_PACKET
358 	if (sa->sa_family == AF_PACKET) {
359 		const struct sockaddr_ll *sll;
360 
361 		sll = (const void *)sa;
362 		return hwaddr_ntoa(sll->sll_addr, sll->sll_halen, buf, len);
363 	}
364 #endif
365 	addr = (const char *)sa + sa_addroffset(sa);
366 	return inet_ntop(sa->sa_family, addr, buf, len);
367 }
368 
369 int
370 sa_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2)
371 {
372 	socklen_t offset, len;
373 
374 	assert(sa1 != NULL);
375 	assert(sa2 != NULL);
376 
377 	/* Treat AF_UNSPEC as the unspecified address. */
378 	if ((sa1->sa_family == AF_UNSPEC || sa2->sa_family == AF_UNSPEC) &&
379 	    sa_is_unspecified(sa1) && sa_is_unspecified(sa2))
380 		return 0;
381 
382 	if (sa1->sa_family != sa2->sa_family)
383 		return sa1->sa_family - sa2->sa_family;
384 
385 #ifdef HAVE_SA_LEN
386 	len = MIN(sa1->sa_len, sa2->sa_len);
387 #endif
388 
389 	switch (sa1->sa_family) {
390 #ifdef INET
391 	case AF_INET:
392 		offset = offsetof(struct sockaddr_in, sin_addr);
393 #ifdef HAVE_SA_LEN
394 		len -= offset;
395 		len = MIN(len, sizeof(struct in_addr));
396 #else
397 		len = sizeof(struct in_addr);
398 #endif
399 		break;
400 #endif
401 #ifdef INET6
402 	case AF_INET6:
403 		offset = offsetof(struct sockaddr_in6, sin6_addr);
404 #ifdef HAVE_SA_LEN
405 		len -= offset;
406 		len = MIN(len, sizeof(struct in6_addr));
407 #else
408 		len = sizeof(struct in6_addr);
409 #endif
410 		break;
411 #endif
412 	default:
413 		offset = 0;
414 #ifndef HAVE_SA_LEN
415 		len = sizeof(struct sockaddr);
416 #endif
417 		break;
418 	}
419 
420 	return memcmp((const char *)sa1 + offset,
421 	    (const char *)sa2 + offset,
422 	    len);
423 }
424 
425 #ifdef INET
426 void
427 sa_in_init(struct sockaddr *sa, const struct in_addr *addr)
428 {
429 	struct sockaddr_in *sin;
430 
431 	assert(sa != NULL);
432 	assert(addr != NULL);
433 	sin = satosin(sa);
434 	sin->sin_family = AF_INET;
435 #ifdef HAVE_SA_LEN
436 	sin->sin_len = sizeof(*sin);
437 #endif
438 	sin->sin_addr.s_addr = addr->s_addr;
439 }
440 #endif
441 
442 #ifdef INET6
443 void
444 sa_in6_init(struct sockaddr *sa, const struct in6_addr *addr)
445 {
446 	struct sockaddr_in6 *sin6;
447 
448 	assert(sa != NULL);
449 	assert(addr != NULL);
450 	sin6 = satosin6(sa);
451 	sin6->sin6_family = AF_INET6;
452 #ifdef HAVE_SA_LEN
453 	sin6->sin6_len = sizeof(*sin6);
454 #endif
455 	memcpy(&sin6->sin6_addr.s6_addr, &addr->s6_addr,
456 	    sizeof(sin6->sin6_addr.s6_addr));
457 }
458 #endif
459