]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/network/networkd-address-label.c
travis: turn on UBSan on Fuzzit
[thirdparty/systemd.git] / src / network / networkd-address-label.c
index 1248719cf349c10f33c300517e848e89dd3c9b81..ab738448c52bdc1c1e6775bdd183ef3491663427 100644 (file)
@@ -1,21 +1,4 @@
-/***
-  This file is part of systemd.
-
-  Copyright 2017 Susant Sahani
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
+/* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <net/if.h>
 #include <linux/if_addrlabel.h>
 #include "parse-util.h"
 #include "socket-util.h"
 
-int address_label_new(AddressLabel **ret) {
-        _cleanup_address_label_free_ AddressLabel *addrlabel = NULL;
-
-        addrlabel = new0(AddressLabel, 1);
-        if (!addrlabel)
-                return -ENOMEM;
-
-        *ret = addrlabel;
-        addrlabel = NULL;
-
-        return 0;
-}
-
 void address_label_free(AddressLabel *label) {
         if (!label)
                 return;
@@ -60,51 +30,85 @@ void address_label_free(AddressLabel *label) {
 }
 
 static int address_label_new_static(Network *network, const char *filename, unsigned section_line, AddressLabel **ret) {
-        _cleanup_network_config_section_free_ NetworkConfigSection *n = NULL;
-        _cleanup_address_label_free_ AddressLabel *label = NULL;
+        _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+        _cleanup_(address_label_freep) AddressLabel *label = NULL;
         int r;
 
         assert(network);
         assert(ret);
         assert(!!filename == (section_line > 0));
 
-        r = network_config_section_new(filename, section_line, &n);
-        if (r < 0)
-                return r;
+        if (filename) {
+                r = network_config_section_new(filename, section_line, &n);
+                if (r < 0)
+                        return r;
 
-        label = hashmap_get(network->address_labels_by_section, n);
-        if (label) {
-                *ret = label;
-                label = NULL;
+                label = hashmap_get(network->address_labels_by_section, n);
+                if (label) {
+                        *ret = TAKE_PTR(label);
 
-                return 0;
+                        return 0;
+                }
         }
 
-        r = address_label_new(&label);
-        if (r < 0)
-                return r;
-
-        label->section = n;
-        n = NULL;
+        label = new(AddressLabel, 1);
+        if (!label)
+                return -ENOMEM;
 
-        r = hashmap_put(network->address_labels_by_section, label->section, label);
-        if (r < 0)
-                return r;
+        *label = (AddressLabel) {
+                .network = network,
+        };
 
-        label->network = network;
         LIST_APPEND(labels, network->address_labels, label);
         network->n_address_labels++;
 
-        *ret = label;
-        label = NULL;
+        if (filename) {
+                label->section = TAKE_PTR(n);
+
+                r = hashmap_ensure_allocated(&network->address_labels_by_section, &network_config_hash_ops);
+                if (r < 0)
+                        return r;
+
+                r = hashmap_put(network->address_labels_by_section, label->section, label);
+                if (r < 0)
+                        return r;
+        }
+
+        *ret = TAKE_PTR(label);
 
         return 0;
 }
 
+static int address_label_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+        int r;
+
+        assert(rtnl);
+        assert(m);
+        assert(link);
+        assert(link->ifname);
+        assert(link->address_label_messages > 0);
+
+        link->address_label_messages--;
+
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+                return 1;
+
+        r = sd_netlink_message_get_errno(m);
+        if (r < 0 && r != -EEXIST)
+                log_link_warning_errno(link, r, "could not set address label: %m");
+        else if (r >= 0)
+                manager_rtnl_process_address(rtnl, m, link->manager);
+
+        if (link->address_label_messages == 0)
+                log_link_debug(link, "Addresses label set");
+
+        return 1;
+}
+
 int address_label_configure(
                 AddressLabel *label,
                 Link *link,
-                sd_netlink_message_handler_t callback,
+                link_netlink_message_handler_t callback,
                 bool update) {
 
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
@@ -117,7 +121,7 @@ int address_label_configure(
         assert(link->manager->rtnl);
 
         r = sd_rtnl_message_new_addrlabel(link->manager->rtnl, &req, RTM_NEWADDRLABEL,
-                                          link->ifindex, label->family);
+                                          link->ifindex, AF_INET6);
         if (r < 0)
                 return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
 
@@ -133,7 +137,9 @@ int address_label_configure(
         if (r < 0)
                 return log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m");
 
-        r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
+        r = netlink_call_async(link->manager->rtnl, NULL, req,
+                               callback ?: address_label_handler,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_error_errno(r, "Could not send rtnetlink message: %m");
 
@@ -153,11 +159,9 @@ int config_parse_address_label_prefix(const char *unit,
                                       void *data,
                                       void *userdata) {
 
-        _cleanup_address_label_free_ AddressLabel *n = NULL;
+        _cleanup_(address_label_free_or_set_invalidp) AddressLabel *n = NULL;
         Network *network = userdata;
-        const char *prefix, *e;
-        union in_addr_union buffer;
-        int r, f;
+        int r;
 
         assert(filename);
         assert(section);
@@ -169,44 +173,12 @@ int config_parse_address_label_prefix(const char *unit,
         if (r < 0)
                 return r;
 
-        /* AddressLabel=prefix/prefixlen */
-
-        /* prefixlen */
-        e = strchr(rvalue, '/');
-        if (e) {
-                unsigned i;
-
-                r = safe_atou(e + 1, &i);
-                if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length is invalid, ignoring assignment: %s", e + 1);
-                        return 0;
-                }
-
-                if (i > 128) {
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length is out of range, ignoring assignment: %s", e + 1);
-                        return 0;
-                }
-
-                n->prefixlen = (unsigned char) i;
-
-                prefix = strndupa(rvalue, e - rvalue);
-        } else
-                prefix = rvalue;
-
-        r = in_addr_from_string_auto(prefix, &f, &buffer);
+        r = in_addr_prefix_from_string(rvalue, AF_INET6, &n->in_addr, &n->prefixlen);
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r, "Address label is invalid, ignoring assignment: %s", prefix);
-                return 0;
-        }
-
-        if (f != AF_INET6) {
-                log_syntax(unit, LOG_ERR, filename, line, 0, "Address label family is not IPv6, ignoring assignment: %s", prefix);
+                log_syntax(unit, LOG_ERR, filename, line, r, "Address label is invalid, ignoring assignment: %s", rvalue);
                 return 0;
         }
 
-        n->family = f;
-        n->in_addr = buffer;
-
         n = NULL;
 
         return 0;
@@ -224,7 +196,7 @@ int config_parse_address_label(
                 void *data,
                 void *userdata) {
 
-        _cleanup_address_label_free_ AddressLabel *n = NULL;
+        _cleanup_(address_label_free_or_set_invalidp) AddressLabel *n = NULL;
         Network *network = userdata;
         uint32_t k;
         int r;
@@ -246,7 +218,7 @@ int config_parse_address_label(
         }
 
         if (k == 0xffffffffUL) {
-                log_syntax(unit, LOG_ERR, filename, line, r, "Adress label is invalid, ignoring: %s", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, r, "Address label is invalid, ignoring: %s", rvalue);
                 return 0;
         }