]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-dhcp-server.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / libsystemd-network / sd-dhcp-server.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright (C) 2013 Intel Corporation. All rights reserved.
6 Copyright (C) 2014 Tom Gundersen
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/ioctl.h>
23
24 #include "sd-dhcp-server.h"
25
26 #include "alloc-util.h"
27 #include "dhcp-internal.h"
28 #include "dhcp-server-internal.h"
29 #include "fd-util.h"
30 #include "in-addr-util.h"
31 #include "siphash24.h"
32 #include "string-util.h"
33 #include "unaligned.h"
34
35 #define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR
36 #define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12)
37
38 static void dhcp_lease_free(DHCPLease *lease) {
39 if (!lease)
40 return;
41
42 free(lease->client_id.data);
43 free(lease);
44 }
45
46 /* configures the server's address and subnet, and optionally the pool's size and offset into the subnet
47 * the whole pool must fit into the subnet, and may not contain the first (any) nor last (broadcast) address
48 * moreover, the server's own address may be in the pool, and is in that case reserved in order not to
49 * accidentally hand it out */
50 int sd_dhcp_server_configure_pool(sd_dhcp_server *server, struct in_addr *address, unsigned char prefixlen, uint32_t offset, uint32_t size) {
51 struct in_addr netmask_addr;
52 be32_t netmask;
53 uint32_t server_off, broadcast_off, size_max;
54
55 assert_return(server, -EINVAL);
56 assert_return(address, -EINVAL);
57 assert_return(address->s_addr != INADDR_ANY, -EINVAL);
58 assert_return(prefixlen <= 32, -ERANGE);
59
60 assert_se(in4_addr_prefixlen_to_netmask(&netmask_addr, prefixlen));
61 netmask = netmask_addr.s_addr;
62
63 server_off = be32toh(address->s_addr & ~netmask);
64 broadcast_off = be32toh(~netmask);
65
66 /* the server address cannot be the subnet address */
67 assert_return(server_off != 0, -ERANGE);
68
69 /* nor the broadcast address */
70 assert_return(server_off != broadcast_off, -ERANGE);
71
72 /* 0 offset means we should set a default, we skip the first (subnet) address
73 and take the next one */
74 if (offset == 0)
75 offset = 1;
76
77 size_max = (broadcast_off + 1) /* the number of addresses in the subnet */
78 - offset /* exclude the addresses before the offset */
79 - 1; /* exclude the last (broadcast) address */
80
81 /* The pool must contain at least one address */
82 assert_return(size_max >= 1, -ERANGE);
83
84 if (size != 0)
85 assert_return(size <= size_max, -ERANGE);
86 else
87 size = size_max;
88
89 if (server->address != address->s_addr || server->netmask != netmask || server->pool_size != size || server->pool_offset != offset) {
90 DHCPLease *lease;
91
92 free(server->bound_leases);
93 server->bound_leases = new0(DHCPLease*, size);
94 if (!server->bound_leases)
95 return -ENOMEM;
96
97 server->pool_offset = offset;
98 server->pool_size = size;
99
100 server->address = address->s_addr;
101 server->netmask = netmask;
102 server->subnet = address->s_addr & netmask;
103
104 if (server_off >= offset && server_off - offset < size)
105 server->bound_leases[server_off - offset] = &server->invalid_lease;
106
107 /* Drop any leases associated with the old address range */
108 while ((lease = hashmap_steal_first(server->leases_by_client_id)))
109 dhcp_lease_free(lease);
110 }
111
112 return 0;
113 }
114
115 int sd_dhcp_server_is_running(sd_dhcp_server *server) {
116 assert_return(server, false);
117
118 return !!server->receive_message;
119 }
120
121 sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server) {
122
123 if (!server)
124 return NULL;
125
126 assert(server->n_ref >= 1);
127 server->n_ref++;
128
129 return server;
130 }
131
132 void client_id_hash_func(const void *p, struct siphash *state) {
133 const DHCPClientId *id = p;
134
135 assert(id);
136 assert(id->length);
137 assert(id->data);
138
139 siphash24_compress(&id->length, sizeof(id->length), state);
140 siphash24_compress(id->data, id->length, state);
141 }
142
143 int client_id_compare_func(const void *_a, const void *_b) {
144 const DHCPClientId *a, *b;
145
146 a = _a;
147 b = _b;
148
149 assert(!a->length || a->data);
150 assert(!b->length || b->data);
151
152 if (a->length != b->length)
153 return a->length < b->length ? -1 : 1;
154
155 return memcmp(a->data, b->data, a->length);
156 }
157
158 static const struct hash_ops client_id_hash_ops = {
159 .hash = client_id_hash_func,
160 .compare = client_id_compare_func
161 };
162
163 sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) {
164 DHCPLease *lease;
165
166 if (!server)
167 return NULL;
168
169 assert(server->n_ref >= 1);
170 server->n_ref--;
171
172 if (server->n_ref > 0)
173 return NULL;
174
175 log_dhcp_server(server, "UNREF");
176
177 sd_dhcp_server_stop(server);
178
179 sd_event_unref(server->event);
180
181 free(server->timezone);
182 free(server->dns);
183 free(server->ntp);
184
185 while ((lease = hashmap_steal_first(server->leases_by_client_id)))
186 dhcp_lease_free(lease);
187 hashmap_free(server->leases_by_client_id);
188
189 free(server->bound_leases);
190 return mfree(server);
191 }
192
193 int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
194 _cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
195
196 assert_return(ret, -EINVAL);
197 assert_return(ifindex > 0, -EINVAL);
198
199 server = new0(sd_dhcp_server, 1);
200 if (!server)
201 return -ENOMEM;
202
203 server->n_ref = 1;
204 server->fd_raw = -1;
205 server->fd = -1;
206 server->address = htobe32(INADDR_ANY);
207 server->netmask = htobe32(INADDR_ANY);
208 server->ifindex = ifindex;
209
210 server->leases_by_client_id = hashmap_new(&client_id_hash_ops);
211 if (!server->leases_by_client_id)
212 return -ENOMEM;
213
214 server->default_lease_time = DIV_ROUND_UP(DHCP_DEFAULT_LEASE_TIME_USEC, USEC_PER_SEC);
215 server->max_lease_time = DIV_ROUND_UP(DHCP_MAX_LEASE_TIME_USEC, USEC_PER_SEC);
216
217 *ret = server;
218 server = NULL;
219
220 return 0;
221 }
222
223 int sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event, int64_t priority) {
224 int r;
225
226 assert_return(server, -EINVAL);
227 assert_return(!server->event, -EBUSY);
228
229 if (event)
230 server->event = sd_event_ref(event);
231 else {
232 r = sd_event_default(&server->event);
233 if (r < 0)
234 return r;
235 }
236
237 server->event_priority = priority;
238
239 return 0;
240 }
241
242 int sd_dhcp_server_detach_event(sd_dhcp_server *server) {
243 assert_return(server, -EINVAL);
244
245 server->event = sd_event_unref(server->event);
246
247 return 0;
248 }
249
250 sd_event *sd_dhcp_server_get_event(sd_dhcp_server *server) {
251 assert_return(server, NULL);
252
253 return server->event;
254 }
255
256 int sd_dhcp_server_stop(sd_dhcp_server *server) {
257 assert_return(server, -EINVAL);
258
259 server->receive_message =
260 sd_event_source_unref(server->receive_message);
261
262 server->fd_raw = safe_close(server->fd_raw);
263 server->fd = safe_close(server->fd);
264
265 log_dhcp_server(server, "STOPPED");
266
267 return 0;
268 }
269
270 static int dhcp_server_send_unicast_raw(sd_dhcp_server *server,
271 DHCPPacket *packet, size_t len) {
272 union sockaddr_union link = {
273 .ll.sll_family = AF_PACKET,
274 .ll.sll_protocol = htobe16(ETH_P_IP),
275 .ll.sll_ifindex = server->ifindex,
276 .ll.sll_halen = ETH_ALEN,
277 };
278
279 assert(server);
280 assert(server->ifindex > 0);
281 assert(server->address);
282 assert(packet);
283 assert(len > sizeof(DHCPPacket));
284
285 memcpy(&link.ll.sll_addr, &packet->dhcp.chaddr, ETH_ALEN);
286
287 dhcp_packet_append_ip_headers(packet, server->address, DHCP_PORT_SERVER,
288 packet->dhcp.yiaddr,
289 DHCP_PORT_CLIENT, len);
290
291 return dhcp_network_send_raw_socket(server->fd_raw, &link, packet, len);
292 }
293
294 static int dhcp_server_send_udp(sd_dhcp_server *server, be32_t destination,
295 uint16_t destination_port,
296 DHCPMessage *message, size_t len) {
297 union sockaddr_union dest = {
298 .in.sin_family = AF_INET,
299 .in.sin_port = htobe16(destination_port),
300 .in.sin_addr.s_addr = destination,
301 };
302 struct iovec iov = {
303 .iov_base = message,
304 .iov_len = len,
305 };
306 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))] = {};
307 struct msghdr msg = {
308 .msg_name = &dest,
309 .msg_namelen = sizeof(dest.in),
310 .msg_iov = &iov,
311 .msg_iovlen = 1,
312 .msg_control = cmsgbuf,
313 .msg_controllen = sizeof(cmsgbuf),
314 };
315 struct cmsghdr *cmsg;
316 struct in_pktinfo *pktinfo;
317 int r;
318
319 assert(server);
320 assert(server->fd > 0);
321 assert(message);
322 assert(len > sizeof(DHCPMessage));
323
324 cmsg = CMSG_FIRSTHDR(&msg);
325 assert(cmsg);
326
327 cmsg->cmsg_level = IPPROTO_IP;
328 cmsg->cmsg_type = IP_PKTINFO;
329 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
330
331 /* we attach source interface and address info to the message
332 rather than binding the socket. This will be mostly useful
333 when we gain support for arbitrary number of server addresses
334 */
335 pktinfo = (struct in_pktinfo*) CMSG_DATA(cmsg);
336 assert(pktinfo);
337
338 pktinfo->ipi_ifindex = server->ifindex;
339 pktinfo->ipi_spec_dst.s_addr = server->address;
340
341 r = sendmsg(server->fd, &msg, 0);
342 if (r < 0)
343 return -errno;
344
345 return 0;
346 }
347
348 static bool requested_broadcast(DHCPRequest *req) {
349 assert(req);
350
351 return req->message->flags & htobe16(0x8000);
352 }
353
354 int dhcp_server_send_packet(sd_dhcp_server *server,
355 DHCPRequest *req, DHCPPacket *packet,
356 int type, size_t optoffset) {
357 be32_t destination = INADDR_ANY;
358 uint16_t destination_port = DHCP_PORT_CLIENT;
359 int r;
360
361 assert(server);
362 assert(req);
363 assert(req->max_optlen);
364 assert(optoffset <= req->max_optlen);
365 assert(packet);
366
367 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
368 SD_DHCP_OPTION_SERVER_IDENTIFIER,
369 4, &server->address);
370 if (r < 0)
371 return r;
372
373 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
374 SD_DHCP_OPTION_END, 0, NULL);
375 if (r < 0)
376 return r;
377
378 /* RFC 2131 Section 4.1
379
380 If the ’giaddr’ field in a DHCP message from a client is non-zero,
381 the server sends any return messages to the ’DHCP server’ port on the
382 BOOTP relay agent whose address appears in ’giaddr’. If the ’giaddr’
383 field is zero and the ’ciaddr’ field is nonzero, then the server
384 unicasts DHCPOFFER and DHCPACK messages to the address in ’ciaddr’.
385 If ’giaddr’ is zero and ’ciaddr’ is zero, and the broadcast bit is
386 set, then the server broadcasts DHCPOFFER and DHCPACK messages to
387 0xffffffff. If the broadcast bit is not set and ’giaddr’ is zero and
388 ’ciaddr’ is zero, then the server unicasts DHCPOFFER and DHCPACK
389 messages to the client’s hardware address and ’yiaddr’ address. In
390 all cases, when ’giaddr’ is zero, the server broadcasts any DHCPNAK
391 messages to 0xffffffff.
392
393 Section 4.3.2
394
395 If ’giaddr’ is set in the DHCPREQUEST message, the client is on a
396 different subnet. The server MUST set the broadcast bit in the
397 DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
398 client, because the client may not have a correct network address
399 or subnet mask, and the client may not be answering ARP requests.
400 */
401 if (req->message->giaddr) {
402 destination = req->message->giaddr;
403 destination_port = DHCP_PORT_SERVER;
404 if (type == DHCP_NAK)
405 packet->dhcp.flags = htobe16(0x8000);
406 } else if (req->message->ciaddr && type != DHCP_NAK)
407 destination = req->message->ciaddr;
408
409 if (destination != INADDR_ANY)
410 return dhcp_server_send_udp(server, destination,
411 destination_port, &packet->dhcp,
412 sizeof(DHCPMessage) + optoffset);
413 else if (requested_broadcast(req) || type == DHCP_NAK)
414 return dhcp_server_send_udp(server, INADDR_BROADCAST,
415 destination_port, &packet->dhcp,
416 sizeof(DHCPMessage) + optoffset);
417 else
418 /* we cannot send UDP packet to specific MAC address when the
419 address is not yet configured, so must fall back to raw
420 packets */
421 return dhcp_server_send_unicast_raw(server, packet,
422 sizeof(DHCPPacket) + optoffset);
423 }
424
425 static int server_message_init(sd_dhcp_server *server, DHCPPacket **ret,
426 uint8_t type, size_t *_optoffset,
427 DHCPRequest *req) {
428 _cleanup_free_ DHCPPacket *packet = NULL;
429 size_t optoffset = 0;
430 int r;
431
432 assert(server);
433 assert(ret);
434 assert(_optoffset);
435 assert(IN_SET(type, DHCP_OFFER, DHCP_ACK, DHCP_NAK));
436
437 packet = malloc0(sizeof(DHCPPacket) + req->max_optlen);
438 if (!packet)
439 return -ENOMEM;
440
441 r = dhcp_message_init(&packet->dhcp, BOOTREPLY,
442 be32toh(req->message->xid), type, ARPHRD_ETHER,
443 req->max_optlen, &optoffset);
444 if (r < 0)
445 return r;
446
447 packet->dhcp.flags = req->message->flags;
448 packet->dhcp.giaddr = req->message->giaddr;
449 memcpy(&packet->dhcp.chaddr, &req->message->chaddr, ETH_ALEN);
450
451 *_optoffset = optoffset;
452 *ret = packet;
453 packet = NULL;
454
455 return 0;
456 }
457
458 static int server_send_offer(sd_dhcp_server *server, DHCPRequest *req,
459 be32_t address) {
460 _cleanup_free_ DHCPPacket *packet = NULL;
461 size_t offset;
462 be32_t lease_time;
463 int r;
464
465 r = server_message_init(server, &packet, DHCP_OFFER, &offset, req);
466 if (r < 0)
467 return r;
468
469 packet->dhcp.yiaddr = address;
470
471 lease_time = htobe32(req->lifetime);
472 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
473 SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4,
474 &lease_time);
475 if (r < 0)
476 return r;
477
478 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
479 SD_DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
480 if (r < 0)
481 return r;
482
483 if (server->emit_router) {
484 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
485 SD_DHCP_OPTION_ROUTER, 4, &server->address);
486 if (r < 0)
487 return r;
488 }
489
490 r = dhcp_server_send_packet(server, req, packet, DHCP_OFFER, offset);
491 if (r < 0)
492 return r;
493
494 return 0;
495 }
496
497 static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req,
498 be32_t address) {
499 _cleanup_free_ DHCPPacket *packet = NULL;
500 size_t offset;
501 be32_t lease_time;
502 int r;
503
504 r = server_message_init(server, &packet, DHCP_ACK, &offset, req);
505 if (r < 0)
506 return r;
507
508 packet->dhcp.yiaddr = address;
509
510 lease_time = htobe32(req->lifetime);
511 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
512 SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4,
513 &lease_time);
514 if (r < 0)
515 return r;
516
517 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
518 SD_DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
519 if (r < 0)
520 return r;
521
522 if (server->emit_router) {
523 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
524 SD_DHCP_OPTION_ROUTER, 4, &server->address);
525 if (r < 0)
526 return r;
527 }
528
529 if (server->n_dns > 0) {
530 r = dhcp_option_append(
531 &packet->dhcp, req->max_optlen, &offset, 0,
532 SD_DHCP_OPTION_DOMAIN_NAME_SERVER,
533 sizeof(struct in_addr) * server->n_dns, server->dns);
534 if (r < 0)
535 return r;
536 }
537
538 if (server->n_ntp > 0) {
539 r = dhcp_option_append(
540 &packet->dhcp, req->max_optlen, &offset, 0,
541 SD_DHCP_OPTION_NTP_SERVER,
542 sizeof(struct in_addr) * server->n_ntp, server->ntp);
543 if (r < 0)
544 return r;
545 }
546
547 if (server->timezone) {
548 r = dhcp_option_append(
549 &packet->dhcp, req->max_optlen, &offset, 0,
550 SD_DHCP_OPTION_NEW_TZDB_TIMEZONE,
551 strlen(server->timezone), server->timezone);
552 if (r < 0)
553 return r;
554 }
555
556 r = dhcp_server_send_packet(server, req, packet, DHCP_ACK, offset);
557 if (r < 0)
558 return r;
559
560 return 0;
561 }
562
563 static int server_send_nak(sd_dhcp_server *server, DHCPRequest *req) {
564 _cleanup_free_ DHCPPacket *packet = NULL;
565 size_t offset;
566 int r;
567
568 r = server_message_init(server, &packet, DHCP_NAK, &offset, req);
569 if (r < 0)
570 return r;
571
572 return dhcp_server_send_packet(server, req, packet, DHCP_NAK, offset);
573 }
574
575 static int server_send_forcerenew(sd_dhcp_server *server, be32_t address,
576 be32_t gateway, uint8_t chaddr[]) {
577 _cleanup_free_ DHCPPacket *packet = NULL;
578 size_t optoffset = 0;
579 int r;
580
581 assert(server);
582 assert(address != INADDR_ANY);
583 assert(chaddr);
584
585 packet = malloc0(sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE);
586 if (!packet)
587 return -ENOMEM;
588
589 r = dhcp_message_init(&packet->dhcp, BOOTREPLY, 0,
590 DHCP_FORCERENEW, ARPHRD_ETHER,
591 DHCP_MIN_OPTIONS_SIZE, &optoffset);
592 if (r < 0)
593 return r;
594
595 r = dhcp_option_append(&packet->dhcp, DHCP_MIN_OPTIONS_SIZE,
596 &optoffset, 0, SD_DHCP_OPTION_END, 0, NULL);
597 if (r < 0)
598 return r;
599
600 memcpy(&packet->dhcp.chaddr, chaddr, ETH_ALEN);
601
602 r = dhcp_server_send_udp(server, address, DHCP_PORT_CLIENT,
603 &packet->dhcp,
604 sizeof(DHCPMessage) + optoffset);
605 if (r < 0)
606 return r;
607
608 return 0;
609 }
610
611 static int parse_request(uint8_t code, uint8_t len, const void *option, void *userdata) {
612 DHCPRequest *req = userdata;
613
614 assert(req);
615
616 switch(code) {
617 case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
618 if (len == 4)
619 req->lifetime = unaligned_read_be32(option);
620
621 break;
622 case SD_DHCP_OPTION_REQUESTED_IP_ADDRESS:
623 if (len == 4)
624 memcpy(&req->requested_ip, option, sizeof(be32_t));
625
626 break;
627 case SD_DHCP_OPTION_SERVER_IDENTIFIER:
628 if (len == 4)
629 memcpy(&req->server_id, option, sizeof(be32_t));
630
631 break;
632 case SD_DHCP_OPTION_CLIENT_IDENTIFIER:
633 if (len >= 2) {
634 uint8_t *data;
635
636 data = memdup(option, len);
637 if (!data)
638 return -ENOMEM;
639
640 free(req->client_id.data);
641 req->client_id.data = data;
642 req->client_id.length = len;
643 }
644
645 break;
646 case SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE:
647
648 if (len == 2 && unaligned_read_be16(option) >= sizeof(DHCPPacket))
649 req->max_optlen = unaligned_read_be16(option) - sizeof(DHCPPacket);
650
651 break;
652 }
653
654 return 0;
655 }
656
657 static void dhcp_request_free(DHCPRequest *req) {
658 if (!req)
659 return;
660
661 free(req->client_id.data);
662 free(req);
663 }
664
665 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest*, dhcp_request_free);
666 #define _cleanup_dhcp_request_free_ _cleanup_(dhcp_request_freep)
667
668 static int ensure_sane_request(sd_dhcp_server *server, DHCPRequest *req, DHCPMessage *message) {
669 assert(req);
670 assert(message);
671
672 req->message = message;
673
674 /* set client id based on MAC address if client did not send an explicit
675 one */
676 if (!req->client_id.data) {
677 void *data;
678
679 data = malloc0(ETH_ALEN + 1);
680 if (!data)
681 return -ENOMEM;
682
683 ((uint8_t*) data)[0] = 0x01;
684 memcpy((uint8_t*) data + 1, &message->chaddr, ETH_ALEN);
685
686 req->client_id.length = ETH_ALEN + 1;
687 req->client_id.data = data;
688 }
689
690 if (req->max_optlen < DHCP_MIN_OPTIONS_SIZE)
691 req->max_optlen = DHCP_MIN_OPTIONS_SIZE;
692
693 if (req->lifetime <= 0)
694 req->lifetime = MAX(1ULL, server->default_lease_time);
695
696 if (server->max_lease_time > 0 && req->lifetime > server->max_lease_time)
697 req->lifetime = server->max_lease_time;
698
699 return 0;
700 }
701
702 static int get_pool_offset(sd_dhcp_server *server, be32_t requested_ip) {
703 assert(server);
704
705 if (!server->pool_size)
706 return -EINVAL;
707
708 if (be32toh(requested_ip) < (be32toh(server->subnet) | server->pool_offset) ||
709 be32toh(requested_ip) >= (be32toh(server->subnet) | (server->pool_offset + server->pool_size)))
710 return -ERANGE;
711
712 return be32toh(requested_ip & ~server->netmask) - server->pool_offset;
713 }
714
715 #define HASH_KEY SD_ID128_MAKE(0d,1d,fe,bd,f1,24,bd,b3,47,f1,dd,6e,73,21,93,30)
716
717 int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
718 size_t length) {
719 _cleanup_dhcp_request_free_ DHCPRequest *req = NULL;
720 _cleanup_free_ char *error_message = NULL;
721 DHCPLease *existing_lease;
722 int type, r;
723
724 assert(server);
725 assert(message);
726
727 if (message->op != BOOTREQUEST ||
728 message->htype != ARPHRD_ETHER ||
729 message->hlen != ETHER_ADDR_LEN)
730 return 0;
731
732 req = new0(DHCPRequest, 1);
733 if (!req)
734 return -ENOMEM;
735
736 type = dhcp_option_parse(message, length, parse_request, req, &error_message);
737 if (type < 0)
738 return 0;
739
740 r = ensure_sane_request(server, req, message);
741 if (r < 0)
742 /* this only fails on critical errors */
743 return r;
744
745 existing_lease = hashmap_get(server->leases_by_client_id,
746 &req->client_id);
747
748 switch(type) {
749
750 case DHCP_DISCOVER: {
751 be32_t address = INADDR_ANY;
752 unsigned i;
753
754 log_dhcp_server(server, "DISCOVER (0x%x)",
755 be32toh(req->message->xid));
756
757 if (!server->pool_size)
758 /* no pool allocated */
759 return 0;
760
761 /* for now pick a random free address from the pool */
762 if (existing_lease)
763 address = existing_lease->address;
764 else {
765 struct siphash state;
766 uint64_t hash;
767 uint32_t next_offer;
768
769 /* even with no persistence of leases, we try to offer the same client
770 the same IP address. we do this by using the hash of the client id
771 as the offset into the pool of leases when finding the next free one */
772
773 siphash24_init(&state, HASH_KEY.bytes);
774 client_id_hash_func(&req->client_id, &state);
775 hash = htole64(siphash24_finalize(&state));
776 next_offer = hash % server->pool_size;
777
778 for (i = 0; i < server->pool_size; i++) {
779 if (!server->bound_leases[next_offer]) {
780 address = server->subnet | htobe32(server->pool_offset + next_offer);
781 break;
782 } else
783 next_offer = (next_offer + 1) % server->pool_size;
784 }
785 }
786
787 if (address == INADDR_ANY)
788 /* no free addresses left */
789 return 0;
790
791 r = server_send_offer(server, req, address);
792 if (r < 0) {
793 /* this only fails on critical errors */
794 log_dhcp_server(server, "could not send offer: %s",
795 strerror(-r));
796 return r;
797 } else {
798 log_dhcp_server(server, "OFFER (0x%x)",
799 be32toh(req->message->xid));
800 return DHCP_OFFER;
801 }
802
803 break;
804 }
805 case DHCP_DECLINE:
806 log_dhcp_server(server, "DECLINE (0x%x): %s", be32toh(req->message->xid), strna(error_message));
807
808 /* TODO: make sure we don't offer this address again */
809
810 return 1;
811
812 case DHCP_REQUEST: {
813 be32_t address;
814 bool init_reboot = false;
815 int pool_offset;
816
817 /* see RFC 2131, section 4.3.2 */
818
819 if (req->server_id) {
820 log_dhcp_server(server, "REQUEST (selecting) (0x%x)",
821 be32toh(req->message->xid));
822
823 /* SELECTING */
824 if (req->server_id != server->address)
825 /* client did not pick us */
826 return 0;
827
828 if (req->message->ciaddr)
829 /* this MUST be zero */
830 return 0;
831
832 if (!req->requested_ip)
833 /* this must be filled in with the yiaddr
834 from the chosen OFFER */
835 return 0;
836
837 address = req->requested_ip;
838 } else if (req->requested_ip) {
839 log_dhcp_server(server, "REQUEST (init-reboot) (0x%x)",
840 be32toh(req->message->xid));
841
842 /* INIT-REBOOT */
843 if (req->message->ciaddr)
844 /* this MUST be zero */
845 return 0;
846
847 /* TODO: check more carefully if IP is correct */
848 address = req->requested_ip;
849 init_reboot = true;
850 } else {
851 log_dhcp_server(server, "REQUEST (rebinding/renewing) (0x%x)",
852 be32toh(req->message->xid));
853
854 /* REBINDING / RENEWING */
855 if (!req->message->ciaddr)
856 /* this MUST be filled in with clients IP address */
857 return 0;
858
859 address = req->message->ciaddr;
860 }
861
862 pool_offset = get_pool_offset(server, address);
863
864 /* verify that the requested address is from the pool, and either
865 owned by the current client or free */
866 if (pool_offset >= 0 &&
867 server->bound_leases[pool_offset] == existing_lease) {
868 DHCPLease *lease;
869 usec_t time_now = 0;
870
871 if (!existing_lease) {
872 lease = new0(DHCPLease, 1);
873 if (!lease)
874 return -ENOMEM;
875 lease->address = address;
876 lease->client_id.data = memdup(req->client_id.data,
877 req->client_id.length);
878 if (!lease->client_id.data) {
879 free(lease);
880 return -ENOMEM;
881 }
882 lease->client_id.length = req->client_id.length;
883 memcpy(&lease->chaddr, &req->message->chaddr,
884 ETH_ALEN);
885 lease->gateway = req->message->giaddr;
886 } else
887 lease = existing_lease;
888
889 r = sd_event_now(server->event,
890 clock_boottime_or_monotonic(),
891 &time_now);
892 if (r < 0) {
893 if (!existing_lease)
894 dhcp_lease_free(lease);
895 return r;
896 }
897
898 lease->expiration = req->lifetime * USEC_PER_SEC + time_now;
899
900 r = server_send_ack(server, req, address);
901 if (r < 0) {
902 /* this only fails on critical errors */
903 log_dhcp_server(server, "could not send ack: %s",
904 strerror(-r));
905
906 if (!existing_lease)
907 dhcp_lease_free(lease);
908
909 return r;
910 } else {
911 log_dhcp_server(server, "ACK (0x%x)",
912 be32toh(req->message->xid));
913
914 server->bound_leases[pool_offset] = lease;
915 hashmap_put(server->leases_by_client_id,
916 &lease->client_id, lease);
917
918 return DHCP_ACK;
919 }
920 } else if (init_reboot) {
921 r = server_send_nak(server, req);
922 if (r < 0) {
923 /* this only fails on critical errors */
924 log_dhcp_server(server, "could not send nak: %s",
925 strerror(-r));
926 return r;
927 } else {
928 log_dhcp_server(server, "NAK (0x%x)",
929 be32toh(req->message->xid));
930 return DHCP_NAK;
931 }
932 }
933
934 break;
935 }
936
937 case DHCP_RELEASE: {
938 int pool_offset;
939
940 log_dhcp_server(server, "RELEASE (0x%x)",
941 be32toh(req->message->xid));
942
943 if (!existing_lease)
944 return 0;
945
946 if (existing_lease->address != req->message->ciaddr)
947 return 0;
948
949 pool_offset = get_pool_offset(server, req->message->ciaddr);
950 if (pool_offset < 0)
951 return 0;
952
953 if (server->bound_leases[pool_offset] == existing_lease) {
954 server->bound_leases[pool_offset] = NULL;
955 hashmap_remove(server->leases_by_client_id, existing_lease);
956 dhcp_lease_free(existing_lease);
957
958 return 1;
959 } else
960 return 0;
961 }
962 }
963
964 return 0;
965 }
966
967 static int server_receive_message(sd_event_source *s, int fd,
968 uint32_t revents, void *userdata) {
969 _cleanup_free_ DHCPMessage *message = NULL;
970 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))];
971 sd_dhcp_server *server = userdata;
972 struct iovec iov = {};
973 struct msghdr msg = {
974 .msg_iov = &iov,
975 .msg_iovlen = 1,
976 .msg_control = cmsgbuf,
977 .msg_controllen = sizeof(cmsgbuf),
978 };
979 struct cmsghdr *cmsg;
980 ssize_t buflen, len;
981
982 assert(server);
983
984 buflen = next_datagram_size_fd(fd);
985 if (buflen < 0)
986 return buflen;
987
988 message = malloc(buflen);
989 if (!message)
990 return -ENOMEM;
991
992 iov.iov_base = message;
993 iov.iov_len = buflen;
994
995 len = recvmsg(fd, &msg, 0);
996 if (len < 0) {
997 if (IN_SET(errno, EAGAIN, EINTR))
998 return 0;
999
1000 return -errno;
1001 } else if ((size_t)len < sizeof(DHCPMessage))
1002 return 0;
1003
1004 CMSG_FOREACH(cmsg, &msg) {
1005 if (cmsg->cmsg_level == IPPROTO_IP &&
1006 cmsg->cmsg_type == IP_PKTINFO &&
1007 cmsg->cmsg_len == CMSG_LEN(sizeof(struct in_pktinfo))) {
1008 struct in_pktinfo *info = (struct in_pktinfo*)CMSG_DATA(cmsg);
1009
1010 /* TODO figure out if this can be done as a filter on
1011 * the socket, like for IPv6 */
1012 if (server->ifindex != info->ipi_ifindex)
1013 return 0;
1014
1015 break;
1016 }
1017 }
1018
1019 return dhcp_server_handle_message(server, message, (size_t)len);
1020 }
1021
1022 int sd_dhcp_server_start(sd_dhcp_server *server) {
1023 int r;
1024
1025 assert_return(server, -EINVAL);
1026 assert_return(server->event, -EINVAL);
1027 assert_return(!server->receive_message, -EBUSY);
1028 assert_return(server->fd_raw == -1, -EBUSY);
1029 assert_return(server->fd == -1, -EBUSY);
1030 assert_return(server->address != htobe32(INADDR_ANY), -EUNATCH);
1031
1032 r = socket(AF_PACKET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
1033 if (r < 0) {
1034 r = -errno;
1035 sd_dhcp_server_stop(server);
1036 return r;
1037 }
1038 server->fd_raw = r;
1039
1040 r = dhcp_network_bind_udp_socket(server->ifindex, INADDR_ANY, DHCP_PORT_SERVER);
1041 if (r < 0) {
1042 sd_dhcp_server_stop(server);
1043 return r;
1044 }
1045 server->fd = r;
1046
1047 r = sd_event_add_io(server->event, &server->receive_message,
1048 server->fd, EPOLLIN,
1049 server_receive_message, server);
1050 if (r < 0) {
1051 sd_dhcp_server_stop(server);
1052 return r;
1053 }
1054
1055 r = sd_event_source_set_priority(server->receive_message,
1056 server->event_priority);
1057 if (r < 0) {
1058 sd_dhcp_server_stop(server);
1059 return r;
1060 }
1061
1062 log_dhcp_server(server, "STARTED");
1063
1064 return 0;
1065 }
1066
1067 int sd_dhcp_server_forcerenew(sd_dhcp_server *server) {
1068 unsigned i;
1069 int r = 0;
1070
1071 assert_return(server, -EINVAL);
1072 assert(server->bound_leases);
1073
1074 for (i = 0; i < server->pool_size; i++) {
1075 DHCPLease *lease = server->bound_leases[i];
1076
1077 if (!lease || lease == &server->invalid_lease)
1078 continue;
1079
1080 r = server_send_forcerenew(server, lease->address,
1081 lease->gateway,
1082 lease->chaddr);
1083 if (r < 0)
1084 return r;
1085 else
1086 log_dhcp_server(server, "FORCERENEW");
1087 }
1088
1089 return r;
1090 }
1091
1092 int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *tz) {
1093 int r;
1094
1095 assert_return(server, -EINVAL);
1096 assert_return(timezone_is_valid(tz), -EINVAL);
1097
1098 if (streq_ptr(tz, server->timezone))
1099 return 0;
1100
1101 r = free_and_strdup(&server->timezone, tz);
1102 if (r < 0)
1103 return r;
1104
1105 return 1;
1106 }
1107
1108 int sd_dhcp_server_set_max_lease_time(sd_dhcp_server *server, uint32_t t) {
1109 assert_return(server, -EINVAL);
1110
1111 if (t == server->max_lease_time)
1112 return 0;
1113
1114 server->max_lease_time = t;
1115 return 1;
1116 }
1117
1118 int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint32_t t) {
1119 assert_return(server, -EINVAL);
1120
1121 if (t == server->default_lease_time)
1122 return 0;
1123
1124 server->default_lease_time = t;
1125 return 1;
1126 }
1127
1128 int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr dns[], unsigned n) {
1129 assert_return(server, -EINVAL);
1130 assert_return(dns || n <= 0, -EINVAL);
1131
1132 if (server->n_dns == n &&
1133 memcmp(server->dns, dns, sizeof(struct in_addr) * n) == 0)
1134 return 0;
1135
1136 if (n <= 0) {
1137 server->dns = mfree(server->dns);
1138 server->n_dns = 0;
1139 } else {
1140 struct in_addr *c;
1141
1142 c = newdup(struct in_addr, dns, n);
1143 if (!c)
1144 return -ENOMEM;
1145
1146 free(server->dns);
1147 server->dns = c;
1148 server->n_dns = n;
1149 }
1150
1151 return 1;
1152 }
1153
1154 int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr ntp[], unsigned n) {
1155 assert_return(server, -EINVAL);
1156 assert_return(ntp || n <= 0, -EINVAL);
1157
1158 if (server->n_ntp == n &&
1159 memcmp(server->ntp, ntp, sizeof(struct in_addr) * n) == 0)
1160 return 0;
1161
1162 if (n <= 0) {
1163 server->ntp = mfree(server->ntp);
1164 server->n_ntp = 0;
1165 } else {
1166 struct in_addr *c;
1167
1168 c = newdup(struct in_addr, ntp, n);
1169 if (!c)
1170 return -ENOMEM;
1171
1172 free(server->ntp);
1173 server->ntp = c;
1174 server->n_ntp = n;
1175 }
1176
1177 return 1;
1178 }
1179
1180 int sd_dhcp_server_set_emit_router(sd_dhcp_server *server, int enabled) {
1181 assert_return(server, -EINVAL);
1182
1183 if (enabled == server->emit_router)
1184 return 0;
1185
1186 server->emit_router = enabled;
1187
1188 return 1;
1189 }