Merge pull request #28132 from rpigott/dhcp-captive-portal

Implement RFC8910: captive portal dhcp options
This commit is contained in:
Yu Watanabe
2023-07-03 14:51:56 +09:00
committed by GitHub
26 changed files with 361 additions and 2 deletions
@@ -60,6 +60,7 @@ struct sd_dhcp_lease {
char **search_domains;
char *hostname;
char *root_path;
char *captive_portal;
void *client_id;
size_t client_id_len;
@@ -43,6 +43,7 @@ struct sd_dhcp6_lease {
struct in6_addr *sntp;
size_t sntp_count;
char *fqdn;
char *captive_portal;
};
int dhcp6_lease_get_lifetime(sd_dhcp6_lease *lease, usec_t *ret_t1, usec_t *ret_t2, usec_t *ret_valid);
@@ -60,6 +61,7 @@ int dhcp6_lease_add_domains(sd_dhcp6_lease *lease, const uint8_t *optval, size_t
int dhcp6_lease_add_ntp(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen);
int dhcp6_lease_add_sntp(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen);
int dhcp6_lease_set_fqdn(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen);
int dhcp6_lease_set_captive_portal(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen);
int dhcp6_lease_new(sd_dhcp6_lease **ret);
int dhcp6_lease_new_from_message(
+20
View File
@@ -524,6 +524,26 @@ int dhcp6_option_parse_status(const uint8_t *data, size_t data_len, char **ret_s
return status;
}
/* parse a string from dhcp option field. *ret must be initialized */
int dhcp6_option_parse_string(const uint8_t *data, size_t data_len, char **ret) {
_cleanup_free_ char *string = NULL;
int r;
assert(data);
assert(ret);
if (data_len <= 0) {
*ret = mfree(*ret);
return 0;
}
r = make_cstring((const char *) data, data_len, MAKE_CSTRING_REFUSE_TRAILING_NUL, &string);
if (r < 0)
return r;
return free_and_replace(*ret, string);
}
static int dhcp6_option_parse_ia_options(sd_dhcp6_client *client, const uint8_t *buf, size_t buflen) {
int r;
+1
View File
@@ -88,6 +88,7 @@ int dhcp6_option_parse(
size_t *ret_option_data_len,
const uint8_t **ret_option_data);
int dhcp6_option_parse_status(const uint8_t *data, size_t data_len, char **ret_status_message);
int dhcp6_option_parse_string(const uint8_t *data, size_t data_len, char **ret);
int dhcp6_option_parse_ia(
sd_dhcp6_client *client,
be32_t iaid,
+42
View 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;
}
+34
View File
@@ -168,6 +168,17 @@ int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) {
return 0;
}
int sd_dhcp_lease_get_captive_portal(sd_dhcp_lease *lease, const char **ret) {
assert_return(lease, -EINVAL);
assert_return(ret, -EINVAL);
if (!lease->captive_portal)
return -ENODATA;
*ret = lease->captive_portal;
return 0;
}
int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr) {
assert_return(lease, -EINVAL);
assert_return(addr, -EINVAL);
@@ -322,6 +333,7 @@ static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) {
free(lease->timezone);
free(lease->hostname);
free(lease->domainname);
free(lease->captive_portal);
for (sd_dhcp_lease_server_type_t i = 0; i < _SD_DHCP_LEASE_SERVER_TYPE_MAX; i++)
free(lease->servers[i].addr);
@@ -406,6 +418,22 @@ static int lease_parse_domain(const uint8_t *option, size_t len, char **ret) {
return 0;
}
static int lease_parse_captive_portal(const uint8_t *option, size_t len, char **ret) {
_cleanup_free_ char *uri = NULL;
int r;
assert(option);
assert(ret);
r = dhcp_option_parse_string(option, len, &uri);
if (r < 0)
return r;
if (uri && !in_charset(uri, URI_VALID))
return -EINVAL;
return free_and_replace(*ret, uri);
}
static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) {
assert(option || len == 0);
assert(ret);
@@ -675,6 +703,12 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void
log_debug_errno(r, "Failed to parse LPR server, ignoring: %m");
break;
case SD_DHCP_OPTION_DHCP_CAPTIVE_PORTAL:
r = lease_parse_captive_portal(option, len, &lease->captive_portal);
if (r < 0)
log_debug_errno(r, "Failed to parse captive portal, ignoring: %m");
break;
case SD_DHCP_OPTION_STATIC_ROUTE:
r = lease_parse_static_routes(lease, option, len);
if (r < 0)
+35
View File
@@ -445,6 +445,34 @@ int sd_dhcp6_lease_get_fqdn(sd_dhcp6_lease *lease, const char **ret) {
return 0;
}
int dhcp6_lease_set_captive_portal(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) {
_cleanup_free_ char *uri = NULL;
int r;
assert(lease);
assert(optval || optlen == 0);
r = dhcp6_option_parse_string(optval, optlen, &uri);
if (r < 0)
return r;
if (uri && !in_charset(uri, URI_VALID))
return -EINVAL;
return free_and_replace(lease->captive_portal, uri);
}
int sd_dhcp6_lease_get_captive_portal(sd_dhcp6_lease *lease, const char **ret) {
assert_return(lease, -EINVAL);
assert_return(ret, -EINVAL);
if (!lease->captive_portal)
return -ENODATA;
*ret = lease->captive_portal;
return 0;
}
static int dhcp6_lease_parse_message(
sd_dhcp6_client *client,
sd_dhcp6_lease *lease,
@@ -610,6 +638,12 @@ static int dhcp6_lease_parse_message(
break;
case SD_DHCP6_OPTION_CAPTIVE_PORTAL:
r = dhcp6_lease_set_captive_portal(lease, optval, optlen);
if (r < 0)
log_dhcp6_client_errno(client, r, "Failed to parse captive portal option, ignoring: %m");
break;
case SD_DHCP6_OPTION_CLIENT_FQDN:
r = dhcp6_lease_set_fqdn(lease, optval, optlen);
if (r < 0)
@@ -670,6 +704,7 @@ static sd_dhcp6_lease *dhcp6_lease_free(sd_dhcp6_lease *lease) {
dhcp6_ia_free(lease->ia_pd);
free(lease->dns);
free(lease->fqdn);
free(lease->captive_portal);
strv_free(lease->domains);
free(lease->ntp);
strv_free(lease->ntp_fqdn);