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