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 (!in_addr_null(address->family, &address->in_addr_peer)) {
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);
354 log_error("Could not append IFA_ADDRESS attribute: %s",
359 if (address->family == AF_INET) {
360 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
362 log_error("Could not append IFA_BROADCAST attribute: %s",
369 if (address->label) {
370 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
372 log_error("Could not append IFA_LABEL attribute: %s",
378 r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO,
381 log_error("Could not append IFA_CACHEINFO attribute: %s",
386 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
388 log_error("Could not send rtnetlink message: %s", strerror(-r));
397 int config_parse_dns(const char *unit,
398 const char *filename,
401 unsigned section_line,
407 Network *network = userdata;
409 _cleanup_address_free_ Address *n = NULL;
418 r = address_new_dynamic(&n);
422 r = net_parse_inaddr(rvalue, &n->family, &n->in_addr);
424 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
425 "DNS address is invalid, ignoring assignment: %s", rvalue);
429 if (streq(lvalue, "DNS")) {
430 LIST_FIND_TAIL(addresses, network->dns, tail);
431 LIST_INSERT_AFTER(addresses, network->dns, tail, n);
432 } else if (streq(lvalue, "NTP")) {
433 LIST_FIND_TAIL(addresses, network->ntp, tail);
434 LIST_INSERT_AFTER(addresses, network->ntp, tail, n);
436 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
437 "Key is invalid, ignoring assignment: %s=%s", lvalue, rvalue);
446 int config_parse_broadcast(const char *unit,
447 const char *filename,
450 unsigned section_line,
456 Network *network = userdata;
457 _cleanup_address_free_ Address *n = NULL;
458 _cleanup_free_ char *address = NULL;
467 r = address_new_static(network, section_line, &n);
471 if (n->family == AF_INET6) {
472 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
473 "Broadcast is not valid for IPv6 addresses, "
474 "ignoring assignment: %s", address);
478 r = net_parse_inaddr(address, &n->family, &n->broadcast);
480 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
481 "Broadcast is invalid, ignoring assignment: %s", address);
490 int config_parse_address(const char *unit,
491 const char *filename,
494 unsigned section_line,
500 Network *network = userdata;
501 _cleanup_address_free_ Address *n = NULL;
502 _cleanup_free_ char *address = NULL;
503 union in_addr_union *addr;
513 if (streq(section, "Network")) {
514 /* we are not in an Address section, so treat
515 * this as the special '0' section */
519 r = address_new_static(network, section_line, &n);
523 if (streq(lvalue, "Address"))
526 addr = &n->in_addr_peer;
528 /* Address=address/prefixlen */
531 e = strchr(rvalue, '/');
534 r = safe_atou(e + 1, &i);
536 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
537 "Interface prefix length is invalid, "
538 "ignoring assignment: %s", e + 1);
542 n->prefixlen = (unsigned char) i;
544 address = strndup(rvalue, e - rvalue);
548 address = strdup(rvalue);
553 r = net_parse_inaddr(address, &n->family, addr);
555 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
556 "Address is invalid, ignoring assignment: %s", address);
560 if (n->family == AF_INET && !n->broadcast.s_addr)
561 n->broadcast.s_addr = n->in_addr.in.s_addr |
562 htonl(0xfffffffflu >> n->prefixlen);
569 int config_parse_label(const char *unit,
570 const char *filename,
573 unsigned section_line,
579 Network *network = userdata;
580 _cleanup_address_free_ Address *n = NULL;
590 r = address_new_static(network, section_line, &n);
594 label = strdup(rvalue);
598 if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
599 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
600 "Interface label is not ASCII clean or is too"
601 " long, ignoring assignment: %s", rvalue);
619 bool address_equal(Address *a1, Address *a2) {
624 /* one, but not both, is NULL */
628 if (a1->family != a2->family)
631 switch (a1->family) {
632 /* use the same notion of equality as the kernel does */
637 if (a1->prefixlen != a2->prefixlen)
642 b1 = be32toh(a1->in_addr.in.s_addr);
643 b2 = be32toh(a2->in_addr.in.s_addr);
645 return (b1 >> (32 - a1->prefixlen)) == (b2 >> (32 - a1->prefixlen));
652 b1 = (uint64_t*)&a1->in_addr.in6;
653 b2 = (uint64_t*)&a2->in_addr.in6;
655 return (((b1[0] ^ b2[0]) | (b1[1] ^ b2[1])) == 0UL);
658 assert_not_reached("Invalid address family");