int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t cb, void *userdata, char **error_message);
+int dhcp_option_parse_string(const uint8_t *option, size_t len, char **ret);
+
int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
uint8_t type, uint16_t arp_type, uint8_t hlen, const uint8_t *chaddr,
size_t optlen, size_t *optoffset);
return message_type;
}
+int dhcp_option_parse_string(const uint8_t *option, size_t len, char **ret) {
+ int r;
+
+ assert(option);
+ assert(ret);
+
+ if (len <= 0)
+ *ret = mfree(*ret);
+ else {
+ char *string;
+
+ /*
+ * One trailing NUL byte is OK, we don't mind. See:
+ * https://github.com/systemd/systemd/issues/1337
+ */
+ r = make_cstring((const char *) option, len, MAKE_CSTRING_ALLOW_TRAILING_NUL, &string);
+ if (r < 0)
+ return r;
+
+ free_and_replace(*ret, string);
+ }
+
+ return 0;
+}
+
static sd_dhcp_option* dhcp_option_free(sd_dhcp_option *i) {
if (!i)
return NULL;
be32_t gateway;
uint8_t chaddr[16];
usec_t expiration;
+ char *hostname;
} DHCPLease;
struct sd_dhcp_server {
be32_t requested_ip;
uint32_t lifetime;
const uint8_t *agent_info_option;
+ char *hostname;
} DHCPRequest;
extern const struct hash_ops dhcp_lease_hash_ops;
#include "sd-dhcp-lease.h"
#include "alloc-util.h"
+#include "dhcp-internal.h"
#include "dhcp-lease-internal.h"
#include "dhcp-protocol.h"
#include "dns-domain.h"
return 0;
}
-static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
- int r;
-
- assert(option);
- assert(ret);
-
- if (len <= 0)
- *ret = mfree(*ret);
- else {
- char *string;
-
- /*
- * One trailing NUL byte is OK, we don't mind. See:
- * https://github.com/systemd/systemd/issues/1337
- */
- r = make_cstring((const char*) option, len, MAKE_CSTRING_ALLOW_TRAILING_NUL, &string);
- if (r < 0)
- return r;
-
- free_and_replace(*ret, string);
- }
-
- return 0;
-}
-
static int lease_parse_domain(const uint8_t *option, size_t len, char **ret) {
_cleanup_free_ char *name = NULL, *normalized = NULL;
int r;
assert(option);
assert(ret);
- r = lease_parse_string(option, len, &name);
+ r = dhcp_option_parse_string(option, len, &name);
if (r < 0)
return r;
if (!name) {
break;
case SD_DHCP_OPTION_ROOT_PATH:
- r = lease_parse_string(option, len, &lease->root_path);
+ r = dhcp_option_parse_string(option, len, &lease->root_path);
if (r < 0)
log_debug_errno(r, "Failed to parse root path, ignoring: %m");
break;
case SD_DHCP_OPTION_TZDB_TIMEZONE: {
_cleanup_free_ char *tz = NULL;
- r = lease_parse_string(option, len, &tz);
+ r = dhcp_option_parse_string(option, len, &tz);
if (r < 0) {
log_debug_errno(r, "Failed to parse timezone option, ignoring: %m");
return 0;
}
free(lease->client_id.data);
+ free(lease->hostname);
return mfree(lease);
}
static int parse_request(uint8_t code, uint8_t len, const void *option, void *userdata) {
DHCPRequest *req = ASSERT_PTR(userdata);
+ int r;
switch (code) {
case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
case SD_DHCP_OPTION_RELAY_AGENT_INFORMATION:
req->agent_info_option = (uint8_t*)option - 2;
+ break;
+ case SD_DHCP_OPTION_HOST_NAME:
+ r = dhcp_option_parse_string(option, len, &req->hostname);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to parse hostname, ignoring: %m");
+ return 0;
+ }
+
break;
}
return NULL;
free(req->client_id.data);
+ free(req->hostname);
return mfree(req);
}
return -EBADMSG;
}
-static int prepare_new_lease(
- DHCPLease **ret_lease,
- be32_t address,
- const DHCPClientId *client_id,
- uint8_t htype,
- uint8_t hlen,
- const uint8_t *chaddr,
- be32_t gateway,
- usec_t expiration) {
-
+static int prepare_new_lease(DHCPLease **ret_lease, be32_t address, DHCPRequest *req, usec_t expiration) {
_cleanup_(dhcp_lease_freep) DHCPLease *lease = NULL;
+ assert(ret_lease);
+ assert(address != 0);
+ assert(req);
+ assert(expiration != 0);
+
lease = new(DHCPLease, 1);
if (!lease)
return -ENOMEM;
*lease = (DHCPLease) {
.address = address,
- .client_id.length = client_id->length,
- .htype = htype,
- .hlen = hlen,
- .gateway = gateway,
+ .client_id.length = req->client_id.length,
+ .htype = req->message->htype,
+ .hlen = req->message->hlen,
+ .gateway = req->message->giaddr,
.expiration = expiration,
};
- lease->client_id.data = memdup(client_id->data, client_id->length);
+ lease->client_id.data = memdup(req->client_id.data, req->client_id.length);
if (!lease->client_id.data)
return -ENOMEM;
- memcpy(lease->chaddr, chaddr, hlen);
+ memcpy(lease->chaddr, req->message->chaddr, req->message->hlen);
+
+ if (req->hostname) {
+ lease->hostname = strdup(req->hostname);
+ if (!lease->hostname)
+ return -ENOMEM;
+ }
*ret_lease = TAKE_PTR(lease);
} else {
_cleanup_(dhcp_lease_freep) DHCPLease *lease = NULL;
- r = prepare_new_lease(&lease, address, &req->client_id,
- req->message->htype, req->message->hlen,
- req->message->chaddr, req->message->giaddr, expiration);
+ r = prepare_new_lease(&lease, address, req, expiration);
if (r < 0)
return log_dhcp_server_errno(server, r, "Failed to create new lease: %m");
uint8_t length;
uint8_t id[7];
} _packed_ option_client_id;
+ struct {
+ uint8_t code;
+ uint8_t length;
+ uint8_t hostname[6];
+ } _packed_ option_hostname;
uint8_t end;
} _packed_ test = {
.message.op = BOOTREQUEST,
.option_type.code = SD_DHCP_OPTION_MESSAGE_TYPE,
.option_type.length = 1,
.option_type.type = DHCP_DISCOVER,
+ .option_hostname.code = SD_DHCP_OPTION_HOST_NAME,
+ .option_hostname.length = 6,
+ .option_hostname.hostname = { 'T', 'E', 'S', 'T', 'H', 'N' },
.end = SD_DHCP_OPTION_END,
};
struct in_addr address_lo = {
lease->client_id.data,
lease->client_id.length),
JSON_BUILD_PAIR_IN4_ADDR_NON_NULL("Address", &address),
+ JSON_BUILD_PAIR_STRING_NON_EMPTY("Hostname", lease->hostname),
JSON_BUILD_PAIR_FINITE_USEC(
"ExpirationUSec", lease->expiration)));
if (r < 0)