Skip to content
Permalink
Browse files

networkd: dhcp server Support Vendor specific 43

Implementes https://tools.ietf.org/html/rfc2132

```
[DHCPServer]
SendRawOption=26:uint32:1400
SendRawOption=23:uint8:10

```
Frame 448: 350 bytes on wire (2800 bits), 350 bytes captured (2800 bits) on interface 0
Linux cooked capture
Internet Protocol Version 4, Src: 192.168.5.1, Dst: 192.168.5.11
User Datagram Protocol, Src Port: 67, Dst Port: 68
Dynamic Host Configuration Protocol (ACK)
    Message type: Boot Reply (2)
    Hardware type: Ethernet (0x01)
    Hardware address length: 6
    Hops: 0
    Transaction ID: 0x71f8de9d
    Seconds elapsed: 0
    Bootp flags: 0x0000 (Unicast)
    Client IP address: 0.0.0.0
    Your (client) IP address: 192.168.5.11
    Next server IP address: 0.0.0.0
    Relay agent IP address: 0.0.0.0
    Client MAC address: 1e:04:f8:b8:2f:d4 (1e:04:f8:b8:2f:d4)
    Client hardware address padding: 00000000000000000000
    Server host name not given
    Boot file name not given
    Magic cookie: DHCP
    Option: (53) DHCP Message Type (ACK)
        Length: 1
        DHCP: ACK (5)
    Option: (51) IP Address Lease Time
        Length: 4
        IP Address Lease Time: (3600s) 1 hour
    Option: (1) Subnet Mask (255.255.255.0)
        Length: 4
        Subnet Mask: 255.255.255.0
    Option: (3) Router
        Length: 4
        Router: 192.168.5.1
    Option: (6) Domain Name Server
        Length: 4
        Domain Name Server: 192.168.5.1
    Option: (42) Network Time Protocol Servers
        Length: 4
        Network Time Protocol Server: 192.168.5.1
    Option: (101) TCode
        Length: 13
        TZ TCode: Europe/Berlin
    Option: (43) Vendor-Specific Information
        Length: 9
        Value: 1701311a0431343030
    Option: (54) DHCP Server Identifier (192.168.5.1)
        Length: 4
        DHCP Server Identifier: 192.168.5.1
    Option: (255) End
        Option End: 255

```
  • Loading branch information...
ssahani authored and yuwata committed Sep 20, 2019
1 parent 597f905 commit 564ca98484d0a5d2ef974e7872c669b926e159c5
@@ -1902,6 +1902,19 @@
<filename>/etc/localtime</filename> symlink.</para></listitem>
</varlistentry>

<varlistentry>
<term><varname>SendRawOption=</varname></term>
<listitem>
<para>Send a raw option with value via DHCPv4 server. Takes a DHCP option, data type and data
(option:type:value). The option ranges [1-254]. The type takes one of <literal>uint8</literal>,
<literal>uint16</literal>, <literal>uint32</literal>, <literal>ipv4address</literal>, or <literal>string</literal>.
Special characters in the data string may be escaped using
<ulink url="https://en.wikipedia.org/wiki/Escape_sequences_in_C#Table_of_escape_sequences">C-style
escapes</ulink>. This option can be specified multiple times. If an empty string is specified, then all
options specified earlier are cleared. Defaults to unset.</para>
</listitem>
</varlistentry>

</variablelist>
</refsect1>

@@ -10,6 +10,7 @@

#include "alloc-util.h"
#include "dhcp-internal.h"
#include "dhcp-server-internal.h"
#include "memory-util.h"
#include "strv.h"
#include "utf8.h"
@@ -77,6 +78,32 @@ static int option_append(uint8_t options[], size_t size, size_t *offset,
*offset += 3 + optlen;

break;
case SD_DHCP_OPTION_VENDOR_SPECIFIC: {
OrderedHashmap *s = (OrderedHashmap *) optval;
struct sd_dhcp_raw_option *p;
size_t l = 0;
Iterator i;

ORDERED_HASHMAP_FOREACH(p, s, i)
l += p->length + 2;

if (*offset + l + 2 > size)
return -ENOBUFS;

options[*offset] = code;
options[*offset + 1] = l;

*offset += 2;

ORDERED_HASHMAP_FOREACH(p, s, i) {
options[*offset] = p->type;
options[*offset + 1] = p->length;
memcpy(&options[*offset + 2], p->data, p->length);
*offset += 2 + p->length;
}

break;
}
default:
if (*offset + 2 + optlen > size)
return -ENOBUFS;
@@ -13,6 +13,16 @@
#include "log.h"
#include "time-util.h"

typedef enum DHCPRawOption {
DHCP_RAW_OPTION_DATA_UINT8,
DHCP_RAW_OPTION_DATA_UINT16,
DHCP_RAW_OPTION_DATA_UINT32,
DHCP_RAW_OPTION_DATA_STRING,
DHCP_RAW_OPTION_DATA_IPV4ADDRESS,
_DHCP_RAW_OPTION_DATA_MAX,
_DHCP_RAW_OPTION_DATA_INVALID,
} DHCPRawOption;

typedef struct DHCPClientId {
size_t length;
void *data;
@@ -27,6 +37,15 @@ typedef struct DHCPLease {
usec_t expiration;
} DHCPLease;

struct sd_dhcp_raw_option {
unsigned n_ref;

uint8_t type;
uint8_t length;

void *data;
};

struct sd_dhcp_server {
unsigned n_ref;

@@ -48,6 +67,8 @@ struct sd_dhcp_server {
struct in_addr *ntp, *dns, *sip;
unsigned n_ntp, n_dns, n_sip;

OrderedHashmap *raw_option;

bool emit_router;

Hashmap *leases_by_client_id;
@@ -127,6 +127,46 @@ int client_id_compare_func(const DHCPClientId *a, const DHCPClientId *b) {
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(dhcp_lease_hash_ops, DHCPClientId, client_id_hash_func, client_id_compare_func,
DHCPLease, dhcp_lease_free);

static sd_dhcp_raw_option* raw_option_free(sd_dhcp_raw_option *i) {
if (!i)
return NULL;

free(i->data);
return mfree(i);
}

_public_ int sd_dhcp_raw_option_new(uint8_t type, char *data, size_t length, sd_dhcp_raw_option **ret) {
sd_dhcp_raw_option *p;

assert_return(ret, -EINVAL);

p = new(sd_dhcp_raw_option, 1);
if (!p)
return -ENOMEM;

*p = (sd_dhcp_raw_option) {
.n_ref = 1,
.data = memdup(data, length),
.length = length,
.type = type,
};

if (!p->data)
return -ENOMEM;

*ret = p;
return 0;
}

DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_raw_option, sd_dhcp_raw_option, raw_option_free);
DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
dhcp_raw_options_hash_ops,
void,
trivial_hash_func,
trivial_compare_func,
sd_dhcp_raw_option,
sd_dhcp_raw_option_unref);

static sd_dhcp_server *dhcp_server_free(sd_dhcp_server *server) {
assert(server);

@@ -143,6 +183,8 @@ static sd_dhcp_server *dhcp_server_free(sd_dhcp_server *server) {

hashmap_free(server->leases_by_client_id);

ordered_hashmap_free(server->raw_option);

free(server->bound_leases);
return mfree(server);
}
@@ -452,8 +494,8 @@ static int server_send_offer(sd_dhcp_server *server, DHCPRequest *req,
static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req,
be32_t address) {
_cleanup_free_ DHCPPacket *packet = NULL;
size_t offset;
be32_t lease_time;
size_t offset;
int r;

r = server_message_init(server, &packet, DHCP_ACK, &offset, req);
@@ -517,6 +559,15 @@ static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req,
return r;
}

if (!ordered_hashmap_isempty(server->raw_option)) {
r = dhcp_option_append(
&packet->dhcp, req->max_optlen, &offset, 0,
SD_DHCP_OPTION_VENDOR_SPECIFIC,
ordered_hashmap_size(server->raw_option), server->raw_option);
if (r < 0)
return r;
}

r = dhcp_server_send_packet(server, req, packet, DHCP_ACK, offset);
if (r < 0)
return r;
@@ -1170,3 +1221,22 @@ int sd_dhcp_server_set_emit_router(sd_dhcp_server *server, int enabled) {

return 1;
}

int sd_dhcp_server_add_raw_option(sd_dhcp_server *server, sd_dhcp_raw_option *v) {
int r;

assert_return(server, -EINVAL);
assert_return(v, -EINVAL);

r = ordered_hashmap_ensure_allocated(&server->raw_option, &dhcp_raw_options_hash_ops);
if (r < 0)
return -ENOMEM;

r = ordered_hashmap_put(server->raw_option, v, v);
if (r < 0)
return r;

sd_dhcp_raw_option_ref(v);

return 1;
}

0 comments on commit 564ca98

Please sign in to comment.
You can’t perform that action at this time.