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);
492 static int parse_request(uint8_t code, uint8_t len, const uint8_t *option,
494 DHCPRequest *req = user_data;
499 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
501 req->lifetime = be32toh(*(be32_t*)option);
504 case DHCP_OPTION_REQUESTED_IP_ADDRESS:
506 req->requested_ip = *(be32_t*)option;
509 case DHCP_OPTION_SERVER_IDENTIFIER:
511 req->server_id = *(be32_t*)option;
514 case DHCP_OPTION_CLIENT_IDENTIFIER:
518 data = memdup(option, len);
522 free(req->client_id.data);
523 req->client_id.data = data;
524 req->client_id.length = len;
528 case DHCP_OPTION_MAXIMUM_MESSAGE_SIZE:
530 req->max_optlen = be16toh(*(be16_t*)option) -
531 - sizeof(DHCPPacket);
539 static void dhcp_request_free(DHCPRequest *req) {
543 free(req->client_id.data);
547 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest*, dhcp_request_free);
548 #define _cleanup_dhcp_request_free_ _cleanup_(dhcp_request_freep)
550 static int ensure_sane_request(DHCPRequest *req, DHCPMessage *message) {
554 req->message = message;
556 /* set client id based on mac address if client did not send an explicit one */
557 if (!req->client_id.data) {
560 data = new0(uint8_t, ETH_ALEN + 1);
564 req->client_id.length = ETH_ALEN + 1;
565 req->client_id.data = data;
566 req->client_id.data[0] = 0x01;
567 memcpy(&req->client_id.data[1], &message->chaddr, ETH_ALEN);
570 if (req->max_optlen < DHCP_MIN_OPTIONS_SIZE)
571 req->max_optlen = DHCP_MIN_OPTIONS_SIZE;
574 req->lifetime = DHCP_DEFAULT_LEASE_TIME;
579 static int get_pool_offset(sd_dhcp_server *server, be32_t requested_ip) {
582 if (!server->pool_size)
585 if (be32toh(requested_ip) < be32toh(server->pool_start) ||
586 be32toh(requested_ip) >= be32toh(server->pool_start) +
590 return be32toh(requested_ip) - be32toh(server->pool_start);
593 int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
595 _cleanup_dhcp_request_free_ DHCPRequest *req = NULL;
596 DHCPLease *existing_lease;
602 if (message->op != BOOTREQUEST ||
603 message->htype != ARPHRD_ETHER ||
604 message->hlen != ETHER_ADDR_LEN)
607 req = new0(DHCPRequest, 1);
611 type = dhcp_option_parse(message, length, parse_request, req);
615 r = ensure_sane_request(req, message);
617 /* this only fails on critical errors */
620 existing_lease = hashmap_get(server->leases_by_client_id, &req->client_id);
625 be32_t address = INADDR_ANY;
628 log_dhcp_server(server, "DISCOVER (0x%x)",
629 be32toh(req->message->xid));
631 if (!server->pool_size)
632 /* no pool allocated */
635 /* for now pick a random free address from the pool */
637 address = existing_lease->address;
639 for (i = 0; i < server->pool_size; i++) {
640 if (!server->bound_leases[server->next_offer]) {
641 address = htobe32(be32toh(server->pool_start) + server->next_offer);
644 server->next_offer = (server->next_offer + 1) % server->pool_size;
648 if (address == INADDR_ANY)
649 /* no free addresses left */
652 r = server_send_offer(server, req, address);
654 /* this only fails on critical errors */
655 log_dhcp_server(server, "could not send offer: %s",
659 log_dhcp_server(server, "OFFER (0x%x)",
660 be32toh(req->message->xid));
667 log_dhcp_server(server, "DECLINE (0x%x)",
668 be32toh(req->message->xid));
670 /* TODO: make sure we don't offer this address again */
678 bool init_reboot = false;
681 /* see RFC 2131, section 4.3.2 */
683 if (req->server_id) {
684 log_dhcp_server(server, "REQUEST (selecting) (0x%x)",
685 be32toh(req->message->xid));
688 if (req->server_id != server->address)
689 /* client did not pick us */
692 if (req->message->ciaddr)
693 /* this MUST be zero */
696 if (!req->requested_ip)
697 /* this must be filled in with the yiaddr
698 from the chosen OFFER */
701 address = req->requested_ip;
702 } else if (req->requested_ip) {
703 log_dhcp_server(server, "REQUEST (init-reboot) (0x%x)",
704 be32toh(req->message->xid));
707 if (req->message->ciaddr)
708 /* this MUST be zero */
711 /* TODO: check more carefully if IP is correct */
712 address = req->requested_ip;
715 log_dhcp_server(server, "REQUEST (rebinding/renewing) (0x%x)",
716 be32toh(req->message->xid));
718 /* REBINDING / RENEWING */
719 if (!req->message->ciaddr)
720 /* this MUST be filled in with clients IP address */
723 address = req->message->ciaddr;
726 pool_offset = get_pool_offset(server, address);
728 /* verify that the requested address is from the pool, and either
729 owned by the current client or free */
730 if (pool_offset >= 0 &&
731 server->bound_leases[pool_offset] == existing_lease) {
735 if (!existing_lease) {
736 lease = new0(DHCPLease, 1);
737 lease->address = req->requested_ip;
738 lease->client_id.data = memdup(req->client_id.data,
739 req->client_id.length);
740 if (!lease->client_id.data) {
744 lease->client_id.length = req->client_id.length;
745 memcpy(&lease->chaddr, &req->message->chaddr, ETH_ALEN);
746 lease->gateway = req->message->giaddr;
748 lease = existing_lease;
750 r = sd_event_now(server->event, clock_boottime_or_monotonic(), &time_now);
752 time_now = now(clock_boottime_or_monotonic());
753 lease->expiration = req->lifetime * USEC_PER_SEC + time_now;
755 r = server_send_ack(server, req, address);
757 /* this only fails on critical errors */
758 log_dhcp_server(server, "could not send ack: %s",
762 dhcp_lease_free(lease);
766 log_dhcp_server(server, "ACK (0x%x)",
767 be32toh(req->message->xid));
769 server->bound_leases[pool_offset] = lease;
770 hashmap_put(server->leases_by_client_id, &lease->client_id, lease);
774 } else if (init_reboot) {
775 r = server_send_nak(server, req);
777 /* this only fails on critical errors */
778 log_dhcp_server(server, "could not send nak: %s",
782 log_dhcp_server(server, "NAK (0x%x)",
783 be32toh(req->message->xid));
793 log_dhcp_server(server, "RELEASE (0x%x)",
794 be32toh(req->message->xid));
799 if (existing_lease->address != req->message->ciaddr)
802 pool_offset = get_pool_offset(server, req->message->ciaddr);
806 if (server->bound_leases[pool_offset] == existing_lease) {
807 server->bound_leases[pool_offset] = NULL;
808 hashmap_remove(server->leases_by_client_id, existing_lease);
809 dhcp_lease_free(existing_lease);
820 static int server_receive_message(sd_event_source *s, int fd,
821 uint32_t revents, void *userdata) {
822 _cleanup_free_ DHCPMessage *message = NULL;
823 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))];
824 sd_dhcp_server *server = userdata;
825 struct iovec iov = {};
826 struct msghdr msg = {
829 .msg_control = cmsgbuf,
830 .msg_controllen = sizeof(cmsgbuf),
832 struct cmsghdr *cmsg;
833 int buflen = 0, len, r;
837 r = ioctl(fd, FIONREAD, &buflen);
843 message = malloc0(buflen);
847 iov.iov_base = message;
848 iov.iov_len = buflen;
850 len = recvmsg(fd, &msg, 0);
853 else if ((size_t)len < sizeof(DHCPMessage))
856 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
857 if (cmsg->cmsg_level == IPPROTO_IP &&
858 cmsg->cmsg_type == IP_PKTINFO &&
859 cmsg->cmsg_len == CMSG_LEN(sizeof(struct in_pktinfo))) {
860 struct in_pktinfo *info = (struct in_pktinfo*)CMSG_DATA(cmsg);
862 /* TODO figure out if this can be done as a filter on the socket, like for IPv6 */
863 if (server->index != info->ipi_ifindex)
870 return dhcp_server_handle_message(server, message, (size_t)len);
873 int sd_dhcp_server_start(sd_dhcp_server *server) {
876 assert_return(server, -EINVAL);
877 assert_return(server->event, -EINVAL);
878 assert_return(!server->receive_message, -EBUSY);
879 assert_return(server->fd_raw == -1, -EBUSY);
880 assert_return(server->fd == -1, -EBUSY);
881 assert_return(server->address != htobe32(INADDR_ANY), -EUNATCH);
883 r = socket(AF_PACKET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
886 sd_dhcp_server_stop(server);
891 r = dhcp_network_bind_udp_socket(INADDR_ANY, DHCP_PORT_SERVER);
893 sd_dhcp_server_stop(server);
898 r = sd_event_add_io(server->event, &server->receive_message,
900 server_receive_message, server);
902 sd_dhcp_server_stop(server);
906 r = sd_event_source_set_priority(server->receive_message,
907 server->event_priority);
909 sd_dhcp_server_stop(server);
913 log_dhcp_server(server, "STARTED");
918 int sd_dhcp_server_forcerenew(sd_dhcp_server *server) {
922 assert_return(server, -EINVAL);
923 assert(server->bound_leases);
925 for (i = 0; i < server->pool_size; i++) {
926 DHCPLease *lease = server->bound_leases[i];
931 r = server_send_forcerenew(server, lease->address,
937 log_dhcp_server(server, "FORCERENEW");