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