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