]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-address.c
treewide: no need to negate errno for log_*_errno()
[thirdparty/systemd.git] / src / network / networkd-address.c
CommitLineData
f579559b
TG
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"
0b1831c2 25#include "networkd-link.h"
f579559b
TG
26
27#include "utf8.h"
28#include "util.h"
29#include "conf-parser.h"
c6f7c917 30#include "network-internal.h"
f579559b 31
aba496a5
UTL
32static 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
f048a16b 41int address_new_static(Network *network, unsigned section, Address **ret) {
f579559b
TG
42 _cleanup_address_free_ Address *address = NULL;
43
6ae115c1 44 if (section) {
16aa63a0 45 address = hashmap_get(network->addresses_by_section, UINT_TO_PTR(section));
6ae115c1
TG
46 if (address) {
47 *ret = address;
48 address = NULL;
49
50 return 0;
51 }
52 }
53
f579559b
TG
54 address = new0(Address, 1);
55 if (!address)
56 return -ENOMEM;
57
aba496a5 58 address_init(address);
801bd9e8 59
f579559b
TG
60 address->network = network;
61
3d3d4255 62 LIST_PREPEND(addresses, network->static_addresses, address);
f579559b 63
6ae115c1
TG
64 if (section) {
65 address->section = section;
16aa63a0
TG
66 hashmap_put(network->addresses_by_section,
67 UINT_TO_PTR(address->section), address);
6ae115c1
TG
68 }
69
f579559b
TG
70 *ret = address;
71 address = NULL;
72
73 return 0;
74}
75
f048a16b
TG
76int 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
aba496a5 83 address_init(address);
801bd9e8 84
f048a16b
TG
85 *ret = address;
86 address = NULL;
87
88 return 0;
89}
90
f579559b
TG
91void address_free(Address *address) {
92 if (!address)
93 return;
94
f048a16b 95 if (address->network) {
3d3d4255 96 LIST_REMOVE(addresses, address->network->static_addresses, address);
f579559b 97
f048a16b
TG
98 if (address->section)
99 hashmap_remove(address->network->addresses_by_section,
16aa63a0 100 UINT_TO_PTR(address->section));
f048a16b 101 }
6ae115c1 102
f579559b
TG
103 free(address);
104}
105
407fe036
TG
106int address_drop(Address *address, Link *link,
107 sd_rtnl_message_handler_t callback) {
cf6a8911 108 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
407fe036
TG
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
151b9b96
LP
118 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
119 link->ifindex, address->family);
407fe036
TG
120 if (r < 0) {
121 log_error("Could not allocate RTM_DELADDR message: %s",
122 strerror(-r));
123 return r;
124 }
125
5a723174
TG
126 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
127 if (r < 0) {
da927ba9 128 log_error_errno(r, "Could not set prefixlen: %m");
5a723174
TG
129 return r;
130 }
131
407fe036
TG
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) {
da927ba9 144 log_error_errno(r, "Could not send rtnetlink message: %m");
407fe036
TG
145 return r;
146 }
147
563c69c6
TG
148 link_ref(link);
149
407fe036
TG
150 return 0;
151}
152
aba496a5
UTL
153int 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) {
da927ba9 174 log_error_errno(r, "Could not set prefixlen: %m");
aba496a5
UTL
175 return r;
176 }
177
178 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
179 if (r < 0) {
da927ba9 180 log_error_errno(r, "Could not set flags: %m");
aba496a5
UTL
181 return r;
182 }
183
184 r = sd_rtnl_message_addr_set_scope(req, address->scope);
185 if (r < 0) {
da927ba9 186 log_error_errno(r, "Could not set scope: %m");
aba496a5
UTL
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) {
da927ba9 227 log_error_errno(r, "Could not send rtnetlink message: %m");
aba496a5
UTL
228 return r;
229 }
230
563c69c6
TG
231 link_ref(link);
232
aba496a5
UTL
233 return 0;
234}
235
11bf3cce
LP
236static int address_acquire(Link *link, Address *original, Address **ret) {
237 union in_addr_union in_addr = {};
238 struct in_addr broadcast = {};
0099bc15 239 _cleanup_address_free_ Address *na = NULL;
11bf3cce
LP
240 int r;
241
242 assert(link);
243 assert(original);
244 assert(ret);
245
246 /* Something useful was configured? just use it */
af93291c 247 if (in_addr_is_null(original->family, &original->in_addr) <= 0)
11bf3cce
LP
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) {
79008bdd 254 log_link_error(link, "Failed to acquire address from pool: %s", strerror(-r));
11bf3cce
LP
255 return r;
256 }
257 if (r == 0) {
79008bdd 258 log_link_error(link, "Couldn't find free address for interface, all taken.");
11bf3cce
LP
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);
0099bc15 282 if (!na->label)
11bf3cce 283 return -ENOMEM;
11bf3cce
LP
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;
0099bc15
SS
292 na = NULL;
293
11bf3cce
LP
294 return 0;
295}
296
f882c247
TG
297int address_configure(Address *address, Link *link,
298 sd_rtnl_message_handler_t callback) {
cf6a8911 299 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
f579559b
TG
300 int r;
301
c166a070
TG
302 assert(address);
303 assert(address->family == AF_INET || address->family == AF_INET6);
304 assert(link);
305 assert(link->ifindex > 0);
f882c247 306 assert(link->manager);
c166a070 307 assert(link->manager->rtnl);
f882c247 308
11bf3cce
LP
309 r = address_acquire(link, address, &address);
310 if (r < 0)
311 return r;
312
151b9b96
LP
313 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
314 link->ifindex, address->family);
f579559b
TG
315 if (r < 0) {
316 log_error("Could not allocate RTM_NEWADDR message: %s",
317 strerror(-r));
318 return r;
319 }
320
5a723174
TG
321 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
322 if (r < 0) {
da927ba9 323 log_error_errno(r, "Could not set prefixlen: %m");
5a723174
TG
324 return r;
325 }
326
327 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
328 if (r < 0) {
da927ba9 329 log_error_errno(r, "Could not set flags: %m");
5a723174
TG
330 return r;
331 }
332
5c1d3fc9 333 r = sd_rtnl_message_addr_set_scope(req, address->scope);
5a723174 334 if (r < 0) {
da927ba9 335 log_error_errno(r, "Could not set scope: %m");
5a723174
TG
336 return r;
337 }
338
0a0dc69b
TG
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);
f579559b
TG
343 if (r < 0) {
344 log_error("Could not append IFA_LOCAL attribute: %s",
345 strerror(-r));
346 return r;
347 }
348
af93291c 349 if (!in_addr_is_null(address->family, &address->in_addr_peer)) {
c081882f
SS
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);
f579559b 354 if (r < 0) {
c081882f 355 log_error("Could not append IFA_ADDRESS attribute: %s",
f579559b
TG
356 strerror(-r));
357 return r;
358 }
c081882f
SS
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 }
f579559b
TG
368 }
369
370 if (address->label) {
0a0dc69b 371 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
f579559b
TG
372 if (r < 0) {
373 log_error("Could not append IFA_LABEL attribute: %s",
374 strerror(-r));
375 return r;
376 }
377 }
378
68ceb9df
PF
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
f882c247 387 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
f579559b 388 if (r < 0) {
da927ba9 389 log_error_errno(r, "Could not send rtnetlink message: %m");
f882c247 390 return r;
f579559b
TG
391 }
392
563c69c6
TG
393 link_ref(link);
394
f579559b
TG
395 return 0;
396}
397
44e7b949
LP
398int config_parse_broadcast(
399 const char *unit,
eb0ea358
TG
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) {
44e7b949 409
eb0ea358
TG
410 Network *network = userdata;
411 _cleanup_address_free_ Address *n = NULL;
eb0ea358
TG
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
482e2ac1
TG
424 if (n->family == AF_INET6) {
425 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
44e7b949 426 "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
482e2ac1
TG
427 return 0;
428 }
429
44e7b949 430 r = in_addr_from_string(AF_INET, rvalue, (union in_addr_union*) &n->broadcast);
eb0ea358
TG
431 if (r < 0) {
432 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
44e7b949 433 "Broadcast is invalid, ignoring assignment: %s", rvalue);
eb0ea358
TG
434 return 0;
435 }
436
44e7b949 437 n->family = AF_INET;
eb0ea358
TG
438 n = NULL;
439
440 return 0;
441}
442
f579559b
TG
443int config_parse_address(const char *unit,
444 const char *filename,
445 unsigned line,
446 const char *section,
71a61510 447 unsigned section_line,
f579559b
TG
448 const char *lvalue,
449 int ltype,
450 const char *rvalue,
451 void *data,
452 void *userdata) {
44e7b949 453
6ae115c1 454 Network *network = userdata;
f579559b 455 _cleanup_address_free_ Address *n = NULL;
44e7b949
LP
456 const char *address, *e;
457 union in_addr_union buffer;
458 int r, f;
f579559b
TG
459
460 assert(filename);
6ae115c1 461 assert(section);
f579559b
TG
462 assert(lvalue);
463 assert(rvalue);
464 assert(data);
465
92fe133a
TG
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
f048a16b 472 r = address_new_static(network, section_line, &n);
f579559b
TG
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,
a2a85a22 485 "Prefix length is invalid, ignoring assignment: %s", e + 1);
f579559b
TG
486 return 0;
487 }
488
489 n->prefixlen = (unsigned char) i;
8cd11a0f 490
44e7b949
LP
491 address = strndupa(rvalue, e - rvalue);
492 } else
493 address = rvalue;
f579559b 494
44e7b949 495 r = in_addr_from_string_auto(address, &f, &buffer);
f579559b
TG
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
a2a85a22
TG
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
44e7b949
LP
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);
eb0ea358 526
f579559b
TG
527 n = NULL;
528
529 return 0;
530}
6ae115c1
TG
531
532int 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;
6ae115c1
TG
544 char *label;
545 int r;
546
547 assert(filename);
548 assert(section);
549 assert(lvalue);
550 assert(rvalue);
551 assert(data);
552
f048a16b 553 r = address_new_static(network, section_line, &n);
6ae115c1
TG
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}
9505d3c6
TG
581
582bool 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}