summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libsystemd-network/sd-dhcp-server.c37
-rw-r--r--src/libsystemd-network/test-dhcp-server.c6
2 files changed, 36 insertions, 7 deletions
diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c
index e170cfabf1..75f4316550 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -303,7 +303,7 @@ static int server_message_init(sd_dhcp_server *server, DHCPPacket **ret,
assert(server);
assert(ret);
assert(_optoffset);
- assert(IN_SET(type, DHCP_OFFER, DHCP_ACK));
+ assert(IN_SET(type, DHCP_OFFER, DHCP_ACK, DHCP_NAK));
packet = malloc0(sizeof(DHCPPacket) + req->max_optlen);
if (!packet)
@@ -377,6 +377,22 @@ static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req, be32_t addr
return 0;
}
+static int server_send_nak(sd_dhcp_server *server, DHCPRequest *req) {
+ _cleanup_free_ DHCPPacket *packet = NULL;
+ size_t offset;
+ int r;
+
+ r = server_message_init(server, &packet, DHCP_NAK, &offset, req);
+ if (r < 0)
+ return r;
+
+ r = dhcp_server_send_packet(server, req, packet, DHCP_NAK, offset);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
static int parse_request(uint8_t code, uint8_t len, const uint8_t *option,
void *user_data) {
DHCPRequest *req = user_data;
@@ -515,6 +531,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
case DHCP_REQUEST:
{
be32_t address;
+ bool init_reboot = false;
/* see RFC 2131, section 4.3.2 */
@@ -546,8 +563,9 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
/* this MUST be zero */
return 0;
- /* TODO: check if requested IP is correct, NAK if not */
+ /* TODO: check more carefully if IP is correct */
address = req->requested_ip;
+ init_reboot = true;
} else {
log_dhcp_server(server, "REQUEST (rebinding/renewing) (0x%x)",
be32toh(req->message->xid));
@@ -576,8 +594,19 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
be32toh(req->message->xid));
return DHCP_ACK;
}
- } else
- return 0;
+ } else if (init_reboot) {
+ r = server_send_nak(server, req);
+ if (r < 0) {
+ /* this only fails on critical errors */
+ log_dhcp_server(server, "could not send nak: %s",
+ strerror(-r));
+ return r;
+ } else {
+ log_dhcp_server(server, "NAK (0x%x)",
+ be32toh(req->message->xid));
+ return DHCP_NAK;
+ }
+ }
break;
}
diff --git a/src/libsystemd-network/test-dhcp-server.c b/src/libsystemd-network/test-dhcp-server.c
index 10fc2368cf..f738b3b427 100644
--- a/src/libsystemd-network/test-dhcp-server.c
+++ b/src/libsystemd-network/test-dhcp-server.c
@@ -150,7 +150,7 @@ static void test_message_handler(void) {
test.option_requested_ip.code = DHCP_OPTION_REQUESTED_IP_ADDRESS;
test.option_requested_ip.length = 4;
test.option_requested_ip.address = htobe32(0x12345678);
- assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
+ assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_NAK);
test.option_server_id.code = DHCP_OPTION_SERVER_IDENTIFIER;
test.option_server_id.length = 4;
test.option_server_id.address = htobe32(INADDR_LOOPBACK);
@@ -159,8 +159,8 @@ static void test_message_handler(void) {
test.option_server_id.address = htobe32(0x12345678);
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 3);
assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
- test.option_server_id.address = htobe32(INADDR_LOOPBACK + 3);
- test.option_requested_ip.address = htobe32(0x12345678);
+ test.option_server_id.address = htobe32(INADDR_LOOPBACK);
+ test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 30);
assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
}