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