]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/in-addr-util.c
resolved: when using the ResolveRecord() bus call, adjust TTL for caching time
[thirdparty/systemd.git] / src / basic / in-addr-util.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2014 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <arpa/inet.h>
21 #include <endian.h>
22 #include <errno.h>
23 #include <net/if.h>
24 #include <stdint.h>
25 #include <stdlib.h>
26
27 #include "alloc-util.h"
28 #include "in-addr-util.h"
29 #include "macro.h"
30 #include "parse-util.h"
31 #include "util.h"
32
33 bool in4_addr_is_null(const struct in_addr *a) {
34 return a->s_addr == 0;
35 }
36
37 bool in6_addr_is_null(const struct in6_addr *a) {
38 return
39 a->s6_addr32[0] == 0 &&
40 a->s6_addr32[1] == 0 &&
41 a->s6_addr32[2] == 0 &&
42 a->s6_addr32[3] == 0;
43 }
44
45 int in_addr_is_null(int family, const union in_addr_union *u) {
46 assert(u);
47
48 if (family == AF_INET)
49 return in4_addr_is_null(&u->in);
50
51 if (family == AF_INET6)
52 return in6_addr_is_null(&u->in6);
53
54 return -EAFNOSUPPORT;
55 }
56
57 int in_addr_is_link_local(int family, const union in_addr_union *u) {
58 assert(u);
59
60 if (family == AF_INET)
61 return (be32toh(u->in.s_addr) & UINT32_C(0xFFFF0000)) == (UINT32_C(169) << 24 | UINT32_C(254) << 16);
62
63 if (family == AF_INET6)
64 return IN6_IS_ADDR_LINKLOCAL(&u->in6);
65
66 return -EAFNOSUPPORT;
67 }
68
69 int in_addr_is_localhost(int family, const union in_addr_union *u) {
70 assert(u);
71
72 if (family == AF_INET)
73 /* All of 127.x.x.x is localhost. */
74 return (be32toh(u->in.s_addr) & UINT32_C(0xFF000000)) == UINT32_C(127) << 24;
75
76 if (family == AF_INET6)
77 return IN6_IS_ADDR_LOOPBACK(&u->in6);
78
79 return -EAFNOSUPPORT;
80 }
81
82 int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b) {
83 assert(a);
84 assert(b);
85
86 if (family == AF_INET)
87 return a->in.s_addr == b->in.s_addr;
88
89 if (family == AF_INET6)
90 return
91 a->in6.s6_addr32[0] == b->in6.s6_addr32[0] &&
92 a->in6.s6_addr32[1] == b->in6.s6_addr32[1] &&
93 a->in6.s6_addr32[2] == b->in6.s6_addr32[2] &&
94 a->in6.s6_addr32[3] == b->in6.s6_addr32[3];
95
96 return -EAFNOSUPPORT;
97 }
98
99 int in_addr_prefix_intersect(
100 int family,
101 const union in_addr_union *a,
102 unsigned aprefixlen,
103 const union in_addr_union *b,
104 unsigned bprefixlen) {
105
106 unsigned m;
107
108 assert(a);
109 assert(b);
110
111 /* Checks whether there are any addresses that are in both
112 * networks */
113
114 m = MIN(aprefixlen, bprefixlen);
115
116 if (family == AF_INET) {
117 uint32_t x, nm;
118
119 x = be32toh(a->in.s_addr ^ b->in.s_addr);
120 nm = (m == 0) ? 0 : 0xFFFFFFFFUL << (32 - m);
121
122 return (x & nm) == 0;
123 }
124
125 if (family == AF_INET6) {
126 unsigned i;
127
128 if (m > 128)
129 m = 128;
130
131 for (i = 0; i < 16; i++) {
132 uint8_t x, nm;
133
134 x = a->in6.s6_addr[i] ^ b->in6.s6_addr[i];
135
136 if (m < 8)
137 nm = 0xFF << (8 - m);
138 else
139 nm = 0xFF;
140
141 if ((x & nm) != 0)
142 return 0;
143
144 if (m > 8)
145 m -= 8;
146 else
147 m = 0;
148 }
149
150 return 1;
151 }
152
153 return -EAFNOSUPPORT;
154 }
155
156 int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen) {
157 assert(u);
158
159 /* Increases the network part of an address by one. Returns
160 * positive it that succeeds, or 0 if this overflows. */
161
162 if (prefixlen <= 0)
163 return 0;
164
165 if (family == AF_INET) {
166 uint32_t c, n;
167
168 if (prefixlen > 32)
169 prefixlen = 32;
170
171 c = be32toh(u->in.s_addr);
172 n = c + (1UL << (32 - prefixlen));
173 if (n < c)
174 return 0;
175 n &= 0xFFFFFFFFUL << (32 - prefixlen);
176
177 u->in.s_addr = htobe32(n);
178 return 1;
179 }
180
181 if (family == AF_INET6) {
182 struct in6_addr add = {}, result;
183 uint8_t overflow = 0;
184 unsigned i;
185
186 if (prefixlen > 128)
187 prefixlen = 128;
188
189 /* First calculate what we have to add */
190 add.s6_addr[(prefixlen-1) / 8] = 1 << (7 - (prefixlen-1) % 8);
191
192 for (i = 16; i > 0; i--) {
193 unsigned j = i - 1;
194
195 result.s6_addr[j] = u->in6.s6_addr[j] + add.s6_addr[j] + overflow;
196 overflow = (result.s6_addr[j] < u->in6.s6_addr[j]);
197 }
198
199 if (overflow)
200 return 0;
201
202 u->in6 = result;
203 return 1;
204 }
205
206 return -EAFNOSUPPORT;
207 }
208
209 int in_addr_to_string(int family, const union in_addr_union *u, char **ret) {
210 char *x;
211 size_t l;
212
213 assert(u);
214 assert(ret);
215
216 if (family == AF_INET)
217 l = INET_ADDRSTRLEN;
218 else if (family == AF_INET6)
219 l = INET6_ADDRSTRLEN;
220 else
221 return -EAFNOSUPPORT;
222
223 x = new(char, l);
224 if (!x)
225 return -ENOMEM;
226
227 errno = 0;
228 if (!inet_ntop(family, u, x, l)) {
229 free(x);
230 return errno > 0 ? -errno : -EINVAL;
231 }
232
233 *ret = x;
234 return 0;
235 }
236
237 int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret) {
238 size_t l;
239 char *x;
240 int r;
241
242 assert(u);
243 assert(ret);
244
245 /* Much like in_addr_to_string(), but optionally appends the zone interface index to the address, to properly
246 * handle IPv6 link-local addresses. */
247
248 if (family != AF_INET6)
249 goto fallback;
250 if (ifindex <= 0)
251 goto fallback;
252
253 r = in_addr_is_link_local(family, u);
254 if (r < 0)
255 return r;
256 if (r == 0)
257 goto fallback;
258
259 l = INET6_ADDRSTRLEN + 1 + DECIMAL_STR_MAX(ifindex) + 1;
260 x = new(char, l);
261 if (!x)
262 return -ENOMEM;
263
264 errno = 0;
265 if (!inet_ntop(family, u, x, l)) {
266 free(x);
267 return errno > 0 ? -errno : -EINVAL;
268 }
269
270 sprintf(strchr(x, 0), "%%%i", ifindex);
271 *ret = x;
272
273 return 0;
274
275 fallback:
276 return in_addr_to_string(family, u, ret);
277 }
278
279 int in_addr_from_string(int family, const char *s, union in_addr_union *ret) {
280
281 assert(s);
282 assert(ret);
283
284 if (!IN_SET(family, AF_INET, AF_INET6))
285 return -EAFNOSUPPORT;
286
287 errno = 0;
288 if (inet_pton(family, s, ret) <= 0)
289 return errno > 0 ? -errno : -EINVAL;
290
291 return 0;
292 }
293
294 int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *ret) {
295 int r;
296
297 assert(s);
298 assert(family);
299 assert(ret);
300
301 r = in_addr_from_string(AF_INET, s, ret);
302 if (r >= 0) {
303 *family = AF_INET;
304 return 0;
305 }
306
307 r = in_addr_from_string(AF_INET6, s, ret);
308 if (r >= 0) {
309 *family = AF_INET6;
310 return 0;
311 }
312
313 return -EINVAL;
314 }
315
316 int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex) {
317 const char *suffix;
318 int r, ifi = 0;
319
320 assert(s);
321 assert(family);
322 assert(ret);
323
324 /* Similar to in_addr_from_string_auto() but also parses an optionally appended IPv6 zone suffix ("scope id")
325 * if one is found. */
326
327 suffix = strchr(s, '%');
328 if (suffix) {
329
330 if (ifindex) {
331 /* If we shall return the interface index, try to parse it */
332 r = parse_ifindex(suffix + 1, &ifi);
333 if (r < 0) {
334 unsigned u;
335
336 u = if_nametoindex(suffix + 1);
337 if (u <= 0)
338 return -errno;
339
340 ifi = (int) u;
341 }
342 }
343
344 s = strndupa(s, suffix - s);
345 }
346
347 r = in_addr_from_string_auto(s, family, ret);
348 if (r < 0)
349 return r;
350
351 if (ifindex)
352 *ifindex = ifi;
353
354 return r;
355 }
356
357 unsigned char in_addr_netmask_to_prefixlen(const struct in_addr *addr) {
358 assert(addr);
359
360 return 32 - u32ctz(be32toh(addr->s_addr));
361 }
362
363 struct in_addr* in_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen) {
364 assert(addr);
365 assert(prefixlen <= 32);
366
367 /* Shifting beyond 32 is not defined, handle this specially. */
368 if (prefixlen == 0)
369 addr->s_addr = 0;
370 else
371 addr->s_addr = htobe32((0xffffffff << (32 - prefixlen)) & 0xffffffff);
372
373 return addr;
374 }
375
376 int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) {
377 uint8_t msb_octet = *(uint8_t*) addr;
378
379 /* addr may not be aligned, so make sure we only access it byte-wise */
380
381 assert(addr);
382 assert(prefixlen);
383
384 if (msb_octet < 128)
385 /* class A, leading bits: 0 */
386 *prefixlen = 8;
387 else if (msb_octet < 192)
388 /* class B, leading bits 10 */
389 *prefixlen = 16;
390 else if (msb_octet < 224)
391 /* class C, leading bits 110 */
392 *prefixlen = 24;
393 else
394 /* class D or E, no default prefixlen */
395 return -ERANGE;
396
397 return 0;
398 }
399
400 int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask) {
401 unsigned char prefixlen;
402 int r;
403
404 assert(addr);
405 assert(mask);
406
407 r = in_addr_default_prefixlen(addr, &prefixlen);
408 if (r < 0)
409 return r;
410
411 in_addr_prefixlen_to_netmask(mask, prefixlen);
412 return 0;
413 }
414
415 int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen) {
416 assert(addr);
417
418 if (family == AF_INET) {
419 struct in_addr mask;
420
421 if (!in_addr_prefixlen_to_netmask(&mask, prefixlen))
422 return -EINVAL;
423
424 addr->in.s_addr &= mask.s_addr;
425 return 0;
426 }
427
428 if (family == AF_INET6) {
429 unsigned i;
430
431 for (i = 0; i < 16; i++) {
432 uint8_t mask;
433
434 if (prefixlen >= 8) {
435 mask = 0xFF;
436 prefixlen -= 8;
437 } else {
438 mask = 0xFF << (8 - prefixlen);
439 prefixlen = 0;
440 }
441
442 addr->in6.s6_addr[i] &= mask;
443 }
444
445 return 0;
446 }
447
448 return -EAFNOSUPPORT;
449 }