From: Paul Donald Date: Fri, 21 Nov 2025 14:45:20 +0000 (+0100) Subject: all: implement RFC8910 §3 URI equality check X-Git-Url: http://git.openwrt.org/?a=commitdiff_plain;h=f98b6ec82362607a01b7421935d99f54068a80e0;p=project%2Fodhcp6c.git all: implement RFC8910 §3 URI equality check §3 Precedence of API URIs " A device may learn about Captive Portal API URIs through more than one of (or indeed all of) the above options. Implementations can select their own precedence order (e.g., prefer one of the IPv6 options before the DHCPv4 option, or vice versa, et cetera). If the URIs learned via more than one option described in Section 2 are not all identical, this condition should be logged for the device owner or administrator; it is a network configuration error if the learned URIs are not all identical. " We log the 'network configuration error' but proceed in an attempt to be useful (since the RFC makes no mention of disregarding the URI) and prefer DHCPv6, since this is the DHCPv6 client. Signed-off-by: Paul Donald Link: https://github.com/openwrt/odhcp6c/pull/127 Signed-off-by: Álvaro Fernández Rojas --- diff --git a/src/dhcpv6.c b/src/dhcpv6.c index 71b163c..32a5e47 100644 --- a/src/dhcpv6.c +++ b/src/dhcpv6.c @@ -1372,7 +1372,7 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _o_unused const int rc, odhcp6c_clear_state(STATE_S46_MAPT); odhcp6c_clear_state(STATE_S46_MAPE); odhcp6c_clear_state(STATE_S46_LW); - odhcp6c_clear_state(STATE_CAPT_PORT); + odhcp6c_clear_state(STATE_CAPT_PORT_DHCPV6); odhcp6c_clear_state(STATE_PASSTHRU); odhcp6c_clear_state(STATE_CUSTOM_OPTS); @@ -1550,7 +1550,7 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _o_unused const int rc, continue; memcpy(copy, odata, olen); copy[uri_len] = '\0'; - odhcp6c_add_state(STATE_CAPT_PORT, odata, olen); + odhcp6c_add_state(STATE_CAPT_PORT_DHCPV6, odata, olen); free(copy); } break; diff --git a/src/odhcp6c.c b/src/odhcp6c.c index cda9ef4..d97ace9 100644 --- a/src/odhcp6c.c +++ b/src/odhcp6c.c @@ -510,7 +510,7 @@ int main(_o_unused int argc, char* const argv[]) odhcp6c_clear_state(STATE_NTP_FQDN); odhcp6c_clear_state(STATE_SIP_IP); odhcp6c_clear_state(STATE_SIP_FQDN); - odhcp6c_clear_state(STATE_CAPT_PORT); + odhcp6c_clear_state(STATE_CAPT_PORT_DHCPV6); bound = false; size_t oro_len = 0; diff --git a/src/odhcp6c.h b/src/odhcp6c.h index 0bd686c..40b9912 100644 --- a/src/odhcp6c.h +++ b/src/odhcp6c.h @@ -435,7 +435,8 @@ enum odhcp6c_state { STATE_S46_MAPT, STATE_S46_MAPE, STATE_S46_LW, - STATE_CAPT_PORT, + STATE_CAPT_PORT_RA, + STATE_CAPT_PORT_DHCPV6, STATE_PASSTHRU, _STATE_MAX }; diff --git a/src/ra.c b/src/ra.c index d44b9f0..0c83e54 100644 --- a/src/ra.c +++ b/src/ra.c @@ -582,8 +582,8 @@ bool ra_process(void) memcpy(copy, buf, uri_len); copy[uri_len] = '\0'; - odhcp6c_clear_state(STATE_CAPT_PORT); - odhcp6c_add_state(STATE_CAPT_PORT, copy, uri_len); + odhcp6c_clear_state(STATE_CAPT_PORT_RA); + odhcp6c_add_state(STATE_CAPT_PORT_RA, copy, uri_len); free(copy); } } diff --git a/src/script.c b/src/script.c index 5a6168d..209f7ee 100644 --- a/src/script.c +++ b/src/script.c @@ -461,7 +461,8 @@ void script_call(const char *status, int delay, bool resume) } else if (pid == 0) { size_t dns_len, search_len, custom_len, sntp_ip_len, ntp_ip_len, ntp_dns_len; size_t sip_ip_len, sip_fqdn_len, aftr_name_len, addr_len; - size_t s46_mapt_len, s46_mape_len, s46_lw_len, capt_port_len, passthru_len; + size_t s46_mapt_len, s46_mape_len, s46_lw_len, passthru_len; + size_t capt_port_ra_len, capt_port_dhcpv6_len; signal(SIGTERM, SIG_DFL); if (delay > 0) { @@ -482,7 +483,8 @@ void script_call(const char *status, int delay, bool resume) uint8_t *s46_mapt = odhcp6c_get_state(STATE_S46_MAPT, &s46_mapt_len); uint8_t *s46_mape = odhcp6c_get_state(STATE_S46_MAPE, &s46_mape_len); uint8_t *s46_lw = odhcp6c_get_state(STATE_S46_LW, &s46_lw_len); - uint8_t *capt_port = odhcp6c_get_state(STATE_CAPT_PORT, &capt_port_len); + uint8_t *capt_port_ra = odhcp6c_get_state(STATE_CAPT_PORT_RA, &capt_port_ra_len); + uint8_t *capt_port_dhcpv6 = odhcp6c_get_state(STATE_CAPT_PORT_DHCPV6, &capt_port_dhcpv6_len); uint8_t *passthru = odhcp6c_get_state(STATE_PASSTHRU, &passthru_len); size_t prefix_len, address_len, ra_pref_len, @@ -494,6 +496,15 @@ void script_call(const char *status, int delay, bool resume) uint8_t *ra_dns = odhcp6c_get_state(STATE_RA_DNS, &ra_dns_len); uint8_t *ra_search = odhcp6c_get_state(STATE_RA_SEARCH, &ra_search_len); + /* RFC8910 §3 */ + if (capt_port_ra_len > 0 && capt_port_dhcpv6_len > 0) { + if (capt_port_ra_len != capt_port_dhcpv6_len || + !memcmp(capt_port_dhcpv6, capt_port_ra, capt_port_dhcpv6_len)) + syslog(LOG_ERR, + "%s received via different vectors differ: preferring URI from DHCPv6", + CAPT_PORT_URI_STR); + } + ipv6_to_env("SERVER", addr, addr_len / sizeof(*addr)); ipv6_to_env("RDNSS", dns, dns_len / sizeof(*dns)); ipv6_to_env("SNTP_IP", sntp, sntp_ip_len / sizeof(*sntp)); @@ -506,7 +517,10 @@ void script_call(const char *status, int delay, bool resume) s46_to_env(STATE_S46_MAPE, s46_mape, s46_mape_len); s46_to_env(STATE_S46_MAPT, s46_mapt, s46_mapt_len); s46_to_env(STATE_S46_LW, s46_lw, s46_lw_len); - string_to_env(CAPT_PORT_URI_STR, capt_port, capt_port_len); + if (capt_port_dhcpv6_len > 0) + string_to_env(CAPT_PORT_URI_STR, capt_port_dhcpv6, capt_port_dhcpv6_len); + else if (capt_port_ra_len > 0) + string_to_env(CAPT_PORT_URI_STR, capt_port_ra, capt_port_ra_len); bin_to_env(custom, custom_len); if (odhcp6c_is_bound()) { diff --git a/src/ubus.c b/src/ubus.c index ab2e362..44349e8 100644 --- a/src/ubus.c +++ b/src/ubus.c @@ -531,7 +531,8 @@ static int states_to_blob(void) char *buf = NULL; size_t dns_len, search_len, custom_len, sntp_ip_len, ntp_ip_len, ntp_dns_len; size_t sip_ip_len, sip_fqdn_len, aftr_name_len, addr_len; - size_t s46_mapt_len, s46_mape_len, s46_lw_len, capt_port_len, passthru_len; + size_t s46_mapt_len, s46_mape_len, s46_lw_len, passthru_len; + size_t capt_port_ra_len, capt_port_dhcpv6_len; struct in6_addr *addr = odhcp6c_get_state(STATE_SERVER_ADDR, &addr_len); struct in6_addr *dns = odhcp6c_get_state(STATE_DNS, &dns_len); uint8_t *search = odhcp6c_get_state(STATE_SEARCH, &search_len); @@ -545,7 +546,8 @@ static int states_to_blob(void) uint8_t *s46_mapt = odhcp6c_get_state(STATE_S46_MAPT, &s46_mapt_len); uint8_t *s46_mape = odhcp6c_get_state(STATE_S46_MAPE, &s46_mape_len); uint8_t *s46_lw = odhcp6c_get_state(STATE_S46_LW, &s46_lw_len); - uint8_t *capt_port = odhcp6c_get_state(STATE_CAPT_PORT, &capt_port_len); + uint8_t *capt_port_ra = odhcp6c_get_state(STATE_CAPT_PORT_RA, &capt_port_ra_len); + uint8_t *capt_port_dhcpv6 = odhcp6c_get_state(STATE_CAPT_PORT_DHCPV6, &capt_port_dhcpv6_len); uint8_t *passthru = odhcp6c_get_state(STATE_PASSTHRU, &passthru_len); size_t prefix_len, address_len, ra_pref_len, @@ -559,6 +561,15 @@ static int states_to_blob(void) blob_buf_init(&b, BLOBMSG_TYPE_TABLE); + /* RFC8910 §3 */ + if (capt_port_ra_len > 0 && capt_port_dhcpv6_len > 0) { + if (capt_port_ra_len != capt_port_dhcpv6_len || + !memcmp(capt_port_dhcpv6, capt_port_ra, capt_port_dhcpv6_len)) + syslog(LOG_ERR, + "%s received via different vectors differ: preferring URI from DHCPv6", + CAPT_PORT_URI_STR); + } + blobmsg_add_string(&b, "DHCPV6_STATE", dhcpv6_state_to_str(dhcpv6_get_state())); CHECK(ipv6_to_blob("SERVER", addr, addr_len / sizeof(*addr))); @@ -573,7 +584,10 @@ static int states_to_blob(void) CHECK(s46_to_blob(STATE_S46_MAPE, s46_mape, s46_mape_len)); CHECK(s46_to_blob(STATE_S46_MAPT, s46_mapt, s46_mapt_len)); CHECK(s46_to_blob(STATE_S46_LW, s46_lw, s46_lw_len)); - blobmsg_add_string(&b, CAPT_PORT_URI_STR, (char *)capt_port); + if (capt_port_dhcpv6_len > 0) + blobmsg_add_string(&b, CAPT_PORT_URI_STR, (char *)capt_port_dhcpv6); + else if (capt_port_ra_len > 0) + blobmsg_add_string(&b, CAPT_PORT_URI_STR, (char *)capt_port_ra); CHECK(bin_to_blob(custom, custom_len)); if (odhcp6c_is_bound()) {