]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/in-addr-util.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / basic / in-addr-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2014 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <arpa/inet.h>
22 #include <endian.h>
23 #include <errno.h>
24 #include <net/if.h>
25 #include <stdint.h>
26 #include <stdlib.h>
27
28 #include "alloc-util.h"
29 #include "in-addr-util.h"
30 #include "macro.h"
31 #include "parse-util.h"
32 #include "util.h"
33
34 bool in4_addr_is_null(const struct in_addr *a) {
35 assert(a);
36
37 return a->s_addr == 0;
38 }
39
40 int in_addr_is_null(int family, const union in_addr_union *u) {
41 assert(u);
42
43 if (family == AF_INET)
44 return in4_addr_is_null(&u->in);
45
46 if (family == AF_INET6)
47 return IN6_IS_ADDR_UNSPECIFIED(&u->in6);
48
49 return -EAFNOSUPPORT;
50 }
51
52 bool in4_addr_is_link_local(const struct in_addr *a) {
53 assert(a);
54
55 return (be32toh(a->s_addr) & UINT32_C(0xFFFF0000)) == (UINT32_C(169) << 24 | UINT32_C(254) << 16);
56 }
57
58 int in_addr_is_link_local(int family, const union in_addr_union *u) {
59 assert(u);
60
61 if (family == AF_INET)
62 return in4_addr_is_link_local(&u->in);
63
64 if (family == AF_INET6)
65 return IN6_IS_ADDR_LINKLOCAL(&u->in6);
66
67 return -EAFNOSUPPORT;
68 }
69
70 int in_addr_is_multicast(int family, const union in_addr_union *u) {
71 assert(u);
72
73 if (family == AF_INET)
74 return IN_MULTICAST(be32toh(u->in.s_addr));
75
76 if (family == AF_INET6)
77 return IN6_IS_ADDR_MULTICAST(&u->in6);
78
79 return -EAFNOSUPPORT;
80 }
81
82 bool in4_addr_is_localhost(const struct in_addr *a) {
83 assert(a);
84
85 /* All of 127.x.x.x is localhost. */
86 return (be32toh(a->s_addr) & UINT32_C(0xFF000000)) == UINT32_C(127) << 24;
87 }
88
89 int in_addr_is_localhost(int family, const union in_addr_union *u) {
90 assert(u);
91
92 if (family == AF_INET)
93 return in4_addr_is_localhost(&u->in);
94
95 if (family == AF_INET6)
96 return IN6_IS_ADDR_LOOPBACK(&u->in6);
97
98 return -EAFNOSUPPORT;
99 }
100
101 int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b) {
102 assert(a);
103 assert(b);
104
105 if (family == AF_INET)
106 return a->in.s_addr == b->in.s_addr;
107
108 if (family == AF_INET6)
109 return
110 a->in6.s6_addr32[0] == b->in6.s6_addr32[0] &&
111 a->in6.s6_addr32[1] == b->in6.s6_addr32[1] &&
112 a->in6.s6_addr32[2] == b->in6.s6_addr32[2] &&
113 a->in6.s6_addr32[3] == b->in6.s6_addr32[3];
114
115 return -EAFNOSUPPORT;
116 }
117
118 int in_addr_prefix_intersect(
119 int family,
120 const union in_addr_union *a,
121 unsigned aprefixlen,
122 const union in_addr_union *b,
123 unsigned bprefixlen) {
124
125 unsigned m;
126
127 assert(a);
128 assert(b);
129
130 /* Checks whether there are any addresses that are in both
131 * networks */
132
133 m = MIN(aprefixlen, bprefixlen);
134
135 if (family == AF_INET) {
136 uint32_t x, nm;
137
138 x = be32toh(a->in.s_addr ^ b->in.s_addr);
139 nm = (m == 0) ? 0 : 0xFFFFFFFFUL << (32 - m);
140
141 return (x & nm) == 0;
142 }
143
144 if (family == AF_INET6) {
145 unsigned i;
146
147 if (m > 128)
148 m = 128;
149
150 for (i = 0; i < 16; i++) {
151 uint8_t x, nm;
152
153 x = a->in6.s6_addr[i] ^ b->in6.s6_addr[i];
154
155 if (m < 8)
156 nm = 0xFF << (8 - m);
157 else
158 nm = 0xFF;
159
160 if ((x & nm) != 0)
161 return 0;
162
163 if (m > 8)
164 m -= 8;
165 else
166 m = 0;
167 }
168
169 return 1;
170 }
171
172 return -EAFNOSUPPORT;
173 }
174
175 int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen) {
176 assert(u);
177
178 /* Increases the network part of an address by one. Returns
179 * positive it that succeeds, or 0 if this overflows. */
180
181 if (prefixlen <= 0)
182 return 0;
183
184 if (family == AF_INET) {
185 uint32_t c, n;
186
187 if (prefixlen > 32)
188 prefixlen = 32;
189
190 c = be32toh(u->in.s_addr);
191 n = c + (1UL << (32 - prefixlen));
192 if (n < c)
193 return 0;
194 n &= 0xFFFFFFFFUL << (32 - prefixlen);
195
196 u->in.s_addr = htobe32(n);
197 return 1;
198 }
199
200 if (family == AF_INET6) {
201 struct in6_addr add = {}, result;
202 uint8_t overflow = 0;
203 unsigned i;
204
205 if (prefixlen > 128)
206 prefixlen = 128;
207
208 /* First calculate what we have to add */
209 add.s6_addr[(prefixlen-1) / 8] = 1 << (7 - (prefixlen-1) % 8);
210
211 for (i = 16; i > 0; i--) {
212 unsigned j = i - 1;
213
214 result.s6_addr[j] = u->in6.s6_addr[j] + add.s6_addr[j] + overflow;
215 overflow = (result.s6_addr[j] < u->in6.s6_addr[j]);
216 }
217
218 if (overflow)
219 return 0;
220
221 u->in6 = result;
222 return 1;
223 }
224
225 return -EAFNOSUPPORT;
226 }
227
228 int in_addr_to_string(int family, const union in_addr_union *u, char **ret) {
229 char *x;
230 size_t l;
231
232 assert(u);
233 assert(ret);
234
235 if (family == AF_INET)
236 l = INET_ADDRSTRLEN;
237 else if (family == AF_INET6)
238 l = INET6_ADDRSTRLEN;
239 else
240 return -EAFNOSUPPORT;
241
242 x = new(char, l);
243 if (!x)
244 return -ENOMEM;
245
246 errno = 0;
247 if (!inet_ntop(family, u, x, l)) {
248 free(x);
249 return errno > 0 ? -errno : -EINVAL;
250 }
251
252 *ret = x;
253 return 0;
254 }
255
256 int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret) {
257 size_t l;
258 char *x;
259 int r;
260
261 assert(u);
262 assert(ret);
263
264 /* Much like in_addr_to_string(), but optionally appends the zone interface index to the address, to properly
265 * handle IPv6 link-local addresses. */
266
267 if (family != AF_INET6)
268 goto fallback;
269 if (ifindex <= 0)
270 goto fallback;
271
272 r = in_addr_is_link_local(family, u);
273 if (r < 0)
274 return r;
275 if (r == 0)
276 goto fallback;
277
278 l = INET6_ADDRSTRLEN + 1 + DECIMAL_STR_MAX(ifindex) + 1;
279 x = new(char, l);
280 if (!x)
281 return -ENOMEM;
282
283 errno = 0;
284 if (!inet_ntop(family, u, x, l)) {
285 free(x);
286 return errno > 0 ? -errno : -EINVAL;
287 }
288
289 sprintf(strchr(x, 0), "%%%i", ifindex);
290 *ret = x;
291
292 return 0;
293
294 fallback:
295 return in_addr_to_string(family, u, ret);
296 }
297
298 int in_addr_from_string(int family, const char *s, union in_addr_union *ret) {
299 union in_addr_union buffer;
300 assert(s);
301
302 if (!IN_SET(family, AF_INET, AF_INET6))
303 return -EAFNOSUPPORT;
304
305 errno = 0;
306 if (inet_pton(family, s, ret ?: &buffer) <= 0)
307 return errno > 0 ? -errno : -EINVAL;
308
309 return 0;
310 }
311
312 int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret) {
313 int r;
314
315 assert(s);
316
317 r = in_addr_from_string(AF_INET, s, ret);
318 if (r >= 0) {
319 if (ret_family)
320 *ret_family = AF_INET;
321 return 0;
322 }
323
324 r = in_addr_from_string(AF_INET6, s, ret);
325 if (r >= 0) {
326 if (ret_family)
327 *ret_family = AF_INET6;
328 return 0;
329 }
330
331 return -EINVAL;
332 }
333
334 int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex) {
335 const char *suffix;
336 int r, ifi = 0;
337
338 assert(s);
339 assert(family);
340 assert(ret);
341
342 /* Similar to in_addr_from_string_auto() but also parses an optionally appended IPv6 zone suffix ("scope id")
343 * if one is found. */
344
345 suffix = strchr(s, '%');
346 if (suffix) {
347
348 if (ifindex) {
349 /* If we shall return the interface index, try to parse it */
350 r = parse_ifindex(suffix + 1, &ifi);
351 if (r < 0) {
352 unsigned u;
353
354 u = if_nametoindex(suffix + 1);
355 if (u <= 0)
356 return -errno;
357
358 ifi = (int) u;
359 }
360 }
361
362 s = strndupa(s, suffix - s);
363 }
364
365 r = in_addr_from_string_auto(s, family, ret);
366 if (r < 0)
367 return r;
368
369 if (ifindex)
370 *ifindex = ifi;
371
372 return r;
373 }
374
375 unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr) {
376 assert(addr);
377
378 return 32 - u32ctz(be32toh(addr->s_addr));
379 }
380
381 struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen) {
382 assert(addr);
383 assert(prefixlen <= 32);
384
385 /* Shifting beyond 32 is not defined, handle this specially. */
386 if (prefixlen == 0)
387 addr->s_addr = 0;
388 else
389 addr->s_addr = htobe32((0xffffffff << (32 - prefixlen)) & 0xffffffff);
390
391 return addr;
392 }
393
394 int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) {
395 uint8_t msb_octet = *(uint8_t*) addr;
396
397 /* addr may not be aligned, so make sure we only access it byte-wise */
398
399 assert(addr);
400 assert(prefixlen);
401
402 if (msb_octet < 128)
403 /* class A, leading bits: 0 */
404 *prefixlen = 8;
405 else if (msb_octet < 192)
406 /* class B, leading bits 10 */
407 *prefixlen = 16;
408 else if (msb_octet < 224)
409 /* class C, leading bits 110 */
410 *prefixlen = 24;
411 else
412 /* class D or E, no default prefixlen */
413 return -ERANGE;
414
415 return 0;
416 }
417
418 int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask) {
419 unsigned char prefixlen;
420 int r;
421
422 assert(addr);
423 assert(mask);
424
425 r = in4_addr_default_prefixlen(addr, &prefixlen);
426 if (r < 0)
427 return r;
428
429 in4_addr_prefixlen_to_netmask(mask, prefixlen);
430 return 0;
431 }
432
433 int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen) {
434 assert(addr);
435
436 if (family == AF_INET) {
437 struct in_addr mask;
438
439 if (!in4_addr_prefixlen_to_netmask(&mask, prefixlen))
440 return -EINVAL;
441
442 addr->in.s_addr &= mask.s_addr;
443 return 0;
444 }
445
446 if (family == AF_INET6) {
447 unsigned i;
448
449 for (i = 0; i < 16; i++) {
450 uint8_t mask;
451
452 if (prefixlen >= 8) {
453 mask = 0xFF;
454 prefixlen -= 8;
455 } else {
456 mask = 0xFF << (8 - prefixlen);
457 prefixlen = 0;
458 }
459
460 addr->in6.s6_addr[i] &= mask;
461 }
462
463 return 0;
464 }
465
466 return -EAFNOSUPPORT;
467 }
468
469 int in_addr_prefix_covers(int family,
470 const union in_addr_union *prefix,
471 unsigned char prefixlen,
472 const union in_addr_union *address) {
473
474 union in_addr_union masked_prefix, masked_address;
475 int r;
476
477 assert(prefix);
478 assert(address);
479
480 masked_prefix = *prefix;
481 r = in_addr_mask(family, &masked_prefix, prefixlen);
482 if (r < 0)
483 return r;
484
485 masked_address = *address;
486 r = in_addr_mask(family, &masked_address, prefixlen);
487 if (r < 0)
488 return r;
489
490 return in_addr_equal(family, &masked_prefix, &masked_address);
491 }
492
493 int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret) {
494 uint8_t u;
495 int r;
496
497 if (!IN_SET(family, AF_INET, AF_INET6))
498 return -EAFNOSUPPORT;
499
500 r = safe_atou8(p, &u);
501 if (r < 0)
502 return r;
503
504 if (u > FAMILY_ADDRESS_SIZE(family) * 8)
505 return -ERANGE;
506
507 *ret = u;
508 return 0;
509 }
510
511 int in_addr_prefix_from_string(
512 const char *p,
513 int family,
514 union in_addr_union *ret_prefix,
515 unsigned char *ret_prefixlen) {
516
517 union in_addr_union buffer;
518 const char *e, *l;
519 unsigned char k;
520 int r;
521
522 assert(p);
523
524 if (!IN_SET(family, AF_INET, AF_INET6))
525 return -EAFNOSUPPORT;
526
527 e = strchr(p, '/');
528 if (e)
529 l = strndupa(p, e - p);
530 else
531 l = p;
532
533 r = in_addr_from_string(family, l, &buffer);
534 if (r < 0)
535 return r;
536
537 if (e) {
538 r = in_addr_parse_prefixlen(family, e+1, &k);
539 if (r < 0)
540 return r;
541 } else
542 k = FAMILY_ADDRESS_SIZE(family) * 8;
543
544 if (ret_prefix)
545 *ret_prefix = buffer;
546 if (ret_prefixlen)
547 *ret_prefixlen = k;
548
549 return 0;
550 }
551
552 int in_addr_prefix_from_string_auto(
553 const char *p,
554 int *ret_family,
555 union in_addr_union *ret_prefix,
556 unsigned char *ret_prefixlen) {
557
558 union in_addr_union buffer;
559 const char *e, *l;
560 unsigned char k;
561 int family, r;
562
563 assert(p);
564
565 e = strchr(p, '/');
566 if (e)
567 l = strndupa(p, e - p);
568 else
569 l = p;
570
571 r = in_addr_from_string_auto(l, &family, &buffer);
572 if (r < 0)
573 return r;
574
575 if (e) {
576 r = in_addr_parse_prefixlen(family, e+1, &k);
577 if (r < 0)
578 return r;
579 } else
580 k = FAMILY_ADDRESS_SIZE(family) * 8;
581
582 if (ret_family)
583 *ret_family = family;
584 if (ret_prefix)
585 *ret_prefix = buffer;
586 if (ret_prefixlen)
587 *ret_prefixlen = k;
588
589 return 0;
590
591 }