]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-dhcp-server.c
Merge pull request #2666 from keszybz/coverity-fixes
[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
33 #define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR
34 #define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12)
35
36 /* configures the server's address and subnet, and optionally the pool's size and offset into the subnet
37 * the whole pool must fit into the subnet, and may not contain the first (any) nor last (broadcast) address
38 * moreover, the server's own address may be in the pool, and is in that case reserved in order not to
39 * accidentally hand it out */
40 int sd_dhcp_server_configure_pool(sd_dhcp_server *server, struct in_addr *address, unsigned char prefixlen, uint32_t offset, uint32_t size) {
41 struct in_addr netmask_addr;
42 be32_t netmask;
43 uint32_t server_off, broadcast_off, size_max;
44
45 assert_return(server, -EINVAL);
46 assert_return(address, -EINVAL);
47 assert_return(address->s_addr != INADDR_ANY, -EINVAL);
48 assert_return(prefixlen <= 32, -ERANGE);
49 assert_return(server->address == INADDR_ANY, -EBUSY);
50
51 assert_se(in_addr_prefixlen_to_netmask(&netmask_addr, prefixlen));
52 netmask = netmask_addr.s_addr;
53
54 server_off = be32toh(address->s_addr & ~netmask);
55 broadcast_off = be32toh(~netmask);
56
57 /* the server address cannot be the subnet address */
58 assert_return(server_off != 0, -ERANGE);
59
60 /* nor the broadcast address */
61 assert_return(server_off != broadcast_off, -ERANGE);
62
63 /* 0 offset means we should set a default, we skip the first (subnet) address
64 and take the next one */
65 if (offset == 0)
66 offset = 1;
67
68 size_max = (broadcast_off + 1) /* the number of addresses in the subnet */
69 - offset /* exclude the addresses before the offset */
70 - 1; /* exclude the last (broadcast) address */
71
72 /* The pool must contain at least one address */
73 assert_return(size_max >= 1, -ERANGE);
74
75 if (size != 0)
76 assert_return(size <= size_max, -ERANGE);
77 else
78 size = size_max;
79
80 server->bound_leases = new0(DHCPLease*, size);
81 if (!server->bound_leases)
82 return -ENOMEM;
83
84 server->pool_offset = offset;
85 server->pool_size = size;
86
87 server->address = address->s_addr;
88 server->netmask = netmask;
89 server->subnet = address->s_addr & netmask;
90
91 if (server_off >= offset && server_off - offset < size)
92 server->bound_leases[server_off - offset] = &server->invalid_lease;
93
94 return 0;
95 }
96
97 int sd_dhcp_server_is_running(sd_dhcp_server *server) {
98 assert_return(server, false);
99
100 return !!server->receive_message;
101 }
102
103 sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server) {
104
105 if (!server)
106 return NULL;
107
108 assert(server->n_ref >= 1);
109 server->n_ref++;
110
111 return server;
112 }
113
114 void client_id_hash_func(const void *p, struct siphash *state) {
115 const DHCPClientId *id = p;
116
117 assert(id);
118 assert(id->length);
119 assert(id->data);
120
121 siphash24_compress(&id->length, sizeof(id->length), state);
122 siphash24_compress(id->data, id->length, state);
123 }
124
125 int client_id_compare_func(const void *_a, const void *_b) {
126 const DHCPClientId *a, *b;
127
128 a = _a;
129 b = _b;
130
131 assert(!a->length || a->data);
132 assert(!b->length || b->data);
133
134 if (a->length != b->length)
135 return a->length < b->length ? -1 : 1;
136
137 return memcmp(a->data, b->data, a->length);
138 }
139
140 static const struct hash_ops client_id_hash_ops = {
141 .hash = client_id_hash_func,
142 .compare = client_id_compare_func
143 };
144
145 static void dhcp_lease_free(DHCPLease *lease) {
146 if (!lease)
147 return;
148
149 free(lease->client_id.data);
150 free(lease);
151 }
152
153 sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) {
154 DHCPLease *lease;
155
156 if (!server)
157 return NULL;
158
159 assert(server->n_ref >= 1);
160 server->n_ref--;
161
162 if (server->n_ref > 0)
163 return NULL;
164
165 log_dhcp_server(server, "UNREF");
166
167 sd_dhcp_server_stop(server);
168
169 sd_event_unref(server->event);
170
171 free(server->timezone);
172 free(server->dns);
173 free(server->ntp);
174
175 while ((lease = hashmap_steal_first(server->leases_by_client_id)))
176 dhcp_lease_free(lease);
177 hashmap_free(server->leases_by_client_id);
178
179 free(server->bound_leases);
180 free(server);
181
182 return NULL;
183 }
184
185 int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
186 _cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
187
188 assert_return(ret, -EINVAL);
189 assert_return(ifindex > 0, -EINVAL);
190
191 server = new0(sd_dhcp_server, 1);
192 if (!server)
193 return -ENOMEM;
194
195 server->n_ref = 1;
196 server->fd_raw = -1;
197 server->fd = -1;
198 server->address = htobe32(INADDR_ANY);
199 server->netmask = htobe32(INADDR_ANY);
200 server->ifindex = ifindex;
201 server->leases_by_client_id = hashmap_new(&client_id_hash_ops);
202 server->default_lease_time = DIV_ROUND_UP(DHCP_DEFAULT_LEASE_TIME_USEC, USEC_PER_SEC);
203 server->max_lease_time = DIV_ROUND_UP(DHCP_MAX_LEASE_TIME_USEC, USEC_PER_SEC);
204
205 *ret = server;
206 server = NULL;
207
208 return 0;
209 }
210
211 int sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event,
212 int 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 DHCPMessage *message, size_t len) {
285 union sockaddr_union dest = {
286 .in.sin_family = AF_INET,
287 .in.sin_port = htobe16(DHCP_PORT_CLIENT),
288 .in.sin_addr.s_addr = destination,
289 };
290 struct iovec iov = {
291 .iov_base = message,
292 .iov_len = len,
293 };
294 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))] = {};
295 struct msghdr msg = {
296 .msg_name = &dest,
297 .msg_namelen = sizeof(dest.in),
298 .msg_iov = &iov,
299 .msg_iovlen = 1,
300 .msg_control = cmsgbuf,
301 .msg_controllen = sizeof(cmsgbuf),
302 };
303 struct cmsghdr *cmsg;
304 struct in_pktinfo *pktinfo;
305 int r;
306
307 assert(server);
308 assert(server->fd > 0);
309 assert(message);
310 assert(len > sizeof(DHCPMessage));
311
312 cmsg = CMSG_FIRSTHDR(&msg);
313 assert(cmsg);
314
315 cmsg->cmsg_level = IPPROTO_IP;
316 cmsg->cmsg_type = IP_PKTINFO;
317 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
318
319 /* we attach source interface and address info to the message
320 rather than binding the socket. This will be mostly useful
321 when we gain support for arbitrary number of server addresses
322 */
323 pktinfo = (struct in_pktinfo*) CMSG_DATA(cmsg);
324 assert(pktinfo);
325
326 pktinfo->ipi_ifindex = server->ifindex;
327 pktinfo->ipi_spec_dst.s_addr = server->address;
328
329 r = sendmsg(server->fd, &msg, 0);
330 if (r < 0)
331 return -errno;
332
333 return 0;
334 }
335
336 static bool requested_broadcast(DHCPRequest *req) {
337 assert(req);
338
339 return req->message->flags & htobe16(0x8000);
340 }
341
342 int dhcp_server_send_packet(sd_dhcp_server *server,
343 DHCPRequest *req, DHCPPacket *packet,
344 int type, size_t optoffset) {
345 be32_t destination = INADDR_ANY;
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 if (type == DHCP_NAK)
391 packet->dhcp.flags = htobe16(0x8000);
392 } else if (req->message->ciaddr && type != DHCP_NAK)
393 destination = req->message->ciaddr;
394
395 if (destination != INADDR_ANY)
396 return dhcp_server_send_udp(server, destination, &packet->dhcp,
397 sizeof(DHCPMessage) + optoffset);
398 else if (requested_broadcast(req) || type == DHCP_NAK)
399 return dhcp_server_send_udp(server, INADDR_BROADCAST,
400 &packet->dhcp,
401 sizeof(DHCPMessage) + optoffset);
402 else
403 /* we cannot send UDP packet to specific MAC address when the
404 address is not yet configured, so must fall back to raw
405 packets */
406 return dhcp_server_send_unicast_raw(server, packet,
407 sizeof(DHCPPacket) + optoffset);
408 }
409
410 static int server_message_init(sd_dhcp_server *server, DHCPPacket **ret,
411 uint8_t type, size_t *_optoffset,
412 DHCPRequest *req) {
413 _cleanup_free_ DHCPPacket *packet = NULL;
414 size_t optoffset = 0;
415 int r;
416
417 assert(server);
418 assert(ret);
419 assert(_optoffset);
420 assert(IN_SET(type, DHCP_OFFER, DHCP_ACK, DHCP_NAK));
421
422 packet = malloc0(sizeof(DHCPPacket) + req->max_optlen);
423 if (!packet)
424 return -ENOMEM;
425
426 r = dhcp_message_init(&packet->dhcp, BOOTREPLY,
427 be32toh(req->message->xid), type, ARPHRD_ETHER,
428 req->max_optlen, &optoffset);
429 if (r < 0)
430 return r;
431
432 packet->dhcp.flags = req->message->flags;
433 packet->dhcp.giaddr = req->message->giaddr;
434 memcpy(&packet->dhcp.chaddr, &req->message->chaddr, ETH_ALEN);
435
436 *_optoffset = optoffset;
437 *ret = packet;
438 packet = NULL;
439
440 return 0;
441 }
442
443 static int server_send_offer(sd_dhcp_server *server, DHCPRequest *req,
444 be32_t address) {
445 _cleanup_free_ DHCPPacket *packet = NULL;
446 size_t offset;
447 be32_t lease_time;
448 int r;
449
450 r = server_message_init(server, &packet, DHCP_OFFER, &offset, req);
451 if (r < 0)
452 return r;
453
454 packet->dhcp.yiaddr = address;
455
456 lease_time = htobe32(req->lifetime);
457 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
458 SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4,
459 &lease_time);
460 if (r < 0)
461 return r;
462
463 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
464 SD_DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
465 if (r < 0)
466 return r;
467
468 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
469 SD_DHCP_OPTION_ROUTER, 4, &server->address);
470 if (r < 0)
471 return r;
472
473 r = dhcp_server_send_packet(server, req, packet, DHCP_OFFER, offset);
474 if (r < 0)
475 return r;
476
477 return 0;
478 }
479
480 static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req,
481 be32_t address) {
482 _cleanup_free_ DHCPPacket *packet = NULL;
483 size_t offset;
484 be32_t lease_time;
485 int r;
486
487 r = server_message_init(server, &packet, DHCP_ACK, &offset, req);
488 if (r < 0)
489 return r;
490
491 packet->dhcp.yiaddr = address;
492
493 lease_time = htobe32(req->lifetime);
494 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
495 SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4,
496 &lease_time);
497 if (r < 0)
498 return r;
499
500 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
501 SD_DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
502 if (r < 0)
503 return r;
504
505 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
506 SD_DHCP_OPTION_ROUTER, 4, &server->address);
507 if (r < 0)
508 return r;
509
510 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, &packet->dhcp,
584 sizeof(DHCPMessage) + optoffset);
585 if (r < 0)
586 return r;
587
588 return 0;
589 }
590
591 static int parse_request(uint8_t code, uint8_t len, const void *option, void *userdata) {
592 DHCPRequest *req = userdata;
593
594 assert(req);
595
596 switch(code) {
597 case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
598 if (len == 4)
599 req->lifetime = be32toh(*(be32_t*)option);
600
601 break;
602 case SD_DHCP_OPTION_REQUESTED_IP_ADDRESS:
603 if (len == 4)
604 req->requested_ip = *(be32_t*)option;
605
606 break;
607 case SD_DHCP_OPTION_SERVER_IDENTIFIER:
608 if (len == 4)
609 req->server_id = *(be32_t*)option;
610
611 break;
612 case SD_DHCP_OPTION_CLIENT_IDENTIFIER:
613 if (len >= 2) {
614 uint8_t *data;
615
616 data = memdup(option, len);
617 if (!data)
618 return -ENOMEM;
619
620 free(req->client_id.data);
621 req->client_id.data = data;
622 req->client_id.length = len;
623 }
624
625 break;
626 case SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE:
627 if (len == 2)
628 req->max_optlen = be16toh(*(be16_t*)option) -
629 - sizeof(DHCPPacket);
630
631 break;
632 }
633
634 return 0;
635 }
636
637 static void dhcp_request_free(DHCPRequest *req) {
638 if (!req)
639 return;
640
641 free(req->client_id.data);
642 free(req);
643 }
644
645 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest*, dhcp_request_free);
646 #define _cleanup_dhcp_request_free_ _cleanup_(dhcp_request_freep)
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_free_ 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 } else
763 next_offer = (next_offer + 1) % server->pool_size;
764 }
765 }
766
767 if (address == INADDR_ANY)
768 /* no free addresses left */
769 return 0;
770
771 r = server_send_offer(server, req, address);
772 if (r < 0) {
773 /* this only fails on critical errors */
774 log_dhcp_server(server, "could not send offer: %s",
775 strerror(-r));
776 return r;
777 } else {
778 log_dhcp_server(server, "OFFER (0x%x)",
779 be32toh(req->message->xid));
780 return DHCP_OFFER;
781 }
782
783 break;
784 }
785 case DHCP_DECLINE:
786 log_dhcp_server(server, "DECLINE (0x%x): %s", be32toh(req->message->xid), strna(error_message));
787
788 /* TODO: make sure we don't offer this address again */
789
790 return 1;
791
792 case DHCP_REQUEST: {
793 be32_t address;
794 bool init_reboot = false;
795 int pool_offset;
796
797 /* see RFC 2131, section 4.3.2 */
798
799 if (req->server_id) {
800 log_dhcp_server(server, "REQUEST (selecting) (0x%x)",
801 be32toh(req->message->xid));
802
803 /* SELECTING */
804 if (req->server_id != server->address)
805 /* client did not pick us */
806 return 0;
807
808 if (req->message->ciaddr)
809 /* this MUST be zero */
810 return 0;
811
812 if (!req->requested_ip)
813 /* this must be filled in with the yiaddr
814 from the chosen OFFER */
815 return 0;
816
817 address = req->requested_ip;
818 } else if (req->requested_ip) {
819 log_dhcp_server(server, "REQUEST (init-reboot) (0x%x)",
820 be32toh(req->message->xid));
821
822 /* INIT-REBOOT */
823 if (req->message->ciaddr)
824 /* this MUST be zero */
825 return 0;
826
827 /* TODO: check more carefully if IP is correct */
828 address = req->requested_ip;
829 init_reboot = true;
830 } else {
831 log_dhcp_server(server, "REQUEST (rebinding/renewing) (0x%x)",
832 be32toh(req->message->xid));
833
834 /* REBINDING / RENEWING */
835 if (!req->message->ciaddr)
836 /* this MUST be filled in with clients IP address */
837 return 0;
838
839 address = req->message->ciaddr;
840 }
841
842 pool_offset = get_pool_offset(server, address);
843
844 /* verify that the requested address is from the pool, and either
845 owned by the current client or free */
846 if (pool_offset >= 0 &&
847 server->bound_leases[pool_offset] == existing_lease) {
848 DHCPLease *lease;
849 usec_t time_now = 0;
850
851 if (!existing_lease) {
852 lease = new0(DHCPLease, 1);
853 lease->address = req->requested_ip;
854 lease->client_id.data = memdup(req->client_id.data,
855 req->client_id.length);
856 if (!lease->client_id.data) {
857 free(lease);
858 return -ENOMEM;
859 }
860 lease->client_id.length = req->client_id.length;
861 memcpy(&lease->chaddr, &req->message->chaddr,
862 ETH_ALEN);
863 lease->gateway = req->message->giaddr;
864 } else
865 lease = existing_lease;
866
867 r = sd_event_now(server->event,
868 clock_boottime_or_monotonic(),
869 &time_now);
870 if (r < 0) {
871 if (!existing_lease)
872 dhcp_lease_free(lease);
873 return r;
874 }
875
876 lease->expiration = req->lifetime * USEC_PER_SEC + time_now;
877
878 r = server_send_ack(server, req, address);
879 if (r < 0) {
880 /* this only fails on critical errors */
881 log_dhcp_server(server, "could not send ack: %s",
882 strerror(-r));
883
884 if (!existing_lease)
885 dhcp_lease_free(lease);
886
887 return r;
888 } else {
889 log_dhcp_server(server, "ACK (0x%x)",
890 be32toh(req->message->xid));
891
892 server->bound_leases[pool_offset] = lease;
893 hashmap_put(server->leases_by_client_id,
894 &lease->client_id, lease);
895
896 return DHCP_ACK;
897 }
898 } else if (init_reboot) {
899 r = server_send_nak(server, req);
900 if (r < 0) {
901 /* this only fails on critical errors */
902 log_dhcp_server(server, "could not send nak: %s",
903 strerror(-r));
904 return r;
905 } else {
906 log_dhcp_server(server, "NAK (0x%x)",
907 be32toh(req->message->xid));
908 return DHCP_NAK;
909 }
910 }
911
912 break;
913 }
914
915 case DHCP_RELEASE: {
916 int pool_offset;
917
918 log_dhcp_server(server, "RELEASE (0x%x)",
919 be32toh(req->message->xid));
920
921 if (!existing_lease)
922 return 0;
923
924 if (existing_lease->address != req->message->ciaddr)
925 return 0;
926
927 pool_offset = get_pool_offset(server, req->message->ciaddr);
928 if (pool_offset < 0)
929 return 0;
930
931 if (server->bound_leases[pool_offset] == existing_lease) {
932 server->bound_leases[pool_offset] = NULL;
933 hashmap_remove(server->leases_by_client_id, existing_lease);
934 dhcp_lease_free(existing_lease);
935
936 return 1;
937 } else
938 return 0;
939 }
940 }
941
942 return 0;
943 }
944
945 static int server_receive_message(sd_event_source *s, int fd,
946 uint32_t revents, void *userdata) {
947 _cleanup_free_ DHCPMessage *message = NULL;
948 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))];
949 sd_dhcp_server *server = userdata;
950 struct iovec iov = {};
951 struct msghdr msg = {
952 .msg_iov = &iov,
953 .msg_iovlen = 1,
954 .msg_control = cmsgbuf,
955 .msg_controllen = sizeof(cmsgbuf),
956 };
957 struct cmsghdr *cmsg;
958 ssize_t buflen, len;
959
960 assert(server);
961
962 buflen = next_datagram_size_fd(fd);
963 if (buflen < 0)
964 return buflen;
965
966 message = malloc(buflen);
967 if (!message)
968 return -ENOMEM;
969
970 iov.iov_base = message;
971 iov.iov_len = buflen;
972
973 len = recvmsg(fd, &msg, 0);
974 if (len < 0) {
975 if (errno == EAGAIN || errno == EINTR)
976 return 0;
977
978 return -errno;
979 } else if ((size_t)len < sizeof(DHCPMessage))
980 return 0;
981
982 CMSG_FOREACH(cmsg, &msg) {
983 if (cmsg->cmsg_level == IPPROTO_IP &&
984 cmsg->cmsg_type == IP_PKTINFO &&
985 cmsg->cmsg_len == CMSG_LEN(sizeof(struct in_pktinfo))) {
986 struct in_pktinfo *info = (struct in_pktinfo*)CMSG_DATA(cmsg);
987
988 /* TODO figure out if this can be done as a filter on
989 * the socket, like for IPv6 */
990 if (server->ifindex != info->ipi_ifindex)
991 return 0;
992
993 break;
994 }
995 }
996
997 return dhcp_server_handle_message(server, message, (size_t)len);
998 }
999
1000 int sd_dhcp_server_start(sd_dhcp_server *server) {
1001 int r;
1002
1003 assert_return(server, -EINVAL);
1004 assert_return(server->event, -EINVAL);
1005 assert_return(!server->receive_message, -EBUSY);
1006 assert_return(server->fd_raw == -1, -EBUSY);
1007 assert_return(server->fd == -1, -EBUSY);
1008 assert_return(server->address != htobe32(INADDR_ANY), -EUNATCH);
1009
1010 r = socket(AF_PACKET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
1011 if (r < 0) {
1012 r = -errno;
1013 sd_dhcp_server_stop(server);
1014 return r;
1015 }
1016 server->fd_raw = r;
1017
1018 r = dhcp_network_bind_udp_socket(INADDR_ANY, DHCP_PORT_SERVER);
1019 if (r < 0) {
1020 sd_dhcp_server_stop(server);
1021 return r;
1022 }
1023 server->fd = r;
1024
1025 r = sd_event_add_io(server->event, &server->receive_message,
1026 server->fd, EPOLLIN,
1027 server_receive_message, server);
1028 if (r < 0) {
1029 sd_dhcp_server_stop(server);
1030 return r;
1031 }
1032
1033 r = sd_event_source_set_priority(server->receive_message,
1034 server->event_priority);
1035 if (r < 0) {
1036 sd_dhcp_server_stop(server);
1037 return r;
1038 }
1039
1040 log_dhcp_server(server, "STARTED");
1041
1042 return 0;
1043 }
1044
1045 int sd_dhcp_server_forcerenew(sd_dhcp_server *server) {
1046 unsigned i;
1047 int r = 0;
1048
1049 assert_return(server, -EINVAL);
1050 assert(server->bound_leases);
1051
1052 for (i = 0; i < server->pool_size; i++) {
1053 DHCPLease *lease = server->bound_leases[i];
1054
1055 if (!lease || lease == &server->invalid_lease)
1056 continue;
1057
1058 r = server_send_forcerenew(server, lease->address,
1059 lease->gateway,
1060 lease->chaddr);
1061 if (r < 0)
1062 return r;
1063 else
1064 log_dhcp_server(server, "FORCERENEW");
1065 }
1066
1067 return r;
1068 }
1069
1070 int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *tz) {
1071 int r;
1072
1073 assert_return(server, -EINVAL);
1074 assert_return(timezone_is_valid(tz), -EINVAL);
1075
1076 if (streq_ptr(tz, server->timezone))
1077 return 0;
1078
1079 r = free_and_strdup(&server->timezone, tz);
1080 if (r < 0)
1081 return r;
1082
1083 return 1;
1084 }
1085
1086 int sd_dhcp_server_set_max_lease_time(sd_dhcp_server *server, uint32_t t) {
1087 assert_return(server, -EINVAL);
1088
1089 if (t == server->max_lease_time)
1090 return 0;
1091
1092 server->max_lease_time = t;
1093 return 1;
1094 }
1095
1096 int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint32_t t) {
1097 assert_return(server, -EINVAL);
1098
1099 if (t == server->default_lease_time)
1100 return 0;
1101
1102 server->default_lease_time = t;
1103 return 1;
1104 }
1105
1106 int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr dns[], unsigned n) {
1107 assert_return(server, -EINVAL);
1108 assert_return(dns || n <= 0, -EINVAL);
1109
1110 if (server->n_dns == n &&
1111 memcmp(server->dns, dns, sizeof(struct in_addr) * n) == 0)
1112 return 0;
1113
1114 if (n <= 0) {
1115 server->dns = mfree(server->dns);
1116 server->n_dns = 0;
1117 } else {
1118 struct in_addr *c;
1119
1120 c = newdup(struct in_addr, dns, n);
1121 if (!c)
1122 return -ENOMEM;
1123
1124 free(server->dns);
1125 server->dns = c;
1126 server->n_dns = n;
1127 }
1128
1129 return 1;
1130 }
1131
1132 int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr ntp[], unsigned n) {
1133 assert_return(server, -EINVAL);
1134 assert_return(ntp || n <= 0, -EINVAL);
1135
1136 if (server->n_ntp == n &&
1137 memcmp(server->ntp, ntp, sizeof(struct in_addr) * n) == 0)
1138 return 0;
1139
1140 if (n <= 0) {
1141 server->ntp = mfree(server->ntp);
1142 server->n_ntp = 0;
1143 } else {
1144 struct in_addr *c;
1145
1146 c = newdup(struct in_addr, ntp, n);
1147 if (!c)
1148 return -ENOMEM;
1149
1150 free(server->ntp);
1151 server->ntp = c;
1152 server->n_ntp = n;
1153 }
1154
1155 return 1;
1156 }