]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-address.c
sd-dhcp-client/networkd: set lifetimes for IPv4 addresses
[thirdparty/systemd.git] / src / network / networkd-address.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <net/if.h>
23
24 #include "networkd.h"
25
26 #include "utf8.h"
27 #include "util.h"
28 #include "conf-parser.h"
29 #include "network-internal.h"
30
31 static void address_init(Address *address) {
32 assert(address);
33
34 address->family = AF_UNSPEC;
35 address->scope = RT_SCOPE_UNIVERSE;
36 address->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME;
37 address->cinfo.ifa_valid = CACHE_INFO_INFINITY_LIFE_TIME;
38 }
39
40 int address_new_static(Network *network, unsigned section, Address **ret) {
41 _cleanup_address_free_ Address *address = NULL;
42
43 if (section) {
44 uint64_t key = section;
45 address = hashmap_get(network->addresses_by_section, &key);
46 if (address) {
47 *ret = address;
48 address = NULL;
49
50 return 0;
51 }
52 }
53
54 address = new0(Address, 1);
55 if (!address)
56 return -ENOMEM;
57
58 address_init(address);
59
60 address->network = network;
61
62 LIST_PREPEND(addresses, network->static_addresses, address);
63
64 if (section) {
65 address->section = section;
66 hashmap_put(network->addresses_by_section, &address->section, address);
67 }
68
69 *ret = address;
70 address = NULL;
71
72 return 0;
73 }
74
75 int address_new_dynamic(Address **ret) {
76 _cleanup_address_free_ Address *address = NULL;
77
78 address = new0(Address, 1);
79 if (!address)
80 return -ENOMEM;
81
82 address_init(address);
83
84 *ret = address;
85 address = NULL;
86
87 return 0;
88 }
89
90 void address_free(Address *address) {
91 if (!address)
92 return;
93
94 if (address->network) {
95 LIST_REMOVE(addresses, address->network->static_addresses, address);
96
97 if (address->section)
98 hashmap_remove(address->network->addresses_by_section,
99 &address->section);
100 }
101
102 free(address);
103 }
104
105 int address_drop(Address *address, Link *link,
106 sd_rtnl_message_handler_t callback) {
107 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
108 int r;
109
110 assert(address);
111 assert(address->family == AF_INET || address->family == AF_INET6);
112 assert(link);
113 assert(link->ifindex > 0);
114 assert(link->manager);
115 assert(link->manager->rtnl);
116
117 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
118 link->ifindex, address->family);
119 if (r < 0) {
120 log_error("Could not allocate RTM_DELADDR message: %s",
121 strerror(-r));
122 return r;
123 }
124
125 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
126 if (r < 0) {
127 log_error("Could not set prefixlen: %s", strerror(-r));
128 return r;
129 }
130
131 if (address->family == AF_INET)
132 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
133 else if (address->family == AF_INET6)
134 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
135 if (r < 0) {
136 log_error("Could not append IFA_LOCAL attribute: %s",
137 strerror(-r));
138 return r;
139 }
140
141 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
142 if (r < 0) {
143 log_error("Could not send rtnetlink message: %s", strerror(-r));
144 return r;
145 }
146
147 return 0;
148 }
149
150 int address_update(Address *address, Link *link,
151 sd_rtnl_message_handler_t callback) {
152 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
153 int r;
154
155 assert(address);
156 assert(address->family == AF_INET || address->family == AF_INET6);
157 assert(link->ifindex > 0);
158 assert(link->manager);
159 assert(link->manager->rtnl);
160
161 r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
162 link->ifindex, address->family);
163 if (r < 0) {
164 log_error("Could not allocate RTM_NEWADDR message: %s",
165 strerror(-r));
166 return r;
167 }
168
169 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
170 if (r < 0) {
171 log_error("Could not set prefixlen: %s", strerror(-r));
172 return r;
173 }
174
175 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
176 if (r < 0) {
177 log_error("Could not set flags: %s", strerror(-r));
178 return r;
179 }
180
181 r = sd_rtnl_message_addr_set_scope(req, address->scope);
182 if (r < 0) {
183 log_error("Could not set scope: %s", strerror(-r));
184 return r;
185 }
186
187 if (address->family == AF_INET)
188 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
189 else if (address->family == AF_INET6)
190 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
191 if (r < 0) {
192 log_error("Could not append IFA_LOCAL attribute: %s",
193 strerror(-r));
194 return r;
195 }
196
197 if (address->family == AF_INET) {
198 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
199 if (r < 0) {
200 log_error("Could not append IFA_BROADCAST attribute: %s",
201 strerror(-r));
202 return r;
203 }
204 }
205
206 if (address->label) {
207 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
208 if (r < 0) {
209 log_error("Could not append IFA_LABEL attribute: %s",
210 strerror(-r));
211 return r;
212 }
213 }
214
215 r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO, &address->cinfo);
216 if (r < 0) {
217 log_error("Could not append IFA_CACHEINFO attribute: %s",
218 strerror(-r));
219 return r;
220 }
221
222 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
223 if (r < 0) {
224 log_error("Could not send rtnetlink message: %s", strerror(-r));
225 return r;
226 }
227
228 return 0;
229 }
230
231 static int address_acquire(Link *link, Address *original, Address **ret) {
232 union in_addr_union in_addr = {};
233 struct in_addr broadcast = {};
234 Address *na = NULL;
235 int r;
236
237 assert(link);
238 assert(original);
239 assert(ret);
240
241 /* Something useful was configured? just use it */
242 if (in_addr_null(original->family, &original->in_addr) <= 0)
243 return 0;
244
245 /* The address is configured to be 0.0.0.0 or [::] by the user?
246 * Then let's acquire something more useful from the pool. */
247 r = manager_address_pool_acquire(link->manager, original->family, original->prefixlen, &in_addr);
248 if (r < 0) {
249 log_error_link(link, "Failed to acquire address from pool: %s", strerror(-r));
250 return r;
251 }
252 if (r == 0) {
253 log_error_link(link, "Couldn't find free address for interface, all taken.");
254 return -EBUSY;
255 }
256
257 if (original->family == AF_INET) {
258 /* Pick first address in range for ourselves ...*/
259 in_addr.in.s_addr = in_addr.in.s_addr | htobe32(1);
260
261 /* .. and use last as broadcast address */
262 broadcast.s_addr = in_addr.in.s_addr | htobe32(0xFFFFFFFFUL >> original->prefixlen);
263 } else if (original->family == AF_INET6)
264 in_addr.in6.s6_addr[15] |= 1;
265
266 r = address_new_dynamic(&na);
267 if (r < 0)
268 return r;
269
270 na->family = original->family;
271 na->prefixlen = original->prefixlen;
272 na->scope = original->scope;
273 na->cinfo = original->cinfo;
274
275 if (original->label) {
276 na->label = strdup(original->label);
277
278 if (!na->label) {
279 free(na);
280 return -ENOMEM;
281 }
282 }
283
284 na->broadcast = broadcast;
285 na->in_addr = in_addr;
286
287 LIST_PREPEND(addresses, link->pool_addresses, na);
288
289 *ret = na;
290 return 0;
291 }
292
293 int address_configure(Address *address, Link *link,
294 sd_rtnl_message_handler_t callback) {
295 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
296 int r;
297
298 assert(address);
299 assert(address->family == AF_INET || address->family == AF_INET6);
300 assert(link);
301 assert(link->ifindex > 0);
302 assert(link->manager);
303 assert(link->manager->rtnl);
304
305 r = address_acquire(link, address, &address);
306 if (r < 0)
307 return r;
308
309 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
310 link->ifindex, address->family);
311 if (r < 0) {
312 log_error("Could not allocate RTM_NEWADDR message: %s",
313 strerror(-r));
314 return r;
315 }
316
317 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
318 if (r < 0) {
319 log_error("Could not set prefixlen: %s", strerror(-r));
320 return r;
321 }
322
323 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
324 if (r < 0) {
325 log_error("Could not set flags: %s", strerror(-r));
326 return r;
327 }
328
329 r = sd_rtnl_message_addr_set_scope(req, address->scope);
330 if (r < 0) {
331 log_error("Could not set scope: %s", strerror(-r));
332 return r;
333 }
334
335 if (address->family == AF_INET)
336 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
337 else if (address->family == AF_INET6)
338 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
339 if (r < 0) {
340 log_error("Could not append IFA_LOCAL attribute: %s",
341 strerror(-r));
342 return r;
343 }
344
345 if (address->family == AF_INET) {
346 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
347 if (r < 0) {
348 log_error("Could not append IFA_BROADCAST attribute: %s",
349 strerror(-r));
350 return r;
351 }
352 }
353
354 if (address->label) {
355 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
356 if (r < 0) {
357 log_error("Could not append IFA_LABEL attribute: %s",
358 strerror(-r));
359 return r;
360 }
361 }
362
363 r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO,
364 &address->cinfo);
365 if (r < 0) {
366 log_error("Could not append IFA_CACHEINFO attribute: %s",
367 strerror(-r));
368 return r;
369 }
370
371 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
372 if (r < 0) {
373 log_error("Could not send rtnetlink message: %s", strerror(-r));
374 return r;
375 }
376
377 return 0;
378 }
379
380 int config_parse_dns(const char *unit,
381 const char *filename,
382 unsigned line,
383 const char *section,
384 unsigned section_line,
385 const char *lvalue,
386 int ltype,
387 const char *rvalue,
388 void *data,
389 void *userdata) {
390 Network *network = userdata;
391 Address *tail;
392 _cleanup_address_free_ Address *n = NULL;
393 int r;
394
395 assert(filename);
396 assert(section);
397 assert(lvalue);
398 assert(rvalue);
399 assert(network);
400
401 r = address_new_dynamic(&n);
402 if (r < 0)
403 return r;
404
405 r = net_parse_inaddr(rvalue, &n->family, &n->in_addr);
406 if (r < 0) {
407 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
408 "DNS address is invalid, ignoring assignment: %s", rvalue);
409 return 0;
410 }
411
412 if (streq(lvalue, "DNS")) {
413 LIST_FIND_TAIL(addresses, network->dns, tail);
414 LIST_INSERT_AFTER(addresses, network->dns, tail, n);
415 } else if (streq(lvalue, "NTP")) {
416 LIST_FIND_TAIL(addresses, network->ntp, tail);
417 LIST_INSERT_AFTER(addresses, network->ntp, tail, n);
418 } else {
419 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
420 "Key is invalid, ignoring assignment: %s=%s", lvalue, rvalue);
421 return 0;
422 }
423
424 n = NULL;
425
426 return 0;
427 }
428
429 int config_parse_broadcast(const char *unit,
430 const char *filename,
431 unsigned line,
432 const char *section,
433 unsigned section_line,
434 const char *lvalue,
435 int ltype,
436 const char *rvalue,
437 void *data,
438 void *userdata) {
439 Network *network = userdata;
440 _cleanup_address_free_ Address *n = NULL;
441 _cleanup_free_ char *address = NULL;
442 int r;
443
444 assert(filename);
445 assert(section);
446 assert(lvalue);
447 assert(rvalue);
448 assert(data);
449
450 r = address_new_static(network, section_line, &n);
451 if (r < 0)
452 return r;
453
454 if (n->family == AF_INET6) {
455 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
456 "Broadcast is not valid for IPv6 addresses, "
457 "ignoring assignment: %s", address);
458 return 0;
459 }
460
461 r = net_parse_inaddr(address, &n->family, &n->broadcast);
462 if (r < 0) {
463 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
464 "Broadcast is invalid, ignoring assignment: %s", address);
465 return 0;
466 }
467
468 n = NULL;
469
470 return 0;
471 }
472
473 int config_parse_address(const char *unit,
474 const char *filename,
475 unsigned line,
476 const char *section,
477 unsigned section_line,
478 const char *lvalue,
479 int ltype,
480 const char *rvalue,
481 void *data,
482 void *userdata) {
483 Network *network = userdata;
484 _cleanup_address_free_ Address *n = NULL;
485 _cleanup_free_ char *address = NULL;
486 const char *e;
487 int r;
488
489 assert(filename);
490 assert(section);
491 assert(lvalue);
492 assert(rvalue);
493 assert(data);
494
495 if (streq(section, "Network")) {
496 /* we are not in an Address section, so treat
497 * this as the special '0' section */
498 section_line = 0;
499 }
500
501 r = address_new_static(network, section_line, &n);
502 if (r < 0)
503 return r;
504
505 /* Address=address/prefixlen */
506
507 /* prefixlen */
508 e = strchr(rvalue, '/');
509 if (e) {
510 unsigned i;
511 r = safe_atou(e + 1, &i);
512 if (r < 0) {
513 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
514 "Interface prefix length is invalid, "
515 "ignoring assignment: %s", e + 1);
516 return 0;
517 }
518
519 n->prefixlen = (unsigned char) i;
520
521 address = strndup(rvalue, e - rvalue);
522 if (!address)
523 return log_oom();
524 } else {
525 address = strdup(rvalue);
526 if (!address)
527 return log_oom();
528 }
529
530 r = net_parse_inaddr(address, &n->family, &n->in_addr);
531 if (r < 0) {
532 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
533 "Address is invalid, ignoring assignment: %s", address);
534 return 0;
535 }
536
537 if (n->family == AF_INET && !n->broadcast.s_addr)
538 n->broadcast.s_addr = n->in_addr.in.s_addr |
539 htonl(0xfffffffflu >> n->prefixlen);
540
541 n = NULL;
542
543 return 0;
544 }
545
546 int config_parse_label(const char *unit,
547 const char *filename,
548 unsigned line,
549 const char *section,
550 unsigned section_line,
551 const char *lvalue,
552 int ltype,
553 const char *rvalue,
554 void *data,
555 void *userdata) {
556 Network *network = userdata;
557 _cleanup_address_free_ Address *n = NULL;
558 char *label;
559 int r;
560
561 assert(filename);
562 assert(section);
563 assert(lvalue);
564 assert(rvalue);
565 assert(data);
566
567 r = address_new_static(network, section_line, &n);
568 if (r < 0)
569 return r;
570
571 label = strdup(rvalue);
572 if (!label)
573 return log_oom();
574
575 if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
576 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
577 "Interface label is not ASCII clean or is too"
578 " long, ignoring assignment: %s", rvalue);
579 free(label);
580 return 0;
581 }
582
583 free(n->label);
584 if (*label)
585 n->label = label;
586 else {
587 free(label);
588 n->label = NULL;
589 }
590
591 n = NULL;
592
593 return 0;
594 }
595
596 bool address_equal(Address *a1, Address *a2) {
597 /* same object */
598 if (a1 == a2)
599 return true;
600
601 /* one, but not both, is NULL */
602 if (!a1 || !a2)
603 return false;
604
605 if (a1->family != a2->family)
606 return false;
607
608 switch (a1->family) {
609 /* use the same notion of equality as the kernel does */
610 case AF_UNSPEC:
611 return true;
612
613 case AF_INET:
614 if (a1->prefixlen != a2->prefixlen)
615 return false;
616 else {
617 uint32_t b1, b2;
618
619 b1 = be32toh(a1->in_addr.in.s_addr);
620 b2 = be32toh(a2->in_addr.in.s_addr);
621
622 return (b1 >> (32 - a1->prefixlen)) == (b2 >> (32 - a1->prefixlen));
623 }
624
625 case AF_INET6:
626 {
627 uint64_t *b1, *b2;
628
629 b1 = (uint64_t*)&a1->in_addr.in6;
630 b2 = (uint64_t*)&a2->in_addr.in6;
631
632 return (((b1[0] ^ b2[0]) | (b1[1] ^ b2[1])) == 0UL);
633 }
634 default:
635 assert_not_reached("Invalid address family");
636 }
637 }