mirror of
https://github.com/systemd/systemd.git
synced 2026-08-10 17:14:31 +00:00
sd-dhcp-server: update conditions when we should send DHCPNAK (#42252)
This commit is contained in:
@@ -247,7 +247,7 @@ static int dhcp_server_process_discover(sd_dhcp_server *server, DHCPRequest *req
|
||||
sd_dhcp_server_lease *l = hashmap_get(server->bound_leases_by_address, UINT32_TO_PTR(static_lease->address));
|
||||
if (l && l != existing_lease)
|
||||
/* The address is already assigned to another host. Refusing. */
|
||||
return 0;
|
||||
return -EADDRINUSE;
|
||||
|
||||
/* Found a matching static lease. */
|
||||
req->static_lease = static_lease;
|
||||
@@ -281,8 +281,7 @@ static int dhcp_server_process_discover(sd_dhcp_server *server, DHCPRequest *req
|
||||
}
|
||||
|
||||
if (req->address == INADDR_ANY)
|
||||
/* no free addresses left */
|
||||
return 0;
|
||||
return -EADDRNOTAVAIL; /* no free addresses left */
|
||||
|
||||
if (server->rapid_commit &&
|
||||
dhcp_message_get_option_flag(req->message, SD_DHCP_OPTION_RAPID_COMMIT) >= 0)
|
||||
@@ -291,6 +290,65 @@ static int dhcp_server_process_discover(sd_dhcp_server *server, DHCPRequest *req
|
||||
return dhcp_server_send_reply(server, req, DHCP_OFFER);
|
||||
}
|
||||
|
||||
static int server_guess_client_state(sd_dhcp_server *server, DHCPRequest *req) {
|
||||
int r;
|
||||
|
||||
assert(server);
|
||||
assert(req);
|
||||
assert(req->message);
|
||||
|
||||
/* This guesses the client is in the renewing or rebinding state.
|
||||
*
|
||||
* If giaddr is zero, then there is no relay agent between the client and us. In that case, a
|
||||
* DHCPREQUEST sent to a unicast destination address implies the client is in RENEWING state, while a
|
||||
* broadcast destination address implies REBINDING state. Note, if packet destination information is
|
||||
* unavailable, we conservatively assume REBINDING.
|
||||
*
|
||||
* If giaddr is non-zero, then there is a relay agent. The relay forwards packets to us using unicast
|
||||
* transport, so the outer IPv4 destination address no longer reflects whether the original client
|
||||
* message was broadcast or unicast. If the message contains the Relay Agent Information option with
|
||||
* Relay Agent Flags suboption, then we can know if the original message is unicast or broadcast. If
|
||||
* the message does not have the option, then we assume the client is in the rebinding state. */
|
||||
|
||||
if (req->message->header.giaddr == INADDR_ANY) {
|
||||
if (!req->pktinfo)
|
||||
return DHCP_STATE_REBINDING;
|
||||
|
||||
/* 255.255.255.255 ? */
|
||||
if (req->pktinfo->ipi_addr.s_addr == INADDR_BROADCAST)
|
||||
return DHCP_STATE_REBINDING;
|
||||
|
||||
/* subnet-directed broadcast, e.g., 192.0.2.0/24 -> 192.0.2.255 ? */
|
||||
if (req->pktinfo->ipi_addr.s_addr == (server->subnet | ~server->netmask))
|
||||
return DHCP_STATE_REBINDING;
|
||||
|
||||
/* unicast, hence renewing. */
|
||||
return DHCP_STATE_RENEWING;
|
||||
}
|
||||
|
||||
_cleanup_(tlv_unrefp) TLV *agent_info = NULL;
|
||||
r = dhcp_message_get_option_sub_tlv(
|
||||
req->message,
|
||||
SD_DHCP_OPTION_RELAY_AGENT_INFORMATION,
|
||||
TLV_DHCP4_SUBOPTION,
|
||||
&agent_info);
|
||||
if (r == -ENODATA)
|
||||
return DHCP_STATE_REBINDING;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
struct iovec iov = {};
|
||||
r = tlv_get_full(agent_info, SD_DHCP_RELAY_AGENT_FLAGS, sizeof(uint8_t), &iov);
|
||||
if (r == -ENODATA)
|
||||
return DHCP_STATE_REBINDING;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
assert(iov.iov_len == sizeof(uint8_t));
|
||||
uint8_t flags = *(const uint8_t*) iov.iov_base;
|
||||
return FLAGS_SET(flags, DHCP_RELAY_AGENT_FLAG_UNICAST) ? DHCP_STATE_RENEWING : DHCP_STATE_REBINDING;
|
||||
}
|
||||
|
||||
static int dhcp_server_process_request(sd_dhcp_server *server, DHCPRequest *req) {
|
||||
int r;
|
||||
|
||||
@@ -301,20 +359,18 @@ static int dhcp_server_process_request(sd_dhcp_server *server, DHCPRequest *req)
|
||||
*existing_lease = hashmap_get(server->bound_leases_by_client_id, &req->client_id),
|
||||
*static_lease = dhcp_server_get_static_lease(server, req);
|
||||
|
||||
DHCPState state;
|
||||
be32_t address;
|
||||
bool init_reboot = false;
|
||||
|
||||
/* see RFC 2131, section 4.3.2 */
|
||||
if (req->server_address != INADDR_ANY) {
|
||||
log_dhcp_server(server, "REQUEST (selecting) (0x%x)",
|
||||
be32toh(req->message->header.xid));
|
||||
state = DHCP_STATE_SELECTING;
|
||||
|
||||
/* SELECTING */
|
||||
if (req->server_address != server->address)
|
||||
return 0; /* The message is not for us. Let's silently ignore the packet. */
|
||||
|
||||
if (req->message->header.ciaddr != INADDR_ANY) /* this MUST be zero */
|
||||
return 0;
|
||||
return -EBADMSG;
|
||||
|
||||
/* this must be filled in with the yiaddr from the chosen OFFER */
|
||||
r = dhcp_message_get_option_be32(req->message, SD_DHCP_OPTION_REQUESTED_IP_ADDRESS, &address);
|
||||
@@ -325,10 +381,10 @@ static int dhcp_server_process_request(sd_dhcp_server *server, DHCPRequest *req)
|
||||
return -EBADMSG;
|
||||
|
||||
} else if (req->message->header.ciaddr != INADDR_ANY) {
|
||||
log_dhcp_server(server, "REQUEST (rebinding/renewing) (0x%x)",
|
||||
be32toh(req->message->header.xid));
|
||||
|
||||
/* REBINDING / RENEWING */
|
||||
r = server_guess_client_state(server, req);
|
||||
if (r < 0)
|
||||
return r;
|
||||
state = r;
|
||||
|
||||
/* this must NOT be filled */
|
||||
if (dhcp_message_get_option_be32(req->message, SD_DHCP_OPTION_REQUESTED_IP_ADDRESS, /* ret= */ NULL) >= 0)
|
||||
@@ -337,20 +393,52 @@ static int dhcp_server_process_request(sd_dhcp_server *server, DHCPRequest *req)
|
||||
address = req->message->header.ciaddr;
|
||||
|
||||
} else {
|
||||
log_dhcp_server(server, "REQUEST (init-reboot) (0x%x)",
|
||||
be32toh(req->message->header.xid));
|
||||
state = DHCP_STATE_INIT_REBOOT;
|
||||
|
||||
/* INIT-REBOOT */
|
||||
r = dhcp_message_get_option_be32(req->message, SD_DHCP_OPTION_REQUESTED_IP_ADDRESS, &address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (address == INADDR_ANY)
|
||||
return -EBADMSG;
|
||||
|
||||
init_reboot = true;
|
||||
}
|
||||
|
||||
log_dhcp_server(server, "REQUEST (%s) (0x%x)", dhcp_state_to_string(state), be32toh(req->message->header.xid));
|
||||
|
||||
/* In the below, when we found some inconsistency with the bound lease or static lease, we send
|
||||
* DHCPNAK if the client is in the selecting, renewing, or init-reboot state. Otherwise, i.e.,
|
||||
* if in the rebinding state, we silently ignore the message. This is because, the network may have
|
||||
* multiple DHCP servers, and the address may be managed by another server, and the request may be
|
||||
* for that server.
|
||||
*
|
||||
* On selecting:
|
||||
* We have already verified the message has matching server identifier, hence we have responsibility
|
||||
* to manage the request, hence we should aggressively reply DHCPNAK.
|
||||
*
|
||||
* On renewing:
|
||||
* The message is sent directly to us using unicast transport, so replying with DHCPNAK is unlikely
|
||||
* to interfere with another server.
|
||||
*
|
||||
* On rebinding:
|
||||
* The message is sent using broadcast delivery, hence if the network has multiple DHCP servers, then
|
||||
* another server may reply DHCPACK. We should not disturb their process. Hence, silently ignore the
|
||||
* message.
|
||||
*
|
||||
* On init-reboot:
|
||||
* Even though the message is broadcast, for faster rebooting, we should aggressively reply DHCPNAK.
|
||||
* Even if this is unnecessarily aggressive, the client will soon enter the usual DISCOVER -> REQUEST
|
||||
* cycle, so that should not cause any big issues. */
|
||||
bool send_nak = IN_SET(state, DHCP_STATE_SELECTING, DHCP_STATE_RENEWING, DHCP_STATE_INIT_REBOOT);
|
||||
|
||||
/* Check if the requested address is already assigned to another host.
|
||||
* - if 'l' is NULL, then the address is not assigned to any host.
|
||||
* - if 'l' is non-NULL, and equivalent to 'existing_lease', then the address is assigned to the host.
|
||||
* - if 'l' is non-NULL, but different from 'existing_lease', then the address is already assigned to
|
||||
* another host. In this case, we explicitly know that the address should not be used by the host. */
|
||||
sd_dhcp_server_lease *l = hashmap_get(server->bound_leases_by_address, UINT32_TO_PTR(address));
|
||||
if (l && l != existing_lease)
|
||||
return send_nak ? dhcp_server_send_reply(server, req, DHCP_NAK) : 0;
|
||||
|
||||
/* Check if the request is consistent with the static lease. */
|
||||
if (static_lease) {
|
||||
/* Found a static lease for the client ID. In this case, the server is explicitly configured
|
||||
@@ -358,12 +446,7 @@ static int dhcp_server_process_request(sd_dhcp_server *server, DHCPRequest *req)
|
||||
|
||||
if (static_lease->address != address)
|
||||
/* The client requested an address which is different from the static lease. Refusing. */
|
||||
return init_reboot ? dhcp_server_send_reply(server, req, DHCP_NAK) : 0;
|
||||
|
||||
sd_dhcp_server_lease *l = hashmap_get(server->bound_leases_by_address, UINT32_TO_PTR(address));
|
||||
if (l && l != existing_lease)
|
||||
/* The requested address is already assigned to another host. Refusing. */
|
||||
return init_reboot ? dhcp_server_send_reply(server, req, DHCP_NAK) : 0;
|
||||
return send_nak ? dhcp_server_send_reply(server, req, DHCP_NAK) : 0;
|
||||
|
||||
req->static_lease = static_lease;
|
||||
req->address = address;
|
||||
@@ -372,14 +455,15 @@ static int dhcp_server_process_request(sd_dhcp_server *server, DHCPRequest *req)
|
||||
}
|
||||
|
||||
if (dhcp_server_address_is_in_pool(server, address)) {
|
||||
/* The requested address is in the pool. */
|
||||
/* The requested address is in the pool. In the above, we have checked the address is free or
|
||||
* already assigned to the host. Hence, ACK. */
|
||||
req->address = address;
|
||||
|
||||
return dhcp_server_ack(server, req);
|
||||
}
|
||||
|
||||
/* Refuse otherwise. */
|
||||
if (init_reboot)
|
||||
/* No static lease is configured for the host, and the requested address is not in our pool. Refusing. */
|
||||
if (send_nak)
|
||||
return dhcp_server_send_reply(server, req, DHCP_NAK);
|
||||
|
||||
return 0;
|
||||
@@ -421,18 +505,19 @@ static int dhcp_server_process_release(sd_dhcp_server *server, DHCPRequest *req)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, size_t length, const triple_timestamp *timestamp) {
|
||||
int dhcp_server_process_message(sd_dhcp_server *server, const struct iovec *iov, struct msghdr *mh) {
|
||||
int r;
|
||||
|
||||
assert(server);
|
||||
assert(message);
|
||||
assert(iov);
|
||||
|
||||
_cleanup_(dhcp_request_freep) DHCPRequest *req = NULL;
|
||||
r = dhcp_server_parse_message(server, &IOVEC_MAKE(message, length), &req);
|
||||
r = dhcp_server_parse_message(server, iov, &req);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
dhcp_request_set_timestamp(req, timestamp);
|
||||
dhcp_request_set_timestamp(req, mh ? TRIPLE_TIMESTAMP_FROM_CMSG(mh) : NULL);
|
||||
req->pktinfo = mh ? CMSG_FIND_DATA(mh, IPPROTO_IP, IP_PKTINFO, struct in_pktinfo) : NULL;
|
||||
|
||||
r = dhcp_server_cleanup_expired_leases(server);
|
||||
if (r < 0)
|
||||
@@ -488,12 +573,7 @@ static int server_receive_message(sd_event_source *s, int fd, uint32_t revents,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO: figure out if this can be done as a filter on the socket, like for IPv6 */
|
||||
struct in_pktinfo *info = CMSG_FIND_DATA(&msg, IPPROTO_IP, IP_PKTINFO, struct in_pktinfo);
|
||||
if (info && info->ipi_ifindex != server->ifindex)
|
||||
return 0;
|
||||
|
||||
r = dhcp_server_handle_message(server, buf, (size_t) len, TRIPLE_TIMESTAMP_FROM_CMSG(&msg));
|
||||
r = dhcp_server_process_message(server, &IOVEC_MAKE(buf, len), &msg);
|
||||
if (r < 0)
|
||||
log_dhcp_server_errno(server, r, "Couldn't process incoming message, ignoring: %m");
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include "dhcp-client-id-internal.h"
|
||||
#include "dhcp-message.h"
|
||||
#include "dhcp-protocol.h"
|
||||
#include "ether-addr-util.h"
|
||||
#include "sd-forward.h"
|
||||
#include "sparse-endian.h"
|
||||
@@ -17,6 +16,7 @@ typedef struct DHCPRequest {
|
||||
/* sender hardware address, may not be set for non-ethernet interface */
|
||||
struct hw_addr_data hw_addr;
|
||||
triple_timestamp timestamp;
|
||||
struct in_pktinfo *pktinfo;
|
||||
|
||||
/* options */
|
||||
uint8_t type;
|
||||
@@ -34,5 +34,5 @@ typedef struct DHCPRequest {
|
||||
|
||||
int dhcp_request_get_lifetime_timestamp(DHCPRequest *req, clockid_t clock, usec_t *ret);
|
||||
|
||||
int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, size_t length, const triple_timestamp *timestamp);
|
||||
int dhcp_server_process_message(sd_dhcp_server *server, const struct iovec *iov, struct msghdr *mh);
|
||||
int dhcp_server_setup_io_event_source(sd_dhcp_server *server);
|
||||
|
||||
@@ -7,9 +7,11 @@
|
||||
#include "alloc-util.h"
|
||||
#include "dhcp-server-internal.h"
|
||||
#include "dhcp-server-lease-internal.h"
|
||||
#include "dhcp-server-request.h"
|
||||
#include "fd-util.h"
|
||||
#include "fuzz.h"
|
||||
#include "hashmap.h"
|
||||
#include "iovec-util.h"
|
||||
#include "rm-rf.h"
|
||||
#include "tests.h"
|
||||
#include "tmpfile-util.h"
|
||||
@@ -89,9 +91,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
ASSERT_OK(add_static_lease(server, 3));
|
||||
ASSERT_OK(add_static_lease(server, 4));
|
||||
|
||||
_cleanup_free_ uint8_t *duped = ASSERT_NOT_NULL(memdup(data, size));
|
||||
ASSERT_OK(sd_dhcp_server_start(server));
|
||||
(void) dhcp_server_handle_message(server, (DHCPMessage*) duped, size, NULL);
|
||||
(void) dhcp_server_process_message(server, &IOVEC_MAKE(data, size), /* mh= */ NULL);
|
||||
|
||||
ASSERT_OK(dhcp_server_save_leases(server));
|
||||
server->bound_leases_by_address = hashmap_free(server->bound_leases_by_address);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "dhcp-server-internal.h"
|
||||
#include "dhcp-server-request.h"
|
||||
#include "fd-util.h"
|
||||
#include "iovec-util.h"
|
||||
#include "tests.h"
|
||||
|
||||
TEST(basic) {
|
||||
@@ -60,7 +61,7 @@ TEST(basic) {
|
||||
ASSERT_OK(sd_dhcp_server_start(server));
|
||||
}
|
||||
|
||||
TEST(dhcp_server_handle_message) {
|
||||
TEST(dhcp_server_process_message) {
|
||||
struct {
|
||||
DHCPMessageHeader header;
|
||||
struct {
|
||||
@@ -131,61 +132,61 @@ TEST(dhcp_server_handle_message) {
|
||||
server->socket_fd = TAKE_FD(socket_fd[0]);
|
||||
ASSERT_OK(sd_dhcp_server_start(server));
|
||||
|
||||
ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_OFFER);
|
||||
ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_OFFER);
|
||||
|
||||
test.end = 0;
|
||||
/* TODO, shouldn't this fail? */
|
||||
ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_OFFER);
|
||||
ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_OFFER);
|
||||
test.end = SD_DHCP_OPTION_END;
|
||||
ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_OFFER);
|
||||
ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_OFFER);
|
||||
|
||||
test.option_type.code = 0;
|
||||
test.option_type.length = 0;
|
||||
test.option_type.type = 0;
|
||||
ASSERT_ERROR(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), ENODATA);
|
||||
ASSERT_ERROR(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), ENODATA);
|
||||
test.option_type.code = SD_DHCP_OPTION_MESSAGE_TYPE;
|
||||
test.option_type.length = 1;
|
||||
test.option_type.type = DHCP_DISCOVER;
|
||||
ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_OFFER);
|
||||
ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_OFFER);
|
||||
|
||||
test.header.op = 0;
|
||||
ASSERT_ERROR(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), EBADMSG);
|
||||
ASSERT_ERROR(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), EBADMSG);
|
||||
test.header.op = BOOTREQUEST;
|
||||
ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_OFFER);
|
||||
ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_OFFER);
|
||||
|
||||
/* Neither client ID nor hardware type is set. There is no way to manage the bound lease for the request. */
|
||||
test.header.htype = 0;
|
||||
ASSERT_ERROR(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), EBADMSG);
|
||||
ASSERT_ERROR(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), EBADMSG);
|
||||
test.header.htype = ARPHRD_ETHER;
|
||||
ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_OFFER);
|
||||
ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_OFFER);
|
||||
|
||||
test.header.hlen = 0;
|
||||
ASSERT_ERROR(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), EBADMSG);
|
||||
ASSERT_ERROR(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), EBADMSG);
|
||||
test.header.hlen = ETHER_ADDR_LEN;
|
||||
ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_OFFER);
|
||||
ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_OFFER);
|
||||
|
||||
/* DHCPREQUEST (init-boot) without requested IP */
|
||||
test.option_type.type = DHCP_REQUEST;
|
||||
ASSERT_ERROR(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), ENODATA);
|
||||
ASSERT_ERROR(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), ENODATA);
|
||||
|
||||
test.option_requested_ip.code = SD_DHCP_OPTION_REQUESTED_IP_ADDRESS;
|
||||
test.option_requested_ip.length = 4;
|
||||
test.option_requested_ip.address = htobe32(0x12345678);
|
||||
ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_NAK);
|
||||
ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_NAK);
|
||||
test.option_server_id.code = SD_DHCP_OPTION_SERVER_IDENTIFIER;
|
||||
test.option_server_id.length = 4;
|
||||
test.option_server_id.address = htobe32(INADDR_LOOPBACK);
|
||||
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 3);
|
||||
ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_ACK);
|
||||
ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_ACK);
|
||||
|
||||
test.option_server_id.address = htobe32(0x12345678);
|
||||
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 3);
|
||||
ASSERT_OK_ZERO(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL));
|
||||
ASSERT_OK_ZERO(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL));
|
||||
test.option_server_id.address = htobe32(INADDR_LOOPBACK);
|
||||
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 4);
|
||||
ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_ACK);
|
||||
ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_ACK);
|
||||
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 3);
|
||||
ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_ACK);
|
||||
ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_ACK);
|
||||
|
||||
test.option_client_id.code = SD_DHCP_OPTION_CLIENT_IDENTIFIER;
|
||||
test.option_client_id.length = 7;
|
||||
@@ -196,10 +197,10 @@ TEST(dhcp_server_handle_message) {
|
||||
test.option_client_id.id[4] = 'D';
|
||||
test.option_client_id.id[5] = 'E';
|
||||
test.option_client_id.id[6] = 'F';
|
||||
ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_ACK);
|
||||
ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_ACK);
|
||||
|
||||
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 30);
|
||||
ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_ACK);
|
||||
ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_ACK);
|
||||
|
||||
/* add the static lease for the client ID */
|
||||
ASSERT_OK(sd_dhcp_server_stop(server));
|
||||
@@ -213,25 +214,25 @@ TEST(dhcp_server_handle_message) {
|
||||
|
||||
/* discover */
|
||||
test.option_type.type = DHCP_DISCOVER;
|
||||
ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_OFFER);
|
||||
ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_OFFER);
|
||||
|
||||
/* request neither bound nor static address */
|
||||
test.option_type.type = DHCP_REQUEST;
|
||||
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 29);
|
||||
ASSERT_OK_ZERO(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL));
|
||||
ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_NAK);
|
||||
|
||||
/* request the currently assigned address */
|
||||
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 30);
|
||||
ASSERT_OK_ZERO(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL));
|
||||
ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_NAK);
|
||||
|
||||
/* request the new static address */
|
||||
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 31);
|
||||
ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_ACK);
|
||||
ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_ACK);
|
||||
|
||||
/* release the bound static lease */
|
||||
test.header.ciaddr = htobe32(INADDR_LOOPBACK + 31);
|
||||
test.option_type.type = DHCP_RELEASE;
|
||||
ASSERT_OK_ZERO(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL));
|
||||
ASSERT_OK_ZERO(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL));
|
||||
|
||||
/* drop the static lease for the client ID */
|
||||
ASSERT_OK(sd_dhcp_server_stop(server));
|
||||
@@ -247,27 +248,27 @@ TEST(dhcp_server_handle_message) {
|
||||
test.header.ciaddr = 0;
|
||||
test.option_type.type = DHCP_REQUEST;
|
||||
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 29);
|
||||
ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_ACK);
|
||||
ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_ACK);
|
||||
|
||||
/* request address reserved for static lease (unmatching client ID) */
|
||||
test.option_client_id.id[6] = 'H';
|
||||
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 42);
|
||||
ASSERT_OK_ZERO(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL));
|
||||
ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_NAK);
|
||||
|
||||
/* request unmatching address */
|
||||
test.option_client_id.id[6] = 'G';
|
||||
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 41);
|
||||
ASSERT_OK_ZERO(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL));
|
||||
ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_NAK);
|
||||
|
||||
/* request matching address */
|
||||
test.option_client_id.id[6] = 'G';
|
||||
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 42);
|
||||
ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_ACK);
|
||||
ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_ACK);
|
||||
|
||||
/* try again */
|
||||
test.option_client_id.id[6] = 'G';
|
||||
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 42);
|
||||
ASSERT_OK_EQ(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL), DHCP_ACK);
|
||||
ASSERT_OK_EQ(dhcp_server_process_message(server, &IOVEC_MAKE(&test, sizeof(test)), NULL), DHCP_ACK);
|
||||
}
|
||||
|
||||
TEST(sd_dhcp_server_set_static_lease) {
|
||||
|
||||
Reference in New Issue
Block a user