Merge pull request #28132 from rpigott/dhcp-captive-portal
Implement RFC8910: captive portal dhcp options
This commit is contained in:
@@ -1678,7 +1678,7 @@ static int link_status_one(
|
||||
|
||||
_cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **sip = NULL, **search_domains = NULL,
|
||||
**route_domains = NULL, **link_dropins = NULL, **network_dropins = NULL;
|
||||
_cleanup_free_ char *t = NULL, *network = NULL, *iaid = NULL, *duid = NULL,
|
||||
_cleanup_free_ char *t = NULL, *network = NULL, *iaid = NULL, *duid = NULL, *captive_portal = NULL,
|
||||
*setup_state = NULL, *operational_state = NULL, *online_state = NULL, *activation_policy = NULL;
|
||||
const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL,
|
||||
*on_color_operational, *off_color_operational, *on_color_setup, *off_color_setup, *on_color_online;
|
||||
@@ -1706,6 +1706,7 @@ static int link_status_one(
|
||||
(void) sd_network_link_get_route_domains(info->ifindex, &route_domains);
|
||||
(void) sd_network_link_get_ntp(info->ifindex, &ntp);
|
||||
(void) sd_network_link_get_sip(info->ifindex, &sip);
|
||||
(void) sd_network_link_get_captive_portal(info->ifindex, &captive_portal);
|
||||
(void) sd_network_link_get_network_file(info->ifindex, &network);
|
||||
(void) sd_network_link_get_network_file_dropins(info->ifindex, &network_dropins);
|
||||
(void) sd_network_link_get_carrier_bound_to(info->ifindex, &carrier_bound_to);
|
||||
@@ -2358,6 +2359,9 @@ static int link_status_one(
|
||||
return table_log_add_error(r);
|
||||
}
|
||||
|
||||
if (captive_portal)
|
||||
table_add_string_line(table, "Captive Portal:", captive_portal);
|
||||
|
||||
if (lease) {
|
||||
const void *client_id;
|
||||
size_t client_id_len;
|
||||
|
||||
@@ -1426,6 +1426,11 @@ static int dhcp4_configure(Link *link) {
|
||||
if (r < 0)
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for SIP server: %m");
|
||||
}
|
||||
if (link->network->dhcp_use_captive_portal) {
|
||||
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_DHCP_CAPTIVE_PORTAL);
|
||||
if (r < 0)
|
||||
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for captive portal: %m");
|
||||
}
|
||||
|
||||
if (link->network->dhcp_use_timezone) {
|
||||
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_TZDB_TIMEZONE);
|
||||
|
||||
@@ -635,6 +635,12 @@ static int dhcp6_configure(Link *link) {
|
||||
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to request domains: %m");
|
||||
}
|
||||
|
||||
if (link->network->dhcp6_use_captive_portal > 0) {
|
||||
r = sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_CAPTIVE_PORTAL);
|
||||
if (r < 0)
|
||||
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to request captive portal: %m");
|
||||
}
|
||||
|
||||
if (link->network->dhcp6_use_ntp) {
|
||||
r = sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_NTP_SERVER);
|
||||
if (r < 0)
|
||||
|
||||
@@ -873,6 +873,41 @@ finalize:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int captive_portal_build_json(Link *link, JsonVariant **ret) {
|
||||
int r;
|
||||
const char *captive_portal = NULL;
|
||||
|
||||
assert(link);
|
||||
assert(ret);
|
||||
|
||||
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, &captive_portal);
|
||||
if (r < 0 && r != -ENODATA)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (link->network->dhcp6_use_captive_portal && link->dhcp6_lease && !captive_portal) {
|
||||
r = sd_dhcp6_lease_get_captive_portal(link->dhcp6_lease, &captive_portal);
|
||||
if (r < 0 && r != -ENODATA)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (link->network->ipv6_accept_ra_use_captive_portal && !captive_portal)
|
||||
captive_portal = link->ndisc_captive_portal;
|
||||
|
||||
if (!captive_portal) {
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return json_build(ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR_STRING("CaptivePortal", captive_portal)));
|
||||
}
|
||||
|
||||
static int domain_build_json(int family, const char *domain, NetworkConfigSource s, const union in_addr_union *p, JsonVariant **ret) {
|
||||
assert(IN_SET(family, AF_UNSPEC, AF_INET, AF_INET6));
|
||||
assert(domain);
|
||||
@@ -1390,6 +1425,16 @@ int link_build_json(Link *link, JsonVariant **ret) {
|
||||
|
||||
w = json_variant_unref(w);
|
||||
|
||||
r = captive_portal_build_json(link, &w);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = json_variant_merge(&v, w);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
w = json_variant_unref(w);
|
||||
|
||||
r = domains_build_json(link, /* is_route = */ false, &w);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -216,6 +216,7 @@ DHCPv4.RoutesToDNS, config_parse_bool,
|
||||
DHCPv4.UseNTP, config_parse_dhcp_use_ntp, AF_INET, 0
|
||||
DHCPv4.RoutesToNTP, config_parse_bool, 0, offsetof(Network, dhcp_routes_to_ntp)
|
||||
DHCPv4.UseSIP, config_parse_bool, 0, offsetof(Network, dhcp_use_sip)
|
||||
DHCPv4.UseCaptivePortal, config_parse_bool, 0, offsetof(Network, dhcp_use_captive_portal)
|
||||
DHCPv4.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_use_mtu)
|
||||
DHCPv4.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_use_hostname)
|
||||
DHCPv4.UseDomains, config_parse_dhcp_use_domains, AF_INET, 0
|
||||
@@ -257,6 +258,7 @@ DHCPv6.UseDNS, config_parse_dhcp_use_dns,
|
||||
DHCPv6.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp6_use_hostname)
|
||||
DHCPv6.UseDomains, config_parse_dhcp_use_domains, AF_INET6, 0
|
||||
DHCPv6.UseNTP, config_parse_dhcp_use_ntp, AF_INET6, 0
|
||||
DHCPv6.UseCaptivePortal, config_parse_bool, 0, offsetof(Network, dhcp6_use_captive_portal)
|
||||
DHCPv6.MUDURL, config_parse_mud_url, 0, offsetof(Network, dhcp6_mudurl)
|
||||
DHCPv6.RequestOptions, config_parse_dhcp_request_options, AF_INET6, 0
|
||||
DHCPv6.UserClass, config_parse_dhcp_user_or_vendor_class, AF_INET6, offsetof(Network, dhcp6_user_class)
|
||||
@@ -282,6 +284,7 @@ IPv6AcceptRA.DHCPv6Client, config_parse_ipv6_accept_ra_start_d
|
||||
IPv6AcceptRA.RouteTable, config_parse_dhcp_or_ra_route_table, AF_INET6, 0
|
||||
IPv6AcceptRA.RouteMetric, config_parse_ipv6_accept_ra_route_metric, 0, 0
|
||||
IPv6AcceptRA.QuickAck, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_quickack)
|
||||
IPv6AcceptRA.UseCaptivePortal, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_captive_portal)
|
||||
IPv6AcceptRA.RouterAllowList, config_parse_in_addr_prefixes, AF_INET6, offsetof(Network, ndisc_allow_listed_router)
|
||||
IPv6AcceptRA.RouterDenyList, config_parse_in_addr_prefixes, AF_INET6, offsetof(Network, ndisc_deny_listed_router)
|
||||
IPv6AcceptRA.PrefixAllowList, config_parse_in_addr_prefixes, AF_INET6, offsetof(Network, ndisc_allow_listed_prefix)
|
||||
|
||||
@@ -395,6 +395,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
|
||||
.dhcp_use_ntp = true,
|
||||
.dhcp_routes_to_ntp = true,
|
||||
.dhcp_use_sip = true,
|
||||
.dhcp_use_captive_portal = true,
|
||||
.dhcp_use_dns = true,
|
||||
.dhcp_routes_to_dns = true,
|
||||
.dhcp_use_hostname = true,
|
||||
@@ -413,6 +414,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
|
||||
.dhcp6_use_dns = true,
|
||||
.dhcp6_use_hostname = true,
|
||||
.dhcp6_use_ntp = true,
|
||||
.dhcp6_use_captive_portal = true,
|
||||
.dhcp6_use_rapid_commit = true,
|
||||
.dhcp6_duid.type = _DUID_TYPE_INVALID,
|
||||
.dhcp6_client_start_mode = _DHCP6_CLIENT_START_MODE_INVALID,
|
||||
@@ -476,6 +478,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,
|
||||
|
||||
@@ -143,6 +143,7 @@ struct Network {
|
||||
bool dhcp_use_ntp_set;
|
||||
bool dhcp_routes_to_ntp;
|
||||
bool dhcp_use_sip;
|
||||
bool dhcp_use_captive_portal;
|
||||
bool dhcp_use_mtu;
|
||||
bool dhcp_use_routes;
|
||||
int dhcp_use_gateway;
|
||||
@@ -169,6 +170,7 @@ struct Network {
|
||||
bool dhcp6_use_hostname;
|
||||
bool dhcp6_use_ntp;
|
||||
bool dhcp6_use_ntp_set;
|
||||
bool dhcp6_use_captive_portal;
|
||||
bool dhcp6_use_rapid_commit;
|
||||
DHCPUseDomains dhcp6_use_domains;
|
||||
bool dhcp6_use_domains_set;
|
||||
@@ -315,6 +317,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;
|
||||
|
||||
@@ -464,7 +464,8 @@ static void link_save_domains(Link *link, FILE *f, OrderedSet *static_domains, D
|
||||
}
|
||||
|
||||
int link_save(Link *link) {
|
||||
const char *admin_state, *oper_state, *carrier_state, *address_state, *ipv4_address_state, *ipv6_address_state;
|
||||
const char *admin_state, *oper_state, *carrier_state, *address_state, *ipv4_address_state, *ipv6_address_state,
|
||||
*dhcp_captive_portal = NULL, *dhcp6_captive_portal = NULL;
|
||||
_cleanup_(unlink_and_freep) char *temp_path = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
int r;
|
||||
@@ -606,6 +607,40 @@ int link_save(Link *link) {
|
||||
|
||||
/************************************************************/
|
||||
|
||||
if (link->dhcp_lease && link->network->dhcp_use_captive_portal) {
|
||||
r = sd_dhcp_lease_get_captive_portal(link->dhcp_lease, &dhcp_captive_portal);
|
||||
if (r < 0 && r != -ENODATA)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (link->dhcp6_lease && link->network->dhcp6_use_captive_portal) {
|
||||
r = sd_dhcp6_lease_get_captive_portal(link->dhcp6_lease, &dhcp6_captive_portal);
|
||||
if (r < 0 && r != -ENODATA)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (dhcp6_captive_portal && dhcp_captive_portal && !streq(dhcp_captive_portal, dhcp6_captive_portal))
|
||||
log_link_warning(link, "DHCPv6 Captive Portal (%s) does not match DHCPv4 (%s). Ignoring DHCPv6 portal.",
|
||||
dhcp6_captive_portal, dhcp_captive_portal);
|
||||
|
||||
if (link->network->ipv6_accept_ra_use_captive_portal && link->ndisc_captive_portal) {
|
||||
if (dhcp_captive_portal && !streq(dhcp_captive_portal, link->ndisc_captive_portal))
|
||||
log_link_warning(link, "IPv6RA captive portal (%s) does not match DHCPv4 (%s). Ignorning IPv6RA portal.",
|
||||
link->ndisc_captive_portal, dhcp_captive_portal);
|
||||
if (dhcp6_captive_portal && !streq(dhcp6_captive_portal, link->ndisc_captive_portal))
|
||||
log_link_warning(link, "IPv6RA captive portal (%s) does not match DHCPv6 (%s). Ignorning IPv6RA portal.",
|
||||
link->ndisc_captive_portal, dhcp6_captive_portal);
|
||||
}
|
||||
|
||||
if (dhcp_captive_portal)
|
||||
fprintf(f, "CAPTIVE_PORTAL=%s\n", dhcp_captive_portal);
|
||||
else if (dhcp6_captive_portal)
|
||||
fprintf(f, "CAPTIVE_PORTAL=%s\n", dhcp6_captive_portal);
|
||||
else if (link->ndisc_captive_portal)
|
||||
fprintf(f, "CAPTIVE_PORTAL=%s\n", link->ndisc_captive_portal);
|
||||
|
||||
/************************************************************/
|
||||
|
||||
fputs("DOMAINS=", f);
|
||||
if (link->search_domains)
|
||||
link_save_domains(link, f, link->search_domains, DHCP_USE_DOMAINS_NO);
|
||||
|
||||
Reference in New Issue
Block a user