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) {
55 assert_return(server, -EINVAL);
56 assert_return(address, -EINVAL);
57 assert_return(address->s_addr, -EINVAL);
58 assert_return(server->address == htobe32(INADDR_ANY), -EBUSY);
60 server->address = address->s_addr;
65 bool sd_dhcp_server_is_running(sd_dhcp_server *server) {
66 assert_return(server, -EINVAL);
68 return !!server->receive_message;
71 sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server) {
73 assert_se(REFCNT_INC(server->n_ref) >= 2);
78 unsigned long client_id_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
80 const DHCPClientId *id = p;
86 siphash24((uint8_t*) &u, id->data, id->length, hash_key);
88 return (unsigned long) u;
91 int client_id_compare_func(const void *_a, const void *_b) {
92 const DHCPClientId *a, *b;
97 assert(!a->length || a->data);
98 assert(!b->length || b->data);
100 if (a->length != b->length)
101 return a->length < b->length ? -1 : 1;
103 return memcmp(a->data, b->data, a->length);
106 static void dhcp_lease_free(DHCPLease *lease) {
110 free(lease->client_id.data);
114 sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) {
120 if (REFCNT_DEC(server->n_ref) > 0)
123 log_dhcp_server(server, "UNREF");
125 sd_dhcp_server_stop(server);
127 sd_event_unref(server->event);
129 while ((lease = hashmap_steal_first(server->leases_by_client_id)))
130 dhcp_lease_free(lease);
131 hashmap_free(server->leases_by_client_id);
133 free(server->bound_leases);
139 int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
140 _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL;
142 assert_return(ret, -EINVAL);
143 assert_return(ifindex > 0, -EINVAL);
145 server = new0(sd_dhcp_server, 1);
149 server->n_ref = REFCNT_INIT;
152 server->address = htobe32(INADDR_ANY);
153 server->index = ifindex;
154 server->leases_by_client_id = hashmap_new(client_id_hash_func, client_id_compare_func);
162 int sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event, int priority) {
165 assert_return(server, -EINVAL);
166 assert_return(!server->event, -EBUSY);
169 server->event = sd_event_ref(event);
171 r = sd_event_default(&server->event);
176 server->event_priority = priority;
181 int sd_dhcp_server_detach_event(sd_dhcp_server *server) {
182 assert_return(server, -EINVAL);
184 server->event = sd_event_unref(server->event);
189 sd_event *sd_dhcp_server_get_event(sd_dhcp_server *server) {
190 assert_return(server, NULL);
192 return server->event;
195 int sd_dhcp_server_stop(sd_dhcp_server *server) {
196 assert_return(server, -EINVAL);
198 server->receive_message =
199 sd_event_source_unref(server->receive_message);
201 server->fd_raw = safe_close(server->fd_raw);
202 server->fd = safe_close(server->fd);
204 log_dhcp_server(server, "STOPPED");
209 static int dhcp_server_send_unicast_raw(sd_dhcp_server *server, DHCPPacket *packet,
211 union sockaddr_union link = {
212 .ll.sll_family = AF_PACKET,
213 .ll.sll_protocol = htons(ETH_P_IP),
214 .ll.sll_ifindex = server->index,
215 .ll.sll_halen = ETH_ALEN,
220 assert(server->index > 0);
221 assert(server->address);
223 assert(len > sizeof(DHCPPacket));
225 memcpy(&link.ll.sll_addr, &packet->dhcp.chaddr, ETH_ALEN);
227 dhcp_packet_append_ip_headers(packet, server->address, DHCP_PORT_SERVER,
228 packet->dhcp.yiaddr, DHCP_PORT_CLIENT, len);
230 r = dhcp_network_send_raw_socket(server->fd_raw, &link, packet, len);
237 static int dhcp_server_send_udp(sd_dhcp_server *server, be32_t destination,
238 DHCPMessage *message, size_t len) {
239 union sockaddr_union dest = {
240 .in.sin_family = AF_INET,
241 .in.sin_port = htobe16(DHCP_PORT_CLIENT),
242 .in.sin_addr.s_addr = destination,
248 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))] = {};
249 struct msghdr msg = {
251 .msg_namelen = sizeof(dest.in),
254 .msg_control = cmsgbuf,
255 .msg_controllen = sizeof(cmsgbuf),
257 struct cmsghdr *cmsg;
258 struct in_pktinfo *pktinfo;
262 assert(server->fd > 0);
264 assert(len > sizeof(DHCPMessage));
266 cmsg = CMSG_FIRSTHDR(&msg);
269 cmsg->cmsg_level = IPPROTO_IP;
270 cmsg->cmsg_type = IP_PKTINFO;
271 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
273 /* we attach source interface and address info to the message
274 rather than binding the socket. This will be mostly useful
275 when we gain support for arbitrary number of server addresses
277 pktinfo = (struct in_pktinfo*) CMSG_DATA(cmsg);
280 pktinfo->ipi_ifindex = server->index;
281 pktinfo->ipi_spec_dst.s_addr = server->address;
283 r = sendmsg(server->fd, &msg, 0);
290 static bool requested_broadcast(DHCPRequest *req) {
293 return req->message->flags & htobe16(0x8000);
296 int dhcp_server_send_packet(sd_dhcp_server *server,
297 DHCPRequest *req, DHCPPacket *packet,
298 int type, size_t optoffset) {
299 be32_t destination = INADDR_ANY;
304 assert(req->max_optlen);
305 assert(optoffset <= req->max_optlen);
308 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
309 DHCP_OPTION_SERVER_IDENTIFIER,
310 4, &server->address);
314 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
315 DHCP_OPTION_END, 0, NULL);
319 /* RFC 2131 Section 4.1
321 If the ’giaddr’ field in a DHCP message from a client is non-zero,
322 the server sends any return messages to the ’DHCP server’ port on the
323 BOOTP relay agent whose address appears in ’giaddr’. If the ’giaddr’
324 field is zero and the ’ciaddr’ field is nonzero, then the server
325 unicasts DHCPOFFER and DHCPACK messages to the address in ’ciaddr’.
326 If ’giaddr’ is zero and ’ciaddr’ is zero, and the broadcast bit is
327 set, then the server broadcasts DHCPOFFER and DHCPACK messages to
328 0xffffffff. If the broadcast bit is not set and ’giaddr’ is zero and
329 ’ciaddr’ is zero, then the server unicasts DHCPOFFER and DHCPACK
330 messages to the client’s hardware address and ’yiaddr’ address. In
331 all cases, when ’giaddr’ is zero, the server broadcasts any DHCPNAK
332 messages to 0xffffffff.
336 If ’giaddr’ is set in the DHCPREQUEST message, the client is on a
337 different subnet. The server MUST set the broadcast bit in the
338 DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
339 client, because the client may not have a correct network address
340 or subnet mask, and the client may not be answering ARP requests.
342 if (req->message->giaddr) {
343 destination = req->message->giaddr;
344 if (type == DHCP_NAK)
345 packet->dhcp.flags = htobe16(0x8000);
346 } else if (req->message->ciaddr && type != DHCP_NAK)
347 destination = req->message->ciaddr;
349 if (destination != INADDR_ANY)
350 return dhcp_server_send_udp(server, destination, &packet->dhcp,
351 sizeof(DHCPMessage) + optoffset);
352 else if (requested_broadcast(req) || type == DHCP_NAK)
353 return dhcp_server_send_udp(server, INADDR_BROADCAST, &packet->dhcp,
354 sizeof(DHCPMessage) + optoffset);
356 /* we cannot send UDP packet to specific MAC address when the address is
357 not yet configured, so must fall back to raw packets */
358 return dhcp_server_send_unicast_raw(server, packet,
359 sizeof(DHCPPacket) + optoffset);
362 static int server_message_init(sd_dhcp_server *server, DHCPPacket **ret,
363 uint8_t type, size_t *_optoffset, DHCPRequest *req) {
364 _cleanup_free_ DHCPPacket *packet = NULL;
365 size_t optoffset = 0;
371 assert(IN_SET(type, DHCP_OFFER, DHCP_ACK, DHCP_NAK));
373 packet = malloc0(sizeof(DHCPPacket) + req->max_optlen);
377 r = dhcp_message_init(&packet->dhcp, BOOTREPLY, be32toh(req->message->xid),
378 type, req->max_optlen, &optoffset);
382 packet->dhcp.flags = req->message->flags;
383 packet->dhcp.giaddr = req->message->giaddr;
384 memcpy(&packet->dhcp.chaddr, &req->message->chaddr, ETH_ALEN);
386 *_optoffset = optoffset;
393 static int server_send_offer(sd_dhcp_server *server, DHCPRequest *req, be32_t address) {
394 _cleanup_free_ DHCPPacket *packet = NULL;
399 r = server_message_init(server, &packet, DHCP_OFFER, &offset, req);
403 packet->dhcp.yiaddr = address;
405 lease_time = htobe32(req->lifetime);
406 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
407 DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4, &lease_time);
411 r = dhcp_server_send_packet(server, req, packet, DHCP_OFFER, offset);
418 static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req, be32_t address) {
419 _cleanup_free_ DHCPPacket *packet = NULL;
424 r = server_message_init(server, &packet, DHCP_ACK, &offset, req);
428 packet->dhcp.yiaddr = address;
430 lease_time = htobe32(req->lifetime);
431 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
432 DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4, &lease_time);
436 r = dhcp_server_send_packet(server, req, packet, DHCP_ACK, offset);
443 static int server_send_nak(sd_dhcp_server *server, DHCPRequest *req) {
444 _cleanup_free_ DHCPPacket *packet = NULL;
448 r = server_message_init(server, &packet, DHCP_NAK, &offset, req);
452 r = dhcp_server_send_packet(server, req, packet, DHCP_NAK, offset);
459 static int server_send_forcerenew(sd_dhcp_server *server, be32_t address, be32_t gateway,
461 _cleanup_free_ DHCPPacket *packet = NULL;
462 size_t optoffset = 0;
466 assert(address != INADDR_ANY);
469 packet = malloc0(sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE);
473 r = dhcp_message_init(&packet->dhcp, BOOTREPLY, 0,
474 DHCP_FORCERENEW, DHCP_MIN_OPTIONS_SIZE,
479 r = dhcp_option_append(&packet->dhcp, DHCP_MIN_OPTIONS_SIZE,
480 &optoffset, 0, DHCP_OPTION_END, 0, NULL);
484 memcpy(&packet->dhcp.chaddr, chaddr, ETH_ALEN);
486 r = dhcp_server_send_udp(server, address, &packet->dhcp,
487 sizeof(DHCPMessage) + optoffset);
494 static int parse_request(uint8_t code, uint8_t len, const uint8_t *option,
496 DHCPRequest *req = user_data;
501 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
503 req->lifetime = be32toh(*(be32_t*)option);
506 case DHCP_OPTION_REQUESTED_IP_ADDRESS:
508 req->requested_ip = *(be32_t*)option;
511 case DHCP_OPTION_SERVER_IDENTIFIER:
513 req->server_id = *(be32_t*)option;
516 case DHCP_OPTION_CLIENT_IDENTIFIER:
520 data = memdup(option, len);
524 free(req->client_id.data);
525 req->client_id.data = data;
526 req->client_id.length = len;
530 case DHCP_OPTION_MAXIMUM_MESSAGE_SIZE:
532 req->max_optlen = be16toh(*(be16_t*)option) -
533 - sizeof(DHCPPacket);
541 static void dhcp_request_free(DHCPRequest *req) {
545 free(req->client_id.data);
549 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest*, dhcp_request_free);
550 #define _cleanup_dhcp_request_free_ _cleanup_(dhcp_request_freep)
552 static int ensure_sane_request(DHCPRequest *req, DHCPMessage *message) {
556 req->message = message;
558 /* set client id based on mac address if client did not send an explicit one */
559 if (!req->client_id.data) {
562 data = new0(uint8_t, ETH_ALEN + 1);
566 req->client_id.length = ETH_ALEN + 1;
567 req->client_id.data = data;
568 req->client_id.data[0] = 0x01;
569 memcpy(&req->client_id.data[1], &message->chaddr, ETH_ALEN);
572 if (req->max_optlen < DHCP_MIN_OPTIONS_SIZE)
573 req->max_optlen = DHCP_MIN_OPTIONS_SIZE;
576 req->lifetime = DHCP_DEFAULT_LEASE_TIME;
581 static int get_pool_offset(sd_dhcp_server *server, be32_t requested_ip) {
584 if (!server->pool_size)
587 if (be32toh(requested_ip) < be32toh(server->pool_start) ||
588 be32toh(requested_ip) >= be32toh(server->pool_start) +
592 return be32toh(requested_ip) - be32toh(server->pool_start);
595 int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
597 _cleanup_dhcp_request_free_ DHCPRequest *req = NULL;
598 DHCPLease *existing_lease;
604 if (message->op != BOOTREQUEST ||
605 message->htype != ARPHRD_ETHER ||
606 message->hlen != ETHER_ADDR_LEN)
609 req = new0(DHCPRequest, 1);
613 type = dhcp_option_parse(message, length, parse_request, req);
617 r = ensure_sane_request(req, message);
619 /* this only fails on critical errors */
622 existing_lease = hashmap_get(server->leases_by_client_id, &req->client_id);
627 be32_t address = INADDR_ANY;
630 log_dhcp_server(server, "DISCOVER (0x%x)",
631 be32toh(req->message->xid));
633 if (!server->pool_size)
634 /* no pool allocated */
637 /* for now pick a random free address from the pool */
639 address = existing_lease->address;
641 for (i = 0; i < server->pool_size; i++) {
642 if (!server->bound_leases[server->next_offer]) {
643 address = htobe32(be32toh(server->pool_start) + server->next_offer);
646 server->next_offer = (server->next_offer + 1) % server->pool_size;
650 if (address == INADDR_ANY)
651 /* no free addresses left */
654 r = server_send_offer(server, req, address);
656 /* this only fails on critical errors */
657 log_dhcp_server(server, "could not send offer: %s",
661 log_dhcp_server(server, "OFFER (0x%x)",
662 be32toh(req->message->xid));
669 log_dhcp_server(server, "DECLINE (0x%x)",
670 be32toh(req->message->xid));
672 /* TODO: make sure we don't offer this address again */
680 bool init_reboot = false;
683 /* see RFC 2131, section 4.3.2 */
685 if (req->server_id) {
686 log_dhcp_server(server, "REQUEST (selecting) (0x%x)",
687 be32toh(req->message->xid));
690 if (req->server_id != server->address)
691 /* client did not pick us */
694 if (req->message->ciaddr)
695 /* this MUST be zero */
698 if (!req->requested_ip)
699 /* this must be filled in with the yiaddr
700 from the chosen OFFER */
703 address = req->requested_ip;
704 } else if (req->requested_ip) {
705 log_dhcp_server(server, "REQUEST (init-reboot) (0x%x)",
706 be32toh(req->message->xid));
709 if (req->message->ciaddr)
710 /* this MUST be zero */
713 /* TODO: check more carefully if IP is correct */
714 address = req->requested_ip;
717 log_dhcp_server(server, "REQUEST (rebinding/renewing) (0x%x)",
718 be32toh(req->message->xid));
720 /* REBINDING / RENEWING */
721 if (!req->message->ciaddr)
722 /* this MUST be filled in with clients IP address */
725 address = req->message->ciaddr;
728 pool_offset = get_pool_offset(server, address);
730 /* verify that the requested address is from the pool, and either
731 owned by the current client or free */
732 if (pool_offset >= 0 &&
733 server->bound_leases[pool_offset] == existing_lease) {
737 if (!existing_lease) {
738 lease = new0(DHCPLease, 1);
739 lease->address = req->requested_ip;
740 lease->client_id.data = memdup(req->client_id.data,
741 req->client_id.length);
742 if (!lease->client_id.data) {
746 lease->client_id.length = req->client_id.length;
747 memcpy(&lease->chaddr, &req->message->chaddr, ETH_ALEN);
748 lease->gateway = req->message->giaddr;
750 lease = existing_lease;
752 r = sd_event_now(server->event, clock_boottime_or_monotonic(), &time_now);
754 time_now = now(clock_boottime_or_monotonic());
755 lease->expiration = req->lifetime * USEC_PER_SEC + time_now;
757 r = server_send_ack(server, req, address);
759 /* this only fails on critical errors */
760 log_dhcp_server(server, "could not send ack: %s",
764 dhcp_lease_free(lease);
768 log_dhcp_server(server, "ACK (0x%x)",
769 be32toh(req->message->xid));
771 server->bound_leases[pool_offset] = lease;
772 hashmap_put(server->leases_by_client_id, &lease->client_id, lease);
776 } else if (init_reboot) {
777 r = server_send_nak(server, req);
779 /* this only fails on critical errors */
780 log_dhcp_server(server, "could not send nak: %s",
784 log_dhcp_server(server, "NAK (0x%x)",
785 be32toh(req->message->xid));
795 log_dhcp_server(server, "RELEASE (0x%x)",
796 be32toh(req->message->xid));
801 if (existing_lease->address != req->message->ciaddr)
804 pool_offset = get_pool_offset(server, req->message->ciaddr);
808 if (server->bound_leases[pool_offset] == existing_lease) {
809 server->bound_leases[pool_offset] = NULL;
810 hashmap_remove(server->leases_by_client_id, existing_lease);
811 dhcp_lease_free(existing_lease);
822 static int server_receive_message(sd_event_source *s, int fd,
823 uint32_t revents, void *userdata) {
824 _cleanup_free_ DHCPMessage *message = NULL;
825 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))];
826 sd_dhcp_server *server = userdata;
827 struct iovec iov = {};
828 struct msghdr msg = {
831 .msg_control = cmsgbuf,
832 .msg_controllen = sizeof(cmsgbuf),
834 struct cmsghdr *cmsg;
835 int buflen = 0, len, r;
839 r = ioctl(fd, FIONREAD, &buflen);
845 message = malloc0(buflen);
849 iov.iov_base = message;
850 iov.iov_len = buflen;
852 len = recvmsg(fd, &msg, 0);
855 else if ((size_t)len < sizeof(DHCPMessage))
858 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
859 if (cmsg->cmsg_level == IPPROTO_IP &&
860 cmsg->cmsg_type == IP_PKTINFO &&
861 cmsg->cmsg_len == CMSG_LEN(sizeof(struct in_pktinfo))) {
862 struct in_pktinfo *info = (struct in_pktinfo*)CMSG_DATA(cmsg);
864 /* TODO figure out if this can be done as a filter on the socket, like for IPv6 */
865 if (server->index != info->ipi_ifindex)
872 return dhcp_server_handle_message(server, message, (size_t)len);
875 int sd_dhcp_server_start(sd_dhcp_server *server) {
878 assert_return(server, -EINVAL);
879 assert_return(server->event, -EINVAL);
880 assert_return(!server->receive_message, -EBUSY);
881 assert_return(server->fd_raw == -1, -EBUSY);
882 assert_return(server->fd == -1, -EBUSY);
883 assert_return(server->address != htobe32(INADDR_ANY), -EUNATCH);
885 r = socket(AF_PACKET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
888 sd_dhcp_server_stop(server);
893 r = dhcp_network_bind_udp_socket(INADDR_ANY, DHCP_PORT_SERVER);
895 sd_dhcp_server_stop(server);
900 r = sd_event_add_io(server->event, &server->receive_message,
902 server_receive_message, server);
904 sd_dhcp_server_stop(server);
908 r = sd_event_source_set_priority(server->receive_message,
909 server->event_priority);
911 sd_dhcp_server_stop(server);
915 log_dhcp_server(server, "STARTED");
920 int sd_dhcp_server_forcerenew(sd_dhcp_server *server) {
924 assert_return(server, -EINVAL);
925 assert(server->bound_leases);
927 for (i = 0; i < server->pool_size; i++) {
928 DHCPLease *lease = server->bound_leases[i];
933 r = server_send_forcerenew(server, lease->address,
939 log_dhcp_server(server, "FORCERENEW");