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));
150 int address_update(Address *address, Link *link,
151 sd_rtnl_message_handler_t callback) {
152 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
156 assert(address->family == AF_INET || address->family == AF_INET6);
157 assert(link->ifindex > 0);
158 assert(link->manager);
159 assert(link->manager->rtnl);
161 r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
162 link->ifindex, address->family);
164 log_error("Could not allocate RTM_NEWADDR message: %s",
169 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
171 log_error("Could not set prefixlen: %s", strerror(-r));
175 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
177 log_error("Could not set flags: %s", strerror(-r));
181 r = sd_rtnl_message_addr_set_scope(req, address->scope);
183 log_error("Could not set scope: %s", strerror(-r));
187 if (address->family == AF_INET)
188 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
189 else if (address->family == AF_INET6)
190 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
192 log_error("Could not append IFA_LOCAL attribute: %s",
197 if (address->family == AF_INET) {
198 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
200 log_error("Could not append IFA_BROADCAST attribute: %s",
206 if (address->label) {
207 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
209 log_error("Could not append IFA_LABEL attribute: %s",
215 r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO, &address->cinfo);
217 log_error("Could not append IFA_CACHEINFO attribute: %s",
222 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
224 log_error("Could not send rtnetlink message: %s", strerror(-r));
231 static int address_acquire(Link *link, Address *original, Address **ret) {
232 union in_addr_union in_addr = {};
233 struct in_addr broadcast = {};
234 _cleanup_address_free_ Address *na = NULL;
241 /* Something useful was configured? just use it */
242 if (in_addr_null(original->family, &original->in_addr) <= 0)
245 /* The address is configured to be 0.0.0.0 or [::] by the user?
246 * Then let's acquire something more useful from the pool. */
247 r = manager_address_pool_acquire(link->manager, original->family, original->prefixlen, &in_addr);
249 log_error_link(link, "Failed to acquire address from pool: %s", strerror(-r));
253 log_error_link(link, "Couldn't find free address for interface, all taken.");
257 if (original->family == AF_INET) {
258 /* Pick first address in range for ourselves ...*/
259 in_addr.in.s_addr = in_addr.in.s_addr | htobe32(1);
261 /* .. and use last as broadcast address */
262 broadcast.s_addr = in_addr.in.s_addr | htobe32(0xFFFFFFFFUL >> original->prefixlen);
263 } else if (original->family == AF_INET6)
264 in_addr.in6.s6_addr[15] |= 1;
266 r = address_new_dynamic(&na);
270 na->family = original->family;
271 na->prefixlen = original->prefixlen;
272 na->scope = original->scope;
273 na->cinfo = original->cinfo;
275 if (original->label) {
276 na->label = strdup(original->label);
281 na->broadcast = broadcast;
282 na->in_addr = in_addr;
284 LIST_PREPEND(addresses, link->pool_addresses, na);
292 int address_configure(Address *address, Link *link,
293 sd_rtnl_message_handler_t callback) {
294 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
298 assert(address->family == AF_INET || address->family == AF_INET6);
300 assert(link->ifindex > 0);
301 assert(link->manager);
302 assert(link->manager->rtnl);
304 r = address_acquire(link, address, &address);
308 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
309 link->ifindex, address->family);
311 log_error("Could not allocate RTM_NEWADDR message: %s",
316 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
318 log_error("Could not set prefixlen: %s", strerror(-r));
322 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
324 log_error("Could not set flags: %s", strerror(-r));
328 r = sd_rtnl_message_addr_set_scope(req, address->scope);
330 log_error("Could not set scope: %s", strerror(-r));
334 if (address->family == AF_INET)
335 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
336 else if (address->family == AF_INET6)
337 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
339 log_error("Could not append IFA_LOCAL attribute: %s",
344 if (address->family == AF_INET) {
345 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
347 log_error("Could not append IFA_BROADCAST attribute: %s",
353 if (address->label) {
354 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
356 log_error("Could not append IFA_LABEL attribute: %s",
362 r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO,
365 log_error("Could not append IFA_CACHEINFO attribute: %s",
370 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
372 log_error("Could not send rtnetlink message: %s", strerror(-r));
379 int config_parse_dns(const char *unit,
380 const char *filename,
383 unsigned section_line,
389 Network *network = userdata;
391 _cleanup_address_free_ Address *n = NULL;
400 r = address_new_dynamic(&n);
404 r = net_parse_inaddr(rvalue, &n->family, &n->in_addr);
406 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
407 "DNS address is invalid, ignoring assignment: %s", rvalue);
411 if (streq(lvalue, "DNS")) {
412 LIST_FIND_TAIL(addresses, network->dns, tail);
413 LIST_INSERT_AFTER(addresses, network->dns, tail, n);
414 } else if (streq(lvalue, "NTP")) {
415 LIST_FIND_TAIL(addresses, network->ntp, tail);
416 LIST_INSERT_AFTER(addresses, network->ntp, tail, n);
418 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
419 "Key is invalid, ignoring assignment: %s=%s", lvalue, rvalue);
428 int config_parse_broadcast(const char *unit,
429 const char *filename,
432 unsigned section_line,
438 Network *network = userdata;
439 _cleanup_address_free_ Address *n = NULL;
440 _cleanup_free_ char *address = NULL;
449 r = address_new_static(network, section_line, &n);
453 if (n->family == AF_INET6) {
454 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
455 "Broadcast is not valid for IPv6 addresses, "
456 "ignoring assignment: %s", address);
460 r = net_parse_inaddr(address, &n->family, &n->broadcast);
462 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
463 "Broadcast is invalid, ignoring assignment: %s", address);
472 int config_parse_address(const char *unit,
473 const char *filename,
476 unsigned section_line,
482 Network *network = userdata;
483 _cleanup_address_free_ Address *n = NULL;
484 _cleanup_free_ char *address = NULL;
494 if (streq(section, "Network")) {
495 /* we are not in an Address section, so treat
496 * this as the special '0' section */
500 r = address_new_static(network, section_line, &n);
504 /* Address=address/prefixlen */
507 e = strchr(rvalue, '/');
510 r = safe_atou(e + 1, &i);
512 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
513 "Interface prefix length is invalid, "
514 "ignoring assignment: %s", e + 1);
518 n->prefixlen = (unsigned char) i;
520 address = strndup(rvalue, e - rvalue);
524 address = strdup(rvalue);
529 r = net_parse_inaddr(address, &n->family, &n->in_addr);
531 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
532 "Address is invalid, ignoring assignment: %s", address);
536 if (n->family == AF_INET && !n->broadcast.s_addr)
537 n->broadcast.s_addr = n->in_addr.in.s_addr |
538 htonl(0xfffffffflu >> n->prefixlen);
545 int config_parse_label(const char *unit,
546 const char *filename,
549 unsigned section_line,
555 Network *network = userdata;
556 _cleanup_address_free_ Address *n = NULL;
566 r = address_new_static(network, section_line, &n);
570 label = strdup(rvalue);
574 if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
575 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
576 "Interface label is not ASCII clean or is too"
577 " long, ignoring assignment: %s", rvalue);
595 bool address_equal(Address *a1, Address *a2) {
600 /* one, but not both, is NULL */
604 if (a1->family != a2->family)
607 switch (a1->family) {
608 /* use the same notion of equality as the kernel does */
613 if (a1->prefixlen != a2->prefixlen)
618 b1 = be32toh(a1->in_addr.in.s_addr);
619 b2 = be32toh(a2->in_addr.in.s_addr);
621 return (b1 >> (32 - a1->prefixlen)) == (b2 >> (32 - a1->prefixlen));
628 b1 = (uint64_t*)&a1->in_addr.in6;
629 b2 = (uint64_t*)&a2->in_addr.in6;
631 return (((b1[0] ^ b2[0]) | (b1[1] ^ b2[1])) == 0UL);
634 assert_not_reached("Invalid address family");