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