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>
25 #include "siphash24.h"
27 #include "sd-dhcp-server.h"
28 #include "dhcp-server-internal.h"
29 #include "dhcp-internal.h"
31 #define DHCP_DEFAULT_LEASE_TIME 3600 /* one hour */
33 int sd_dhcp_server_set_lease_pool(sd_dhcp_server *server,
34 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,
55 unsigned char prefixlen) {
56 assert_return(server, -EINVAL);
57 assert_return(address, -EINVAL);
58 assert_return(address->s_addr, -EINVAL);
59 assert_return(prefixlen <= 32, -ERANGE);
60 assert_return(server->address == htobe32(INADDR_ANY), -EBUSY);
61 assert_return(server->netmask == htobe32(INADDR_ANY), -EBUSY);
63 server->address = address->s_addr;
64 server->netmask = htobe32(0xfffffffflu << (32 - prefixlen));
69 bool sd_dhcp_server_is_running(sd_dhcp_server *server) {
70 assert_return(server, -EINVAL);
72 return !!server->receive_message;
75 sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server) {
77 assert_se(REFCNT_INC(server->n_ref) >= 2);
82 unsigned long client_id_hash_func(const void *p,
83 const uint8_t hash_key[HASH_KEY_SIZE]) {
85 const DHCPClientId *id = p;
91 siphash24((uint8_t*) &u, id->data, id->length, hash_key);
93 return (unsigned long) u;
96 int client_id_compare_func(const void *_a, const void *_b) {
97 const DHCPClientId *a, *b;
102 assert(!a->length || a->data);
103 assert(!b->length || b->data);
105 if (a->length != b->length)
106 return a->length < b->length ? -1 : 1;
108 return memcmp(a->data, b->data, a->length);
111 static const struct hash_ops client_id_hash_ops = {
112 .hash = client_id_hash_func,
113 .compare = client_id_compare_func
116 static void dhcp_lease_free(DHCPLease *lease) {
120 free(lease->client_id.data);
124 sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) {
130 if (REFCNT_DEC(server->n_ref) > 0)
133 log_dhcp_server(server, "UNREF");
135 sd_dhcp_server_stop(server);
137 sd_event_unref(server->event);
139 while ((lease = hashmap_steal_first(server->leases_by_client_id)))
140 dhcp_lease_free(lease);
141 hashmap_free(server->leases_by_client_id);
143 free(server->bound_leases);
149 int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
150 _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL;
152 assert_return(ret, -EINVAL);
153 assert_return(ifindex > 0, -EINVAL);
155 server = new0(sd_dhcp_server, 1);
159 server->n_ref = REFCNT_INIT;
162 server->address = htobe32(INADDR_ANY);
163 server->netmask = htobe32(INADDR_ANY);
164 server->index = ifindex;
165 server->leases_by_client_id = hashmap_new(&client_id_hash_ops);
173 int sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event,
177 assert_return(server, -EINVAL);
178 assert_return(!server->event, -EBUSY);
181 server->event = sd_event_ref(event);
183 r = sd_event_default(&server->event);
188 server->event_priority = priority;
193 int sd_dhcp_server_detach_event(sd_dhcp_server *server) {
194 assert_return(server, -EINVAL);
196 server->event = sd_event_unref(server->event);
201 sd_event *sd_dhcp_server_get_event(sd_dhcp_server *server) {
202 assert_return(server, NULL);
204 return server->event;
207 int sd_dhcp_server_stop(sd_dhcp_server *server) {
208 assert_return(server, -EINVAL);
210 server->receive_message =
211 sd_event_source_unref(server->receive_message);
213 server->fd_raw = safe_close(server->fd_raw);
214 server->fd = safe_close(server->fd);
216 log_dhcp_server(server, "STOPPED");
221 static int dhcp_server_send_unicast_raw(sd_dhcp_server *server,
222 DHCPPacket *packet, size_t len) {
223 union sockaddr_union link = {
224 .ll.sll_family = AF_PACKET,
225 .ll.sll_protocol = htons(ETH_P_IP),
226 .ll.sll_ifindex = server->index,
227 .ll.sll_halen = ETH_ALEN,
232 assert(server->index > 0);
233 assert(server->address);
235 assert(len > sizeof(DHCPPacket));
237 memcpy(&link.ll.sll_addr, &packet->dhcp.chaddr, ETH_ALEN);
239 dhcp_packet_append_ip_headers(packet, server->address, DHCP_PORT_SERVER,
241 DHCP_PORT_CLIENT, len);
243 r = dhcp_network_send_raw_socket(server->fd_raw, &link, packet, len);
250 static int dhcp_server_send_udp(sd_dhcp_server *server, be32_t destination,
251 DHCPMessage *message, size_t len) {
252 union sockaddr_union dest = {
253 .in.sin_family = AF_INET,
254 .in.sin_port = htobe16(DHCP_PORT_CLIENT),
255 .in.sin_addr.s_addr = destination,
261 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))] = {};
262 struct msghdr msg = {
264 .msg_namelen = sizeof(dest.in),
267 .msg_control = cmsgbuf,
268 .msg_controllen = sizeof(cmsgbuf),
270 struct cmsghdr *cmsg;
271 struct in_pktinfo *pktinfo;
275 assert(server->fd > 0);
277 assert(len > sizeof(DHCPMessage));
279 cmsg = CMSG_FIRSTHDR(&msg);
282 cmsg->cmsg_level = IPPROTO_IP;
283 cmsg->cmsg_type = IP_PKTINFO;
284 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
286 /* we attach source interface and address info to the message
287 rather than binding the socket. This will be mostly useful
288 when we gain support for arbitrary number of server addresses
290 pktinfo = (struct in_pktinfo*) CMSG_DATA(cmsg);
293 pktinfo->ipi_ifindex = server->index;
294 pktinfo->ipi_spec_dst.s_addr = server->address;
296 r = sendmsg(server->fd, &msg, 0);
303 static bool requested_broadcast(DHCPRequest *req) {
306 return req->message->flags & htobe16(0x8000);
309 int dhcp_server_send_packet(sd_dhcp_server *server,
310 DHCPRequest *req, DHCPPacket *packet,
311 int type, size_t optoffset) {
312 be32_t destination = INADDR_ANY;
317 assert(req->max_optlen);
318 assert(optoffset <= req->max_optlen);
321 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
322 DHCP_OPTION_SERVER_IDENTIFIER,
323 4, &server->address);
327 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
328 DHCP_OPTION_END, 0, NULL);
332 /* RFC 2131 Section 4.1
334 If the ’giaddr’ field in a DHCP message from a client is non-zero,
335 the server sends any return messages to the ’DHCP server’ port on the
336 BOOTP relay agent whose address appears in ’giaddr’. If the ’giaddr’
337 field is zero and the ’ciaddr’ field is nonzero, then the server
338 unicasts DHCPOFFER and DHCPACK messages to the address in ’ciaddr’.
339 If ’giaddr’ is zero and ’ciaddr’ is zero, and the broadcast bit is
340 set, then the server broadcasts DHCPOFFER and DHCPACK messages to
341 0xffffffff. If the broadcast bit is not set and ’giaddr’ is zero and
342 ’ciaddr’ is zero, then the server unicasts DHCPOFFER and DHCPACK
343 messages to the client’s hardware address and ’yiaddr’ address. In
344 all cases, when ’giaddr’ is zero, the server broadcasts any DHCPNAK
345 messages to 0xffffffff.
349 If ’giaddr’ is set in the DHCPREQUEST message, the client is on a
350 different subnet. The server MUST set the broadcast bit in the
351 DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
352 client, because the client may not have a correct network address
353 or subnet mask, and the client may not be answering ARP requests.
355 if (req->message->giaddr) {
356 destination = req->message->giaddr;
357 if (type == DHCP_NAK)
358 packet->dhcp.flags = htobe16(0x8000);
359 } else if (req->message->ciaddr && type != DHCP_NAK)
360 destination = req->message->ciaddr;
362 if (destination != INADDR_ANY)
363 return dhcp_server_send_udp(server, destination, &packet->dhcp,
364 sizeof(DHCPMessage) + optoffset);
365 else if (requested_broadcast(req) || type == DHCP_NAK)
366 return dhcp_server_send_udp(server, INADDR_BROADCAST,
368 sizeof(DHCPMessage) + optoffset);
370 /* we cannot send UDP packet to specific MAC address when the
371 address is not yet configured, so must fall back to raw
373 return dhcp_server_send_unicast_raw(server, packet,
374 sizeof(DHCPPacket) + optoffset);
377 static int server_message_init(sd_dhcp_server *server, DHCPPacket **ret,
378 uint8_t type, size_t *_optoffset,
380 _cleanup_free_ DHCPPacket *packet = NULL;
381 size_t optoffset = 0;
387 assert(IN_SET(type, DHCP_OFFER, DHCP_ACK, DHCP_NAK));
389 packet = malloc0(sizeof(DHCPPacket) + req->max_optlen);
393 r = dhcp_message_init(&packet->dhcp, BOOTREPLY,
394 be32toh(req->message->xid), type, ARPHRD_ETHER,
395 req->max_optlen, &optoffset);
399 packet->dhcp.flags = req->message->flags;
400 packet->dhcp.giaddr = req->message->giaddr;
401 memcpy(&packet->dhcp.chaddr, &req->message->chaddr, ETH_ALEN);
403 *_optoffset = optoffset;
410 static int server_send_offer(sd_dhcp_server *server, DHCPRequest *req,
412 _cleanup_free_ DHCPPacket *packet = NULL;
417 r = server_message_init(server, &packet, DHCP_OFFER, &offset, req);
421 packet->dhcp.yiaddr = address;
423 lease_time = htobe32(req->lifetime);
424 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
425 DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4,
430 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
431 DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
435 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
436 DHCP_OPTION_ROUTER, 4, &server->address);
440 r = dhcp_server_send_packet(server, req, packet, DHCP_OFFER, offset);
447 static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req,
449 _cleanup_free_ DHCPPacket *packet = NULL;
454 r = server_message_init(server, &packet, DHCP_ACK, &offset, req);
458 packet->dhcp.yiaddr = address;
460 lease_time = htobe32(req->lifetime);
461 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
462 DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4,
467 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
468 DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
472 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
473 DHCP_OPTION_ROUTER, 4, &server->address);
477 r = dhcp_server_send_packet(server, req, packet, DHCP_ACK, offset);
484 static int server_send_nak(sd_dhcp_server *server, DHCPRequest *req) {
485 _cleanup_free_ DHCPPacket *packet = NULL;
489 r = server_message_init(server, &packet, DHCP_NAK, &offset, req);
493 r = dhcp_server_send_packet(server, req, packet, DHCP_NAK, offset);
500 static int server_send_forcerenew(sd_dhcp_server *server, be32_t address,
501 be32_t gateway, uint8_t chaddr[]) {
502 _cleanup_free_ DHCPPacket *packet = NULL;
503 size_t optoffset = 0;
507 assert(address != INADDR_ANY);
510 packet = malloc0(sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE);
514 r = dhcp_message_init(&packet->dhcp, BOOTREPLY, 0,
515 DHCP_FORCERENEW, ARPHRD_ETHER,
516 DHCP_MIN_OPTIONS_SIZE, &optoffset);
520 r = dhcp_option_append(&packet->dhcp, DHCP_MIN_OPTIONS_SIZE,
521 &optoffset, 0, DHCP_OPTION_END, 0, NULL);
525 memcpy(&packet->dhcp.chaddr, chaddr, ETH_ALEN);
527 r = dhcp_server_send_udp(server, address, &packet->dhcp,
528 sizeof(DHCPMessage) + optoffset);
535 static int parse_request(uint8_t code, uint8_t len, const uint8_t *option,
537 DHCPRequest *req = user_data;
542 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
544 req->lifetime = be32toh(*(be32_t*)option);
547 case DHCP_OPTION_REQUESTED_IP_ADDRESS:
549 req->requested_ip = *(be32_t*)option;
552 case DHCP_OPTION_SERVER_IDENTIFIER:
554 req->server_id = *(be32_t*)option;
557 case DHCP_OPTION_CLIENT_IDENTIFIER:
561 data = memdup(option, len);
565 free(req->client_id.data);
566 req->client_id.data = data;
567 req->client_id.length = len;
571 case DHCP_OPTION_MAXIMUM_MESSAGE_SIZE:
573 req->max_optlen = be16toh(*(be16_t*)option) -
574 - sizeof(DHCPPacket);
582 static void dhcp_request_free(DHCPRequest *req) {
586 free(req->client_id.data);
590 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest*, dhcp_request_free);
591 #define _cleanup_dhcp_request_free_ _cleanup_(dhcp_request_freep)
593 static int ensure_sane_request(DHCPRequest *req, DHCPMessage *message) {
597 req->message = message;
599 /* set client id based on MAC address if client did not send an explicit
601 if (!req->client_id.data) {
604 data = new0(uint8_t, ETH_ALEN + 1);
608 req->client_id.length = ETH_ALEN + 1;
609 req->client_id.data = data;
610 req->client_id.data[0] = 0x01;
611 memcpy(&req->client_id.data[1], &message->chaddr, ETH_ALEN);
614 if (req->max_optlen < DHCP_MIN_OPTIONS_SIZE)
615 req->max_optlen = DHCP_MIN_OPTIONS_SIZE;
618 req->lifetime = DHCP_DEFAULT_LEASE_TIME;
623 static int get_pool_offset(sd_dhcp_server *server, be32_t requested_ip) {
626 if (!server->pool_size)
629 if (be32toh(requested_ip) < be32toh(server->pool_start) ||
630 be32toh(requested_ip) >= be32toh(server->pool_start) +
634 return be32toh(requested_ip) - be32toh(server->pool_start);
637 int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
639 _cleanup_dhcp_request_free_ DHCPRequest *req = NULL;
640 DHCPLease *existing_lease;
646 if (message->op != BOOTREQUEST ||
647 message->htype != ARPHRD_ETHER ||
648 message->hlen != ETHER_ADDR_LEN)
651 req = new0(DHCPRequest, 1);
655 type = dhcp_option_parse(message, length, parse_request, req);
659 r = ensure_sane_request(req, message);
661 /* this only fails on critical errors */
664 existing_lease = hashmap_get(server->leases_by_client_id,
670 be32_t address = INADDR_ANY;
673 log_dhcp_server(server, "DISCOVER (0x%x)",
674 be32toh(req->message->xid));
676 if (!server->pool_size)
677 /* no pool allocated */
680 /* for now pick a random free address from the pool */
682 address = existing_lease->address;
684 for (i = 0; i < server->pool_size; i++) {
685 if (!server->bound_leases[server->next_offer]) {
686 address = htobe32(be32toh(server->pool_start) + server->next_offer);
689 server->next_offer = (server->next_offer + 1) % server->pool_size;
693 if (address == INADDR_ANY)
694 /* no free addresses left */
697 r = server_send_offer(server, req, address);
699 /* this only fails on critical errors */
700 log_dhcp_server(server, "could not send offer: %s",
704 log_dhcp_server(server, "OFFER (0x%x)",
705 be32toh(req->message->xid));
712 log_dhcp_server(server, "DECLINE (0x%x)",
713 be32toh(req->message->xid));
715 /* TODO: make sure we don't offer this address again */
723 bool init_reboot = false;
726 /* see RFC 2131, section 4.3.2 */
728 if (req->server_id) {
729 log_dhcp_server(server, "REQUEST (selecting) (0x%x)",
730 be32toh(req->message->xid));
733 if (req->server_id != server->address)
734 /* client did not pick us */
737 if (req->message->ciaddr)
738 /* this MUST be zero */
741 if (!req->requested_ip)
742 /* this must be filled in with the yiaddr
743 from the chosen OFFER */
746 address = req->requested_ip;
747 } else if (req->requested_ip) {
748 log_dhcp_server(server, "REQUEST (init-reboot) (0x%x)",
749 be32toh(req->message->xid));
752 if (req->message->ciaddr)
753 /* this MUST be zero */
756 /* TODO: check more carefully if IP is correct */
757 address = req->requested_ip;
760 log_dhcp_server(server, "REQUEST (rebinding/renewing) (0x%x)",
761 be32toh(req->message->xid));
763 /* REBINDING / RENEWING */
764 if (!req->message->ciaddr)
765 /* this MUST be filled in with clients IP address */
768 address = req->message->ciaddr;
771 pool_offset = get_pool_offset(server, address);
773 /* verify that the requested address is from the pool, and either
774 owned by the current client or free */
775 if (pool_offset >= 0 &&
776 server->bound_leases[pool_offset] == existing_lease) {
780 if (!existing_lease) {
781 lease = new0(DHCPLease, 1);
782 lease->address = req->requested_ip;
783 lease->client_id.data = memdup(req->client_id.data,
784 req->client_id.length);
785 if (!lease->client_id.data) {
789 lease->client_id.length = req->client_id.length;
790 memcpy(&lease->chaddr, &req->message->chaddr,
792 lease->gateway = req->message->giaddr;
794 lease = existing_lease;
796 r = sd_event_now(server->event,
797 clock_boottime_or_monotonic(),
800 time_now = now(clock_boottime_or_monotonic());
801 lease->expiration = req->lifetime * USEC_PER_SEC + time_now;
803 r = server_send_ack(server, req, address);
805 /* this only fails on critical errors */
806 log_dhcp_server(server, "could not send ack: %s",
810 dhcp_lease_free(lease);
814 log_dhcp_server(server, "ACK (0x%x)",
815 be32toh(req->message->xid));
817 server->bound_leases[pool_offset] = lease;
818 hashmap_put(server->leases_by_client_id,
819 &lease->client_id, lease);
823 } else if (init_reboot) {
824 r = server_send_nak(server, req);
826 /* this only fails on critical errors */
827 log_dhcp_server(server, "could not send nak: %s",
831 log_dhcp_server(server, "NAK (0x%x)",
832 be32toh(req->message->xid));
842 log_dhcp_server(server, "RELEASE (0x%x)",
843 be32toh(req->message->xid));
848 if (existing_lease->address != req->message->ciaddr)
851 pool_offset = get_pool_offset(server, req->message->ciaddr);
855 if (server->bound_leases[pool_offset] == existing_lease) {
856 server->bound_leases[pool_offset] = NULL;
857 hashmap_remove(server->leases_by_client_id, existing_lease);
858 dhcp_lease_free(existing_lease);
869 static int server_receive_message(sd_event_source *s, int fd,
870 uint32_t revents, void *userdata) {
871 _cleanup_free_ DHCPMessage *message = NULL;
872 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))];
873 sd_dhcp_server *server = userdata;
874 struct iovec iov = {};
875 struct msghdr msg = {
878 .msg_control = cmsgbuf,
879 .msg_controllen = sizeof(cmsgbuf),
881 struct cmsghdr *cmsg;
882 int buflen = 0, len, r;
886 r = ioctl(fd, FIONREAD, &buflen);
892 message = malloc0(buflen);
896 iov.iov_base = message;
897 iov.iov_len = buflen;
899 len = recvmsg(fd, &msg, 0);
902 else if ((size_t)len < sizeof(DHCPMessage))
905 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
906 if (cmsg->cmsg_level == IPPROTO_IP &&
907 cmsg->cmsg_type == IP_PKTINFO &&
908 cmsg->cmsg_len == CMSG_LEN(sizeof(struct in_pktinfo))) {
909 struct in_pktinfo *info = (struct in_pktinfo*)CMSG_DATA(cmsg);
911 /* TODO figure out if this can be done as a filter on
912 * the socket, like for IPv6 */
913 if (server->index != info->ipi_ifindex)
920 return dhcp_server_handle_message(server, message, (size_t)len);
923 int sd_dhcp_server_start(sd_dhcp_server *server) {
926 assert_return(server, -EINVAL);
927 assert_return(server->event, -EINVAL);
928 assert_return(!server->receive_message, -EBUSY);
929 assert_return(server->fd_raw == -1, -EBUSY);
930 assert_return(server->fd == -1, -EBUSY);
931 assert_return(server->address != htobe32(INADDR_ANY), -EUNATCH);
933 r = socket(AF_PACKET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
936 sd_dhcp_server_stop(server);
941 r = dhcp_network_bind_udp_socket(INADDR_ANY, DHCP_PORT_SERVER);
943 sd_dhcp_server_stop(server);
948 r = sd_event_add_io(server->event, &server->receive_message,
950 server_receive_message, server);
952 sd_dhcp_server_stop(server);
956 r = sd_event_source_set_priority(server->receive_message,
957 server->event_priority);
959 sd_dhcp_server_stop(server);
963 log_dhcp_server(server, "STARTED");
968 int sd_dhcp_server_forcerenew(sd_dhcp_server *server) {
972 assert_return(server, -EINVAL);
973 assert(server->bound_leases);
975 for (i = 0; i < server->pool_size; i++) {
976 DHCPLease *lease = server->bound_leases[i];
981 r = server_send_forcerenew(server, lease->address,
987 log_dhcp_server(server, "FORCERENEW");