From 4dc355680460fdc8e0d590d8572dff1b6a257d88 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Sun, 25 May 2014 17:31:17 +0200 Subject: [PATCH] sd-dhcp-server: add basic DISCOVER/OFFER support --- src/libsystemd-network/sd-dhcp-server.c | 82 ++++++++++++++++++++++- src/libsystemd-network/test-dhcp-server.c | 14 ++-- 2 files changed, 87 insertions(+), 9 deletions(-) diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index 994c7beb3..07715c5e9 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -27,6 +27,8 @@ #include "dhcp-server-internal.h" #include "dhcp-internal.h" +#define DHCP_DEFAULT_LEASE_TIME 60 + int sd_dhcp_server_set_address(sd_dhcp_server *server, struct in_addr *address) { assert_return(server, -EINVAL); assert_return(address, -EINVAL); @@ -277,6 +279,64 @@ int dhcp_server_send_packet(sd_dhcp_server *server, sizeof(DHCPPacket) + optoffset); } +static int server_message_init(sd_dhcp_server *server, DHCPPacket **ret, + uint8_t type, size_t *_optoffset, DHCPRequest *req) { + _cleanup_free_ DHCPPacket *packet = NULL; + size_t optoffset; + int r; + + assert(server); + assert(ret); + assert(_optoffset); + assert(type == DHCP_OFFER); + + packet = malloc0(sizeof(DHCPPacket) + req->max_optlen); + if (!packet) + return -ENOMEM; + + r = dhcp_message_init(&packet->dhcp, BOOTREPLY, be32toh(req->message->xid), + type, req->max_optlen, &optoffset); + if (r < 0) + return r; + + packet->dhcp.flags = req->message->flags; + packet->dhcp.giaddr = req->message->giaddr; + memcpy(&packet->dhcp.chaddr, &req->message->chaddr, ETH_ALEN); + + *_optoffset = optoffset; + *ret = packet; + packet = NULL; + + return 0; +} + +static int server_send_offer(sd_dhcp_server *server, DHCPRequest *req) { + _cleanup_free_ DHCPPacket *packet = NULL; + size_t offset; + be32_t lease_time; + int r; + + r = server_message_init(server, &packet, DHCP_OFFER, &offset, req); + if (r < 0) + return r; + + /* for now offer a random IP */ + packet->dhcp.yiaddr = random_u32(); + + /* for one minute */ + lease_time = htobe32(DHCP_DEFAULT_LEASE_TIME); + r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0, + DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4, &lease_time); + if (r < 0) + return r; + + r = dhcp_server_send_packet(server, req, packet, DHCP_OFFER, 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; @@ -377,9 +437,27 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, /* this only fails on critical errors */ return r; - log_dhcp_server(server, "received message of type %d", type); + switch(type) { + case DHCP_DISCOVER: + log_dhcp_server(server, "DISCOVER (0x%x)", + be32toh(req->message->xid)); + + r = server_send_offer(server, req); + if (r < 0) { + /* this only fails on critical errors */ + log_dhcp_server(server, "could not send offer: %s", + strerror(-r)); + return r; + } else { + log_dhcp_server(server, "OFFER (0x%x)", + be32toh(req->message->xid)); + return DHCP_OFFER; + } - return 1; + break; + } + + return 0; } static int server_receive_message(sd_event_source *s, int fd, diff --git a/src/libsystemd-network/test-dhcp-server.c b/src/libsystemd-network/test-dhcp-server.c index f0f9cfe58..a252e7022 100644 --- a/src/libsystemd-network/test-dhcp-server.c +++ b/src/libsystemd-network/test-dhcp-server.c @@ -94,13 +94,13 @@ static void test_message_handler(void) { assert_se(sd_dhcp_server_attach_event(server, NULL, 0) >= 0); assert_se(sd_dhcp_server_start(server) >= 0); - assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 1); + assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER); test.end = 0; /* TODO, shouldn't this fail? */ - assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 1); + assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER); test.end = DHCP_OPTION_END; - assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 1); + assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER); test.option_type.code = 0; test.option_type.length = 0; @@ -109,22 +109,22 @@ static void test_message_handler(void) { test.option_type.code = DHCP_OPTION_MESSAGE_TYPE; test.option_type.length = 1; test.option_type.type = DHCP_DISCOVER; - assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 1); + assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER); test.message.op = 0; assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0); test.message.op = BOOTREQUEST; - assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 1); + assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER); test.message.htype = 0; assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0); test.message.htype = ARPHRD_ETHER; - assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 1); + assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER); test.message.hlen = 0; assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0); test.message.hlen = ETHER_ADDR_LEN; - assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 1); + assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER); } int main(int argc, char *argv[]) { -- 2.30.2