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