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 void dhcp_lease_free(DHCPLease *lease) {
116 free(lease->client_id.data);
120 sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) {
126 if (REFCNT_DEC(server->n_ref) > 0)
129 log_dhcp_server(server, "UNREF");
131 sd_dhcp_server_stop(server);
133 sd_event_unref(server->event);
135 while ((lease = hashmap_steal_first(server->leases_by_client_id)))
136 dhcp_lease_free(lease);
137 hashmap_free(server->leases_by_client_id);
139 free(server->bound_leases);
145 int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
146 _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL;
148 assert_return(ret, -EINVAL);
149 assert_return(ifindex > 0, -EINVAL);
151 server = new0(sd_dhcp_server, 1);
155 server->n_ref = REFCNT_INIT;
158 server->address = htobe32(INADDR_ANY);
159 server->netmask = htobe32(INADDR_ANY);
160 server->index = ifindex;
161 server->leases_by_client_id = hashmap_new(client_id_hash_func,
162 client_id_compare_func);
170 int sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event,
174 assert_return(server, -EINVAL);
175 assert_return(!server->event, -EBUSY);
178 server->event = sd_event_ref(event);
180 r = sd_event_default(&server->event);
185 server->event_priority = priority;
190 int sd_dhcp_server_detach_event(sd_dhcp_server *server) {
191 assert_return(server, -EINVAL);
193 server->event = sd_event_unref(server->event);
198 sd_event *sd_dhcp_server_get_event(sd_dhcp_server *server) {
199 assert_return(server, NULL);
201 return server->event;
204 int sd_dhcp_server_stop(sd_dhcp_server *server) {
205 assert_return(server, -EINVAL);
207 server->receive_message =
208 sd_event_source_unref(server->receive_message);
210 server->fd_raw = safe_close(server->fd_raw);
211 server->fd = safe_close(server->fd);
213 log_dhcp_server(server, "STOPPED");
218 static int dhcp_server_send_unicast_raw(sd_dhcp_server *server,
219 DHCPPacket *packet, size_t len) {
220 union sockaddr_union link = {
221 .ll.sll_family = AF_PACKET,
222 .ll.sll_protocol = htons(ETH_P_IP),
223 .ll.sll_ifindex = server->index,
224 .ll.sll_halen = ETH_ALEN,
229 assert(server->index > 0);
230 assert(server->address);
232 assert(len > sizeof(DHCPPacket));
234 memcpy(&link.ll.sll_addr, &packet->dhcp.chaddr, ETH_ALEN);
236 dhcp_packet_append_ip_headers(packet, server->address, DHCP_PORT_SERVER,
238 DHCP_PORT_CLIENT, len);
240 r = dhcp_network_send_raw_socket(server->fd_raw, &link, packet, len);
247 static int dhcp_server_send_udp(sd_dhcp_server *server, be32_t destination,
248 DHCPMessage *message, size_t len) {
249 union sockaddr_union dest = {
250 .in.sin_family = AF_INET,
251 .in.sin_port = htobe16(DHCP_PORT_CLIENT),
252 .in.sin_addr.s_addr = destination,
258 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))] = {};
259 struct msghdr msg = {
261 .msg_namelen = sizeof(dest.in),
264 .msg_control = cmsgbuf,
265 .msg_controllen = sizeof(cmsgbuf),
267 struct cmsghdr *cmsg;
268 struct in_pktinfo *pktinfo;
272 assert(server->fd > 0);
274 assert(len > sizeof(DHCPMessage));
276 cmsg = CMSG_FIRSTHDR(&msg);
279 cmsg->cmsg_level = IPPROTO_IP;
280 cmsg->cmsg_type = IP_PKTINFO;
281 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
283 /* we attach source interface and address info to the message
284 rather than binding the socket. This will be mostly useful
285 when we gain support for arbitrary number of server addresses
287 pktinfo = (struct in_pktinfo*) CMSG_DATA(cmsg);
290 pktinfo->ipi_ifindex = server->index;
291 pktinfo->ipi_spec_dst.s_addr = server->address;
293 r = sendmsg(server->fd, &msg, 0);
300 static bool requested_broadcast(DHCPRequest *req) {
303 return req->message->flags & htobe16(0x8000);
306 int dhcp_server_send_packet(sd_dhcp_server *server,
307 DHCPRequest *req, DHCPPacket *packet,
308 int type, size_t optoffset) {
309 be32_t destination = INADDR_ANY;
314 assert(req->max_optlen);
315 assert(optoffset <= req->max_optlen);
318 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
319 DHCP_OPTION_SERVER_IDENTIFIER,
320 4, &server->address);
324 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
325 DHCP_OPTION_END, 0, NULL);
329 /* RFC 2131 Section 4.1
331 If the ’giaddr’ field in a DHCP message from a client is non-zero,
332 the server sends any return messages to the ’DHCP server’ port on the
333 BOOTP relay agent whose address appears in ’giaddr’. If the ’giaddr’
334 field is zero and the ’ciaddr’ field is nonzero, then the server
335 unicasts DHCPOFFER and DHCPACK messages to the address in ’ciaddr’.
336 If ’giaddr’ is zero and ’ciaddr’ is zero, and the broadcast bit is
337 set, then the server broadcasts DHCPOFFER and DHCPACK messages to
338 0xffffffff. If the broadcast bit is not set and ’giaddr’ is zero and
339 ’ciaddr’ is zero, then the server unicasts DHCPOFFER and DHCPACK
340 messages to the client’s hardware address and ’yiaddr’ address. In
341 all cases, when ’giaddr’ is zero, the server broadcasts any DHCPNAK
342 messages to 0xffffffff.
346 If ’giaddr’ is set in the DHCPREQUEST message, the client is on a
347 different subnet. The server MUST set the broadcast bit in the
348 DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
349 client, because the client may not have a correct network address
350 or subnet mask, and the client may not be answering ARP requests.
352 if (req->message->giaddr) {
353 destination = req->message->giaddr;
354 if (type == DHCP_NAK)
355 packet->dhcp.flags = htobe16(0x8000);
356 } else if (req->message->ciaddr && type != DHCP_NAK)
357 destination = req->message->ciaddr;
359 if (destination != INADDR_ANY)
360 return dhcp_server_send_udp(server, destination, &packet->dhcp,
361 sizeof(DHCPMessage) + optoffset);
362 else if (requested_broadcast(req) || type == DHCP_NAK)
363 return dhcp_server_send_udp(server, INADDR_BROADCAST,
365 sizeof(DHCPMessage) + optoffset);
367 /* we cannot send UDP packet to specific MAC address when the
368 address is not yet configured, so must fall back to raw
370 return dhcp_server_send_unicast_raw(server, packet,
371 sizeof(DHCPPacket) + optoffset);
374 static int server_message_init(sd_dhcp_server *server, DHCPPacket **ret,
375 uint8_t type, size_t *_optoffset,
377 _cleanup_free_ DHCPPacket *packet = NULL;
378 size_t optoffset = 0;
384 assert(IN_SET(type, DHCP_OFFER, DHCP_ACK, DHCP_NAK));
386 packet = malloc0(sizeof(DHCPPacket) + req->max_optlen);
390 r = dhcp_message_init(&packet->dhcp, BOOTREPLY,
391 be32toh(req->message->xid), type, req->max_optlen,
396 packet->dhcp.flags = req->message->flags;
397 packet->dhcp.giaddr = req->message->giaddr;
398 memcpy(&packet->dhcp.chaddr, &req->message->chaddr, ETH_ALEN);
400 *_optoffset = optoffset;
407 static int server_send_offer(sd_dhcp_server *server, DHCPRequest *req,
409 _cleanup_free_ DHCPPacket *packet = NULL;
414 r = server_message_init(server, &packet, DHCP_OFFER, &offset, req);
418 packet->dhcp.yiaddr = address;
420 lease_time = htobe32(req->lifetime);
421 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
422 DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4,
427 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
428 DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
432 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
433 DHCP_OPTION_ROUTER, 4, &server->address);
437 r = dhcp_server_send_packet(server, req, packet, DHCP_OFFER, offset);
444 static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req,
446 _cleanup_free_ DHCPPacket *packet = NULL;
451 r = server_message_init(server, &packet, DHCP_ACK, &offset, req);
455 packet->dhcp.yiaddr = address;
457 lease_time = htobe32(req->lifetime);
458 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
459 DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4,
464 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
465 DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
469 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
470 DHCP_OPTION_ROUTER, 4, &server->address);
474 r = dhcp_server_send_packet(server, req, packet, DHCP_ACK, offset);
481 static int server_send_nak(sd_dhcp_server *server, DHCPRequest *req) {
482 _cleanup_free_ DHCPPacket *packet = NULL;
486 r = server_message_init(server, &packet, DHCP_NAK, &offset, req);
490 r = dhcp_server_send_packet(server, req, packet, DHCP_NAK, offset);
497 static int server_send_forcerenew(sd_dhcp_server *server, be32_t address,
498 be32_t gateway, uint8_t chaddr[]) {
499 _cleanup_free_ DHCPPacket *packet = NULL;
500 size_t optoffset = 0;
504 assert(address != INADDR_ANY);
507 packet = malloc0(sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE);
511 r = dhcp_message_init(&packet->dhcp, BOOTREPLY, 0,
512 DHCP_FORCERENEW, DHCP_MIN_OPTIONS_SIZE,
517 r = dhcp_option_append(&packet->dhcp, DHCP_MIN_OPTIONS_SIZE,
518 &optoffset, 0, DHCP_OPTION_END, 0, NULL);
522 memcpy(&packet->dhcp.chaddr, chaddr, ETH_ALEN);
524 r = dhcp_server_send_udp(server, address, &packet->dhcp,
525 sizeof(DHCPMessage) + optoffset);
532 static int parse_request(uint8_t code, uint8_t len, const uint8_t *option,
534 DHCPRequest *req = user_data;
539 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
541 req->lifetime = be32toh(*(be32_t*)option);
544 case DHCP_OPTION_REQUESTED_IP_ADDRESS:
546 req->requested_ip = *(be32_t*)option;
549 case DHCP_OPTION_SERVER_IDENTIFIER:
551 req->server_id = *(be32_t*)option;
554 case DHCP_OPTION_CLIENT_IDENTIFIER:
558 data = memdup(option, len);
562 free(req->client_id.data);
563 req->client_id.data = data;
564 req->client_id.length = len;
568 case DHCP_OPTION_MAXIMUM_MESSAGE_SIZE:
570 req->max_optlen = be16toh(*(be16_t*)option) -
571 - sizeof(DHCPPacket);
579 static void dhcp_request_free(DHCPRequest *req) {
583 free(req->client_id.data);
587 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest*, dhcp_request_free);
588 #define _cleanup_dhcp_request_free_ _cleanup_(dhcp_request_freep)
590 static int ensure_sane_request(DHCPRequest *req, DHCPMessage *message) {
594 req->message = message;
596 /* set client id based on mac address if client did not send an explicit
598 if (!req->client_id.data) {
601 data = new0(uint8_t, ETH_ALEN + 1);
605 req->client_id.length = ETH_ALEN + 1;
606 req->client_id.data = data;
607 req->client_id.data[0] = 0x01;
608 memcpy(&req->client_id.data[1], &message->chaddr, ETH_ALEN);
611 if (req->max_optlen < DHCP_MIN_OPTIONS_SIZE)
612 req->max_optlen = DHCP_MIN_OPTIONS_SIZE;
615 req->lifetime = DHCP_DEFAULT_LEASE_TIME;
620 static int get_pool_offset(sd_dhcp_server *server, be32_t requested_ip) {
623 if (!server->pool_size)
626 if (be32toh(requested_ip) < be32toh(server->pool_start) ||
627 be32toh(requested_ip) >= be32toh(server->pool_start) +
631 return be32toh(requested_ip) - be32toh(server->pool_start);
634 int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
636 _cleanup_dhcp_request_free_ DHCPRequest *req = NULL;
637 DHCPLease *existing_lease;
643 if (message->op != BOOTREQUEST ||
644 message->htype != ARPHRD_ETHER ||
645 message->hlen != ETHER_ADDR_LEN)
648 req = new0(DHCPRequest, 1);
652 type = dhcp_option_parse(message, length, parse_request, req);
656 r = ensure_sane_request(req, message);
658 /* this only fails on critical errors */
661 existing_lease = hashmap_get(server->leases_by_client_id,
667 be32_t address = INADDR_ANY;
670 log_dhcp_server(server, "DISCOVER (0x%x)",
671 be32toh(req->message->xid));
673 if (!server->pool_size)
674 /* no pool allocated */
677 /* for now pick a random free address from the pool */
679 address = existing_lease->address;
681 for (i = 0; i < server->pool_size; i++) {
682 if (!server->bound_leases[server->next_offer]) {
683 address = htobe32(be32toh(server->pool_start) + server->next_offer);
686 server->next_offer = (server->next_offer + 1) % server->pool_size;
690 if (address == INADDR_ANY)
691 /* no free addresses left */
694 r = server_send_offer(server, req, address);
696 /* this only fails on critical errors */
697 log_dhcp_server(server, "could not send offer: %s",
701 log_dhcp_server(server, "OFFER (0x%x)",
702 be32toh(req->message->xid));
709 log_dhcp_server(server, "DECLINE (0x%x)",
710 be32toh(req->message->xid));
712 /* TODO: make sure we don't offer this address again */
720 bool init_reboot = false;
723 /* see RFC 2131, section 4.3.2 */
725 if (req->server_id) {
726 log_dhcp_server(server, "REQUEST (selecting) (0x%x)",
727 be32toh(req->message->xid));
730 if (req->server_id != server->address)
731 /* client did not pick us */
734 if (req->message->ciaddr)
735 /* this MUST be zero */
738 if (!req->requested_ip)
739 /* this must be filled in with the yiaddr
740 from the chosen OFFER */
743 address = req->requested_ip;
744 } else if (req->requested_ip) {
745 log_dhcp_server(server, "REQUEST (init-reboot) (0x%x)",
746 be32toh(req->message->xid));
749 if (req->message->ciaddr)
750 /* this MUST be zero */
753 /* TODO: check more carefully if IP is correct */
754 address = req->requested_ip;
757 log_dhcp_server(server, "REQUEST (rebinding/renewing) (0x%x)",
758 be32toh(req->message->xid));
760 /* REBINDING / RENEWING */
761 if (!req->message->ciaddr)
762 /* this MUST be filled in with clients IP address */
765 address = req->message->ciaddr;
768 pool_offset = get_pool_offset(server, address);
770 /* verify that the requested address is from the pool, and either
771 owned by the current client or free */
772 if (pool_offset >= 0 &&
773 server->bound_leases[pool_offset] == existing_lease) {
777 if (!existing_lease) {
778 lease = new0(DHCPLease, 1);
779 lease->address = req->requested_ip;
780 lease->client_id.data = memdup(req->client_id.data,
781 req->client_id.length);
782 if (!lease->client_id.data) {
786 lease->client_id.length = req->client_id.length;
787 memcpy(&lease->chaddr, &req->message->chaddr,
789 lease->gateway = req->message->giaddr;
791 lease = existing_lease;
793 r = sd_event_now(server->event,
794 clock_boottime_or_monotonic(),
797 time_now = now(clock_boottime_or_monotonic());
798 lease->expiration = req->lifetime * USEC_PER_SEC + time_now;
800 r = server_send_ack(server, req, address);
802 /* this only fails on critical errors */
803 log_dhcp_server(server, "could not send ack: %s",
807 dhcp_lease_free(lease);
811 log_dhcp_server(server, "ACK (0x%x)",
812 be32toh(req->message->xid));
814 server->bound_leases[pool_offset] = lease;
815 hashmap_put(server->leases_by_client_id,
816 &lease->client_id, lease);
820 } else if (init_reboot) {
821 r = server_send_nak(server, req);
823 /* this only fails on critical errors */
824 log_dhcp_server(server, "could not send nak: %s",
828 log_dhcp_server(server, "NAK (0x%x)",
829 be32toh(req->message->xid));
839 log_dhcp_server(server, "RELEASE (0x%x)",
840 be32toh(req->message->xid));
845 if (existing_lease->address != req->message->ciaddr)
848 pool_offset = get_pool_offset(server, req->message->ciaddr);
852 if (server->bound_leases[pool_offset] == existing_lease) {
853 server->bound_leases[pool_offset] = NULL;
854 hashmap_remove(server->leases_by_client_id, existing_lease);
855 dhcp_lease_free(existing_lease);
866 static int server_receive_message(sd_event_source *s, int fd,
867 uint32_t revents, void *userdata) {
868 _cleanup_free_ DHCPMessage *message = NULL;
869 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))];
870 sd_dhcp_server *server = userdata;
871 struct iovec iov = {};
872 struct msghdr msg = {
875 .msg_control = cmsgbuf,
876 .msg_controllen = sizeof(cmsgbuf),
878 struct cmsghdr *cmsg;
879 int buflen = 0, len, r;
883 r = ioctl(fd, FIONREAD, &buflen);
889 message = malloc0(buflen);
893 iov.iov_base = message;
894 iov.iov_len = buflen;
896 len = recvmsg(fd, &msg, 0);
899 else if ((size_t)len < sizeof(DHCPMessage))
902 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
903 if (cmsg->cmsg_level == IPPROTO_IP &&
904 cmsg->cmsg_type == IP_PKTINFO &&
905 cmsg->cmsg_len == CMSG_LEN(sizeof(struct in_pktinfo))) {
906 struct in_pktinfo *info = (struct in_pktinfo*)CMSG_DATA(cmsg);
908 /* TODO figure out if this can be done as a filter on
909 * the socket, like for IPv6 */
910 if (server->index != info->ipi_ifindex)
917 return dhcp_server_handle_message(server, message, (size_t)len);
920 int sd_dhcp_server_start(sd_dhcp_server *server) {
923 assert_return(server, -EINVAL);
924 assert_return(server->event, -EINVAL);
925 assert_return(!server->receive_message, -EBUSY);
926 assert_return(server->fd_raw == -1, -EBUSY);
927 assert_return(server->fd == -1, -EBUSY);
928 assert_return(server->address != htobe32(INADDR_ANY), -EUNATCH);
930 r = socket(AF_PACKET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
933 sd_dhcp_server_stop(server);
938 r = dhcp_network_bind_udp_socket(INADDR_ANY, DHCP_PORT_SERVER);
940 sd_dhcp_server_stop(server);
945 r = sd_event_add_io(server->event, &server->receive_message,
947 server_receive_message, server);
949 sd_dhcp_server_stop(server);
953 r = sd_event_source_set_priority(server->receive_message,
954 server->event_priority);
956 sd_dhcp_server_stop(server);
960 log_dhcp_server(server, "STARTED");
965 int sd_dhcp_server_forcerenew(sd_dhcp_server *server) {
969 assert_return(server, -EINVAL);
970 assert(server->bound_leases);
972 for (i = 0; i < server->pool_size; i++) {
973 DHCPLease *lease = server->bound_leases[i];
978 r = server_send_forcerenew(server, lease->address,
984 log_dhcp_server(server, "FORCERENEW");