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