]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
ndisc: parse RFC8910 captive portal ipv6ra option
authorRonan Pigott <ronan@rjp.ie>
Thu, 29 Jun 2023 23:22:45 +0000 (16:22 -0700)
committerRonan Pigott <ronan@rjp.ie>
Sun, 2 Jul 2023 08:13:29 +0000 (01:13 -0700)
src/libsystemd-network/ndisc-router.c
src/network/networkd-link.c
src/network/networkd-link.h
src/network/networkd-ndisc.c
src/network/networkd-network.c
src/network/networkd-network.h
src/systemd/sd-ndisc.h

index e4cbf714b970c9267633afdfd0bb098615e74a0d..997ac5758621cfa1a615267ed4c7a143cebda639 100644 (file)
@@ -715,3 +715,45 @@ int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router *rt, uint32_t *ret_sec) {
         *ret_sec = be32toh(*(uint32_t*) (ri + 4));
         return 0;
 }
+
+int sd_ndisc_router_captive_portal_get_uri(sd_ndisc_router *rt, const char **ret_uri, size_t *ret_size) {
+        int r;
+        const char *nd_opt_captive_portal;
+        size_t length;
+
+        assert_return(rt, -EINVAL);
+        assert_return(ret_uri, -EINVAL);
+
+        r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_CAPTIVE_PORTAL);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return -EMEDIUMTYPE;
+
+        r = sd_ndisc_router_option_get_raw(rt, (void *)&nd_opt_captive_portal, &length);
+        if (r < 0)
+                return r;
+
+        /* The length field has units of 8 octets */
+        assert(length % 8 == 0);
+        if (length == 0)
+                return -EBADMSG;
+
+        /* Check that the message is not truncated by an embedded NUL.
+         * NUL padding to a multiple of 8 is expected. */
+        size_t size = strnlen(nd_opt_captive_portal + 2, length - 2);
+        if (DIV_ROUND_UP(size + 2, 8) != length / 8)
+                return -EBADMSG;
+
+        /* Let's not return an empty buffer */
+        if (size == 0) {
+                *ret_uri = NULL;
+                *ret_size = 0;
+                return 0;
+        }
+
+        *ret_uri = nd_opt_captive_portal + 2;
+        *ret_size = size;
+
+        return 0;
+}
index 62dd892afaa42ed9f62cf9cdd0ecd75e385e82f6..7d9ea6f8e7b385733d7257ee41f021eff3fea07c 100644 (file)
@@ -196,6 +196,7 @@ static Link *link_free(Link *link) {
         free(link->ssid);
         free(link->previous_ssid);
         free(link->driver);
+        free(link->ndisc_captive_portal);
 
         unlink_and_free(link->lease_file);
         unlink_and_free(link->lldp_file);
index 0d601ab5482a7b1cbcbf108ee1520f05650848e3..bc8fe083746cfe3e6611a9726df3b2a7f1cbf0ec 100644 (file)
@@ -154,6 +154,7 @@ typedef struct Link {
         sd_event_source *ndisc_expire;
         Set *ndisc_rdnss;
         Set *ndisc_dnssl;
+        char *ndisc_captive_portal;
         unsigned ndisc_messages;
         bool ndisc_configured:1;
 
index 99a07e16fcf8981c41ba85c43de3299a720d855e..da5312c5ff47cfe8325ff04d47a9c4e3d4315d97 100644 (file)
@@ -716,6 +716,43 @@ DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
                 ndisc_dnssl_compare_func,
                 free);
 
+static int ndisc_router_process_captive_portal(Link *link, sd_ndisc_router *rt) {
+        const char *uri;
+        _cleanup_free_ char *captive_portal = NULL;
+        size_t len;
+        int r;
+
+        assert(link);
+        assert(link->network);
+        assert(rt);
+
+        if (!link->network->ipv6_accept_ra_use_captive_portal)
+                return 0;
+
+        r = sd_ndisc_router_captive_portal_get_uri(rt, &uri, &len);
+        if (r < 0)
+                return r;
+
+        if (len == 0) {
+                mfree(link->ndisc_captive_portal);
+                return 0;
+        }
+
+        r = make_cstring(uri, len, MAKE_CSTRING_REFUSE_TRAILING_NUL, &captive_portal);
+        if (r < 0)
+                return r;
+
+        if (!in_charset(captive_portal, URI_VALID))
+                return -EINVAL;
+
+        if (!streq_ptr(link->ndisc_captive_portal, captive_portal)) {
+                free_and_replace(link->ndisc_captive_portal, captive_portal);
+                link_dirty(link);
+        }
+
+        return 0;
+}
+
 static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
         _cleanup_strv_free_ char **l = NULL;
         usec_t lifetime_usec, timestamp_usec;
@@ -832,6 +869,9 @@ static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
                 case SD_NDISC_OPTION_DNSSL:
                         r = ndisc_router_process_dnssl(link, rt);
                         break;
+                case SD_NDISC_OPTION_CAPTIVE_PORTAL:
+                        r = ndisc_router_process_captive_portal(link, rt);
+                        break;
                 }
                 if (r < 0 && r != -EBADMSG)
                         return r;
index 9a0511eeef75fab46629b51aec4adc9667582e79..2423d891d3bf68a8c8a80f249f32fdc5fa41fd9c 100644 (file)
@@ -476,6 +476,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
                 .ipv6_accept_ra = -1,
                 .ipv6_accept_ra_use_dns = true,
                 .ipv6_accept_ra_use_gateway = true,
+                .ipv6_accept_ra_use_captive_portal = true,
                 .ipv6_accept_ra_use_route_prefix = true,
                 .ipv6_accept_ra_use_autonomous_prefix = true,
                 .ipv6_accept_ra_use_onlink_prefix = true,
index 7685c98f652901b6f8b71c43463eeac5672236bf..c692fad991be68fff3d2e70fc864601651390d0c 100644 (file)
@@ -315,6 +315,7 @@ struct Network {
         bool ipv6_accept_ra_use_onlink_prefix;
         bool ipv6_accept_ra_use_mtu;
         bool ipv6_accept_ra_quickack;
+        bool ipv6_accept_ra_use_captive_portal;
         bool active_slave;
         bool primary_slave;
         DHCPUseDomains ipv6_accept_ra_use_domains;
index ee309a4253e13ba02306858b92168f6cbec33f61..b4faa4428e5d6f35a91a94d3efbf5967ddd61d6a 100644 (file)
@@ -123,6 +123,9 @@ int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router *rt, uint32_t *ret);
 int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router *rt, char ***ret);
 int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router *rt, uint32_t *ret);
 
+/* Specific option access: SD_NDISC_OPTION_CAPTIVE_PORTAL */
+int sd_ndisc_router_captive_portal_get_uri(sd_ndisc_router *rt, const char **uri, size_t *size);
+
 _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc, sd_ndisc_unref);
 _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc_router, sd_ndisc_router_unref);