1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright (C) 2013 Intel Corporation. All rights reserved.
7 Copyright (C) 2014 Tom Gundersen
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <sys/ioctl.h>
24 #include <netinet/if_ether.h>
26 #include "siphash24.h"
28 #include "sd-dhcp-server.h"
29 #include "dhcp-server-internal.h"
30 #include "dhcp-internal.h"
32 #define DHCP_DEFAULT_LEASE_TIME 3600 /* one hour */
34 int sd_dhcp_server_set_lease_pool(sd_dhcp_server *server, struct in_addr *address,
36 assert_return(server, -EINVAL);
37 assert_return(address, -EINVAL);
38 assert_return(address->s_addr, -EINVAL);
39 assert_return(size, -EINVAL);
40 assert_return(server->pool_start == htobe32(INADDR_ANY), -EBUSY);
41 assert_return(!server->pool_size, -EBUSY);
42 assert_return(!server->bound_leases, -EBUSY);
44 server->bound_leases = new0(DHCPLease*, size);
45 if (!server->bound_leases)
48 server->pool_start = address->s_addr;
49 server->pool_size = size;
54 int sd_dhcp_server_set_address(sd_dhcp_server *server, struct in_addr *address, unsigned char prefixlen) {
55 assert_return(server, -EINVAL);
56 assert_return(address, -EINVAL);
57 assert_return(address->s_addr, -EINVAL);
58 assert_return(prefixlen <= 32, -ERANGE);
59 assert_return(server->address == htobe32(INADDR_ANY), -EBUSY);
60 assert_return(server->netmask == htobe32(INADDR_ANY), -EBUSY);
62 server->address = address->s_addr;
63 server->netmask = htobe32(0xfffffffflu << (32 - prefixlen));
68 bool sd_dhcp_server_is_running(sd_dhcp_server *server) {
69 assert_return(server, -EINVAL);
71 return !!server->receive_message;
74 sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server) {
76 assert_se(REFCNT_INC(server->n_ref) >= 2);
81 unsigned long client_id_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
83 const DHCPClientId *id = p;
89 siphash24((uint8_t*) &u, id->data, id->length, hash_key);
91 return (unsigned long) u;
94 int client_id_compare_func(const void *_a, const void *_b) {
95 const DHCPClientId *a, *b;
100 assert(!a->length || a->data);
101 assert(!b->length || b->data);
103 if (a->length != b->length)
104 return a->length < b->length ? -1 : 1;
106 return memcmp(a->data, b->data, a->length);
109 static void dhcp_lease_free(DHCPLease *lease) {
113 free(lease->client_id.data);
117 sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) {
123 if (REFCNT_DEC(server->n_ref) > 0)
126 log_dhcp_server(server, "UNREF");
128 sd_dhcp_server_stop(server);
130 sd_event_unref(server->event);
132 while ((lease = hashmap_steal_first(server->leases_by_client_id)))
133 dhcp_lease_free(lease);
134 hashmap_free(server->leases_by_client_id);
136 free(server->bound_leases);
142 int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
143 _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL;
145 assert_return(ret, -EINVAL);
146 assert_return(ifindex > 0, -EINVAL);
148 server = new0(sd_dhcp_server, 1);
152 server->n_ref = REFCNT_INIT;
155 server->address = htobe32(INADDR_ANY);
156 server->netmask = htobe32(INADDR_ANY);
157 server->index = ifindex;
158 server->leases_by_client_id = hashmap_new(client_id_hash_func, client_id_compare_func);
166 int sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event, int priority) {
169 assert_return(server, -EINVAL);
170 assert_return(!server->event, -EBUSY);
173 server->event = sd_event_ref(event);
175 r = sd_event_default(&server->event);
180 server->event_priority = priority;
185 int sd_dhcp_server_detach_event(sd_dhcp_server *server) {
186 assert_return(server, -EINVAL);
188 server->event = sd_event_unref(server->event);
193 sd_event *sd_dhcp_server_get_event(sd_dhcp_server *server) {
194 assert_return(server, NULL);
196 return server->event;
199 int sd_dhcp_server_stop(sd_dhcp_server *server) {
200 assert_return(server, -EINVAL);
202 server->receive_message =
203 sd_event_source_unref(server->receive_message);
205 server->fd_raw = safe_close(server->fd_raw);
206 server->fd = safe_close(server->fd);
208 log_dhcp_server(server, "STOPPED");
213 static int dhcp_server_send_unicast_raw(sd_dhcp_server *server, DHCPPacket *packet,
215 union sockaddr_union link = {
216 .ll.sll_family = AF_PACKET,
217 .ll.sll_protocol = htons(ETH_P_IP),
218 .ll.sll_ifindex = server->index,
219 .ll.sll_halen = ETH_ALEN,
224 assert(server->index > 0);
225 assert(server->address);
227 assert(len > sizeof(DHCPPacket));
229 memcpy(&link.ll.sll_addr, &packet->dhcp.chaddr, ETH_ALEN);
231 dhcp_packet_append_ip_headers(packet, server->address, DHCP_PORT_SERVER,
232 packet->dhcp.yiaddr, DHCP_PORT_CLIENT, len);
234 r = dhcp_network_send_raw_socket(server->fd_raw, &link, packet, len);
241 static int dhcp_server_send_udp(sd_dhcp_server *server, be32_t destination,
242 DHCPMessage *message, size_t len) {
243 union sockaddr_union dest = {
244 .in.sin_family = AF_INET,
245 .in.sin_port = htobe16(DHCP_PORT_CLIENT),
246 .in.sin_addr.s_addr = destination,
252 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))] = {};
253 struct msghdr msg = {
255 .msg_namelen = sizeof(dest.in),
258 .msg_control = cmsgbuf,
259 .msg_controllen = sizeof(cmsgbuf),
261 struct cmsghdr *cmsg;
262 struct in_pktinfo *pktinfo;
266 assert(server->fd > 0);
268 assert(len > sizeof(DHCPMessage));
270 cmsg = CMSG_FIRSTHDR(&msg);
273 cmsg->cmsg_level = IPPROTO_IP;
274 cmsg->cmsg_type = IP_PKTINFO;
275 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
277 /* we attach source interface and address info to the message
278 rather than binding the socket. This will be mostly useful
279 when we gain support for arbitrary number of server addresses
281 pktinfo = (struct in_pktinfo*) CMSG_DATA(cmsg);
284 pktinfo->ipi_ifindex = server->index;
285 pktinfo->ipi_spec_dst.s_addr = server->address;
287 r = sendmsg(server->fd, &msg, 0);
294 static bool requested_broadcast(DHCPRequest *req) {
297 return req->message->flags & htobe16(0x8000);
300 int dhcp_server_send_packet(sd_dhcp_server *server,
301 DHCPRequest *req, DHCPPacket *packet,
302 int type, size_t optoffset) {
303 be32_t destination = INADDR_ANY;
308 assert(req->max_optlen);
309 assert(optoffset <= req->max_optlen);
312 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
313 DHCP_OPTION_SERVER_IDENTIFIER,
314 4, &server->address);
318 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
319 DHCP_OPTION_END, 0, NULL);
323 /* RFC 2131 Section 4.1
325 If the ’giaddr’ field in a DHCP message from a client is non-zero,
326 the server sends any return messages to the ’DHCP server’ port on the
327 BOOTP relay agent whose address appears in ’giaddr’. If the ’giaddr’
328 field is zero and the ’ciaddr’ field is nonzero, then the server
329 unicasts DHCPOFFER and DHCPACK messages to the address in ’ciaddr’.
330 If ’giaddr’ is zero and ’ciaddr’ is zero, and the broadcast bit is
331 set, then the server broadcasts DHCPOFFER and DHCPACK messages to
332 0xffffffff. If the broadcast bit is not set and ’giaddr’ is zero and
333 ’ciaddr’ is zero, then the server unicasts DHCPOFFER and DHCPACK
334 messages to the client’s hardware address and ’yiaddr’ address. In
335 all cases, when ’giaddr’ is zero, the server broadcasts any DHCPNAK
336 messages to 0xffffffff.
340 If ’giaddr’ is set in the DHCPREQUEST message, the client is on a
341 different subnet. The server MUST set the broadcast bit in the
342 DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
343 client, because the client may not have a correct network address
344 or subnet mask, and the client may not be answering ARP requests.
346 if (req->message->giaddr) {
347 destination = req->message->giaddr;
348 if (type == DHCP_NAK)
349 packet->dhcp.flags = htobe16(0x8000);
350 } else if (req->message->ciaddr && type != DHCP_NAK)
351 destination = req->message->ciaddr;
353 if (destination != INADDR_ANY)
354 return dhcp_server_send_udp(server, destination, &packet->dhcp,
355 sizeof(DHCPMessage) + optoffset);
356 else if (requested_broadcast(req) || type == DHCP_NAK)
357 return dhcp_server_send_udp(server, INADDR_BROADCAST, &packet->dhcp,
358 sizeof(DHCPMessage) + optoffset);
360 /* we cannot send UDP packet to specific MAC address when the address is
361 not yet configured, so must fall back to raw packets */
362 return dhcp_server_send_unicast_raw(server, packet,
363 sizeof(DHCPPacket) + optoffset);
366 static int server_message_init(sd_dhcp_server *server, DHCPPacket **ret,
367 uint8_t type, size_t *_optoffset, DHCPRequest *req) {
368 _cleanup_free_ DHCPPacket *packet = NULL;
369 size_t optoffset = 0;
375 assert(IN_SET(type, DHCP_OFFER, DHCP_ACK, DHCP_NAK));
377 packet = malloc0(sizeof(DHCPPacket) + req->max_optlen);
381 r = dhcp_message_init(&packet->dhcp, BOOTREPLY, be32toh(req->message->xid),
382 type, req->max_optlen, &optoffset);
386 packet->dhcp.flags = req->message->flags;
387 packet->dhcp.giaddr = req->message->giaddr;
388 memcpy(&packet->dhcp.chaddr, &req->message->chaddr, ETH_ALEN);
390 *_optoffset = optoffset;
397 static int server_send_offer(sd_dhcp_server *server, DHCPRequest *req, be32_t address) {
398 _cleanup_free_ DHCPPacket *packet = NULL;
403 r = server_message_init(server, &packet, DHCP_OFFER, &offset, req);
407 packet->dhcp.yiaddr = address;
409 lease_time = htobe32(req->lifetime);
410 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
411 DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4, &lease_time);
415 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
416 DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
420 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
421 DHCP_OPTION_ROUTER, 4, &server->address);
425 r = dhcp_server_send_packet(server, req, packet, DHCP_OFFER, offset);
432 static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req, be32_t address) {
433 _cleanup_free_ DHCPPacket *packet = NULL;
438 r = server_message_init(server, &packet, DHCP_ACK, &offset, req);
442 packet->dhcp.yiaddr = address;
444 lease_time = htobe32(req->lifetime);
445 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
446 DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4, &lease_time);
450 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
451 DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
455 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
456 DHCP_OPTION_ROUTER, 4, &server->address);
460 r = dhcp_server_send_packet(server, req, packet, DHCP_ACK, offset);
467 static int server_send_nak(sd_dhcp_server *server, DHCPRequest *req) {
468 _cleanup_free_ DHCPPacket *packet = NULL;
472 r = server_message_init(server, &packet, DHCP_NAK, &offset, req);
476 r = dhcp_server_send_packet(server, req, packet, DHCP_NAK, offset);
483 static int server_send_forcerenew(sd_dhcp_server *server, be32_t address, be32_t gateway,
485 _cleanup_free_ DHCPPacket *packet = NULL;
486 size_t optoffset = 0;
490 assert(address != INADDR_ANY);
493 packet = malloc0(sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE);
497 r = dhcp_message_init(&packet->dhcp, BOOTREPLY, 0,
498 DHCP_FORCERENEW, DHCP_MIN_OPTIONS_SIZE,
503 r = dhcp_option_append(&packet->dhcp, DHCP_MIN_OPTIONS_SIZE,
504 &optoffset, 0, DHCP_OPTION_END, 0, NULL);
508 memcpy(&packet->dhcp.chaddr, chaddr, ETH_ALEN);
510 r = dhcp_server_send_udp(server, address, &packet->dhcp,
511 sizeof(DHCPMessage) + optoffset);
518 static int parse_request(uint8_t code, uint8_t len, const uint8_t *option,
520 DHCPRequest *req = user_data;
525 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
527 req->lifetime = be32toh(*(be32_t*)option);
530 case DHCP_OPTION_REQUESTED_IP_ADDRESS:
532 req->requested_ip = *(be32_t*)option;
535 case DHCP_OPTION_SERVER_IDENTIFIER:
537 req->server_id = *(be32_t*)option;
540 case DHCP_OPTION_CLIENT_IDENTIFIER:
544 data = memdup(option, len);
548 free(req->client_id.data);
549 req->client_id.data = data;
550 req->client_id.length = len;
554 case DHCP_OPTION_MAXIMUM_MESSAGE_SIZE:
556 req->max_optlen = be16toh(*(be16_t*)option) -
557 - sizeof(DHCPPacket);
565 static void dhcp_request_free(DHCPRequest *req) {
569 free(req->client_id.data);
573 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest*, dhcp_request_free);
574 #define _cleanup_dhcp_request_free_ _cleanup_(dhcp_request_freep)
576 static int ensure_sane_request(DHCPRequest *req, DHCPMessage *message) {
580 req->message = message;
582 /* set client id based on mac address if client did not send an explicit one */
583 if (!req->client_id.data) {
586 data = new0(uint8_t, ETH_ALEN + 1);
590 req->client_id.length = ETH_ALEN + 1;
591 req->client_id.data = data;
592 req->client_id.data[0] = 0x01;
593 memcpy(&req->client_id.data[1], &message->chaddr, ETH_ALEN);
596 if (req->max_optlen < DHCP_MIN_OPTIONS_SIZE)
597 req->max_optlen = DHCP_MIN_OPTIONS_SIZE;
600 req->lifetime = DHCP_DEFAULT_LEASE_TIME;
605 static int get_pool_offset(sd_dhcp_server *server, be32_t requested_ip) {
608 if (!server->pool_size)
611 if (be32toh(requested_ip) < be32toh(server->pool_start) ||
612 be32toh(requested_ip) >= be32toh(server->pool_start) +
616 return be32toh(requested_ip) - be32toh(server->pool_start);
619 int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
621 _cleanup_dhcp_request_free_ DHCPRequest *req = NULL;
622 DHCPLease *existing_lease;
628 if (message->op != BOOTREQUEST ||
629 message->htype != ARPHRD_ETHER ||
630 message->hlen != ETHER_ADDR_LEN)
633 req = new0(DHCPRequest, 1);
637 type = dhcp_option_parse(message, length, parse_request, req);
641 r = ensure_sane_request(req, message);
643 /* this only fails on critical errors */
646 existing_lease = hashmap_get(server->leases_by_client_id, &req->client_id);
651 be32_t address = INADDR_ANY;
654 log_dhcp_server(server, "DISCOVER (0x%x)",
655 be32toh(req->message->xid));
657 if (!server->pool_size)
658 /* no pool allocated */
661 /* for now pick a random free address from the pool */
663 address = existing_lease->address;
665 for (i = 0; i < server->pool_size; i++) {
666 if (!server->bound_leases[server->next_offer]) {
667 address = htobe32(be32toh(server->pool_start) + server->next_offer);
670 server->next_offer = (server->next_offer + 1) % server->pool_size;
674 if (address == INADDR_ANY)
675 /* no free addresses left */
678 r = server_send_offer(server, req, address);
680 /* this only fails on critical errors */
681 log_dhcp_server(server, "could not send offer: %s",
685 log_dhcp_server(server, "OFFER (0x%x)",
686 be32toh(req->message->xid));
693 log_dhcp_server(server, "DECLINE (0x%x)",
694 be32toh(req->message->xid));
696 /* TODO: make sure we don't offer this address again */
704 bool init_reboot = false;
707 /* see RFC 2131, section 4.3.2 */
709 if (req->server_id) {
710 log_dhcp_server(server, "REQUEST (selecting) (0x%x)",
711 be32toh(req->message->xid));
714 if (req->server_id != server->address)
715 /* client did not pick us */
718 if (req->message->ciaddr)
719 /* this MUST be zero */
722 if (!req->requested_ip)
723 /* this must be filled in with the yiaddr
724 from the chosen OFFER */
727 address = req->requested_ip;
728 } else if (req->requested_ip) {
729 log_dhcp_server(server, "REQUEST (init-reboot) (0x%x)",
730 be32toh(req->message->xid));
733 if (req->message->ciaddr)
734 /* this MUST be zero */
737 /* TODO: check more carefully if IP is correct */
738 address = req->requested_ip;
741 log_dhcp_server(server, "REQUEST (rebinding/renewing) (0x%x)",
742 be32toh(req->message->xid));
744 /* REBINDING / RENEWING */
745 if (!req->message->ciaddr)
746 /* this MUST be filled in with clients IP address */
749 address = req->message->ciaddr;
752 pool_offset = get_pool_offset(server, address);
754 /* verify that the requested address is from the pool, and either
755 owned by the current client or free */
756 if (pool_offset >= 0 &&
757 server->bound_leases[pool_offset] == existing_lease) {
761 if (!existing_lease) {
762 lease = new0(DHCPLease, 1);
763 lease->address = req->requested_ip;
764 lease->client_id.data = memdup(req->client_id.data,
765 req->client_id.length);
766 if (!lease->client_id.data) {
770 lease->client_id.length = req->client_id.length;
771 memcpy(&lease->chaddr, &req->message->chaddr, ETH_ALEN);
772 lease->gateway = req->message->giaddr;
774 lease = existing_lease;
776 r = sd_event_now(server->event, clock_boottime_or_monotonic(), &time_now);
778 time_now = now(clock_boottime_or_monotonic());
779 lease->expiration = req->lifetime * USEC_PER_SEC + time_now;
781 r = server_send_ack(server, req, address);
783 /* this only fails on critical errors */
784 log_dhcp_server(server, "could not send ack: %s",
788 dhcp_lease_free(lease);
792 log_dhcp_server(server, "ACK (0x%x)",
793 be32toh(req->message->xid));
795 server->bound_leases[pool_offset] = lease;
796 hashmap_put(server->leases_by_client_id, &lease->client_id, lease);
800 } else if (init_reboot) {
801 r = server_send_nak(server, req);
803 /* this only fails on critical errors */
804 log_dhcp_server(server, "could not send nak: %s",
808 log_dhcp_server(server, "NAK (0x%x)",
809 be32toh(req->message->xid));
819 log_dhcp_server(server, "RELEASE (0x%x)",
820 be32toh(req->message->xid));
825 if (existing_lease->address != req->message->ciaddr)
828 pool_offset = get_pool_offset(server, req->message->ciaddr);
832 if (server->bound_leases[pool_offset] == existing_lease) {
833 server->bound_leases[pool_offset] = NULL;
834 hashmap_remove(server->leases_by_client_id, existing_lease);
835 dhcp_lease_free(existing_lease);
846 static int server_receive_message(sd_event_source *s, int fd,
847 uint32_t revents, void *userdata) {
848 _cleanup_free_ DHCPMessage *message = NULL;
849 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))];
850 sd_dhcp_server *server = userdata;
851 struct iovec iov = {};
852 struct msghdr msg = {
855 .msg_control = cmsgbuf,
856 .msg_controllen = sizeof(cmsgbuf),
858 struct cmsghdr *cmsg;
859 int buflen = 0, len, r;
863 r = ioctl(fd, FIONREAD, &buflen);
869 message = malloc0(buflen);
873 iov.iov_base = message;
874 iov.iov_len = buflen;
876 len = recvmsg(fd, &msg, 0);
879 else if ((size_t)len < sizeof(DHCPMessage))
882 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
883 if (cmsg->cmsg_level == IPPROTO_IP &&
884 cmsg->cmsg_type == IP_PKTINFO &&
885 cmsg->cmsg_len == CMSG_LEN(sizeof(struct in_pktinfo))) {
886 struct in_pktinfo *info = (struct in_pktinfo*)CMSG_DATA(cmsg);
888 /* TODO figure out if this can be done as a filter on the socket, like for IPv6 */
889 if (server->index != info->ipi_ifindex)
896 return dhcp_server_handle_message(server, message, (size_t)len);
899 int sd_dhcp_server_start(sd_dhcp_server *server) {
902 assert_return(server, -EINVAL);
903 assert_return(server->event, -EINVAL);
904 assert_return(!server->receive_message, -EBUSY);
905 assert_return(server->fd_raw == -1, -EBUSY);
906 assert_return(server->fd == -1, -EBUSY);
907 assert_return(server->address != htobe32(INADDR_ANY), -EUNATCH);
909 r = socket(AF_PACKET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
912 sd_dhcp_server_stop(server);
917 r = dhcp_network_bind_udp_socket(INADDR_ANY, DHCP_PORT_SERVER);
919 sd_dhcp_server_stop(server);
924 r = sd_event_add_io(server->event, &server->receive_message,
926 server_receive_message, server);
928 sd_dhcp_server_stop(server);
932 r = sd_event_source_set_priority(server->receive_message,
933 server->event_priority);
935 sd_dhcp_server_stop(server);
939 log_dhcp_server(server, "STARTED");
944 int sd_dhcp_server_forcerenew(sd_dhcp_server *server) {
948 assert_return(server, -EINVAL);
949 assert(server->bound_leases);
951 for (i = 0; i < server->pool_size; i++) {
952 DHCPLease *lease = server->bound_leases[i];
957 r = server_send_forcerenew(server, lease->address,
963 log_dhcp_server(server, "FORCERENEW");