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/>.
26 #include "conf-parser.h"
29 #include "networkd-link.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 address = hashmap_get(network->addresses_by_section, UINT_TO_PTR(section));
53 address = new0(Address, 1);
57 address_init(address);
59 address->network = network;
61 LIST_APPEND(addresses, network->static_addresses, address);
64 address->section = section;
65 hashmap_put(network->addresses_by_section,
66 UINT_TO_PTR(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,
99 UINT_TO_PTR(address->section));
105 int address_establish(Address *address, Link *link) {
112 masq = link->network &&
113 link->network->ip_masquerade &&
114 address->family == AF_INET &&
115 address->scope < RT_SCOPE_LINK;
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);
122 r = fw_add_masquerade(masq, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
124 log_link_warning_errno(link, r, "Could not enable IP masquerading: %m");
126 address->ip_masquerade_done = masq;
132 int address_release(Address *address, Link *link) {
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);
143 r = fw_add_masquerade(false, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
145 log_link_warning_errno(link, r, "Failed to disable IP masquerading: %m");
147 address->ip_masquerade_done = false;
153 int address_drop(Address *address, Link *link,
154 sd_rtnl_message_handler_t callback) {
155 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
159 assert(address->family == AF_INET || address->family == AF_INET6);
161 assert(link->ifindex > 0);
162 assert(link->manager);
163 assert(link->manager->rtnl);
165 address_release(address, link);
167 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
168 link->ifindex, address->family);
170 return log_error_errno(r, "Could not allocate RTM_DELADDR message: %m");
172 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
174 return log_error_errno(r, "Could not set prefixlen: %m");
176 if (address->family == AF_INET)
177 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
178 else if (address->family == AF_INET6)
179 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
181 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
183 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
185 return log_error_errno(r, "Could not send rtnetlink message: %m");
192 int address_update(Address *address, Link *link,
193 sd_rtnl_message_handler_t callback) {
194 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
198 assert(address->family == AF_INET || address->family == AF_INET6);
199 assert(link->ifindex > 0);
200 assert(link->manager);
201 assert(link->manager->rtnl);
203 r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
204 link->ifindex, address->family);
206 return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
208 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
210 return log_error_errno(r, "Could not set prefixlen: %m");
212 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
214 return log_error_errno(r, "Could not set flags: %m");
216 r = sd_rtnl_message_addr_set_scope(req, address->scope);
218 return log_error_errno(r, "Could not set scope: %m");
220 if (address->family == AF_INET)
221 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
222 else if (address->family == AF_INET6)
223 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
225 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
227 if (address->family == AF_INET) {
228 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
230 return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
233 if (address->label) {
234 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
236 return log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
239 r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO, &address->cinfo);
241 return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
243 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
245 return log_error_errno(r, "Could not send rtnetlink message: %m");
252 static int address_acquire(Link *link, Address *original, Address **ret) {
253 union in_addr_union in_addr = {};
254 struct in_addr broadcast = {};
255 _cleanup_address_free_ Address *na = NULL;
262 /* Something useful was configured? just use it */
263 if (in_addr_is_null(original->family, &original->in_addr) <= 0)
266 /* The address is configured to be 0.0.0.0 or [::] by the user?
267 * Then let's acquire something more useful from the pool. */
268 r = manager_address_pool_acquire(link->manager, original->family, original->prefixlen, &in_addr);
270 log_link_error(link, "Failed to acquire address from pool: %s", strerror(-r));
274 log_link_error(link, "Couldn't find free address for interface, all taken.");
278 if (original->family == AF_INET) {
279 /* Pick first address in range for ourselves ... */
280 in_addr.in.s_addr = in_addr.in.s_addr | htobe32(1);
282 /* .. and use last as broadcast address */
283 broadcast.s_addr = in_addr.in.s_addr | htobe32(0xFFFFFFFFUL >> original->prefixlen);
284 } else if (original->family == AF_INET6)
285 in_addr.in6.s6_addr[15] |= 1;
287 r = address_new_dynamic(&na);
291 na->family = original->family;
292 na->prefixlen = original->prefixlen;
293 na->scope = original->scope;
294 na->cinfo = original->cinfo;
296 if (original->label) {
297 na->label = strdup(original->label);
302 na->broadcast = broadcast;
303 na->in_addr = in_addr;
305 LIST_PREPEND(addresses, link->pool_addresses, na);
313 int address_configure(Address *address, Link *link,
314 sd_rtnl_message_handler_t callback) {
315 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
319 assert(address->family == AF_INET || address->family == AF_INET6);
321 assert(link->ifindex > 0);
322 assert(link->manager);
323 assert(link->manager->rtnl);
325 r = address_acquire(link, address, &address);
329 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
330 link->ifindex, address->family);
332 return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
334 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
336 return log_error_errno(r, "Could not set prefixlen: %m");
338 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
340 return log_error_errno(r, "Could not set flags: %m");
342 r = sd_rtnl_message_addr_set_scope(req, address->scope);
344 return log_error_errno(r, "Could not set scope: %m");
346 if (address->family == AF_INET)
347 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
348 else if (address->family == AF_INET6)
349 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
351 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
353 if (!in_addr_is_null(address->family, &address->in_addr_peer)) {
354 if (address->family == AF_INET)
355 r = sd_rtnl_message_append_in_addr(req, IFA_ADDRESS, &address->in_addr_peer.in);
356 else if (address->family == AF_INET6)
357 r = sd_rtnl_message_append_in6_addr(req, IFA_ADDRESS, &address->in_addr_peer.in6);
359 return log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m");
361 if (address->family == AF_INET) {
362 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
364 return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
368 if (address->label) {
369 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
371 return log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
374 r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO,
377 return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
379 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
381 return log_error_errno(r, "Could not send rtnetlink message: %m");
385 address_establish(address, link);
390 int config_parse_broadcast(
392 const char *filename,
395 unsigned section_line,
402 Network *network = userdata;
403 _cleanup_address_free_ Address *n = NULL;
412 r = address_new_static(network, section_line, &n);
416 if (n->family == AF_INET6) {
417 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
418 "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
422 r = in_addr_from_string(AF_INET, rvalue, (union in_addr_union*) &n->broadcast);
424 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
425 "Broadcast is invalid, ignoring assignment: %s", rvalue);
435 int config_parse_address(const char *unit,
436 const char *filename,
439 unsigned section_line,
446 Network *network = userdata;
447 _cleanup_address_free_ Address *n = NULL;
448 const char *address, *e;
449 union in_addr_union buffer;
458 if (streq(section, "Network")) {
459 /* we are not in an Address section, so treat
460 * this as the special '0' section */
464 r = address_new_static(network, section_line, &n);
468 /* Address=address/prefixlen */
471 e = strchr(rvalue, '/');
474 r = safe_atou(e + 1, &i);
476 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
477 "Prefix length is invalid, ignoring assignment: %s", e + 1);
481 n->prefixlen = (unsigned char) i;
483 address = strndupa(rvalue, e - rvalue);
487 r = in_addr_from_string_auto(address, &f, &buffer);
489 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
490 "Address is invalid, ignoring assignment: %s", address);
494 if (!e && f == AF_INET) {
495 r = in_addr_default_prefixlen(&buffer.in, &n->prefixlen);
497 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
498 "Prefix length not specified, and a default one can not be deduced for '%s', ignoring assignment", address);
503 if (n->family != AF_UNSPEC && f != n->family) {
504 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
505 "Address is incompatible, ignoring assignment: %s", address);
511 if (streq(lvalue, "Address"))
514 n->in_addr_peer = buffer;
516 if (n->family == AF_INET && n->broadcast.s_addr == 0)
517 n->broadcast.s_addr = n->in_addr.in.s_addr | htonl(0xfffffffflu >> n->prefixlen);
524 int config_parse_label(const char *unit,
525 const char *filename,
528 unsigned section_line,
534 Network *network = userdata;
535 _cleanup_address_free_ Address *n = NULL;
545 r = address_new_static(network, section_line, &n);
549 label = strdup(rvalue);
553 if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
554 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
555 "Interface label is not ASCII clean or is too"
556 " long, ignoring assignment: %s", rvalue);
574 bool address_equal(Address *a1, Address *a2) {
579 /* one, but not both, is NULL */
583 if (a1->family != a2->family)
586 switch (a1->family) {
587 /* use the same notion of equality as the kernel does */
592 if (a1->prefixlen != a2->prefixlen)
594 else if (a1->prefixlen == 0)
595 /* make sure we don't try to shift by 32.
596 * See ISO/IEC 9899:TC3 ยง 6.5.7.3. */
601 b1 = be32toh(a1->in_addr.in.s_addr);
602 b2 = be32toh(a2->in_addr.in.s_addr);
604 return (b1 >> (32 - a1->prefixlen)) == (b2 >> (32 - a1->prefixlen));
610 b1 = (uint64_t*)&a1->in_addr.in6;
611 b2 = (uint64_t*)&a2->in_addr.in6;
613 return (((b1[0] ^ b2[0]) | (b1[1] ^ b2[1])) == 0UL);
617 assert_not_reached("Invalid address family");