]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: introduce UplinkInterface= in [IPv6SendRA]
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 15 Jun 2021 18:51:57 +0000 (03:51 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 4 Aug 2021 13:20:56 +0000 (22:20 +0900)
man/systemd.network.xml
src/network/networkd-dhcp-server.c
src/network/networkd-dhcp-server.h
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h
src/network/networkd-radv.c
test/fuzz/fuzz-network-parser/directives.network

index 0de1994e2092c455ea3f98c707b480f0f4afb3b0..299c56df0ad400cd9a48a74a6fd36d83380a6d95 100644 (file)
@@ -2586,18 +2586,28 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
         for details. Defaults to <literal>medium</literal>.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>UplinkInterface=</varname></term>
+        <listitem><para>Specifies the name or the index of the uplink interface, or one of the special
+        values <literal>:none</literal> and <literal>:auto</literal>. When emitting DNS servers or
+        search domains is enabled but no servers are specified, the servers configured in the uplink
+        interface will be emitted. When <literal>:auto</literal>, the link which has a default gateway
+        with the highest priority will be automatically selected. When <literal>:none</literal>, no
+        uplink interface will be selected. Defaults to <literal>:auto</literal>.</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><varname>EmitDNS=</varname></term>
         <term><varname>DNS=</varname></term>
 
-        <listitem><para><varname>DNS=</varname> specifies a list of recursive DNS server IPv6 addresses that
-        are distributed via Router Advertisement messages when <varname>EmitDNS=</varname> is
-        true. <varname>DNS=</varname> also takes special value <literal>_link_local</literal>; in that case
-        the IPv6 link local address is distributed. If <varname>DNS=</varname> is empty, DNS servers are read
-        from the [Network] section. If the [Network] section does not contain any DNS servers either, DNS
-        servers from the uplink with the highest priority default route are used. When
-        <varname>EmitDNS=</varname> is false, no DNS server information is sent in Router Advertisement
-        messages. <varname>EmitDNS=</varname> defaults to true.</para></listitem>
+        <listitem><para><varname>DNS=</varname> specifies a list of recursive DNS server IPv6 addresses
+        that are distributed via Router Advertisement messages when <varname>EmitDNS=</varname> is true.
+        <varname>DNS=</varname> also takes special value <literal>_link_local</literal>; in that case
+        the IPv6 link local address is distributed. If <varname>DNS=</varname> is empty, DNS servers are
+        read from the [Network] section. If the [Network] section does not contain any DNS servers
+        either, DNS servers from the uplink interface specified in <varname>UplinkInterface=</varname>
+        will be used. When <varname>EmitDNS=</varname> is false, no DNS server information is sent in
+        Router Advertisement messages. <varname>EmitDNS=</varname> defaults to true.</para></listitem>
       </varlistentry>
 
       <varlistentry>
@@ -2605,11 +2615,12 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
         <term><varname>Domains=</varname></term>
 
         <listitem><para>A list of DNS search domains distributed via Router Advertisement messages when
-        <varname>EmitDomains=</varname> is true. If <varname>Domains=</varname> is empty, DNS search domains
-        are read from the [Network] section. If the [Network] section does not contain any DNS search domains
-        either, DNS search domains from the uplink with the highest priority default route are used. When
-        <varname>EmitDomains=</varname> is false, no DNS search domain information is sent in Router
-        Advertisement messages. <varname>EmitDomains=</varname> defaults to true.</para></listitem>
+        <varname>EmitDomains=</varname> is true. If <varname>Domains=</varname> is empty, DNS search
+        domains are read from the [Network] section. If the [Network] section does not contain any DNS
+        search domains either, DNS search domains from the uplink interface specified in
+        <varname>UplinkInterface=</varname> will be used. When <varname>EmitDomains=</varname> is false,
+        no DNS search domain information is sent in Router Advertisement messages.
+        <varname>EmitDomains=</varname> defaults to true.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index e4be034a4c7c2f5bff805270567981e740219613..f190bcf428b029c0802476c000b90b0a49e9e360 100644 (file)
@@ -106,7 +106,7 @@ static int dhcp_server_find_uplink(Link *link, Link **ret) {
         if (link->network->dhcp_server_uplink_index > 0)
                 return link_get_by_index(link->manager, link->network->dhcp_server_uplink_index, ret);
 
-        if (link->network->dhcp_server_uplink_index == 0) {
+        if (link->network->dhcp_server_uplink_index == UPLINK_INDEX_AUTO) {
                 /* It is not necessary to propagate error in automatic selection. */
                 if (manager_find_uplink(link->manager, AF_INET, link, ret) < 0)
                         *ret = NULL;
@@ -663,55 +663,3 @@ int config_parse_dhcp_server_address(
         network->dhcp_server_address_prefixlen = prefixlen;
         return 0;
 }
-
-int config_parse_dhcp_server_uplink(
-                const char *unit,
-                const char *filename,
-                unsigned line,
-                const char *section,
-                unsigned section_line,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        Network *network = userdata;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-
-        if (isempty(rvalue) || streq(rvalue, ":auto")) {
-                network->dhcp_server_uplink_index = 0; /* uplink will be selected automatically */
-                network->dhcp_server_uplink_name = mfree(network->dhcp_server_uplink_name);
-                return 0;
-        }
-
-        if (streq(rvalue, ":none")) {
-                network->dhcp_server_uplink_index = -1; /* uplink will not be selected automatically */
-                network->dhcp_server_uplink_name = mfree(network->dhcp_server_uplink_name);
-                return 0;
-        }
-
-        r = parse_ifindex(rvalue);
-        if (r > 0) {
-                network->dhcp_server_uplink_index = r;
-                network->dhcp_server_uplink_name = mfree(network->dhcp_server_uplink_name);
-                return 0;
-        }
-
-        if (!ifname_valid_full(rvalue, IFNAME_VALID_ALTERNATIVE)) {
-                log_syntax(unit, LOG_WARNING, filename, line, 0,
-                           "Invalid interface name in %s=, ignoring assignment: %s", lvalue, rvalue);
-                return 0;
-        }
-
-        r = free_and_strdup_warn(&network->dhcp_server_uplink_name, rvalue);
-        if (r < 0)
-                return r;
-
-        network->dhcp_server_uplink_index = 0;
-        return 0;
-}
index 3f23f97bb8dbb789a268eba197711e41be5a830c..a02cd995ec049c3247a9417add3d072a7709cdc6 100644 (file)
@@ -15,4 +15,3 @@ int request_process_dhcp_server(Request *req);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_relay_agent_suboption);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_emit);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_address);
-CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_uplink);
index de4120c47ec55db8518b0c5825475b153520861c..9166376aaa872a6045c586f778b7429c96d33809 100644 (file)
@@ -265,7 +265,7 @@ IPv6AcceptRA.PrefixDenyList,                 config_parse_ndisc_address_filter,
 IPv6AcceptRA.RouteAllowList,                 config_parse_ndisc_address_filter,                        0,                             offsetof(Network, ndisc_allow_listed_route_prefix)
 IPv6AcceptRA.RouteDenyList,                  config_parse_ndisc_address_filter,                        0,                             offsetof(Network, ndisc_deny_listed_route_prefix)
 DHCPServer.ServerAddress,                    config_parse_dhcp_server_address,                         0,                             0
-DHCPServer.UplinkInterface,                  config_parse_dhcp_server_uplink,                          0,                             0
+DHCPServer.UplinkInterface,                  config_parse_uplink,                                      0,                             0
 DHCPServer.RelayTarget,                      config_parse_in_addr_non_null,                            AF_INET,                       offsetof(Network, dhcp_server_relay_target)
 DHCPServer.RelayAgentCircuitId,              config_parse_dhcp_server_relay_agent_suboption,           0,                             offsetof(Network, dhcp_server_relay_agent_circuit_id)
 DHCPServer.RelayAgentRemoteId,               config_parse_dhcp_server_relay_agent_suboption,           0,                             offsetof(Network, dhcp_server_relay_agent_remote_id)
@@ -333,6 +333,7 @@ IPv6SendRA.DNS,                              config_parse_radv_dns,
 IPv6SendRA.EmitDomains,                      config_parse_bool,                                        0,                             offsetof(Network, router_emit_domains)
 IPv6SendRA.Domains,                          config_parse_radv_search_domains,                         0,                             0
 IPv6SendRA.DNSLifetimeSec,                   config_parse_sec,                                         0,                             offsetof(Network, router_dns_lifetime_usec)
+IPv6SendRA.UplinkInterface,                  config_parse_uplink,                                      0,                             0
 IPv6Prefix.Prefix,                           config_parse_prefix,                                      0,                             0
 IPv6Prefix.OnLink,                           config_parse_prefix_flags,                                0,                             0
 IPv6Prefix.AddressAutoconfiguration,         config_parse_prefix_flags,                                0,                             0
index 850b4f449e10a825fd1c35485420e589b6df1361..f16553a6d9d72d692231d7b62fb3d6c167f09871 100644 (file)
@@ -640,6 +640,7 @@ static Network *network_free(Network *network) {
 
         free(network->dhcp_server_timezone);
         free(network->dhcp_server_uplink_name);
+        free(network->router_uplink_name);
 
         for (sd_dhcp_lease_server_type_t t = 0; t < _SD_DHCP_LEASE_SERVER_TYPE_MAX; t++)
                 free(network->dhcp_server_emit[t].addresses);
@@ -1185,6 +1186,73 @@ int config_parse_link_group(
         return 0;
 }
 
+
+int config_parse_uplink(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        Network *network = userdata;
+        int *index, r;
+        char **name;
+
+        assert(filename);
+        assert(section);
+        assert(lvalue);
+        assert(rvalue);
+
+        if (streq(section, "DHCPServer")) {
+                index = &network->dhcp_server_uplink_index;
+                name = &network->dhcp_server_uplink_name;
+        } else if (streq(section, "IPv6SendRA")) {
+                index = &network->router_uplink_index;
+                name = &network->router_uplink_name;
+        } else
+                assert_not_reached();
+
+        if (isempty(rvalue) || streq(rvalue, ":auto")) {
+                *index = UPLINK_INDEX_AUTO;
+                *name = mfree(*name);
+                return 0;
+        }
+
+        if (streq(rvalue, ":none")) {
+                *index = UPLINK_INDEX_NONE;
+                *name = mfree(*name);
+                return 0;
+        }
+
+        r = parse_ifindex(rvalue);
+        if (r > 0) {
+                *index = r;
+                *name = mfree(*name);
+                return 0;
+        }
+
+        if (!ifname_valid_full(rvalue, IFNAME_VALID_ALTERNATIVE)) {
+                log_syntax(unit, LOG_WARNING, filename, line, 0,
+                           "Invalid interface name in %s=, ignoring assignment: %s", lvalue, rvalue);
+                return 0;
+        }
+
+        /* The interface name will be resolved later. */
+        r = free_and_strdup_warn(name, rvalue);
+        if (r < 0)
+                return r;
+
+        /* Note, if uplink_name is set, then uplink_index will be ignored. So, the below does not mean
+         * an uplink interface will be selected automatically. */
+        *index = UPLINK_INDEX_AUTO;
+        return 0;
+}
+
 DEFINE_CONFIG_PARSE_ENUM(config_parse_required_family_for_online, link_required_address_family, AddressFamily,
                          "Failed to parse RequiredFamilyForOnline= setting");
 
index b39063fe8ad918590070fd2c26c739c7870ac1fc..bf0e1a733e7e5ddadc1c43106acc41a9bde99110 100644 (file)
 #include "resolve-util.h"
 #include "socket-netlink.h"
 
+/* Special values for *_uplink_index. */
+#define UPLINK_INDEX_AUTO  0 /* uplink will be selected automatically */
+#define UPLINK_INDEX_NONE -1 /* uplink will not be selected automatically */
+
 typedef enum KeepConfiguration {
         KEEP_CONFIGURATION_NO            = 0,
         KEEP_CONFIGURATION_DHCP_ON_START = 1 << 0,
@@ -224,6 +228,8 @@ struct Network {
         struct in6_addr *router_dns;
         unsigned n_router_dns;
         OrderedSet *router_search_domains;
+        int router_uplink_index;
+        char *router_uplink_name;
 
         /* DHCPv6 Prefix Delegation support */
         int dhcp6_pd;
@@ -364,6 +370,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_keep_configuration);
 CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_link_local_address_gen_mode);
 CONFIG_PARSER_PROTOTYPE(config_parse_activation_policy);
 CONFIG_PARSER_PROTOTYPE(config_parse_link_group);
+CONFIG_PARSER_PROTOTYPE(config_parse_uplink);
 
 const struct ConfigPerfItem* network_network_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
 
index a21f69d6f3bda928c746fd7506a2485a8a928d41..953a12b5724d58182e07faf5020ea6853fab97bd 100644 (file)
@@ -584,10 +584,7 @@ static int radv_set_dns(Link *link, Link *uplink) {
                 goto set_dns;
 
         if (uplink) {
-                if (!uplink->network) {
-                        log_link_debug(uplink, "Cannot fetch DNS servers as uplink interface is not managed by us");
-                        return 0;
-                }
+                assert(uplink->network);
 
                 r = network_get_ipv6_dns(uplink->network, &dns, &n_dns);
                 if (r > 0)
@@ -623,10 +620,7 @@ static int radv_set_domains(Link *link, Link *uplink) {
                 goto set_domains;
 
         if (uplink) {
-                if (!uplink->network) {
-                        log_link_debug(uplink, "Cannot fetch DNS search domains as uplink interface is not managed by us");
-                        return 0;
-                }
+                assert(uplink->network);
 
                 search_domains = uplink->network->search_domains;
                 if (search_domains)
@@ -646,6 +640,26 @@ set_domains:
 
 }
 
+static int radv_find_uplink(Link *link, Link **ret) {
+        assert(link);
+
+        if (link->network->router_uplink_name)
+                return link_get_by_name(link->manager, link->network->router_uplink_name, ret);
+
+        if (link->network->router_uplink_index > 0)
+                return link_get_by_index(link->manager, link->network->router_uplink_index, ret);
+
+        if (link->network->router_uplink_index == UPLINK_INDEX_AUTO) {
+                /* It is not necessary to propagate error in automatic selection. */
+                if (manager_find_uplink(link->manager, AF_INET6, link, ret) < 0)
+                        *ret = NULL;
+                return 0;
+        }
+
+        *ret = NULL;
+        return 0;
+}
+
 static bool link_radv_enabled(Link *link) {
         assert(link);
 
@@ -730,7 +744,7 @@ static int radv_configure(Link *link) {
                         return r;
         }
 
-        (void) manager_find_uplink(link->manager, AF_INET6, link, &uplink);
+        (void) radv_find_uplink(link, &uplink);
 
         r = radv_set_dns(link, uplink);
         if (r < 0)
@@ -771,7 +785,10 @@ int radv_update_mac(Link *link) {
         return 0;
 }
 
-static bool radv_is_ready_to_configure(Link *link) {
+static int radv_is_ready_to_configure(Link *link) {
+        bool needs_uplink = false;
+        int r;
+
         assert(link);
         assert(link->network);
 
@@ -781,6 +798,32 @@ static bool radv_is_ready_to_configure(Link *link) {
         if (in6_addr_is_null(&link->ipv6ll_address))
                 return false;
 
+        if (link->network->router_emit_dns && !link->network->router_dns) {
+                _cleanup_free_ struct in6_addr *dns = NULL;
+                size_t n_dns;
+
+                r = network_get_ipv6_dns(link->network, &dns, &n_dns);
+                if (r < 0)
+                        return r;
+
+                needs_uplink = r == 0;
+        }
+
+        if (link->network->router_emit_domains &&
+            !link->network->router_search_domains &&
+            !link->network->search_domains)
+                needs_uplink = true;
+
+        if (needs_uplink) {
+                Link *uplink = NULL;
+
+                if (radv_find_uplink(link, &uplink) < 0)
+                        return false;
+
+                if (uplink && !uplink->network)
+                        return false;
+        }
+
         return true;
 }
 
@@ -794,8 +837,9 @@ int request_process_radv(Request *req) {
 
         link = req->link;
 
-        if (!radv_is_ready_to_configure(link))
-                return 0;
+        r = radv_is_ready_to_configure(link);
+        if (r <= 0)
+                return r;
 
         r = radv_configure(link);
         if (r < 0)
index f1305a04b2bdaeb2ab77831558afb2554f98be95..2dca1cda3ab4db3ecbdd4f03b28b1b7b16e35216 100644 (file)
@@ -307,6 +307,7 @@ EmitDNS=
 EmitDomains=
 Managed=
 OtherInformation=
+UplinkInterface=
 [IPv6PrefixDelegation]
 RouterPreference=
 DNSLifetimeSec=