LCOV - code coverage report
Current view: top level - network - networkd-address.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 81 349 23.2 %
Date: 2015-07-29 18:47:03 Functions: 6 14 42.9 %

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

Generated by: LCOV version 1.11