#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"
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;
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,
#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 */
*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;
#include "sort-util.h"
#include "string-table.h"
#include "string-util.h"
-#include "strv.h"
#include "time-util.h"
#include "web-util.h"
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 (iovw_isempty(user_class)) {
+ iovw_done_free(&client->user_class);
+ return 0;
+ }
- if (n > 255 || n == 0)
+ _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;
- }
- s = strv_copy(user_class);
- if (!s)
- return -ENOMEM;
+ r = iovw_extend_iov(&iovw, iovec);
+ if (r < 0)
+ return r;
+ }
- return strv_free_and_replace(client->user_class, s);
+ iovw_done_free(&client->user_class);
+ client->user_class = TAKE_STRUCT(iovw);
+ return 0;
}
int sd_dhcp_client_set_client_port(
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) {
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);
return 0;
}
-int config_parse_dhcp_user_or_vendor_class(
+int config_parse_dhcp4_user_class(
const char *unit,
const char *filename,
unsigned line,
void *data,
void *userdata) {
- char ***l = ASSERT_PTR(data);
+ struct iovec_wrapper *iovw = ASSERT_PTR(data);
int r;
assert(lvalue);
assert(rvalue);
- assert(IN_SET(ltype, AF_INET, AF_INET6));
if (isempty(rvalue)) {
- *l = strv_free(*l);
+ iovw_done_free(iovw);
return 0;
}
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);
+ 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,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ char ***l = ASSERT_PTR(data);
+ int r;
+
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ *l = strv_free(*l);
+ 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;
- 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));
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);
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) {
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
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)
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
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);
#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"
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;
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);