From f4759ae05178df149661cd45173741e42b6e8f47 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 23 Jan 2022 02:27:26 +0900 Subject: [PATCH 1/7] sd-dhcp-server: drop unnecessary buffer duplication The block try to find and remove the existing static lease which matches the provided client ID, and the provided client ID will not be stored anywhere. Hence, it is not necessary to duplicate it. --- src/libsystemd-network/sd-dhcp-server.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index ea98060ea2..4124abfc8c 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -1536,18 +1536,13 @@ int sd_dhcp_server_set_static_lease( assert_return(!sd_dhcp_server_is_running(server), -EBUSY); /* Static lease with an empty or omitted address is a valid entry, - * the server removes any static lease with the specified mac address. */ + * the server removes any static lease with the specified mac address. */ if (!address || address->s_addr == 0) { - _cleanup_free_ void *data = NULL; DHCPClientId c; - data = memdup(client_id, client_id_size); - if (!data) - return -ENOMEM; - c = (DHCPClientId) { .length = client_id_size, - .data = data, + .data = client_id, }; dhcp_lease_free(hashmap_remove(server->static_leases_by_client_id, &c)); From 4f9dcf3dc5a8379c4d56df1826f879235523160c Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 23 Jan 2022 11:11:43 +0900 Subject: [PATCH 2/7] sd-dhcp-server: shorten code a bit --- src/libsystemd-network/sd-dhcp-server.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index 4124abfc8c..78901fa2bf 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -591,11 +591,7 @@ static int server_send_offer_or_ack( return r; } - r = dhcp_server_send_packet(server, req, packet, type, offset); - if (r < 0) - return r; - - return 0; + return dhcp_server_send_packet(server, req, packet, type, offset); } static int server_send_nak(sd_dhcp_server *server, DHCPRequest *req) { @@ -637,13 +633,9 @@ static int server_send_forcerenew(sd_dhcp_server *server, be32_t address, memcpy(&packet->dhcp.chaddr, chaddr, ETH_ALEN); - r = dhcp_server_send_udp(server, address, DHCP_PORT_CLIENT, - &packet->dhcp, - sizeof(DHCPMessage) + optoffset); - if (r < 0) - return r; - - return 0; + return dhcp_server_send_udp(server, address, DHCP_PORT_CLIENT, + &packet->dhcp, + sizeof(DHCPMessage) + optoffset); } static int parse_request(uint8_t code, uint8_t len, const void *option, void *userdata) { @@ -868,12 +860,11 @@ static int dhcp_server_cleanup_expired_leases(sd_dhcp_server *server) { if (r < 0) return r; - HASHMAP_FOREACH(lease, server->bound_leases_by_client_id) { + HASHMAP_FOREACH(lease, server->bound_leases_by_client_id) if (lease->expiration < time_now) { log_dhcp_server(server, "CLEAN (0x%x)", be32toh(lease->address)); dhcp_lease_free(lease); } - } return 0; } @@ -1222,7 +1213,7 @@ static int server_receive_message(sd_event_source *s, int fd, if ((size_t) len < sizeof(DHCPMessage)) return 0; - CMSG_FOREACH(cmsg, &msg) { + CMSG_FOREACH(cmsg, &msg) if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO && cmsg->cmsg_len == CMSG_LEN(sizeof(struct in_pktinfo))) { @@ -1235,7 +1226,6 @@ static int server_receive_message(sd_event_source *s, int fd, break; } - } if (sd_dhcp_server_is_in_relay_mode(server)) { r = dhcp_server_relay_message(server, message, len - sizeof(DHCPMessage), buflen); From 255d493324793ba31398d996fc40b212203a51b1 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 23 Jan 2022 02:46:46 +0900 Subject: [PATCH 3/7] sd-dhcp-server: use free_and_replace() at one more place --- src/libsystemd-network/sd-dhcp-server.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index 78901fa2bf..45d5a9e59c 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -667,8 +667,7 @@ static int parse_request(uint8_t code, uint8_t len, const void *option, void *us if (!data) return -ENOMEM; - free(req->client_id.data); - req->client_id.data = data; + free_and_replace(req->client_id.data, data); req->client_id.length = len; } From 2cb66bbdfb30d58e9b0c960db0b714960685c774 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 23 Jan 2022 02:47:32 +0900 Subject: [PATCH 4/7] sd-dhcp-server: change the type of the client ID data --- src/libsystemd-network/dhcp-server-internal.h | 2 +- src/libsystemd-network/sd-dhcp-server.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libsystemd-network/dhcp-server-internal.h b/src/libsystemd-network/dhcp-server-internal.h index 13d8cd77b4..0193ab9503 100644 --- a/src/libsystemd-network/dhcp-server-internal.h +++ b/src/libsystemd-network/dhcp-server-internal.h @@ -26,7 +26,7 @@ typedef enum DHCPRawOption { typedef struct DHCPClientId { size_t length; - void *data; + uint8_t *data; } DHCPClientId; typedef struct DHCPLease { diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index 45d5a9e59c..f00a1754e2 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -706,14 +706,14 @@ static int ensure_sane_request(sd_dhcp_server *server, DHCPRequest *req, DHCPMes /* set client id based on MAC address if client did not send an explicit one */ if (!req->client_id.data) { - void *data; + uint8_t *data; - data = malloc0(ETH_ALEN + 1); + data = new0(uint8_t, ETH_ALEN + 1); if (!data) return -ENOMEM; - ((uint8_t*) data)[0] = 0x01; - memcpy((uint8_t*) data + 1, &message->chaddr, ETH_ALEN); + data[0] = 0x01; + memcpy(data + 1, message->chaddr, ETH_ALEN); req->client_id.length = ETH_ALEN + 1; req->client_id.data = data; From a6508f37c9321c93f5d0b0184611d0fd5e85e2fe Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 23 Jan 2022 11:15:43 +0900 Subject: [PATCH 5/7] sd-dhcp-client: fix RFC number --- src/libsystemd-network/sd-dhcp-client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index c33be947b7..c89d9f3f2b 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -848,7 +848,7 @@ static int client_message_init( secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1; packet->dhcp.secs = htobe16(secs); - /* RFC2132 section 4.1 + /* RFC2131 section 4.1 A client that cannot receive unicast IP datagrams until its protocol software has been configured with an IP address SHOULD set the BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or @@ -862,7 +862,7 @@ static int client_message_init( if (client->request_broadcast || client->arp_type != ARPHRD_ETHER) packet->dhcp.flags = htobe16(0x8000); - /* RFC2132 section 4.1.1: + /* RFC2131 section 4.1.1: The client MUST include its hardware address in the ’chaddr’ field, if necessary for delivery of DHCP reply messages. Non-Ethernet interfaces will leave 'chaddr' empty and use the client identifier From 97fa338dceb8c59f9dd5047d327c819aca328e5c Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 23 Jan 2022 02:14:31 +0900 Subject: [PATCH 6/7] sd-dhcp-client,sd-dhcp-client-server: set chaddr in dhcp_message_init() And also set chaddr and hlen for packets on non-Ethernet interfaces, except for InfiniBand. --- src/libsystemd-network/dhcp-internal.h | 4 +-- src/libsystemd-network/dhcp-packet.c | 33 +++++++++++++++++++---- src/libsystemd-network/sd-dhcp-client.c | 12 ++------- src/libsystemd-network/sd-dhcp-server.c | 8 +++--- src/libsystemd-network/test-dhcp-option.c | 3 ++- 5 files changed, 37 insertions(+), 23 deletions(-) diff --git a/src/libsystemd-network/dhcp-internal.h b/src/libsystemd-network/dhcp-internal.h index 6538f05bdb..466d8e4b3f 100644 --- a/src/libsystemd-network/dhcp-internal.h +++ b/src/libsystemd-network/dhcp-internal.h @@ -53,8 +53,8 @@ typedef int (*dhcp_option_callback_t)(uint8_t code, uint8_t len, int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t cb, void *userdata, char **error_message); int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid, - uint8_t type, uint16_t arp_type, size_t optlen, - size_t *optoffset); + uint8_t type, uint16_t arp_type, uint8_t hlen, const uint8_t *chaddr, + size_t optlen, size_t *optoffset); uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len); diff --git a/src/libsystemd-network/dhcp-packet.c b/src/libsystemd-network/dhcp-packet.c index cace916f44..d1a1cf57f3 100644 --- a/src/libsystemd-network/dhcp-packet.c +++ b/src/libsystemd-network/dhcp-packet.c @@ -10,21 +10,44 @@ #include "dhcp-internal.h" #include "dhcp-protocol.h" +#include "memory-util.h" #define DHCP_CLIENT_MIN_OPTIONS_SIZE 312 -int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid, - uint8_t type, uint16_t arp_type, size_t optlen, - size_t *optoffset) { +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) { + size_t offset = 0; int r; assert(IN_SET(op, BOOTREQUEST, BOOTREPLY)); - assert(IN_SET(arp_type, ARPHRD_ETHER, ARPHRD_INFINIBAND)); + assert(chaddr || hlen == 0); message->op = op; message->htype = arp_type; - message->hlen = (arp_type == ARPHRD_ETHER) ? ETHER_ADDR_LEN : 0; + + /* RFC2131 section 4.1.1: + The client MUST include its hardware address in the ’chaddr’ field, if + necessary for delivery of DHCP reply messages. + + RFC 4390 section 2.1: + A DHCP client, when working over an IPoIB interface, MUST follow the + following rules: + "htype" (hardware address type) MUST be 32 [ARPPARAM]. + "hlen" (hardware address length) MUST be 0. + "chaddr" (client hardware address) field MUST be zeroed. + */ + message->hlen = (arp_type == ARPHRD_INFINIBAND) ? 0 : hlen; + memcpy_safe(message->chaddr, chaddr, message->hlen); + message->xid = htobe32(xid); message->magic = htobe32(DHCP_MAGIC_COOKIE); diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index c89d9f3f2b..7b296ae4a0 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -832,7 +832,8 @@ static int client_message_init( return -ENOMEM; r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type, - client->arp_type, optlen, &optoffset); + client->arp_type, client->mac_addr_len, client->mac_addr, + optlen, &optoffset); if (r < 0) return r; @@ -862,15 +863,6 @@ static int client_message_init( if (client->request_broadcast || client->arp_type != ARPHRD_ETHER) packet->dhcp.flags = htobe16(0x8000); - /* RFC2131 section 4.1.1: - The client MUST include its hardware address in the ’chaddr’ field, if - necessary for delivery of DHCP reply messages. Non-Ethernet - interfaces will leave 'chaddr' empty and use the client identifier - instead (eg, RFC 4390 section 2.1). - */ - if (client->arp_type == ARPHRD_ETHER) - memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN); - /* If no client identifier exists, construct an RFC 4361-compliant one */ if (client->client_id_len == 0) { size_t duid_len; diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index f00a1754e2..91069c0782 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -482,14 +482,14 @@ static int server_message_init(sd_dhcp_server *server, DHCPPacket **ret, return -ENOMEM; r = dhcp_message_init(&packet->dhcp, BOOTREPLY, - be32toh(req->message->xid), type, ARPHRD_ETHER, + be32toh(req->message->xid), type, + req->message->htype, req->message->hlen, req->message->chaddr, 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 = TAKE_PTR(packet); @@ -621,7 +621,7 @@ static int server_send_forcerenew(sd_dhcp_server *server, be32_t address, return -ENOMEM; r = dhcp_message_init(&packet->dhcp, BOOTREPLY, 0, - DHCP_FORCERENEW, ARPHRD_ETHER, + DHCP_FORCERENEW, ARPHRD_ETHER, ETH_ALEN, chaddr, DHCP_MIN_OPTIONS_SIZE, &optoffset); if (r < 0) return r; @@ -631,8 +631,6 @@ static int server_send_forcerenew(sd_dhcp_server *server, be32_t address, if (r < 0) return r; - memcpy(&packet->dhcp.chaddr, chaddr, ETH_ALEN); - return dhcp_server_send_udp(server, address, DHCP_PORT_CLIENT, &packet->dhcp, sizeof(DHCPMessage) + optoffset); diff --git a/src/libsystemd-network/test-dhcp-option.c b/src/libsystemd-network/test-dhcp-option.c index 800a6641e3..b01b1f57a3 100644 --- a/src/libsystemd-network/test-dhcp-option.c +++ b/src/libsystemd-network/test-dhcp-option.c @@ -89,7 +89,8 @@ static void test_message_init(void) { message = malloc0(len); assert_se(dhcp_message_init(message, BOOTREQUEST, 0x12345678, - DHCP_DISCOVER, ARPHRD_ETHER, optlen, &optoffset) >= 0); + DHCP_DISCOVER, ARPHRD_ETHER, ETH_ALEN, (uint8_t[16]){}, + optlen, &optoffset) >= 0); assert_se(message->xid == htobe32(0x12345678)); assert_se(message->op == BOOTREQUEST); From 54d95d02e3fdcfda1041da7df04df82b0a63077b Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 23 Jan 2022 02:27:32 +0900 Subject: [PATCH 7/7] sd-dhcp-server: support packet from non-Ethernet interface Fixes #22217. --- src/libsystemd-network/dhcp-server-internal.h | 2 + src/libsystemd-network/sd-dhcp-server.c | 103 +++++++++++++----- src/libsystemd-network/test-dhcp-server.c | 4 +- 3 files changed, 82 insertions(+), 27 deletions(-) diff --git a/src/libsystemd-network/dhcp-server-internal.h b/src/libsystemd-network/dhcp-server-internal.h index 0193ab9503..51510b9d22 100644 --- a/src/libsystemd-network/dhcp-server-internal.h +++ b/src/libsystemd-network/dhcp-server-internal.h @@ -34,6 +34,8 @@ typedef struct DHCPLease { DHCPClientId client_id; + uint8_t htype; /* e.g. ARPHRD_ETHER */ + uint8_t hlen; /* e.g. ETH_ALEN */ be32_t address; be32_t gateway; uint8_t chaddr[16]; diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index 91069c0782..38c202975f 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -15,6 +15,7 @@ #include "fd-util.h" #include "in-addr-util.h" #include "io-util.h" +#include "memory-util.h" #include "network-common.h" #include "ordered-set.h" #include "siphash24.h" @@ -294,22 +295,29 @@ int sd_dhcp_server_stop(sd_dhcp_server *server) { return 0; } -static int dhcp_server_send_unicast_raw(sd_dhcp_server *server, - DHCPPacket *packet, size_t len) { +static int dhcp_server_send_unicast_raw( + sd_dhcp_server *server, + uint8_t hlen, + const uint8_t *chaddr, + DHCPPacket *packet, + size_t len) { + union sockaddr_union link = { .ll.sll_family = AF_PACKET, .ll.sll_protocol = htobe16(ETH_P_IP), .ll.sll_ifindex = server->ifindex, - .ll.sll_halen = ETH_ALEN, + .ll.sll_halen = hlen, }; assert(server); assert(server->ifindex > 0); assert(server->address); + assert(hlen > 0); + assert(chaddr); assert(packet); assert(len > sizeof(DHCPPacket)); - memcpy(&link.ll.sll_addr, &packet->dhcp.chaddr, ETH_ALEN); + memcpy(link.ll.sll_addr, chaddr, hlen); dhcp_packet_append_ip_headers(packet, server->address, DHCP_PORT_SERVER, packet->dhcp.yiaddr, @@ -378,8 +386,16 @@ static bool requested_broadcast(DHCPMessage *message) { return message->flags & htobe16(0x8000); } -static int dhcp_server_send(sd_dhcp_server *server, be32_t destination, uint16_t destination_port, - DHCPPacket *packet, size_t optoffset, bool l2_broadcast) { +static int dhcp_server_send( + sd_dhcp_server *server, + uint8_t hlen, + const uint8_t *chaddr, + be32_t destination, + uint16_t destination_port, + DHCPPacket *packet, + size_t optoffset, + bool l2_broadcast) { + if (destination != INADDR_ANY) return dhcp_server_send_udp(server, destination, destination_port, &packet->dhcp, @@ -392,7 +408,7 @@ static int dhcp_server_send(sd_dhcp_server *server, be32_t destination, uint16_t /* we cannot send UDP packet to specific MAC address when the address is not yet configured, so must fall back to raw packets */ - return dhcp_server_send_unicast_raw(server, packet, + return dhcp_server_send_unicast_raw(server, hlen, chaddr, packet, sizeof(DHCPPacket) + optoffset); } @@ -462,7 +478,8 @@ int dhcp_server_send_packet(sd_dhcp_server *server, destination = req->message->ciaddr; bool l2_broadcast = requested_broadcast(req->message) || type == DHCP_NAK; - return dhcp_server_send(server, destination, destination_port, packet, optoffset, l2_broadcast); + return dhcp_server_send(server, req->message->hlen, req->message->chaddr, + destination, destination_port, packet, optoffset, l2_broadcast); } static int server_message_init(sd_dhcp_server *server, DHCPPacket **ret, @@ -606,8 +623,14 @@ static int server_send_nak(sd_dhcp_server *server, DHCPRequest *req) { return dhcp_server_send_packet(server, req, packet, DHCP_NAK, offset); } -static int server_send_forcerenew(sd_dhcp_server *server, be32_t address, - be32_t gateway, const uint8_t chaddr[]) { +static int server_send_forcerenew( + sd_dhcp_server *server, + be32_t address, + be32_t gateway, + uint8_t htype, + uint8_t hlen, + const uint8_t *chaddr) { + _cleanup_free_ DHCPPacket *packet = NULL; size_t optoffset = 0; int r; @@ -621,7 +644,7 @@ static int server_send_forcerenew(sd_dhcp_server *server, be32_t address, return -ENOMEM; r = dhcp_message_init(&packet->dhcp, BOOTREPLY, 0, - DHCP_FORCERENEW, ARPHRD_ETHER, ETH_ALEN, chaddr, + DHCP_FORCERENEW, htype, hlen, chaddr, DHCP_MIN_OPTIONS_SIZE, &optoffset); if (r < 0) return r; @@ -701,22 +724,45 @@ static int ensure_sane_request(sd_dhcp_server *server, DHCPRequest *req, DHCPMes req->message = message; - /* set client id based on MAC address if client did not send an explicit - one */ + /* set client id based on MAC address if client did not send an explicit one */ if (!req->client_id.data) { uint8_t *data; - data = new0(uint8_t, ETH_ALEN + 1); + if (message->hlen == 0) + return -EBADMSG; + + data = new0(uint8_t, message->hlen + 1); if (!data) return -ENOMEM; data[0] = 0x01; - memcpy(data + 1, message->chaddr, ETH_ALEN); + memcpy(data + 1, message->chaddr, message->hlen); - req->client_id.length = ETH_ALEN + 1; + req->client_id.length = message->hlen + 1; req->client_id.data = data; } + if (message->hlen > sizeof(message->chaddr)) + return -EBADMSG; + + if (message->hlen == 0 || memeqzero(message->chaddr, message->hlen)) { + /* See RFC2131 section 4.1.1. + * hlen and chaddr may not be set for non-ethernet interface. + * Let's try to retrieve it from the client ID. */ + + if (!req->client_id.data) + return -EBADMSG; + + if (req->client_id.length <= 1 || req->client_id.length > sizeof(message->chaddr) + 1) + return -EBADMSG; + + if (req->client_id.data[0] != 0x01) + return -EBADMSG; + + message->hlen = req->client_id.length - 1; + memcpy(message->chaddr, req->client_id.data + 1, message->hlen); + } + if (req->max_optlen < DHCP_MIN_OPTIONS_SIZE) req->max_optlen = DHCP_MIN_OPTIONS_SIZE; @@ -771,6 +817,10 @@ static int dhcp_server_relay_message(sd_dhcp_server *server, DHCPMessage *messag assert(message); assert(sd_dhcp_server_is_in_relay_mode(server)); + if (message->hlen == 0 || message->hlen > sizeof(message->chaddr) || memeqzero(message->chaddr, message->hlen)) + return log_dhcp_server_errno(server, SYNTHETIC_ERRNO(EBADMSG), + "(relay agent) received message without/invalid hardware address, discarding."); + if (message->op == BOOTREQUEST) { log_dhcp_server(server, "(relay agent) BOOTREQUEST (0x%x)", be32toh(message->xid)); if (message->hops >= 16) @@ -810,7 +860,7 @@ static int dhcp_server_relay_message(sd_dhcp_server *server, DHCPMessage *messag bool l2_broadcast = requested_broadcast(message) || message_type == DHCP_NAK; const be32_t destination = message_type == DHCP_NAK ? INADDR_ANY : message->ciaddr; - return dhcp_server_send(server, destination, DHCP_PORT_CLIENT, packet, opt_length, l2_broadcast); + return dhcp_server_send(server, message->hlen, message->chaddr, destination, DHCP_PORT_CLIENT, packet, opt_length, l2_broadcast); } return -EBADMSG; } @@ -819,7 +869,9 @@ static int prepare_new_lease( DHCPLease **ret_lease, be32_t address, const DHCPClientId *client_id, - const uint8_t chaddr[static ETH_ALEN], + uint8_t htype, + uint8_t hlen, + const uint8_t *chaddr, be32_t gateway, usec_t expiration) { @@ -832,6 +884,8 @@ static int prepare_new_lease( *lease = (DHCPLease) { .address = address, .client_id.length = client_id->length, + .htype = htype, + .hlen = hlen, .gateway = gateway, .expiration = expiration, }; @@ -839,7 +893,7 @@ static int prepare_new_lease( if (!lease->client_id.data) return -ENOMEM; - memcpy(&lease->chaddr, chaddr, ETH_ALEN); + memcpy(lease->chaddr, chaddr, hlen); *ret_lease = TAKE_PTR(lease); @@ -888,9 +942,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz assert(server); assert(message); - if (message->op != BOOTREQUEST || - message->htype != ARPHRD_ETHER || - message->hlen != ETHER_ADDR_LEN) + if (message->op != BOOTREQUEST) return 0; req = new0(DHCPRequest, 1); @@ -903,7 +955,6 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz r = ensure_sane_request(server, req, message); if (r < 0) - /* this only fails on critical errors */ return r; r = dhcp_server_cleanup_expired_leases(server); @@ -1042,6 +1093,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz expiration = usec_add(req->lifetime * USEC_PER_SEC, time_now); r = prepare_new_lease(&lease, static_lease->address, &req->client_id, + req->message->htype, req->message->hlen, req->message->chaddr, req->message->giaddr, expiration); if (r < 0) return r; @@ -1085,6 +1137,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz if (!existing_lease) { r = prepare_new_lease(&new_lease, address, &req->client_id, + req->message->htype, req->message->hlen, req->message->chaddr, req->message->giaddr, expiration); if (r < 0) return r; @@ -1313,7 +1366,8 @@ int sd_dhcp_server_forcerenew(sd_dhcp_server *server) { log_dhcp_server(server, "FORCERENEW"); HASHMAP_FOREACH(lease, server->bound_leases_by_client_id) { - k = server_send_forcerenew(server, lease->address, lease->gateway, lease->chaddr); + k = server_send_forcerenew(server, lease->address, lease->gateway, + lease->htype, lease->hlen, lease->chaddr); if (k < 0) r = k; } @@ -1519,7 +1573,6 @@ int sd_dhcp_server_set_static_lease( assert_return(server, -EINVAL); assert_return(client_id, -EINVAL); - assert_return(client_id_size == ETH_ALEN + 1, -EINVAL); assert_return(!sd_dhcp_server_is_running(server), -EBUSY); /* Static lease with an empty or omitted address is a valid entry, diff --git a/src/libsystemd-network/test-dhcp-server.c b/src/libsystemd-network/test-dhcp-server.c index a5c9bfeafb..b0e37352c3 100644 --- a/src/libsystemd-network/test-dhcp-server.c +++ b/src/libsystemd-network/test-dhcp-server.c @@ -137,12 +137,12 @@ static void test_message_handler(void) { 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); + assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER); test.message.htype = ARPHRD_ETHER; 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); + assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == -EBADMSG); test.message.hlen = ETHER_ADDR_LEN; assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER);