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,
35 struct in_addr *address,
37 assert_return(server, -EINVAL);
38 assert_return(address, -EINVAL);
39 assert_return(address->s_addr, -EINVAL);
40 assert_return(size, -EINVAL);
41 assert_return(server->pool_start == htobe32(INADDR_ANY), -EBUSY);
42 assert_return(!server->pool_size, -EBUSY);
43 assert_return(!server->bound_leases, -EBUSY);
45 server->bound_leases = new0(DHCPLease*, size);
46 if (!server->bound_leases)
49 server->pool_start = address->s_addr;
50 server->pool_size = size;
55 int sd_dhcp_server_set_address(sd_dhcp_server *server, struct in_addr *address,
56 unsigned char prefixlen) {
57 assert_return(server, -EINVAL);
58 assert_return(address, -EINVAL);
59 assert_return(address->s_addr, -EINVAL);
60 assert_return(prefixlen <= 32, -ERANGE);
61 assert_return(server->address == htobe32(INADDR_ANY), -EBUSY);
62 assert_return(server->netmask == htobe32(INADDR_ANY), -EBUSY);
64 server->address = address->s_addr;
65 server->netmask = htobe32(0xfffffffflu << (32 - prefixlen));
70 bool sd_dhcp_server_is_running(sd_dhcp_server *server) {
71 assert_return(server, -EINVAL);
73 return !!server->receive_message;
76 sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server) {
78 assert_se(REFCNT_INC(server->n_ref) >= 2);
83 unsigned long client_id_hash_func(const void *p,
84 const uint8_t hash_key[HASH_KEY_SIZE]) {
86 const DHCPClientId *id = p;
92 siphash24((uint8_t*) &u, id->data, id->length, hash_key);
94 return (unsigned long) u;
97 int client_id_compare_func(const void *_a, const void *_b) {
98 const DHCPClientId *a, *b;
103 assert(!a->length || a->data);
104 assert(!b->length || b->data);
106 if (a->length != b->length)
107 return a->length < b->length ? -1 : 1;
109 return memcmp(a->data, b->data, a->length);
112 static const struct hash_ops client_id_hash_ops = {
113 .hash = client_id_hash_func,
114 .compare = client_id_compare_func
117 static void dhcp_lease_free(DHCPLease *lease) {
121 free(lease->client_id.data);
125 sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) {
131 if (REFCNT_DEC(server->n_ref) > 0)
134 log_dhcp_server(server, "UNREF");
136 sd_dhcp_server_stop(server);
138 sd_event_unref(server->event);
140 while ((lease = hashmap_steal_first(server->leases_by_client_id)))
141 dhcp_lease_free(lease);
142 hashmap_free(server->leases_by_client_id);
144 free(server->bound_leases);
150 int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
151 _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL;
153 assert_return(ret, -EINVAL);
154 assert_return(ifindex > 0, -EINVAL);
156 server = new0(sd_dhcp_server, 1);
160 server->n_ref = REFCNT_INIT;
163 server->address = htobe32(INADDR_ANY);
164 server->netmask = htobe32(INADDR_ANY);
165 server->index = ifindex;
166 server->leases_by_client_id = hashmap_new(&client_id_hash_ops);
174 int sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event,
178 assert_return(server, -EINVAL);
179 assert_return(!server->event, -EBUSY);
182 server->event = sd_event_ref(event);
184 r = sd_event_default(&server->event);
189 server->event_priority = priority;
194 int sd_dhcp_server_detach_event(sd_dhcp_server *server) {
195 assert_return(server, -EINVAL);
197 server->event = sd_event_unref(server->event);
202 sd_event *sd_dhcp_server_get_event(sd_dhcp_server *server) {
203 assert_return(server, NULL);
205 return server->event;
208 int sd_dhcp_server_stop(sd_dhcp_server *server) {
209 assert_return(server, -EINVAL);
211 server->receive_message =
212 sd_event_source_unref(server->receive_message);
214 server->fd_raw = safe_close(server->fd_raw);
215 server->fd = safe_close(server->fd);
217 log_dhcp_server(server, "STOPPED");
222 static int dhcp_server_send_unicast_raw(sd_dhcp_server *server,
223 DHCPPacket *packet, size_t len) {
224 union sockaddr_union link = {
225 .ll.sll_family = AF_PACKET,
226 .ll.sll_protocol = htons(ETH_P_IP),
227 .ll.sll_ifindex = server->index,
228 .ll.sll_halen = ETH_ALEN,
233 assert(server->index > 0);
234 assert(server->address);
236 assert(len > sizeof(DHCPPacket));
238 memcpy(&link.ll.sll_addr, &packet->dhcp.chaddr, ETH_ALEN);
240 dhcp_packet_append_ip_headers(packet, server->address, DHCP_PORT_SERVER,
242 DHCP_PORT_CLIENT, len);
244 r = dhcp_network_send_raw_socket(server->fd_raw, &link, packet, len);
251 static int dhcp_server_send_udp(sd_dhcp_server *server, be32_t destination,
252 DHCPMessage *message, size_t len) {
253 union sockaddr_union dest = {
254 .in.sin_family = AF_INET,
255 .in.sin_port = htobe16(DHCP_PORT_CLIENT),
256 .in.sin_addr.s_addr = destination,
262 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))] = {};
263 struct msghdr msg = {
265 .msg_namelen = sizeof(dest.in),
268 .msg_control = cmsgbuf,
269 .msg_controllen = sizeof(cmsgbuf),
271 struct cmsghdr *cmsg;
272 struct in_pktinfo *pktinfo;
276 assert(server->fd > 0);
278 assert(len > sizeof(DHCPMessage));
280 cmsg = CMSG_FIRSTHDR(&msg);
283 cmsg->cmsg_level = IPPROTO_IP;
284 cmsg->cmsg_type = IP_PKTINFO;
285 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
287 /* we attach source interface and address info to the message
288 rather than binding the socket. This will be mostly useful
289 when we gain support for arbitrary number of server addresses
291 pktinfo = (struct in_pktinfo*) CMSG_DATA(cmsg);
294 pktinfo->ipi_ifindex = server->index;
295 pktinfo->ipi_spec_dst.s_addr = server->address;
297 r = sendmsg(server->fd, &msg, 0);
304 static bool requested_broadcast(DHCPRequest *req) {
307 return req->message->flags & htobe16(0x8000);
310 int dhcp_server_send_packet(sd_dhcp_server *server,
311 DHCPRequest *req, DHCPPacket *packet,
312 int type, size_t optoffset) {
313 be32_t destination = INADDR_ANY;
318 assert(req->max_optlen);
319 assert(optoffset <= req->max_optlen);
322 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
323 DHCP_OPTION_SERVER_IDENTIFIER,
324 4, &server->address);
328 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
329 DHCP_OPTION_END, 0, NULL);
333 /* RFC 2131 Section 4.1
335 If the ’giaddr’ field in a DHCP message from a client is non-zero,
336 the server sends any return messages to the ’DHCP server’ port on the
337 BOOTP relay agent whose address appears in ’giaddr’. If the ’giaddr’
338 field is zero and the ’ciaddr’ field is nonzero, then the server
339 unicasts DHCPOFFER and DHCPACK messages to the address in ’ciaddr’.
340 If ’giaddr’ is zero and ’ciaddr’ is zero, and the broadcast bit is
341 set, then the server broadcasts DHCPOFFER and DHCPACK messages to
342 0xffffffff. If the broadcast bit is not set and ’giaddr’ is zero and
343 ’ciaddr’ is zero, then the server unicasts DHCPOFFER and DHCPACK
344 messages to the client’s hardware address and ’yiaddr’ address. In
345 all cases, when ’giaddr’ is zero, the server broadcasts any DHCPNAK
346 messages to 0xffffffff.
350 If ’giaddr’ is set in the DHCPREQUEST message, the client is on a
351 different subnet. The server MUST set the broadcast bit in the
352 DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
353 client, because the client may not have a correct network address
354 or subnet mask, and the client may not be answering ARP requests.
356 if (req->message->giaddr) {
357 destination = req->message->giaddr;
358 if (type == DHCP_NAK)
359 packet->dhcp.flags = htobe16(0x8000);
360 } else if (req->message->ciaddr && type != DHCP_NAK)
361 destination = req->message->ciaddr;
363 if (destination != INADDR_ANY)
364 return dhcp_server_send_udp(server, destination, &packet->dhcp,
365 sizeof(DHCPMessage) + optoffset);
366 else if (requested_broadcast(req) || type == DHCP_NAK)
367 return dhcp_server_send_udp(server, INADDR_BROADCAST,
369 sizeof(DHCPMessage) + optoffset);
371 /* we cannot send UDP packet to specific MAC address when the
372 address is not yet configured, so must fall back to raw
374 return dhcp_server_send_unicast_raw(server, packet,
375 sizeof(DHCPPacket) + optoffset);
378 static int server_message_init(sd_dhcp_server *server, DHCPPacket **ret,
379 uint8_t type, size_t *_optoffset,
381 _cleanup_free_ DHCPPacket *packet = NULL;
382 size_t optoffset = 0;
388 assert(IN_SET(type, DHCP_OFFER, DHCP_ACK, DHCP_NAK));
390 packet = malloc0(sizeof(DHCPPacket) + req->max_optlen);
394 r = dhcp_message_init(&packet->dhcp, BOOTREPLY,
395 be32toh(req->message->xid), type, ARPHRD_ETHER,
396 req->max_optlen, &optoffset);
400 packet->dhcp.flags = req->message->flags;
401 packet->dhcp.giaddr = req->message->giaddr;
402 memcpy(&packet->dhcp.chaddr, &req->message->chaddr, ETH_ALEN);
404 *_optoffset = optoffset;
411 static int server_send_offer(sd_dhcp_server *server, DHCPRequest *req,
413 _cleanup_free_ DHCPPacket *packet = NULL;
418 r = server_message_init(server, &packet, DHCP_OFFER, &offset, req);
422 packet->dhcp.yiaddr = address;
424 lease_time = htobe32(req->lifetime);
425 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
426 DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4,
431 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
432 DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
436 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
437 DHCP_OPTION_ROUTER, 4, &server->address);
441 r = dhcp_server_send_packet(server, req, packet, DHCP_OFFER, offset);
448 static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req,
450 _cleanup_free_ DHCPPacket *packet = NULL;
455 r = server_message_init(server, &packet, DHCP_ACK, &offset, req);
459 packet->dhcp.yiaddr = address;
461 lease_time = htobe32(req->lifetime);
462 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
463 DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4,
468 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
469 DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
473 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
474 DHCP_OPTION_ROUTER, 4, &server->address);
478 r = dhcp_server_send_packet(server, req, packet, DHCP_ACK, offset);
485 static int server_send_nak(sd_dhcp_server *server, DHCPRequest *req) {
486 _cleanup_free_ DHCPPacket *packet = NULL;
490 r = server_message_init(server, &packet, DHCP_NAK, &offset, req);
494 r = dhcp_server_send_packet(server, req, packet, DHCP_NAK, offset);
501 static int server_send_forcerenew(sd_dhcp_server *server, be32_t address,
502 be32_t gateway, uint8_t chaddr[]) {
503 _cleanup_free_ DHCPPacket *packet = NULL;
504 size_t optoffset = 0;
508 assert(address != INADDR_ANY);
511 packet = malloc0(sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE);
515 r = dhcp_message_init(&packet->dhcp, BOOTREPLY, 0,
516 DHCP_FORCERENEW, ARPHRD_ETHER,
517 DHCP_MIN_OPTIONS_SIZE, &optoffset);
521 r = dhcp_option_append(&packet->dhcp, DHCP_MIN_OPTIONS_SIZE,
522 &optoffset, 0, DHCP_OPTION_END, 0, NULL);
526 memcpy(&packet->dhcp.chaddr, chaddr, ETH_ALEN);
528 r = dhcp_server_send_udp(server, address, &packet->dhcp,
529 sizeof(DHCPMessage) + optoffset);
536 static int parse_request(uint8_t code, uint8_t len, const uint8_t *option,
538 DHCPRequest *req = user_data;
543 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
545 req->lifetime = be32toh(*(be32_t*)option);
548 case DHCP_OPTION_REQUESTED_IP_ADDRESS:
550 req->requested_ip = *(be32_t*)option;
553 case DHCP_OPTION_SERVER_IDENTIFIER:
555 req->server_id = *(be32_t*)option;
558 case DHCP_OPTION_CLIENT_IDENTIFIER:
562 data = memdup(option, len);
566 free(req->client_id.data);
567 req->client_id.data = data;
568 req->client_id.length = len;
572 case DHCP_OPTION_MAXIMUM_MESSAGE_SIZE:
574 req->max_optlen = be16toh(*(be16_t*)option) -
575 - sizeof(DHCPPacket);
583 static void dhcp_request_free(DHCPRequest *req) {
587 free(req->client_id.data);
591 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest*, dhcp_request_free);
592 #define _cleanup_dhcp_request_free_ _cleanup_(dhcp_request_freep)
594 static int ensure_sane_request(DHCPRequest *req, DHCPMessage *message) {
598 req->message = message;
600 /* set client id based on mac address if client did not send an explicit
602 if (!req->client_id.data) {
605 data = new0(uint8_t, ETH_ALEN + 1);
609 req->client_id.length = ETH_ALEN + 1;
610 req->client_id.data = data;
611 req->client_id.data[0] = 0x01;
612 memcpy(&req->client_id.data[1], &message->chaddr, ETH_ALEN);
615 if (req->max_optlen < DHCP_MIN_OPTIONS_SIZE)
616 req->max_optlen = DHCP_MIN_OPTIONS_SIZE;
619 req->lifetime = DHCP_DEFAULT_LEASE_TIME;
624 static int get_pool_offset(sd_dhcp_server *server, be32_t requested_ip) {
627 if (!server->pool_size)
630 if (be32toh(requested_ip) < be32toh(server->pool_start) ||
631 be32toh(requested_ip) >= be32toh(server->pool_start) +
635 return be32toh(requested_ip) - be32toh(server->pool_start);
638 int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
640 _cleanup_dhcp_request_free_ DHCPRequest *req = NULL;
641 DHCPLease *existing_lease;
647 if (message->op != BOOTREQUEST ||
648 message->htype != ARPHRD_ETHER ||
649 message->hlen != ETHER_ADDR_LEN)
652 req = new0(DHCPRequest, 1);
656 type = dhcp_option_parse(message, length, parse_request, req);
660 r = ensure_sane_request(req, message);
662 /* this only fails on critical errors */
665 existing_lease = hashmap_get(server->leases_by_client_id,
671 be32_t address = INADDR_ANY;
674 log_dhcp_server(server, "DISCOVER (0x%x)",
675 be32toh(req->message->xid));
677 if (!server->pool_size)
678 /* no pool allocated */
681 /* for now pick a random free address from the pool */
683 address = existing_lease->address;
685 for (i = 0; i < server->pool_size; i++) {
686 if (!server->bound_leases[server->next_offer]) {
687 address = htobe32(be32toh(server->pool_start) + server->next_offer);
690 server->next_offer = (server->next_offer + 1) % server->pool_size;
694 if (address == INADDR_ANY)
695 /* no free addresses left */
698 r = server_send_offer(server, req, address);
700 /* this only fails on critical errors */
701 log_dhcp_server(server, "could not send offer: %s",
705 log_dhcp_server(server, "OFFER (0x%x)",
706 be32toh(req->message->xid));
713 log_dhcp_server(server, "DECLINE (0x%x)",
714 be32toh(req->message->xid));
716 /* TODO: make sure we don't offer this address again */
724 bool init_reboot = false;
727 /* see RFC 2131, section 4.3.2 */
729 if (req->server_id) {
730 log_dhcp_server(server, "REQUEST (selecting) (0x%x)",
731 be32toh(req->message->xid));
734 if (req->server_id != server->address)
735 /* client did not pick us */
738 if (req->message->ciaddr)
739 /* this MUST be zero */
742 if (!req->requested_ip)
743 /* this must be filled in with the yiaddr
744 from the chosen OFFER */
747 address = req->requested_ip;
748 } else if (req->requested_ip) {
749 log_dhcp_server(server, "REQUEST (init-reboot) (0x%x)",
750 be32toh(req->message->xid));
753 if (req->message->ciaddr)
754 /* this MUST be zero */
757 /* TODO: check more carefully if IP is correct */
758 address = req->requested_ip;
761 log_dhcp_server(server, "REQUEST (rebinding/renewing) (0x%x)",
762 be32toh(req->message->xid));
764 /* REBINDING / RENEWING */
765 if (!req->message->ciaddr)
766 /* this MUST be filled in with clients IP address */
769 address = req->message->ciaddr;
772 pool_offset = get_pool_offset(server, address);
774 /* verify that the requested address is from the pool, and either
775 owned by the current client or free */
776 if (pool_offset >= 0 &&
777 server->bound_leases[pool_offset] == existing_lease) {
781 if (!existing_lease) {
782 lease = new0(DHCPLease, 1);
783 lease->address = req->requested_ip;
784 lease->client_id.data = memdup(req->client_id.data,
785 req->client_id.length);
786 if (!lease->client_id.data) {
790 lease->client_id.length = req->client_id.length;
791 memcpy(&lease->chaddr, &req->message->chaddr,
793 lease->gateway = req->message->giaddr;
795 lease = existing_lease;
797 r = sd_event_now(server->event,
798 clock_boottime_or_monotonic(),
801 time_now = now(clock_boottime_or_monotonic());
802 lease->expiration = req->lifetime * USEC_PER_SEC + time_now;
804 r = server_send_ack(server, req, address);
806 /* this only fails on critical errors */
807 log_dhcp_server(server, "could not send ack: %s",
811 dhcp_lease_free(lease);
815 log_dhcp_server(server, "ACK (0x%x)",
816 be32toh(req->message->xid));
818 server->bound_leases[pool_offset] = lease;
819 hashmap_put(server->leases_by_client_id,
820 &lease->client_id, lease);
824 } else if (init_reboot) {
825 r = server_send_nak(server, req);
827 /* this only fails on critical errors */
828 log_dhcp_server(server, "could not send nak: %s",
832 log_dhcp_server(server, "NAK (0x%x)",
833 be32toh(req->message->xid));
843 log_dhcp_server(server, "RELEASE (0x%x)",
844 be32toh(req->message->xid));
849 if (existing_lease->address != req->message->ciaddr)
852 pool_offset = get_pool_offset(server, req->message->ciaddr);
856 if (server->bound_leases[pool_offset] == existing_lease) {
857 server->bound_leases[pool_offset] = NULL;
858 hashmap_remove(server->leases_by_client_id, existing_lease);
859 dhcp_lease_free(existing_lease);
870 static int server_receive_message(sd_event_source *s, int fd,
871 uint32_t revents, void *userdata) {
872 _cleanup_free_ DHCPMessage *message = NULL;
873 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))];
874 sd_dhcp_server *server = userdata;
875 struct iovec iov = {};
876 struct msghdr msg = {
879 .msg_control = cmsgbuf,
880 .msg_controllen = sizeof(cmsgbuf),
882 struct cmsghdr *cmsg;
883 int buflen = 0, len, r;
887 r = ioctl(fd, FIONREAD, &buflen);
893 message = malloc0(buflen);
897 iov.iov_base = message;
898 iov.iov_len = buflen;
900 len = recvmsg(fd, &msg, 0);
903 else if ((size_t)len < sizeof(DHCPMessage))
906 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
907 if (cmsg->cmsg_level == IPPROTO_IP &&
908 cmsg->cmsg_type == IP_PKTINFO &&
909 cmsg->cmsg_len == CMSG_LEN(sizeof(struct in_pktinfo))) {
910 struct in_pktinfo *info = (struct in_pktinfo*)CMSG_DATA(cmsg);
912 /* TODO figure out if this can be done as a filter on
913 * the socket, like for IPv6 */
914 if (server->index != info->ipi_ifindex)
921 return dhcp_server_handle_message(server, message, (size_t)len);
924 int sd_dhcp_server_start(sd_dhcp_server *server) {
927 assert_return(server, -EINVAL);
928 assert_return(server->event, -EINVAL);
929 assert_return(!server->receive_message, -EBUSY);
930 assert_return(server->fd_raw == -1, -EBUSY);
931 assert_return(server->fd == -1, -EBUSY);
932 assert_return(server->address != htobe32(INADDR_ANY), -EUNATCH);
934 r = socket(AF_PACKET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
937 sd_dhcp_server_stop(server);
942 r = dhcp_network_bind_udp_socket(INADDR_ANY, DHCP_PORT_SERVER);
944 sd_dhcp_server_stop(server);
949 r = sd_event_add_io(server->event, &server->receive_message,
951 server_receive_message, server);
953 sd_dhcp_server_stop(server);
957 r = sd_event_source_set_priority(server->receive_message,
958 server->event_priority);
960 sd_dhcp_server_stop(server);
964 log_dhcp_server(server, "STARTED");
969 int sd_dhcp_server_forcerenew(sd_dhcp_server *server) {
973 assert_return(server, -EINVAL);
974 assert(server->bound_leases);
976 for (i = 0; i < server->pool_size; i++) {
977 DHCPLease *lease = server->bound_leases[i];
982 r = server_send_forcerenew(server, lease->address,
988 log_dhcp_server(server, "FORCERENEW");