]> git.proxmox.com Git - systemd.git/blame - src/libsystemd-network/sd-dhcp-server.c
Merge tag 'upstream/229'
[systemd.git] / src / libsystemd-network / sd-dhcp-server.c
CommitLineData
e842803a
MB
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>
e842803a 22
e842803a 23#include "sd-dhcp-server.h"
db2df898
MP
24
25#include "alloc-util.h"
e842803a 26#include "dhcp-internal.h"
db2df898
MP
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"
e842803a 32
d9dfd233
MP
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 */
40int 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;
e842803a 44
e842803a
MB
45 assert_return(server, -EINVAL);
46 assert_return(address, -EINVAL);
d9dfd233
MP
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;
e842803a
MB
79
80 server->bound_leases = new0(DHCPLease*, size);
81 if (!server->bound_leases)
82 return -ENOMEM;
83
d9dfd233 84 server->pool_offset = offset;
e842803a
MB
85 server->pool_size = size;
86
e842803a 87 server->address = address->s_addr;
d9dfd233
MP
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;
e842803a
MB
93
94 return 0;
95}
96
db2df898 97int sd_dhcp_server_is_running(sd_dhcp_server *server) {
13d276d0 98 assert_return(server, false);
e842803a
MB
99
100 return !!server->receive_message;
101}
102
103sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server) {
d9dfd233
MP
104
105 if (!server)
106 return NULL;
107
108 assert(server->n_ref >= 1);
109 server->n_ref++;
e842803a
MB
110
111 return server;
112}
113
6300502b 114void client_id_hash_func(const void *p, struct siphash *state) {
e842803a
MB
115 const DHCPClientId *id = p;
116
117 assert(id);
118 assert(id->length);
119 assert(id->data);
120
6300502b
MP
121 siphash24_compress(&id->length, sizeof(id->length), state);
122 siphash24_compress(id->data, id->length, state);
e842803a
MB
123}
124
125int 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
5eef597e
MP
140static const struct hash_ops client_id_hash_ops = {
141 .hash = client_id_hash_func,
142 .compare = client_id_compare_func
143};
144
e842803a
MB
145static void dhcp_lease_free(DHCPLease *lease) {
146 if (!lease)
147 return;
148
149 free(lease->client_id.data);
150 free(lease);
151}
152
153sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) {
154 DHCPLease *lease;
155
156 if (!server)
157 return NULL;
158
d9dfd233
MP
159 assert(server->n_ref >= 1);
160 server->n_ref--;
161
162 if (server->n_ref > 0)
e842803a
MB
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
d9dfd233
MP
171 free(server->timezone);
172 free(server->dns);
173 free(server->ntp);
174
e842803a
MB
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
185int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
4c89c718 186 _cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
e842803a
MB
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
d9dfd233 195 server->n_ref = 1;
e842803a
MB
196 server->fd_raw = -1;
197 server->fd = -1;
198 server->address = htobe32(INADDR_ANY);
5eef597e 199 server->netmask = htobe32(INADDR_ANY);
d9dfd233 200 server->ifindex = ifindex;
5eef597e 201 server->leases_by_client_id = hashmap_new(&client_id_hash_ops);
d9dfd233
MP
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);
e842803a
MB
204
205 *ret = server;
206 server = NULL;
207
208 return 0;
209}
210
5eef597e
MP
211int sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event,
212 int priority) {
e842803a
MB
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
231int 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
239sd_event *sd_dhcp_server_get_event(sd_dhcp_server *server) {
240 assert_return(server, NULL);
241
242 return server->event;
243}
244
245int 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
5eef597e
MP
259static int dhcp_server_send_unicast_raw(sd_dhcp_server *server,
260 DHCPPacket *packet, size_t len) {
e842803a
MB
261 union sockaddr_union link = {
262 .ll.sll_family = AF_PACKET,
263 .ll.sll_protocol = htons(ETH_P_IP),
d9dfd233 264 .ll.sll_ifindex = server->ifindex,
e842803a
MB
265 .ll.sll_halen = ETH_ALEN,
266 };
e842803a
MB
267
268 assert(server);
d9dfd233 269 assert(server->ifindex > 0);
e842803a
MB
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,
5eef597e
MP
277 packet->dhcp.yiaddr,
278 DHCP_PORT_CLIENT, len);
e842803a 279
d9dfd233 280 return dhcp_network_send_raw_socket(server->fd_raw, &link, packet, len);
e842803a
MB
281}
282
283static 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
d9dfd233 326 pktinfo->ipi_ifindex = server->ifindex;
e842803a
MB
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
336static bool requested_broadcast(DHCPRequest *req) {
337 assert(req);
338
339 return req->message->flags & htobe16(0x8000);
340}
341
342int 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,
4c89c718 355 SD_DHCP_OPTION_SERVER_IDENTIFIER,
e842803a
MB
356 4, &server->address);
357 if (r < 0)
358 return r;
359
360 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
4c89c718 361 SD_DHCP_OPTION_END, 0, NULL);
e842803a
MB
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)
5eef597e
MP
399 return dhcp_server_send_udp(server, INADDR_BROADCAST,
400 &packet->dhcp,
e842803a
MB
401 sizeof(DHCPMessage) + optoffset);
402 else
5eef597e
MP
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 */
e842803a
MB
406 return dhcp_server_send_unicast_raw(server, packet,
407 sizeof(DHCPPacket) + optoffset);
408}
409
410static int server_message_init(sd_dhcp_server *server, DHCPPacket **ret,
5eef597e
MP
411 uint8_t type, size_t *_optoffset,
412 DHCPRequest *req) {
e842803a 413 _cleanup_free_ DHCPPacket *packet = NULL;
5eef597e 414 size_t optoffset = 0;
e842803a
MB
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
5eef597e
MP
426 r = dhcp_message_init(&packet->dhcp, BOOTREPLY,
427 be32toh(req->message->xid), type, ARPHRD_ETHER,
428 req->max_optlen, &optoffset);
e842803a
MB
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
5eef597e
MP
443static int server_send_offer(sd_dhcp_server *server, DHCPRequest *req,
444 be32_t address) {
e842803a
MB
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,
4c89c718 458 SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4,
5eef597e
MP
459 &lease_time);
460 if (r < 0)
461 return r;
462
463 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
4c89c718 464 SD_DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
5eef597e
MP
465 if (r < 0)
466 return r;
467
468 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
4c89c718 469 SD_DHCP_OPTION_ROUTER, 4, &server->address);
e842803a
MB
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
5eef597e
MP
480static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req,
481 be32_t address) {
e842803a
MB
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,
4c89c718 495 SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4,
5eef597e
MP
496 &lease_time);
497 if (r < 0)
498 return r;
499
500 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
4c89c718 501 SD_DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
5eef597e
MP
502 if (r < 0)
503 return r;
504
505 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
4c89c718 506 SD_DHCP_OPTION_ROUTER, 4, &server->address);
e842803a
MB
507 if (r < 0)
508 return r;
509
d9dfd233
MP
510 if (server->n_dns > 0) {
511 r = dhcp_option_append(
512 &packet->dhcp, req->max_optlen, &offset, 0,
4c89c718 513 SD_DHCP_OPTION_DOMAIN_NAME_SERVER,
d9dfd233
MP
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,
4c89c718 522 SD_DHCP_OPTION_NTP_SERVER,
d9dfd233
MP
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,
4c89c718 531 SD_DHCP_OPTION_NEW_TZDB_TIMEZONE,
d9dfd233
MP
532 strlen(server->timezone), server->timezone);
533 if (r < 0)
534 return r;
535 }
536
e842803a
MB
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
544static 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
d9dfd233 553 return dhcp_server_send_packet(server, req, packet, DHCP_NAK, offset);
e842803a
MB
554}
555
5eef597e
MP
556static 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,
4c89c718 577 &optoffset, 0, SD_DHCP_OPTION_END, 0, NULL);
5eef597e
MP
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
d9dfd233
MP
591static int parse_request(uint8_t code, uint8_t len, const void *option, void *userdata) {
592 DHCPRequest *req = userdata;
e842803a
MB
593
594 assert(req);
595
596 switch(code) {
4c89c718 597 case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
e842803a
MB
598 if (len == 4)
599 req->lifetime = be32toh(*(be32_t*)option);
600
601 break;
4c89c718 602 case SD_DHCP_OPTION_REQUESTED_IP_ADDRESS:
e842803a
MB
603 if (len == 4)
604 req->requested_ip = *(be32_t*)option;
605
606 break;
4c89c718 607 case SD_DHCP_OPTION_SERVER_IDENTIFIER:
e842803a
MB
608 if (len == 4)
609 req->server_id = *(be32_t*)option;
610
611 break;
4c89c718 612 case SD_DHCP_OPTION_CLIENT_IDENTIFIER:
e842803a
MB
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;
4c89c718 626 case SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE:
e842803a
MB
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
637static void dhcp_request_free(DHCPRequest *req) {
638 if (!req)
639 return;
640
641 free(req->client_id.data);
642 free(req);
643}
644
645DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest*, dhcp_request_free);
646#define _cleanup_dhcp_request_free_ _cleanup_(dhcp_request_freep)
647
d9dfd233 648static int ensure_sane_request(sd_dhcp_server *server, DHCPRequest *req, DHCPMessage *message) {
e842803a
MB
649 assert(req);
650 assert(message);
651
652 req->message = message;
653
e735f4d4 654 /* set client id based on MAC address if client did not send an explicit
5eef597e 655 one */
e842803a 656 if (!req->client_id.data) {
d9dfd233 657 void *data;
e842803a 658
d9dfd233 659 data = malloc0(ETH_ALEN + 1);
e842803a
MB
660 if (!data)
661 return -ENOMEM;
662
d9dfd233
MP
663 ((uint8_t*) data)[0] = 0x01;
664 memcpy((uint8_t*) data + 1, &message->chaddr, ETH_ALEN);
665
e842803a
MB
666 req->client_id.length = ETH_ALEN + 1;
667 req->client_id.data = data;
e842803a
MB
668 }
669
670 if (req->max_optlen < DHCP_MIN_OPTIONS_SIZE)
671 req->max_optlen = DHCP_MIN_OPTIONS_SIZE;
672
d9dfd233
MP
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;
e842803a
MB
678
679 return 0;
680}
681
682static 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
d9dfd233
MP
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;
e842803a 691
d9dfd233 692 return be32toh(requested_ip & ~server->netmask) - server->pool_offset;
e842803a
MB
693}
694
d9dfd233
MP
695#define HASH_KEY SD_ID128_MAKE(0d,1d,fe,bd,f1,24,bd,b3,47,f1,dd,6e,73,21,93,30)
696
e842803a
MB
697int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
698 size_t length) {
699 _cleanup_dhcp_request_free_ DHCPRequest *req = NULL;
4c89c718 700 _cleanup_free_ char *error_message = NULL;
e842803a
MB
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
4c89c718 716 type = dhcp_option_parse(message, length, parse_request, req, &error_message);
e842803a
MB
717 if (type < 0)
718 return 0;
719
d9dfd233 720 r = ensure_sane_request(server, req, message);
e842803a
MB
721 if (r < 0)
722 /* this only fails on critical errors */
723 return r;
724
5eef597e
MP
725 existing_lease = hashmap_get(server->leases_by_client_id,
726 &req->client_id);
e842803a
MB
727
728 switch(type) {
d9dfd233
MP
729
730 case DHCP_DISCOVER: {
e842803a
MB
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 {
6300502b
MP
745 struct siphash state;
746 uint64_t hash;
d9dfd233
MP
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
6300502b
MP
753 siphash24_init(&state, HASH_KEY.bytes);
754 client_id_hash_func(&req->client_id, &state);
db2df898 755 hash = htole64(siphash24_finalize(&state));
6300502b 756 next_offer = hash % server->pool_size;
d9dfd233 757
e842803a 758 for (i = 0; i < server->pool_size; i++) {
d9dfd233
MP
759 if (!server->bound_leases[next_offer]) {
760 address = server->subnet | htobe32(server->pool_offset + next_offer);
e842803a
MB
761 break;
762 } else
d9dfd233 763 next_offer = (next_offer + 1) % server->pool_size;
e842803a
MB
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:
4c89c718 786 log_dhcp_server(server, "DECLINE (0x%x): %s", be32toh(req->message->xid), strna(error_message));
e842803a
MB
787
788 /* TODO: make sure we don't offer this address again */
789
790 return 1;
791
d9dfd233 792 case DHCP_REQUEST: {
e842803a
MB
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;
e3bff60a 849 usec_t time_now = 0;
e842803a
MB
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;
5eef597e
MP
861 memcpy(&lease->chaddr, &req->message->chaddr,
862 ETH_ALEN);
863 lease->gateway = req->message->giaddr;
e842803a
MB
864 } else
865 lease = existing_lease;
866
5eef597e
MP
867 r = sd_event_now(server->event,
868 clock_boottime_or_monotonic(),
869 &time_now);
13d276d0
MP
870 if (r < 0) {
871 if (!existing_lease)
872 dhcp_lease_free(lease);
873 return r;
874 }
875
e842803a
MB
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;
5eef597e
MP
893 hashmap_put(server->leases_by_client_id,
894 &lease->client_id, lease);
e842803a
MB
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 }
d9dfd233 914
e842803a
MB
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
945static 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;
d9dfd233 958 int buflen = 0, len;
e842803a
MB
959
960 assert(server);
961
d9dfd233
MP
962 if (ioctl(fd, FIONREAD, &buflen) < 0)
963 return -errno;
4c89c718 964 else if (buflen < 0)
e842803a
MB
965 return -EIO;
966
4c89c718 967 message = malloc(buflen);
e842803a
MB
968 if (!message)
969 return -ENOMEM;
970
971 iov.iov_base = message;
972 iov.iov_len = buflen;
973
974 len = recvmsg(fd, &msg, 0);
4c89c718
MP
975 if (len < 0) {
976 if (errno == EAGAIN || errno == EINTR)
977 return 0;
978
979 return -errno;
980 } else if ((size_t)len < sizeof(DHCPMessage))
e842803a
MB
981 return 0;
982
86f210e9 983 CMSG_FOREACH(cmsg, &msg) {
e842803a
MB
984 if (cmsg->cmsg_level == IPPROTO_IP &&
985 cmsg->cmsg_type == IP_PKTINFO &&
986 cmsg->cmsg_len == CMSG_LEN(sizeof(struct in_pktinfo))) {
987 struct in_pktinfo *info = (struct in_pktinfo*)CMSG_DATA(cmsg);
988
5eef597e
MP
989 /* TODO figure out if this can be done as a filter on
990 * the socket, like for IPv6 */
d9dfd233 991 if (server->ifindex != info->ipi_ifindex)
e842803a
MB
992 return 0;
993
994 break;
995 }
996 }
997
998 return dhcp_server_handle_message(server, message, (size_t)len);
999}
1000
1001int sd_dhcp_server_start(sd_dhcp_server *server) {
1002 int r;
1003
1004 assert_return(server, -EINVAL);
1005 assert_return(server->event, -EINVAL);
1006 assert_return(!server->receive_message, -EBUSY);
1007 assert_return(server->fd_raw == -1, -EBUSY);
1008 assert_return(server->fd == -1, -EBUSY);
1009 assert_return(server->address != htobe32(INADDR_ANY), -EUNATCH);
1010
1011 r = socket(AF_PACKET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
1012 if (r < 0) {
1013 r = -errno;
1014 sd_dhcp_server_stop(server);
1015 return r;
1016 }
1017 server->fd_raw = r;
1018
1019 r = dhcp_network_bind_udp_socket(INADDR_ANY, DHCP_PORT_SERVER);
1020 if (r < 0) {
1021 sd_dhcp_server_stop(server);
1022 return r;
1023 }
1024 server->fd = r;
1025
1026 r = sd_event_add_io(server->event, &server->receive_message,
1027 server->fd, EPOLLIN,
1028 server_receive_message, server);
1029 if (r < 0) {
1030 sd_dhcp_server_stop(server);
1031 return r;
1032 }
1033
1034 r = sd_event_source_set_priority(server->receive_message,
1035 server->event_priority);
1036 if (r < 0) {
1037 sd_dhcp_server_stop(server);
1038 return r;
1039 }
1040
1041 log_dhcp_server(server, "STARTED");
1042
1043 return 0;
1044}
5eef597e
MP
1045
1046int sd_dhcp_server_forcerenew(sd_dhcp_server *server) {
1047 unsigned i;
1048 int r = 0;
1049
1050 assert_return(server, -EINVAL);
1051 assert(server->bound_leases);
1052
1053 for (i = 0; i < server->pool_size; i++) {
1054 DHCPLease *lease = server->bound_leases[i];
1055
d9dfd233 1056 if (!lease || lease == &server->invalid_lease)
5eef597e
MP
1057 continue;
1058
1059 r = server_send_forcerenew(server, lease->address,
1060 lease->gateway,
1061 lease->chaddr);
1062 if (r < 0)
1063 return r;
1064 else
1065 log_dhcp_server(server, "FORCERENEW");
1066 }
1067
1068 return r;
1069}
d9dfd233
MP
1070
1071int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *tz) {
1072 int r;
1073
1074 assert_return(server, -EINVAL);
1075 assert_return(timezone_is_valid(tz), -EINVAL);
1076
1077 if (streq_ptr(tz, server->timezone))
1078 return 0;
1079
1080 r = free_and_strdup(&server->timezone, tz);
1081 if (r < 0)
1082 return r;
1083
1084 return 1;
1085}
1086
1087int sd_dhcp_server_set_max_lease_time(sd_dhcp_server *server, uint32_t t) {
1088 assert_return(server, -EINVAL);
1089
1090 if (t == server->max_lease_time)
1091 return 0;
1092
1093 server->max_lease_time = t;
1094 return 1;
1095}
1096
1097int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint32_t t) {
1098 assert_return(server, -EINVAL);
1099
1100 if (t == server->default_lease_time)
1101 return 0;
1102
1103 server->default_lease_time = t;
1104 return 1;
1105}
1106
1107int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr dns[], unsigned n) {
1108 assert_return(server, -EINVAL);
1109 assert_return(dns || n <= 0, -EINVAL);
1110
1111 if (server->n_dns == n &&
1112 memcmp(server->dns, dns, sizeof(struct in_addr) * n) == 0)
1113 return 0;
1114
1115 if (n <= 0) {
1116 server->dns = mfree(server->dns);
1117 server->n_dns = 0;
1118 } else {
1119 struct in_addr *c;
1120
1121 c = newdup(struct in_addr, dns, n);
1122 if (!c)
1123 return -ENOMEM;
1124
1125 free(server->dns);
1126 server->dns = c;
1127 server->n_dns = n;
1128 }
1129
1130 return 1;
1131}
1132
1133int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr ntp[], unsigned n) {
1134 assert_return(server, -EINVAL);
1135 assert_return(ntp || n <= 0, -EINVAL);
1136
1137 if (server->n_ntp == n &&
1138 memcmp(server->ntp, ntp, sizeof(struct in_addr) * n) == 0)
1139 return 0;
1140
1141 if (n <= 0) {
1142 server->ntp = mfree(server->ntp);
1143 server->n_ntp = 0;
1144 } else {
1145 struct in_addr *c;
1146
1147 c = newdup(struct in_addr, ntp, n);
1148 if (!c)
1149 return -ENOMEM;
1150
1151 free(server->ntp);
1152 server->ntp = c;
1153 server->n_ntp = n;
1154 }
1155
1156 return 1;
1157}