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