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