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