1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
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.
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.
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/>.
28 #include "conf-parser.h"
29 #include "network-internal.h"
31 static void address_init(Address *address) {
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;
40 int address_new_static(Network *network, unsigned section, Address **ret) {
41 _cleanup_address_free_ Address *address = NULL;
44 uint64_t key = section;
45 address = hashmap_get(network->addresses_by_section, &key);
54 address = new0(Address, 1);
58 address_init(address);
60 address->network = network;
62 LIST_PREPEND(addresses, network->static_addresses, address);
65 address->section = section;
66 hashmap_put(network->addresses_by_section, &address->section, address);
75 int address_new_dynamic(Address **ret) {
76 _cleanup_address_free_ Address *address = NULL;
78 address = new0(Address, 1);
82 address_init(address);
90 void address_free(Address *address) {
94 if (address->network) {
95 LIST_REMOVE(addresses, address->network->static_addresses, address);
98 hashmap_remove(address->network->addresses_by_section,
105 int address_drop(Address *address, Link *link,
106 sd_rtnl_message_handler_t callback) {
107 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
111 assert(address->family == AF_INET || address->family == AF_INET6);
113 assert(link->ifindex > 0);
114 assert(link->manager);
115 assert(link->manager->rtnl);
117 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
118 link->ifindex, address->family);
120 log_error("Could not allocate RTM_DELADDR message: %s",
125 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
127 log_error("Could not set prefixlen: %s", strerror(-r));
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);
136 log_error("Could not append IFA_LOCAL attribute: %s",
141 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
143 log_error("Could not send rtnetlink message: %s", strerror(-r));
152 int address_update(Address *address, Link *link,
153 sd_rtnl_message_handler_t callback) {
154 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
158 assert(address->family == AF_INET || address->family == AF_INET6);
159 assert(link->ifindex > 0);
160 assert(link->manager);
161 assert(link->manager->rtnl);
163 r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
164 link->ifindex, address->family);
166 log_error("Could not allocate RTM_NEWADDR message: %s",
171 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
173 log_error("Could not set prefixlen: %s", strerror(-r));
177 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
179 log_error("Could not set flags: %s", strerror(-r));
183 r = sd_rtnl_message_addr_set_scope(req, address->scope);
185 log_error("Could not set scope: %s", strerror(-r));
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);
194 log_error("Could not append IFA_LOCAL attribute: %s",
199 if (address->family == AF_INET) {
200 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
202 log_error("Could not append IFA_BROADCAST attribute: %s",
208 if (address->label) {
209 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
211 log_error("Could not append IFA_LABEL attribute: %s",
217 r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO, &address->cinfo);
219 log_error("Could not append IFA_CACHEINFO attribute: %s",
224 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
226 log_error("Could not send rtnetlink message: %s", strerror(-r));
235 static int address_acquire(Link *link, Address *original, Address **ret) {
236 union in_addr_union in_addr = {};
237 struct in_addr broadcast = {};
238 _cleanup_address_free_ Address *na = NULL;
245 /* Something useful was configured? just use it */
246 if (in_addr_null(original->family, &original->in_addr) <= 0)
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);
253 log_error_link(link, "Failed to acquire address from pool: %s", strerror(-r));
257 log_error_link(link, "Couldn't find free address for interface, all taken.");
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);
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;
270 r = address_new_dynamic(&na);
274 na->family = original->family;
275 na->prefixlen = original->prefixlen;
276 na->scope = original->scope;
277 na->cinfo = original->cinfo;
279 if (original->label) {
280 na->label = strdup(original->label);
285 na->broadcast = broadcast;
286 na->in_addr = in_addr;
288 LIST_PREPEND(addresses, link->pool_addresses, na);
296 int address_configure(Address *address, Link *link,
297 sd_rtnl_message_handler_t callback) {
298 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
302 assert(address->family == AF_INET || address->family == AF_INET6);
304 assert(link->ifindex > 0);
305 assert(link->manager);
306 assert(link->manager->rtnl);
308 r = address_acquire(link, address, &address);
312 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
313 link->ifindex, address->family);
315 log_error("Could not allocate RTM_NEWADDR message: %s",
320 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
322 log_error("Could not set prefixlen: %s", strerror(-r));
326 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
328 log_error("Could not set flags: %s", strerror(-r));
332 r = sd_rtnl_message_addr_set_scope(req, address->scope);
334 log_error("Could not set scope: %s", strerror(-r));
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);
343 log_error("Could not append IFA_LOCAL attribute: %s",
348 if (address->family == AF_INET) {
349 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
351 log_error("Could not append IFA_BROADCAST attribute: %s",
357 if (address->label) {
358 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
360 log_error("Could not append IFA_LABEL attribute: %s",
366 r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO,
369 log_error("Could not append IFA_CACHEINFO attribute: %s",
374 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
376 log_error("Could not send rtnetlink message: %s", strerror(-r));
385 int config_parse_dns(const char *unit,
386 const char *filename,
389 unsigned section_line,
395 Network *network = userdata;
397 _cleanup_address_free_ Address *n = NULL;
406 r = address_new_dynamic(&n);
410 r = net_parse_inaddr(rvalue, &n->family, &n->in_addr);
412 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
413 "DNS address is invalid, ignoring assignment: %s", rvalue);
417 if (streq(lvalue, "DNS")) {
418 LIST_FIND_TAIL(addresses, network->dns, tail);
419 LIST_INSERT_AFTER(addresses, network->dns, tail, n);
420 } else if (streq(lvalue, "NTP")) {
421 LIST_FIND_TAIL(addresses, network->ntp, tail);
422 LIST_INSERT_AFTER(addresses, network->ntp, tail, n);
424 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
425 "Key is invalid, ignoring assignment: %s=%s", lvalue, rvalue);
434 int config_parse_broadcast(const char *unit,
435 const char *filename,
438 unsigned section_line,
444 Network *network = userdata;
445 _cleanup_address_free_ Address *n = NULL;
446 _cleanup_free_ char *address = NULL;
455 r = address_new_static(network, section_line, &n);
459 if (n->family == AF_INET6) {
460 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
461 "Broadcast is not valid for IPv6 addresses, "
462 "ignoring assignment: %s", address);
466 r = net_parse_inaddr(address, &n->family, &n->broadcast);
468 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
469 "Broadcast is invalid, ignoring assignment: %s", address);
478 int config_parse_address(const char *unit,
479 const char *filename,
482 unsigned section_line,
488 Network *network = userdata;
489 _cleanup_address_free_ Address *n = NULL;
490 _cleanup_free_ char *address = NULL;
500 if (streq(section, "Network")) {
501 /* we are not in an Address section, so treat
502 * this as the special '0' section */
506 r = address_new_static(network, section_line, &n);
510 /* Address=address/prefixlen */
513 e = strchr(rvalue, '/');
516 r = safe_atou(e + 1, &i);
518 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
519 "Interface prefix length is invalid, "
520 "ignoring assignment: %s", e + 1);
524 n->prefixlen = (unsigned char) i;
526 address = strndup(rvalue, e - rvalue);
530 address = strdup(rvalue);
535 r = net_parse_inaddr(address, &n->family, &n->in_addr);
537 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
538 "Address is invalid, ignoring assignment: %s", address);
542 if (n->family == AF_INET && !n->broadcast.s_addr)
543 n->broadcast.s_addr = n->in_addr.in.s_addr |
544 htonl(0xfffffffflu >> n->prefixlen);
551 int config_parse_label(const char *unit,
552 const char *filename,
555 unsigned section_line,
561 Network *network = userdata;
562 _cleanup_address_free_ Address *n = NULL;
572 r = address_new_static(network, section_line, &n);
576 label = strdup(rvalue);
580 if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
581 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
582 "Interface label is not ASCII clean or is too"
583 " long, ignoring assignment: %s", rvalue);
601 bool address_equal(Address *a1, Address *a2) {
606 /* one, but not both, is NULL */
610 if (a1->family != a2->family)
613 switch (a1->family) {
614 /* use the same notion of equality as the kernel does */
619 if (a1->prefixlen != a2->prefixlen)
624 b1 = be32toh(a1->in_addr.in.s_addr);
625 b2 = be32toh(a2->in_addr.in.s_addr);
627 return (b1 >> (32 - a1->prefixlen)) == (b2 >> (32 - a1->prefixlen));
634 b1 = (uint64_t*)&a1->in_addr.in6;
635 b2 = (uint64_t*)&a2->in_addr.in6;
637 return (((b1[0] ^ b2[0]) | (b1[1] ^ b2[1])) == 0UL);
640 assert_not_reached("Invalid address family");