]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/network/networkd-network.c
network: allocate hashmap objects when they are required
[thirdparty/systemd.git] / src / network / networkd-network.c
index c3a11ddca07a7ef8ad55a38e3833f1c0a59360c4..989c92322bb3d5ad489fe896f7ff41cec14bf87d 100644 (file)
@@ -1,9 +1,4 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
-/***
-  This file is part of systemd.
-
-  Copyright 2013 Tom Gundersen <teg@jklm.no>
-***/
 
 #include <ctype.h>
 #include <net/if.h>
@@ -41,7 +36,7 @@ static int network_config_compare_func(const void *a, const void *b) {
         if (r != 0)
                 return r;
 
-        return y->line - x->line;
+        return CMP(x->line, y->line);
 }
 
 const struct hash_ops network_config_hash_ops = {
@@ -85,8 +80,7 @@ void network_apply_anonymize_if_set(Network *network) {
         network->dhcp_client_identifier = DHCP_CLIENT_ID_MAC;
         /* RFC 7844 3.10:
          SHOULD NOT use the Vendor Class Identifier option */
-        /* NOTE: it was not initiallized to any value in network_load_one. */
-        network->dhcp_vendor_class_identifier = false;
+        network->dhcp_vendor_class_identifier = mfree(network->dhcp_vendor_class_identifier);
         /* RFC7844 section 3.6.:
          The client intending to protect its privacy SHOULD only request a
          minimal number of options in the PRL and SHOULD also randomly shuffle
@@ -108,7 +102,7 @@ void network_apply_anonymize_if_set(Network *network) {
         network->dhcp_use_timezone = false;
 }
 
-static int network_load_one(Manager *manager, const char *filename) {
+int network_load_one(Manager *manager, const char *filename) {
         _cleanup_(network_freep) Network *network = NULL;
         _cleanup_fclose_ FILE *file = NULL;
         char *d;
@@ -133,47 +127,71 @@ static int network_load_one(Manager *manager, const char *filename) {
                 return 0;
         }
 
-        network = new0(Network, 1);
+        network = new(Network, 1);
         if (!network)
                 return log_oom();
 
-        network->manager = manager;
-
-        LIST_HEAD_INIT(network->static_addresses);
-        LIST_HEAD_INIT(network->static_routes);
-        LIST_HEAD_INIT(network->static_fdb_entries);
-        LIST_HEAD_INIT(network->ipv6_proxy_ndp_addresses);
-        LIST_HEAD_INIT(network->address_labels);
-        LIST_HEAD_INIT(network->static_prefixes);
-        LIST_HEAD_INIT(network->rules);
-
-        network->stacked_netdevs = hashmap_new(&string_hash_ops);
-        if (!network->stacked_netdevs)
-                return log_oom();
-
-        network->addresses_by_section = hashmap_new(&network_config_hash_ops);
-        if (!network->addresses_by_section)
-                return log_oom();
-
-        network->routes_by_section = hashmap_new(&network_config_hash_ops);
-        if (!network->routes_by_section)
-                return log_oom();
-
-        network->fdb_entries_by_section = hashmap_new(NULL);
-        if (!network->fdb_entries_by_section)
-                return log_oom();
-
-        network->address_labels_by_section = hashmap_new(&network_config_hash_ops);
-        if (!network->address_labels_by_section)
-                log_oom();
-
-        network->prefixes_by_section = hashmap_new(&network_config_hash_ops);
-        if (!network->prefixes_by_section)
-                return log_oom();
-
-        network->rules_by_section = hashmap_new(&network_config_hash_ops);
-        if (!network->rules_by_section)
-                return log_oom();
+        *network = (Network) {
+                .manager = manager,
+
+                .required_for_online = true,
+                .dhcp = ADDRESS_FAMILY_NO,
+                .dhcp_use_ntp = true,
+                .dhcp_use_dns = true,
+                .dhcp_use_hostname = true,
+                .dhcp_use_routes = true,
+                /* NOTE: this var might be overwriten by network_apply_anonymize_if_set */
+                .dhcp_send_hostname = true,
+                /* To enable/disable RFC7844 Anonymity Profiles */
+                .dhcp_anonymize = false,
+                .dhcp_route_metric = DHCP_ROUTE_METRIC,
+                /* NOTE: this var might be overwrite by network_apply_anonymize_if_set */
+                .dhcp_client_identifier = DHCP_CLIENT_ID_DUID,
+                .dhcp_route_table = RT_TABLE_MAIN,
+                .dhcp_route_table_set = false,
+                /* NOTE: from man: UseMTU=... Defaults to false*/
+                .dhcp_use_mtu = false,
+                /* NOTE: from man: UseTimezone=... Defaults to "no".*/
+                .dhcp_use_timezone = false,
+                .rapid_commit = true,
+
+                .dhcp_server_emit_dns = true,
+                .dhcp_server_emit_ntp = true,
+                .dhcp_server_emit_router = true,
+                .dhcp_server_emit_timezone = true,
+
+                .router_emit_dns = true,
+                .router_emit_domains = true,
+
+                .use_bpdu = -1,
+                .hairpin = -1,
+                .fast_leave = -1,
+                .allow_port_to_be_root = -1,
+                .unicast_flood = -1,
+                .priority = LINK_BRIDGE_PORT_PRIORITY_INVALID,
+
+                .lldp_mode = LLDP_MODE_ROUTERS_ONLY,
+
+                .llmnr = RESOLVE_SUPPORT_YES,
+                .mdns = RESOLVE_SUPPORT_NO,
+                .dnssec_mode = _DNSSEC_MODE_INVALID,
+                .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
+
+                .link_local = ADDRESS_FAMILY_IPV6,
+
+                .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
+                .ipv6_accept_ra = -1,
+                .ipv6_dad_transmits = -1,
+                .ipv6_hop_limit = -1,
+                .ipv6_proxy_ndp = -1,
+                .duid.type = _DUID_TYPE_INVALID,
+                .proxy_arp = -1,
+                .arp = -1,
+                .multicast = -1,
+                .allmulticast = -1,
+                .ipv6_accept_ra_use_dns = true,
+                .ipv6_accept_ra_route_table = RT_TABLE_MAIN,
+        };
 
         network->filename = strdup(filename);
         if (!network->filename)
@@ -187,72 +205,8 @@ static int network_load_one(Manager *manager, const char *filename) {
         if (!d)
                 return -EINVAL;
 
-        assert(streq(d, ".network"));
-
         *d = '\0';
 
-        network->required_for_online = true;
-        network->dhcp = ADDRESS_FAMILY_NO;
-        network->dhcp_use_ntp = true;
-        network->dhcp_use_dns = true;
-        network->dhcp_use_hostname = true;
-        network->dhcp_use_routes = true;
-        /* NOTE: this var might be overwriten by network_apply_anonymize_if_set */
-        network->dhcp_send_hostname = true;
-        /* To enable/disable RFC7844 Anonymity Profiles */
-        network->dhcp_anonymize = false;
-        network->dhcp_route_metric = DHCP_ROUTE_METRIC;
-        /* NOTE: this var might be overwrite by network_apply_anonymize_if_set */
-        network->dhcp_client_identifier = DHCP_CLIENT_ID_DUID;
-        network->dhcp_route_table = RT_TABLE_MAIN;
-        network->dhcp_route_table_set = false;
-        /* NOTE: the following vars were not set to any default,
-         * even if they are commented in the man?
-         * These vars might be overwriten by network_apply_anonymize_if_set */
-        network->dhcp_vendor_class_identifier = false;
-        /* NOTE: from man: UseMTU=... Defaults to false*/
-        network->dhcp_use_mtu = false;
-        /* NOTE: from man: UseTimezone=... Defaults to "no".*/
-        network->dhcp_use_timezone = false;
-        network->rapid_commit = true;
-
-        network->dhcp_server_emit_dns = true;
-        network->dhcp_server_emit_ntp = true;
-        network->dhcp_server_emit_router = true;
-        network->dhcp_server_emit_timezone = true;
-
-        network->router_emit_dns = true;
-        network->router_emit_domains = true;
-
-        network->use_bpdu = -1;
-        network->hairpin = -1;
-        network->fast_leave = -1;
-        network->allow_port_to_be_root = -1;
-        network->unicast_flood = -1;
-        network->priority = LINK_BRIDGE_PORT_PRIORITY_INVALID;
-
-        network->lldp_mode = LLDP_MODE_ROUTERS_ONLY;
-
-        network->llmnr = RESOLVE_SUPPORT_YES;
-        network->mdns = RESOLVE_SUPPORT_NO;
-        network->dnssec_mode = _DNSSEC_MODE_INVALID;
-
-        network->link_local = ADDRESS_FAMILY_IPV6;
-
-        network->ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
-        network->ipv6_accept_ra = -1;
-        network->ipv6_dad_transmits = -1;
-        network->ipv6_hop_limit = -1;
-        network->ipv6_proxy_ndp = -1;
-        network->duid.type = _DUID_TYPE_INVALID;
-        network->proxy_arp = -1;
-        network->arp = -1;
-        network->multicast = -1;
-        network->allmulticast = -1;
-        network->ipv6_accept_ra_use_dns = true;
-        network->ipv6_accept_ra_route_table = RT_TABLE_MAIN;
-        network->ipv6_mtu = 0;
-
         dropin_dirname = strjoina(network->name, ".network.d");
 
         r = config_parse_many(filename, network_dirs, dropin_dirname,
@@ -272,7 +226,8 @@ static int network_load_one(Manager *manager, const char *filename) {
                               "BridgeFDB\0"
                               "BridgeVLAN\0"
                               "IPv6PrefixDelegation\0"
-                              "IPv6Prefix\0",
+                              "IPv6Prefix\0"
+                              "CAN\0",
                               config_item_perf_lookup, network_network_gperf_lookup,
                               CONFIG_PARSE_WARN, network);
         if (r < 0)
@@ -284,6 +239,12 @@ static int network_load_one(Manager *manager, const char *filename) {
         if (network->ip_masquerade)
                 network->ip_forward |= ADDRESS_FAMILY_IPV4;
 
+        if (network->mtu > 0 && network->dhcp_use_mtu) {
+                log_warning("MTUBytes= in [Link] section and UseMTU= in [DHCP] section are set in %s. "
+                            "Disabling UseMTU=.", filename);
+                network->dhcp_use_mtu = false;
+        }
+
         LIST_PREPEND(networks, manager->networks, network);
 
         r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
@@ -346,9 +307,7 @@ void network_free(Network *network) {
         AddressLabel *label;
         Prefix *prefix;
         Address *address;
-        NetDev *netdev;
         Route *route;
-        Iterator i;
 
         if (!network)
                 return;
@@ -374,15 +333,14 @@ void network_free(Network *network) {
         strv_free(network->route_domains);
         strv_free(network->bind_carrier);
 
+        strv_free(network->router_search_domains);
+        free(network->router_dns);
+
         netdev_unref(network->bridge);
         netdev_unref(network->bond);
         netdev_unref(network->vrf);
 
-        HASHMAP_FOREACH(netdev, network->stacked_netdevs, i) {
-                hashmap_remove(network->stacked_netdevs, netdev->ifname);
-                netdev_unref(netdev);
-        }
-        hashmap_free(network->stacked_netdevs);
+        hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
 
         while ((route = network->static_routes))
                 route_free(route);
@@ -416,8 +374,11 @@ void network_free(Network *network) {
                 if (network->manager->networks)
                         LIST_REMOVE(networks, network->manager->networks, network);
 
-                if (network->manager->networks_by_name)
+                if (network->manager->networks_by_name && network->name)
                         hashmap_remove(network->manager->networks_by_name, network->name);
+
+                if (network->manager->duids_requesting_uuid)
+                        set_remove(network->manager->duids_requesting_uuid, &network->duid);
         }
 
         free(network->name);
@@ -453,26 +414,25 @@ int network_get_by_name(Manager *manager, const char *name, Network **ret) {
         return 0;
 }
 
-int network_get(Manager *manager, struct udev_device *device,
+int network_get(Manager *manager, sd_device *device,
                 const char *ifname, const struct ether_addr *address,
                 Network **ret) {
-        Network *network;
-        struct udev_device *parent;
         const char *path = NULL, *parent_driver = NULL, *driver = NULL, *devtype = NULL;
+        sd_device *parent;
+        Network *network;
 
         assert(manager);
         assert(ret);
 
         if (device) {
-                path = udev_device_get_property_value(device, "ID_PATH");
+                (void) sd_device_get_property_value(device, "ID_PATH", &path);
 
-                parent = udev_device_get_parent(device);
-                if (parent)
-                        parent_driver = udev_device_get_driver(parent);
+                if (sd_device_get_parent(device, &parent) >= 0)
+                        (void) sd_device_get_driver(parent, &parent_driver);
 
-                driver = udev_device_get_property_value(device, "ID_NET_DRIVER");
+                (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &driver);
 
-                devtype = udev_device_get_devtype(device);
+                (void) sd_device_get_devtype(device, &devtype);
         }
 
         LIST_FOREACH(networks, network, manager->networks) {
@@ -487,8 +447,7 @@ int network_get(Manager *manager, struct udev_device *device,
                                 const char *attr;
                                 uint8_t name_assign_type = NET_NAME_UNKNOWN;
 
-                                attr = udev_device_get_sysattr_value(device, "name_assign_type");
-                                if (attr)
+                                if (sd_device_get_sysattr_value(device, "name_assign_type", &attr) >= 0)
                                         (void) safe_atou8(attr, &name_assign_type);
 
                                 if (name_assign_type == NET_NAME_ENUM)
@@ -608,14 +567,17 @@ int config_parse_netdev(const char *unit,
 
         switch (kind) {
         case NETDEV_KIND_BRIDGE:
+                network->bridge = netdev_unref(network->bridge);
                 network->bridge = netdev;
 
                 break;
         case NETDEV_KIND_BOND:
+                network->bond = netdev_unref(network->bond);
                 network->bond = netdev;
 
                 break;
         case NETDEV_KIND_VRF:
+                network->vrf = netdev_unref(network->vrf);
                 network->vrf = netdev;
 
                 break;
@@ -625,6 +587,10 @@ int config_parse_netdev(const char *unit,
         case NETDEV_KIND_IPVLAN:
         case NETDEV_KIND_VXLAN:
         case NETDEV_KIND_VCAN:
+                r = hashmap_ensure_allocated(&network->stacked_netdevs, &string_hash_ops);
+                if (r < 0)
+                        return log_oom();
+
                 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
                 if (r < 0) {
                         log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add NetDev '%s' to network: %m", rvalue);
@@ -763,6 +729,10 @@ int config_parse_tunnel(const char *unit,
                 return 0;
         }
 
+        r = hashmap_ensure_allocated(&network->stacked_netdevs, &string_hash_ops);
+        if (r < 0)
+                return log_oom();
+
         r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
         if (r < 0) {
                 log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue);
@@ -969,7 +939,8 @@ int config_parse_hostname(
                 void *data,
                 void *userdata) {
 
-        char **hostname = data, *hn = NULL;
+        _cleanup_free_ char *hn = NULL;
+        char **hostname = data;
         int r;
 
         assert(filename);
@@ -982,13 +953,20 @@ int config_parse_hostname(
 
         if (!hostname_is_valid(hn, false)) {
                 log_syntax(unit, LOG_ERR, filename, line, 0, "Hostname is not valid, ignoring assignment: %s", rvalue);
-                free(hn);
                 return 0;
         }
 
-        free(*hostname);
-        *hostname = hostname_cleanup(hn);
-        return 0;
+        r = dns_name_is_valid(hn);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
+                return 0;
+        }
+        if (r == 0) {
+                log_syntax(unit, LOG_ERR, filename, line, 0, "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
+                return 0;
+        }
+
+        return free_and_replace(*hostname, hn);
 }
 
 int config_parse_timezone(
@@ -1003,7 +981,8 @@ int config_parse_timezone(
                 void *data,
                 void *userdata) {
 
-        char **datap = data, *tz = NULL;
+        _cleanup_free_ char *tz = NULL;
+        char **datap = data;
         int r;
 
         assert(filename);
@@ -1016,14 +995,10 @@ int config_parse_timezone(
 
         if (!timezone_is_valid(tz, LOG_ERR)) {
                 log_syntax(unit, LOG_ERR, filename, line, 0, "Timezone is not valid, ignoring assignment: %s", rvalue);
-                free(tz);
                 return 0;
         }
 
-        free(*datap);
-        *datap = tz;
-
-        return 0;
+        return free_and_replace(*datap, tz);
 }
 
 int config_parse_dhcp_server_dns(
@@ -1149,8 +1124,7 @@ int config_parse_radv_search_domains(
         assert(rvalue);
 
         for (;;) {
-                _cleanup_free_ char *w = NULL;
-                _cleanup_free_ char *idna = NULL;
+                _cleanup_free_ char *w = NULL, *idna = NULL;
 
                 r = extract_first_word(&p, &w, NULL, 0);
                 if (r == -ENOMEM)
@@ -1163,11 +1137,15 @@ int config_parse_radv_search_domains(
                         break;
 
                 r = dns_name_apply_idna(w, &idna);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to apply IDNA to domain name '%s', ignoring: %m", w);
+                        continue;
+                }
                 if (r > 0) {
                         r = strv_push(&n->router_search_domains, idna);
                         if (r >= 0)
                                 idna = NULL;
-                } else if (r == 0) {
+                } else {
                         r = strv_push(&n->router_search_domains, w);
                         if (r >= 0)
                                 w = NULL;