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