dhcp: use struct iovec_wrapper to manage user class

This commit is contained in:
Yu Watanabe
2026-05-12 20:06:28 +09:00
parent fa881fda15
commit 30b14a0886
10 changed files with 106 additions and 100 deletions
@@ -5,6 +5,7 @@
#include "dhcp-client-id-internal.h"
#include "ether-addr-util.h"
#include "iovec-wrapper.h"
#include "network-common.h"
#include "sd-forward.h"
#include "socket-util.h"
@@ -55,7 +56,7 @@ struct sd_dhcp_client {
char *hostname;
char *vendor_class_identifier;
char *mudurl;
char **user_class;
struct iovec_wrapper user_class;
uint32_t mtu;
usec_t fallback_lease_lifetime;
uint32_t xid;
@@ -93,6 +94,7 @@ int dhcp_client_get_state(sd_dhcp_client *client);
int dhcp_client_set_extra_options(sd_dhcp_client *client, TLV *options);
int dhcp_client_set_vendor_options(sd_dhcp_client *client, TLV *options);
int dhcp_client_set_user_class(sd_dhcp_client *client, const struct iovec_wrapper *user_class);
int client_receive_message_raw(
sd_event_source *s,
-38
View File
@@ -12,7 +12,6 @@
#include "hostname-util.h"
#include "memory-util.h"
#include "string-util.h"
#include "strv.h"
#include "utf8.h"
/* Append type-length value structure to the options buffer */
@@ -57,43 +56,6 @@ static int option_append(uint8_t options[], size_t size, size_t *offset,
*offset += 1;
break;
case SD_DHCP_OPTION_USER_CLASS: {
/* When called with raw data (optlen > 0), e.g. from SendOption=, append as a plain TLV.
* The structured handling below expects optval to be a strv. */
if (optlen > 0)
return dhcp_option_append_tlv(options, size, offset, code, optlen, optval);
size_t total = 0;
if (strv_isempty((char **) optval))
return -EINVAL;
STRV_FOREACH(s, (const char* const*) optval) {
size_t len = strlen(*s);
if (len > 255 || len == 0)
return -EINVAL;
total += 1 + len;
}
if (*offset + 2 + total > size)
return -ENOBUFS;
options[*offset] = code;
options[*offset + 1] = total;
*offset += 2;
STRV_FOREACH(s, (const char* const*) optval) {
size_t len = strlen(*s);
options[*offset] = len;
memcpy(&options[*offset + 1], *s, len);
*offset += 1 + len;
}
break;
}
case SD_DHCP_OPTION_SIP_SERVER:
if (*offset + 3 + optlen > size)
return -ENOBUFS;
+38 -23
View File
@@ -27,7 +27,6 @@
#include "sort-util.h"
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
#include "time-util.h"
#include "web-util.h"
@@ -434,28 +433,30 @@ int sd_dhcp_client_set_mud_url(
return free_and_strdup(&client->mudurl, mudurl);
}
int sd_dhcp_client_set_user_class(
sd_dhcp_client *client,
char * const *user_class) {
char **s = NULL;
int dhcp_client_set_user_class(sd_dhcp_client *client, const struct iovec_wrapper *user_class) {
int r;
assert_return(client, -EINVAL);
assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
assert_return(!strv_isempty(user_class), -EINVAL);
STRV_FOREACH(p, user_class) {
size_t n = strlen(*p);
if (n > 255 || n == 0)
return -EINVAL;
if (iovw_isempty(user_class)) {
iovw_done_free(&client->user_class);
return 0;
}
s = strv_copy(user_class);
if (!s)
return -ENOMEM;
_cleanup_(iovw_done_free) struct iovec_wrapper iovw = {};
FOREACH_ARRAY(iovec, user_class->iovec, user_class->count) {
if (iovec->iov_len == 0 || iovec->iov_len > UINT8_MAX)
return -EINVAL;
return strv_free_and_replace(client->user_class, s);
r = iovw_extend_iov(&iovw, iovec);
if (r < 0)
return r;
}
iovw_done_free(&client->user_class);
client->user_class = TAKE_STRUCT(iovw);
return 0;
}
int sd_dhcp_client_set_client_port(
@@ -933,12 +934,26 @@ static int client_append_common_discover_request_options(sd_dhcp_client *client,
return r;
}
if (client->user_class) {
r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
SD_DHCP_OPTION_USER_CLASS,
/* optlen= */ 0, client->user_class);
if (r < 0)
return r;
if (!iovw_isempty(&client->user_class)) {
size_t sz = iovw_size(&client->user_class) + client->user_class.count;
if (sz <= UINT8_MAX) {
_cleanup_free_ uint8_t *buf = new(uint8_t, sz);
if (!buf)
return -ENOMEM;
uint8_t *p = buf;
FOREACH_ARRAY(iovec, client->user_class.iovec, client->user_class.count) {
assert(iovec->iov_len > 0 && iovec->iov_len <= UINT8_MAX);
*p++ = iovec->iov_len;
p = mempcpy(p, iovec->iov_base, iovec->iov_len);
}
r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
SD_DHCP_OPTION_USER_CLASS,
sz, buf);
if (r < 0)
return r;
}
}
if (client->extra_options) {
@@ -2297,7 +2312,7 @@ static sd_dhcp_client* dhcp_client_free(sd_dhcp_client *client) {
free(client->hostname);
free(client->vendor_class_identifier);
free(client->mudurl);
client->user_class = strv_free(client->user_class);
iovw_done_free(&client->user_class);
tlv_unref(client->extra_options);
tlv_unref(client->vendor_options);
free(client->ifname);
+53 -23
View File
@@ -636,7 +636,52 @@ int config_parse_iaid(
return 0;
}
int config_parse_dhcp_user_or_vendor_class(
int config_parse_dhcp4_user_class(
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) {
struct iovec_wrapper *iovw = ASSERT_PTR(data);
int r;
assert(lvalue);
assert(rvalue);
if (isempty(rvalue)) {
iovw_done_free(iovw);
return 0;
}
for (const char *p = rvalue;;) {
_cleanup_free_ char *w = NULL;
r = extract_first_word(&p, &w, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
if (r < 0)
return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
if (r == 0)
return 0;
size_t len = strlen(w);
if (len > UINT8_MAX || len == 0) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"The length of the %s entry '%s' is not in the range 1…255, ignoring.", lvalue, w);
continue;
}
r = iovw_consume(iovw, TAKE_PTR(w), len);
if (r < 0)
return log_oom();
}
}
int config_parse_dhcp6_user_or_vendor_class(
const char *unit,
const char *filename,
unsigned line,
@@ -653,7 +698,6 @@ int config_parse_dhcp_user_or_vendor_class(
assert(lvalue);
assert(rvalue);
assert(IN_SET(ltype, AF_INET, AF_INET6));
if (isempty(rvalue)) {
*l = strv_free(*l);
@@ -662,32 +706,18 @@ int config_parse_dhcp_user_or_vendor_class(
for (const char *p = rvalue;;) {
_cleanup_free_ char *w = NULL;
size_t len;
r = extract_first_word(&p, &w, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to split user classes option, ignoring: %s", rvalue);
return 0;
}
if (r < 0)
return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
if (r == 0)
return 0;
len = strlen(w);
if (ltype == AF_INET) {
if (len > UINT8_MAX || len == 0) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"%s length is not in the range 1…255, ignoring.", w);
continue;
}
} else {
if (len > UINT16_MAX || len == 0) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"%s length is not in the range 1…65535, ignoring.", w);
continue;
}
size_t len = strlen(w);
if (len > UINT16_MAX || len == 0) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"The length of the %s entry '%s' is not in the range 1…65535, ignoring.", lvalue, w);
continue;
}
r = strv_consume(l, TAKE_PTR(w));
+2 -1
View File
@@ -81,7 +81,8 @@ CONFIG_PARSER_PROTOTYPE(config_parse_ndisc_route_metric);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_send_hostname);
CONFIG_PARSER_PROTOTYPE(config_parse_iaid);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_or_ra_route_table);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_user_or_vendor_class);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp4_user_class);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_user_or_vendor_class);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_send_option);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_option);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_option_tlv);
+3 -5
View File
@@ -1643,11 +1643,9 @@ static int dhcp4_configure(Link *link) {
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set MUD URL: %m");
}
if (link->network->dhcp_user_class) {
r = sd_dhcp_client_set_user_class(link->dhcp_client, link->network->dhcp_user_class);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set user class: %m");
}
r = dhcp_client_set_user_class(link->dhcp_client, &link->network->dhcp_user_class);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set user class: %m");
}
if (link->network->dhcp_client_port > 0) {
+4 -4
View File
@@ -278,7 +278,7 @@ DHCPv4.RequestBroadcast, config_parse_tristate,
DHCPv4.VendorClassIdentifier, config_parse_string, CONFIG_PARSE_STRING_SAFE, offsetof(Network, dhcp_vendor_class_identifier)
DHCPv4.MUDURL, config_parse_mud_url, 0, offsetof(Network, dhcp_mudurl)
DHCPv4.MaxAttempts, config_parse_dhcp_max_attempts, 0, 0
DHCPv4.UserClass, config_parse_dhcp_user_or_vendor_class, AF_INET, offsetof(Network, dhcp_user_class)
DHCPv4.UserClass, config_parse_dhcp4_user_class, 0, offsetof(Network, dhcp_user_class)
DHCPv4.IAID, config_parse_iaid, AF_INET, 0
DHCPv4.DUIDType, config_parse_network_duid_type, 0, 0
DHCPv4.DUIDRawData, config_parse_network_duid_rawdata, 0, 0
@@ -318,8 +318,8 @@ DHCPv6.MUDURL, config_parse_mud_url,
DHCPv6.SendHostname, config_parse_dhcp_send_hostname, AF_INET6, 0
DHCPv6.Hostname, config_parse_hostname, 0, offsetof(Network, dhcp6_hostname)
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)
DHCPv6.VendorClass, config_parse_dhcp_user_or_vendor_class, AF_INET6, offsetof(Network, dhcp6_vendor_class)
DHCPv6.UserClass, config_parse_dhcp6_user_or_vendor_class, 0, offsetof(Network, dhcp6_user_class)
DHCPv6.VendorClass, config_parse_dhcp6_user_or_vendor_class, 0, offsetof(Network, dhcp6_vendor_class)
DHCPv6.SendVendorOption, config_parse_dhcp6_send_option, 0, offsetof(Network, dhcp6_client_send_vendor_options)
DHCPv6.PrefixDelegationHint, config_parse_dhcp6_pd_prefix_hint, 0, 0
DHCPv6.UnassignedSubnetPolicy, config_parse_dhcp_pd_prefix_route_type, 0, offsetof(Network, dhcp6_pd_prefix_route_type)
@@ -664,7 +664,7 @@ DHCP.Hostname, config_parse_hostname,
DHCP.RequestBroadcast, config_parse_tristate, 0, offsetof(Network, dhcp_broadcast)
DHCP.CriticalConnection, config_parse_tristate, 0, offsetof(Network, dhcp_critical)
DHCP.VendorClassIdentifier, config_parse_string, CONFIG_PARSE_STRING_SAFE, offsetof(Network, dhcp_vendor_class_identifier)
DHCP.UserClass, config_parse_dhcp_user_or_vendor_class, AF_INET, offsetof(Network, dhcp_user_class)
DHCP.UserClass, config_parse_dhcp4_user_class, 0, offsetof(Network, dhcp_user_class)
DHCP.IAID, config_parse_iaid, AF_INET, 0
DHCP.DUIDType, config_parse_network_duid_type, 0, 0
DHCP.DUIDRawData, config_parse_network_duid_rawdata, 0, 0
+1 -1
View File
@@ -786,7 +786,7 @@ static Network *network_free(Network *network) {
free(network->dhcp_label);
set_free(network->dhcp_deny_listed_ip);
set_free(network->dhcp_allow_listed_ip);
strv_free(network->dhcp_user_class);
iovw_done_free(&network->dhcp_user_class);
set_free(network->dhcp_request_options);
tlv_done(&network->dhcp_extra_options);
tlv_done(&network->dhcp_vendor_options);
+2 -1
View File
@@ -7,6 +7,7 @@
#include "bridge.h"
#include "firewall-util.h"
#include "ipoib.h"
#include "iovec-wrapper.h"
#include "net-condition.h"
#include "network-util.h"
#include "networkd-bridge-vlan.h"
@@ -124,7 +125,7 @@ typedef struct Network {
bool dhcp_iaid_set;
char *dhcp_vendor_class_identifier;
char *dhcp_mudurl;
char **dhcp_user_class;
struct iovec_wrapper dhcp_user_class;
char *dhcp_hostname;
char *dhcp_label;
uint64_t dhcp_max_attempts;
-3
View File
@@ -129,9 +129,6 @@ int sd_dhcp_client_set_vendor_class_identifier(
int sd_dhcp_client_set_mud_url(
sd_dhcp_client *client,
const char *mudurl);
int sd_dhcp_client_set_user_class(
sd_dhcp_client *client,
char * const *user_class);
int sd_dhcp_client_get_lease(
sd_dhcp_client *client,
sd_dhcp_lease **ret);