]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/network/networkd-dhcp-common.c
Merge pull request #32917 from YHNdnzj/ptyfwd-cleanup
[thirdparty/systemd.git] / src / network / networkd-dhcp-common.c
index 6526d3378fae25f65c945049a87fa3bd743b2bc5..9f0268d934e472432fd6506a0b377529ccd4e720 100644 (file)
@@ -5,8 +5,7 @@
 
 #include "bus-error.h"
 #include "bus-locator.h"
-#include "dhcp-identifier.h"
-#include "dhcp-internal.h"
+#include "dhcp-option.h"
 #include "dhcp6-internal.h"
 #include "escape.h"
 #include "hexdecoct.h"
@@ -15,6 +14,7 @@
 #include "networkd-link.h"
 #include "networkd-manager.h"
 #include "networkd-network.h"
+#include "networkd-route-util.h"
 #include "parse-util.h"
 #include "socket-util.h"
 #include "string-table.h"
@@ -40,12 +40,12 @@ uint32_t link_get_dhcp4_route_table(Link *link) {
         return link_get_vrf_table(link);
 }
 
-uint32_t link_get_ipv6_accept_ra_route_table(Link *link) {
+uint32_t link_get_ndisc_route_table(Link *link) {
         assert(link);
         assert(link->network);
 
-        if (link->network->ipv6_accept_ra_route_table_set)
-                return link->network->ipv6_accept_ra_route_table;
+        if (link->network->ndisc_route_table_set)
+                return link->network->ndisc_route_table;
         return link_get_vrf_table(link);
 }
 
@@ -258,6 +258,74 @@ bool address_is_filtered(int family, const union in_addr_union *address, uint8_t
         return false;
 }
 
+int link_get_captive_portal(Link *link, const char **ret) {
+        const char *dhcp4_cp = NULL, *dhcp6_cp = NULL, *ndisc_cp = NULL;
+        int r;
+
+        assert(link);
+
+        if (!link->network) {
+                *ret = NULL;
+                return 0;
+        }
+
+        if (link->network->dhcp_use_captive_portal && link->dhcp_lease) {
+                r = sd_dhcp_lease_get_captive_portal(link->dhcp_lease, &dhcp4_cp);
+                if (r < 0 && r != -ENODATA)
+                        return r;
+        }
+
+        if (link->network->dhcp6_use_captive_portal && link->dhcp6_lease) {
+                r = sd_dhcp6_lease_get_captive_portal(link->dhcp6_lease, &dhcp6_cp);
+                if (r < 0 && r != -ENODATA)
+                        return r;
+        }
+
+        if (link->network->ndisc_use_captive_portal) {
+                NDiscCaptivePortal *cp;
+                usec_t usec = 0;
+
+                /* Use the captive portal with the longest lifetime. */
+
+                SET_FOREACH(cp, link->ndisc_captive_portals) {
+                        if (cp->lifetime_usec < usec)
+                                continue;
+
+                        ndisc_cp = cp->captive_portal;
+                        usec = cp->lifetime_usec;
+                }
+
+                if (set_size(link->ndisc_captive_portals) > 1)
+                        log_link_debug(link, "Multiple captive portals obtained by IPv6RA, using \"%s\" and ignoring others.",
+                                       ndisc_cp);
+        }
+
+        if (dhcp4_cp) {
+                if (dhcp6_cp && !streq(dhcp4_cp, dhcp6_cp))
+                        log_link_debug(link, "DHCPv6 captive portal (%s) does not match DHCPv4 (%s), ignoring DHCPv6 captive portal.",
+                                       dhcp6_cp, dhcp4_cp);
+
+                if (ndisc_cp && !streq(dhcp4_cp, ndisc_cp))
+                        log_link_debug(link, "IPv6RA captive portal (%s) does not match DHCPv4 (%s), ignoring IPv6RA captive portal.",
+                                       ndisc_cp, dhcp4_cp);
+
+                *ret = dhcp4_cp;
+                return 1;
+        }
+
+        if (dhcp6_cp) {
+                if (ndisc_cp && !streq(dhcp6_cp, ndisc_cp))
+                        log_link_debug(link, "IPv6RA captive portal (%s) does not match DHCPv6 (%s), ignoring IPv6RA captive portal.",
+                                       ndisc_cp, dhcp6_cp);
+
+                *ret = dhcp6_cp;
+                return 1;
+        }
+
+        *ret = ndisc_cp;
+        return !!ndisc_cp;
+}
+
 int config_parse_dhcp(
                 const char* unit,
                 const char *filename,
@@ -303,7 +371,7 @@ int config_parse_dhcp(
         return 0;
 }
 
-int config_parse_dhcp_or_ra_route_metric(
+int config_parse_dhcp_route_metric(
                 const char* unit,
                 const char *filename,
                 unsigned line,
@@ -321,7 +389,7 @@ int config_parse_dhcp_or_ra_route_metric(
 
         assert(filename);
         assert(lvalue);
-        assert(IN_SET(ltype, AF_UNSPEC, AF_INET, AF_INET6));
+        assert(IN_SET(ltype, AF_UNSPEC, AF_INET));
         assert(rvalue);
         assert(data);
 
@@ -337,16 +405,15 @@ int config_parse_dhcp_or_ra_route_metric(
                 network->dhcp_route_metric = metric;
                 network->dhcp_route_metric_set = true;
                 break;
-        case AF_INET6:
-                network->ipv6_accept_ra_route_metric = metric;
-                network->ipv6_accept_ra_route_metric_set = true;
-                break;
         case AF_UNSPEC:
                 /* For backward compatibility. */
                 if (!network->dhcp_route_metric_set)
                         network->dhcp_route_metric = metric;
-                if (!network->ipv6_accept_ra_route_metric_set)
-                        network->ipv6_accept_ra_route_metric = metric;
+                if (!network->ndisc_route_metric_set) {
+                        network->ndisc_route_metric_high = metric;
+                        network->ndisc_route_metric_medium = metric;
+                        network->ndisc_route_metric_low = metric;
+                }
                 break;
         default:
                 assert_not_reached();
@@ -355,8 +422,8 @@ int config_parse_dhcp_or_ra_route_metric(
         return 0;
 }
 
-int config_parse_dhcp_use_dns(
-                const charunit,
+int config_parse_ndisc_route_metric(
+                const char *unit,
                 const char *filename,
                 unsigned line,
                 const char *section,
@@ -367,97 +434,53 @@ int config_parse_dhcp_use_dns(
                 void *data,
                 void *userdata) {
 
-        Network *network = userdata;
-        int r;
+        Network *network = ASSERT_PTR(userdata);
+        uint32_t metric_high, metric_medium, metric_low;
+        int r, s, t;
 
         assert(filename);
-        assert(lvalue);
-        assert(IN_SET(ltype, AF_UNSPEC, AF_INET, AF_INET6));
         assert(rvalue);
-        assert(data);
 
-        r = parse_boolean(rvalue);
-        if (r < 0) {
-                log_syntax(unit, LOG_WARNING, filename, line, r,
-                           "Failed to parse UseDNS=%s, ignoring assignment: %m", rvalue);
-                return 0;
-        }
+        if (safe_atou32(rvalue, &metric_low) >= 0)
+                metric_high = metric_medium = metric_low;
+        else {
+                _cleanup_free_ char *high = NULL, *medium = NULL, *low = NULL;
+                const char *p = rvalue;
 
-        switch (ltype) {
-        case AF_INET:
-                network->dhcp_use_dns = r;
-                network->dhcp_use_dns_set = true;
-                break;
-        case AF_INET6:
-                network->dhcp6_use_dns = r;
-                network->dhcp6_use_dns_set = true;
-                break;
-        case AF_UNSPEC:
-                /* For backward compatibility. */
-                if (!network->dhcp_use_dns_set)
-                        network->dhcp_use_dns = r;
-                if (!network->dhcp6_use_dns_set)
-                        network->dhcp6_use_dns = r;
-                break;
-        default:
-                assert_not_reached();
-        }
-
-        return 0;
-}
-
-int config_parse_dhcp_use_domains(
-                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;
-        DHCPUseDomains d;
+                r = extract_many_words(&p, ":", EXTRACT_DONT_COALESCE_SEPARATORS, &high, &medium, &low);
+                if (r == -ENOMEM)
+                        return log_oom();
+                if (r != 3 || !isempty(p)) {
+                        log_syntax(unit, LOG_WARNING, filename, line, r < 0 ? r : 0,
+                                   "Failed to parse RouteTable=%s, ignoring assignment: %m", rvalue);
+                        return 0;
+                }
 
-        assert(filename);
-        assert(lvalue);
-        assert(IN_SET(ltype, AF_UNSPEC, AF_INET, AF_INET6));
-        assert(rvalue);
-        assert(data);
+                r = safe_atou32(high, &metric_high);
+                s = safe_atou32(medium, &metric_medium);
+                t = safe_atou32(low, &metric_low);
+                if (r < 0 || s < 0 || t < 0) {
+                        log_syntax(unit, LOG_WARNING, filename, line, r < 0 ? r : s < 0 ? s : t,
+                                   "Failed to parse RouteTable=%s, ignoring assignment: %m", rvalue);
+                        return 0;
+                }
 
-        d = dhcp_use_domains_from_string(rvalue);
-        if (d < 0) {
-                log_syntax(unit, LOG_WARNING, filename, line, d,
-                           "Failed to parse %s=%s, ignoring assignment: %m", lvalue, rvalue);
-                return 0;
+                if (metric_high >= metric_medium || metric_medium >= metric_low) {
+                        log_syntax(unit, LOG_WARNING, filename, line, 0,
+                                   "Invalid RouteTable=%s, ignoring assignment: %m", rvalue);
+                        return 0;
+                }
         }
 
-        switch (ltype) {
-        case AF_INET:
-                network->dhcp_use_domains = d;
-                network->dhcp_use_domains_set = true;
-                break;
-        case AF_INET6:
-                network->dhcp6_use_domains = d;
-                network->dhcp6_use_domains_set = true;
-                break;
-        case AF_UNSPEC:
-                /* For backward compatibility. */
-                if (!network->dhcp_use_domains_set)
-                        network->dhcp_use_domains = d;
-                if (!network->dhcp6_use_domains_set)
-                        network->dhcp6_use_domains = d;
-                break;
-        default:
-                assert_not_reached();
-        }
+        network->ndisc_route_metric_high = metric_high;
+        network->ndisc_route_metric_medium = metric_medium;
+        network->ndisc_route_metric_low = metric_low;
+        network->ndisc_route_metric_set = true;
 
         return 0;
 }
 
-int config_parse_dhcp_use_ntp(
+int config_parse_dhcp_send_hostname(
                 const char* unit,
                 const char *filename,
                 unsigned line,
@@ -481,25 +504,25 @@ int config_parse_dhcp_use_ntp(
         r = parse_boolean(rvalue);
         if (r < 0) {
                 log_syntax(unit, LOG_WARNING, filename, line, r,
-                           "Failed to parse UseNTP=%s, ignoring assignment: %m", rvalue);
+                           "Failed to parse SendHostname=%s, ignoring assignment: %m", rvalue);
                 return 0;
         }
 
         switch (ltype) {
         case AF_INET:
-                network->dhcp_use_ntp = r;
-                network->dhcp_use_ntp_set = true;
+                network->dhcp_send_hostname = r;
+                network->dhcp_send_hostname_set = true;
                 break;
         case AF_INET6:
-                network->dhcp6_use_ntp = r;
-                network->dhcp6_use_ntp_set = true;
+                network->dhcp6_send_hostname = r;
+                network->dhcp6_send_hostname_set = true;
                 break;
         case AF_UNSPEC:
                 /* For backward compatibility. */
-                if (!network->dhcp_use_ntp_set)
-                        network->dhcp_use_ntp = r;
-                if (!network->dhcp6_use_ntp_set)
-                        network->dhcp6_use_ntp = r;
+                if (!network->dhcp_send_hostname_set)
+                        network->dhcp_send_hostname = r;
+                if (!network->dhcp6_send_hostname_set)
+                        network->dhcp6_send_hostname = r;
                 break;
         default:
                 assert_not_reached();
@@ -529,7 +552,7 @@ int config_parse_dhcp_or_ra_route_table(
         assert(IN_SET(ltype, AF_INET, AF_INET6));
         assert(rvalue);
 
-        r = safe_atou32(rvalue, &rt);
+        r = manager_get_route_table_from_string(network->manager, rvalue, &rt);
         if (r < 0) {
                 log_syntax(unit, LOG_WARNING, filename, line, r,
                            "Failed to parse RouteTable=%s, ignoring assignment: %m", rvalue);
@@ -542,8 +565,8 @@ int config_parse_dhcp_or_ra_route_table(
                 network->dhcp_route_table_set = true;
                 break;
         case AF_INET6:
-                network->ipv6_accept_ra_route_table = rt;
-                network->ipv6_accept_ra_route_table_set = true;
+                network->ndisc_route_table = rt;
+                network->ndisc_route_table_set = true;
                 break;
         default:
                 assert_not_reached();
@@ -838,9 +861,11 @@ int config_parse_dhcp_send_option(
         }
         case DHCP_OPTION_DATA_STRING:
                 sz = cunescape(p, UNESCAPE_ACCEPT_NUL, &q);
-                if (sz < 0)
+                if (sz < 0) {
                         log_syntax(unit, LOG_WARNING, filename, line, sz,
                                    "Failed to decode DHCP option data, ignoring assignment: %s", p);
+                        return 0;
+                }
 
                 udata = q;
                 break;
@@ -960,14 +985,6 @@ int config_parse_dhcp_request_options(
         }
 }
 
-static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
-        [DHCP_USE_DOMAINS_NO] = "no",
-        [DHCP_USE_DOMAINS_ROUTE] = "route",
-        [DHCP_USE_DOMAINS_YES] = "yes",
-};
-
-DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
-
 static const char * const dhcp_option_data_type_table[_DHCP_OPTION_DATA_MAX] = {
         [DHCP_OPTION_DATA_UINT8]       = "uint8",
         [DHCP_OPTION_DATA_UINT16]      = "uint16",
@@ -1028,9 +1045,17 @@ int config_parse_duid_type(
 
         type = duid_type_from_string(type_string);
         if (type < 0) {
-                log_syntax(unit, LOG_WARNING, filename, line, type,
-                           "Failed to parse DUID type '%s', ignoring.", type_string);
-                return 0;
+                uint16_t t;
+
+                r = safe_atou16(type_string, &t);
+                if (r < 0) {
+                        log_syntax(unit, LOG_WARNING, filename, line, r,
+                                   "Failed to parse DUID type '%s', ignoring.", type_string);
+                        return 0;
+                }
+
+                type = t;
+                assert(type == t); /* Check if type can store uint16_t. */
         }
 
         if (!isempty(p)) {
@@ -1117,7 +1142,7 @@ int config_parse_duid_rawdata(
                 void *data,
                 void *userdata) {
 
-        uint8_t raw_data[MAX_DUID_LEN];
+        uint8_t raw_data[MAX_DUID_DATA_LEN];
         unsigned count = 0;
         bool force = ltype;
         DUID *duid = ASSERT_PTR(data);
@@ -1145,7 +1170,7 @@ int config_parse_duid_rawdata(
                 if (r == 0)
                         break;
 
-                if (count >= MAX_DUID_LEN) {
+                if (count >= MAX_DUID_DATA_LEN) {
                         log_syntax(unit, LOG_WARNING, filename, line, 0, "Max DUID length exceeded, ignoring assignment: %s.", rvalue);
                         return 0;
                 }