networkd: add support to send DHCP user class option (#7499)

This patch add support to enables to send User Class option code 77
RFC 3004.

This option MAY carry multiple User Classes.

The format of this option is as follows:

         Code   Len   Value
        +-----+-----+---------------------  . . .  --+
        | 77  |  N  | User Class Data ('Len' octets) |
        +-----+-----+---------------------  . . .  --+

   where Value consists of one or more instances of User Class Data.
   Each instance of User Class Data is formatted as follows:

         UC_Len_i     User_Class_Data_i
        +--------+------------------------  . . .  --+
        |  L_i   | Opaque-Data ('UC_Len_i' octets)   |
        +--------+------------------------  . . .  --+

UserClass=
A DHCPv4 client can use UserClass option to identify the type or category of user or applications
it represents. The information contained in this option is an string that represents the user class
of which the client is a member. Each class sets an identifying string of information to be used by the DHCP service to classify clients. Takes a whitespace-separated list.

UserClass= hello world how are you

Closes: RFC: #5134
This commit is contained in:
Susant Sahani 2018-05-07 17:51:02 +05:30 committed by Zbigniew Jędrzejewski-Szmek
parent 348b44372f
commit af1c0de0e1
8 changed files with 137 additions and 1 deletions

View File

@ -1245,6 +1245,16 @@
</listitem>
</varlistentry>
<varlistentry>
<term><varname>UserClass=</varname></term>
<listitem>
<para>A DHCPv4 client can use UserClass option to identify the type or category of user or applications
it represents. The information contained in this option is a string that represents the user class of which
the client is a member. Each class sets an identifying string of information to be used by the DHCP
service to classify clients. Takes a whitespace-separated list of strings.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>DUIDType=</varname></term>
<listitem>

View File

@ -12,6 +12,7 @@
#include "alloc-util.h"
#include "utf8.h"
#include "strv.h"
#include "dhcp-internal.h"
@ -35,6 +36,34 @@ static int option_append(uint8_t options[], size_t size, size_t *offset,
*offset += 1;
break;
case SD_DHCP_OPTION_USER_CLASS: {
size_t len = 0;
char **s;
STRV_FOREACH(s, (char **) optval)
len += strlen(*s) + 1;
if (size < *offset + len + 2)
return -ENOBUFS;
options[*offset] = code;
options[*offset + 1] = len;
*offset += 2;
STRV_FOREACH(s, (char **) optval) {
len = strlen(*s);
if (len > 255)
return -ENAMETOOLONG;
options[*offset] = len;
memcpy_safe(&options[*offset + 1], *s, len);
*offset += len + 1;
}
break;
}
default:
if (size < *offset + optlen + 2)
return -ENOBUFS;

View File

@ -27,6 +27,7 @@
#include "random-util.h"
#include "string-util.h"
#include "util.h"
#include "strv.h"
#define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */
#define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)
@ -83,6 +84,7 @@ struct sd_dhcp_client {
size_t client_id_len;
char *hostname;
char *vendor_class_identifier;
char **user_class;
uint32_t mtu;
uint32_t xid;
usec_t start_time;
@ -440,6 +442,26 @@ int sd_dhcp_client_set_vendor_class_identifier(
return free_and_strdup(&client->vendor_class_identifier, vci);
}
int sd_dhcp_client_set_user_class(
sd_dhcp_client *client,
const char* const* user_class) {
_cleanup_strv_free_ char **s = NULL;
char **p;
STRV_FOREACH(p, (char **) user_class)
if (strlen(*p) > 255)
return -ENAMETOOLONG;
s = strv_copy((char **) user_class);
if (!s)
return -ENOMEM;
client->user_class = TAKE_PTR(s);
return 0;
}
int sd_dhcp_client_set_client_port(
sd_dhcp_client *client,
uint16_t port) {
@ -763,6 +785,15 @@ static int client_send_discover(sd_dhcp_client *client) {
return r;
}
if (client->user_class) {
r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
SD_DHCP_OPTION_USER_CLASS,
strv_length(client->user_class),
client->user_class);
if (r < 0)
return r;
}
r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
SD_DHCP_OPTION_END, 0, NULL);
if (r < 0)
@ -1918,6 +1949,7 @@ sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
free(client->req_opts);
free(client->hostname);
free(client->vendor_class_identifier);
client->user_class = strv_free(client->user_class);
return mfree(client);
}

View File

@ -748,6 +748,12 @@ int dhcp4_configure(Link *link) {
return r;
}
if (link->network->dhcp_user_class) {
r = sd_dhcp_client_set_user_class(link->dhcp_client, (const char **) link->network->dhcp_user_class);
if (r < 0)
return r;
}
if (link->network->dhcp_client_port) {
r = sd_dhcp_client_set_client_port(link->dhcp_client, link->network->dhcp_client_port);
if (r < 0)

View File

@ -125,6 +125,7 @@ DHCP.Hostname, config_parse_hostname,
DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast)
DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical)
DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier)
DHCP.UserClass, config_parse_dhcp_user_class, 0, offsetof(Network, dhcp_user_class)
DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid.type)
DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, duid)
DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric)

View File

@ -361,6 +361,7 @@ void network_free(Network *network) {
free(network->description);
free(network->dhcp_vendor_class_identifier);
strv_free(network->dhcp_user_class);
free(network->dhcp_hostname);
free(network->mac);
@ -1387,6 +1388,58 @@ int config_parse_ntp(
return 0;
}
int config_parse_dhcp_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) {
char ***l = data;
int r;
assert(l);
assert(lvalue);
assert(rvalue);
if (isempty(rvalue)) {
*l = strv_free(*l);
return 0;
}
for (;;) {
_cleanup_free_ char *w = NULL;
r = extract_first_word(&rvalue, &w, NULL, 0);
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to split user classes option, ignoring: %s", rvalue);
break;
}
if (r == 0)
break;
if (strlen(w) > 255) {
log_syntax(unit, LOG_ERR, filename, line, r, "%s length is not in the range 1-255, ignoring.", w);
continue;
}
r = strv_push(l, w);
if (r < 0)
return log_oom();
w = NULL;
}
return 0;
}
int config_parse_dhcp_route_table(const char *unit,
const char *filename,
unsigned line,

View File

@ -126,6 +126,7 @@ struct Network {
AddressFamilyBoolean dhcp;
DHCPClientIdentifier dhcp_client_identifier;
char *dhcp_vendor_class_identifier;
char **dhcp_user_class;
char *dhcp_hostname;
unsigned dhcp_route_metric;
uint32_t dhcp_route_table;
@ -288,7 +289,7 @@ int config_parse_dhcp_server_ntp(const char *unit, const char *filename, unsigne
int config_parse_dnssec_negative_trust_anchors(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);
int config_parse_dhcp_use_domains(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);
int config_parse_lldp_mode(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);
int config_parse_dhcp_route_table(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);
int config_parse_dhcp_route_table(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);int config_parse_dhcp_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);
int config_parse_ntp(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);
/* Legacy IPv4LL support */
int config_parse_ipv4ll(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);

View File

@ -82,6 +82,7 @@ enum {
SD_DHCP_OPTION_REBINDING_T2_TIME = 59,
SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60,
SD_DHCP_OPTION_CLIENT_IDENTIFIER = 61,
SD_DHCP_OPTION_USER_CLASS = 77,
SD_DHCP_OPTION_FQDN = 81,
SD_DHCP_OPTION_NEW_POSIX_TIMEZONE = 100,
SD_DHCP_OPTION_NEW_TZDB_TIMEZONE = 101,
@ -154,6 +155,9 @@ int sd_dhcp_client_set_hostname(
int sd_dhcp_client_set_vendor_class_identifier(
sd_dhcp_client *client,
const char *vci);
int sd_dhcp_client_set_user_class(
sd_dhcp_client *client,
const char* const *user_class);
int sd_dhcp_client_get_lease(
sd_dhcp_client *client,
sd_dhcp_lease **ret);