]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-dhcp-server.c
login: respect install_sysconfdir_samples in meson file
[thirdparty/systemd.git] / src / libsystemd-network / sd-dhcp-server.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /***
3 Copyright © 2013 Intel Corporation. All rights reserved.
4 ***/
5
6 #include <net/if_arp.h>
7 #include <sys/ioctl.h>
8
9 #include "sd-dhcp-server.h"
10 #include "sd-id128.h"
11
12 #include "alloc-util.h"
13 #include "dhcp-internal.h"
14 #include "dhcp-server-internal.h"
15 #include "fd-util.h"
16 #include "in-addr-util.h"
17 #include "io-util.h"
18 #include "network-common.h"
19 #include "ordered-set.h"
20 #include "siphash24.h"
21 #include "string-util.h"
22 #include "unaligned.h"
23
24 #define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR
25 #define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12)
26
27 static DHCPLease *dhcp_lease_free(DHCPLease *lease) {
28 if (!lease)
29 return NULL;
30
31 free(lease->client_id.data);
32 return mfree(lease);
33 }
34
35 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPLease*, dhcp_lease_free);
36
37 /* configures the server's address and subnet, and optionally the pool's size and offset into the subnet
38 * the whole pool must fit into the subnet, and may not contain the first (any) nor last (broadcast) address
39 * moreover, the server's own address may be in the pool, and is in that case reserved in order not to
40 * accidentally hand it out */
41 int sd_dhcp_server_configure_pool(
42 sd_dhcp_server *server,
43 const struct in_addr *address,
44 unsigned char prefixlen,
45 uint32_t offset,
46 uint32_t size) {
47
48 struct in_addr netmask_addr;
49 be32_t netmask;
50 uint32_t server_off, broadcast_off, size_max;
51
52 assert_return(server, -EINVAL);
53 assert_return(address, -EINVAL);
54 assert_return(address->s_addr != INADDR_ANY, -EINVAL);
55 assert_return(prefixlen <= 32, -ERANGE);
56
57 assert_se(in4_addr_prefixlen_to_netmask(&netmask_addr, prefixlen));
58 netmask = netmask_addr.s_addr;
59
60 server_off = be32toh(address->s_addr & ~netmask);
61 broadcast_off = be32toh(~netmask);
62
63 /* the server address cannot be the subnet address */
64 assert_return(server_off != 0, -ERANGE);
65
66 /* nor the broadcast address */
67 assert_return(server_off != broadcast_off, -ERANGE);
68
69 /* 0 offset means we should set a default, we skip the first (subnet) address
70 and take the next one */
71 if (offset == 0)
72 offset = 1;
73
74 size_max = (broadcast_off + 1) /* the number of addresses in the subnet */
75 - offset /* exclude the addresses before the offset */
76 - 1; /* exclude the last (broadcast) address */
77
78 /* The pool must contain at least one address */
79 assert_return(size_max >= 1, -ERANGE);
80
81 if (size != 0)
82 assert_return(size <= size_max, -ERANGE);
83 else
84 size = size_max;
85
86 if (server->address != address->s_addr || server->netmask != netmask || server->pool_size != size || server->pool_offset != offset) {
87
88 free(server->bound_leases);
89 server->bound_leases = new0(DHCPLease*, size);
90 if (!server->bound_leases)
91 return -ENOMEM;
92
93 server->pool_offset = offset;
94 server->pool_size = size;
95
96 server->address = address->s_addr;
97 server->netmask = netmask;
98 server->subnet = address->s_addr & netmask;
99
100 if (server_off >= offset && server_off - offset < size)
101 server->bound_leases[server_off - offset] = &server->invalid_lease;
102
103 /* Drop any leases associated with the old address range */
104 hashmap_clear(server->leases_by_client_id);
105
106 if (server->callback)
107 server->callback(server, SD_DHCP_SERVER_EVENT_LEASE_CHANGED, server->callback_userdata);
108 }
109
110 return 0;
111 }
112
113 int sd_dhcp_server_is_running(sd_dhcp_server *server) {
114 assert_return(server, false);
115
116 return !!server->receive_message;
117 }
118
119 int sd_dhcp_server_is_in_relay_mode(sd_dhcp_server *server) {
120 assert_return(server, -EINVAL);
121
122 return in4_addr_is_set(&server->relay_target);
123 }
124
125 void client_id_hash_func(const DHCPClientId *id, struct siphash *state) {
126 assert(id);
127 assert(id->length);
128 assert(id->data);
129
130 siphash24_compress(&id->length, sizeof(id->length), state);
131 siphash24_compress(id->data, id->length, state);
132 }
133
134 int client_id_compare_func(const DHCPClientId *a, const DHCPClientId *b) {
135 int r;
136
137 assert(!a->length || a->data);
138 assert(!b->length || b->data);
139
140 r = CMP(a->length, b->length);
141 if (r != 0)
142 return r;
143
144 return memcmp(a->data, b->data, a->length);
145 }
146
147 DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(dhcp_lease_hash_ops, DHCPClientId, client_id_hash_func, client_id_compare_func,
148 DHCPLease, dhcp_lease_free);
149
150 static sd_dhcp_server *dhcp_server_free(sd_dhcp_server *server) {
151 assert(server);
152
153 log_dhcp_server(server, "UNREF");
154
155 sd_dhcp_server_stop(server);
156
157 sd_event_unref(server->event);
158
159 free(server->timezone);
160
161 for (sd_dhcp_lease_server_type_t i = 0; i < _SD_DHCP_LEASE_SERVER_TYPE_MAX; i++)
162 free(server->servers[i].addr);
163
164 hashmap_free(server->leases_by_client_id);
165 hashmap_free(server->static_leases_by_client_id);
166
167 ordered_set_free(server->extra_options);
168 ordered_set_free(server->vendor_options);
169
170 free(server->agent_circuit_id);
171 free(server->agent_remote_id);
172
173 free(server->bound_leases);
174
175 free(server->ifname);
176 return mfree(server);
177 }
178
179 DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_server, sd_dhcp_server, dhcp_server_free);
180
181 int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
182 _cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
183
184 assert_return(ret, -EINVAL);
185 assert_return(ifindex > 0, -EINVAL);
186
187 server = new(sd_dhcp_server, 1);
188 if (!server)
189 return -ENOMEM;
190
191 *server = (sd_dhcp_server) {
192 .n_ref = 1,
193 .fd_raw = -1,
194 .fd = -1,
195 .fd_broadcast = -1,
196 .address = htobe32(INADDR_ANY),
197 .netmask = htobe32(INADDR_ANY),
198 .ifindex = ifindex,
199 .bind_to_interface = true,
200 .default_lease_time = DIV_ROUND_UP(DHCP_DEFAULT_LEASE_TIME_USEC, USEC_PER_SEC),
201 .max_lease_time = DIV_ROUND_UP(DHCP_MAX_LEASE_TIME_USEC, USEC_PER_SEC),
202 };
203
204 server->leases_by_client_id = hashmap_new(&dhcp_lease_hash_ops);
205 if (!server->leases_by_client_id)
206 return -ENOMEM;
207 server->static_leases_by_client_id = hashmap_new(&dhcp_lease_hash_ops);
208 if (!server->static_leases_by_client_id)
209 return -ENOMEM;
210
211 *ret = TAKE_PTR(server);
212
213 return 0;
214 }
215
216 int sd_dhcp_server_set_ifname(sd_dhcp_server *server, const char *ifname) {
217 assert_return(server, -EINVAL);
218 assert_return(ifname, -EINVAL);
219
220 if (!ifname_valid_full(ifname, IFNAME_VALID_ALTERNATIVE))
221 return -EINVAL;
222
223 return free_and_strdup(&server->ifname, ifname);
224 }
225
226 const char *sd_dhcp_server_get_ifname(sd_dhcp_server *server) {
227 if (!server)
228 return NULL;
229
230 return get_ifname(server->ifindex, &server->ifname);
231 }
232
233 int sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event, int64_t priority) {
234 int r;
235
236 assert_return(server, -EINVAL);
237 assert_return(!server->event, -EBUSY);
238
239 if (event)
240 server->event = sd_event_ref(event);
241 else {
242 r = sd_event_default(&server->event);
243 if (r < 0)
244 return r;
245 }
246
247 server->event_priority = priority;
248
249 return 0;
250 }
251
252 int sd_dhcp_server_detach_event(sd_dhcp_server *server) {
253 assert_return(server, -EINVAL);
254
255 server->event = sd_event_unref(server->event);
256
257 return 0;
258 }
259
260 sd_event *sd_dhcp_server_get_event(sd_dhcp_server *server) {
261 assert_return(server, NULL);
262
263 return server->event;
264 }
265
266 int sd_dhcp_server_stop(sd_dhcp_server *server) {
267 if (!server)
268 return 0;
269
270 server->receive_message = sd_event_source_unref(server->receive_message);
271 server->receive_broadcast = sd_event_source_unref(server->receive_broadcast);
272
273 server->fd_raw = safe_close(server->fd_raw);
274 server->fd = safe_close(server->fd);
275 server->fd_broadcast = safe_close(server->fd_broadcast);
276
277 log_dhcp_server(server, "STOPPED");
278
279 return 0;
280 }
281
282 static int dhcp_server_send_unicast_raw(sd_dhcp_server *server,
283 DHCPPacket *packet, size_t len) {
284 union sockaddr_union link = {
285 .ll.sll_family = AF_PACKET,
286 .ll.sll_protocol = htobe16(ETH_P_IP),
287 .ll.sll_ifindex = server->ifindex,
288 .ll.sll_halen = ETH_ALEN,
289 };
290
291 assert(server);
292 assert(server->ifindex > 0);
293 assert(server->address);
294 assert(packet);
295 assert(len > sizeof(DHCPPacket));
296
297 memcpy(&link.ll.sll_addr, &packet->dhcp.chaddr, ETH_ALEN);
298
299 dhcp_packet_append_ip_headers(packet, server->address, DHCP_PORT_SERVER,
300 packet->dhcp.yiaddr,
301 DHCP_PORT_CLIENT, len, -1);
302
303 return dhcp_network_send_raw_socket(server->fd_raw, &link, packet, len);
304 }
305
306 static int dhcp_server_send_udp(sd_dhcp_server *server, be32_t destination,
307 uint16_t destination_port,
308 DHCPMessage *message, size_t len) {
309 union sockaddr_union dest = {
310 .in.sin_family = AF_INET,
311 .in.sin_port = htobe16(destination_port),
312 .in.sin_addr.s_addr = destination,
313 };
314 struct iovec iov = {
315 .iov_base = message,
316 .iov_len = len,
317 };
318 CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct in_pktinfo))) control = {};
319 struct msghdr msg = {
320 .msg_name = &dest,
321 .msg_namelen = sizeof(dest.in),
322 .msg_iov = &iov,
323 .msg_iovlen = 1,
324 };
325 struct cmsghdr *cmsg;
326 struct in_pktinfo *pktinfo;
327
328 assert(server);
329 assert(server->fd >= 0);
330 assert(message);
331 assert(len > sizeof(DHCPMessage));
332
333 if (server->bind_to_interface) {
334 msg.msg_control = &control;
335 msg.msg_controllen = sizeof(control);
336
337 cmsg = CMSG_FIRSTHDR(&msg);
338 assert(cmsg);
339
340 cmsg->cmsg_level = IPPROTO_IP;
341 cmsg->cmsg_type = IP_PKTINFO;
342 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
343
344 /* we attach source interface and address info to the message
345 rather than binding the socket. This will be mostly useful
346 when we gain support for arbitrary number of server addresses
347 */
348 pktinfo = (struct in_pktinfo*) CMSG_DATA(cmsg);
349 assert(pktinfo);
350
351 pktinfo->ipi_ifindex = server->ifindex;
352 pktinfo->ipi_spec_dst.s_addr = server->address;
353 }
354
355 if (sendmsg(server->fd, &msg, 0) < 0)
356 return -errno;
357
358 return 0;
359 }
360
361 static bool requested_broadcast(DHCPMessage *message) {
362 assert(message);
363 return message->flags & htobe16(0x8000);
364 }
365
366 static int dhcp_server_send(sd_dhcp_server *server, be32_t destination, uint16_t destination_port,
367 DHCPPacket *packet, size_t optoffset, bool l2_broadcast) {
368 if (destination != INADDR_ANY)
369 return dhcp_server_send_udp(server, destination,
370 destination_port, &packet->dhcp,
371 sizeof(DHCPMessage) + optoffset);
372 else if (l2_broadcast)
373 return dhcp_server_send_udp(server, INADDR_BROADCAST,
374 destination_port, &packet->dhcp,
375 sizeof(DHCPMessage) + optoffset);
376 else
377 /* we cannot send UDP packet to specific MAC address when the
378 address is not yet configured, so must fall back to raw
379 packets */
380 return dhcp_server_send_unicast_raw(server, packet,
381 sizeof(DHCPPacket) + optoffset);
382 }
383
384 int dhcp_server_send_packet(sd_dhcp_server *server,
385 DHCPRequest *req, DHCPPacket *packet,
386 int type, size_t optoffset) {
387 be32_t destination = INADDR_ANY;
388 uint16_t destination_port = DHCP_PORT_CLIENT;
389 int r;
390
391 assert(server);
392 assert(req);
393 assert(req->max_optlen);
394 assert(req->message);
395 assert(optoffset <= req->max_optlen);
396 assert(packet);
397
398 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
399 SD_DHCP_OPTION_SERVER_IDENTIFIER,
400 4, &server->address);
401 if (r < 0)
402 return r;
403
404 if (req->agent_info_option) {
405 size_t opt_full_length = *(req->agent_info_option + 1) + 2;
406 /* there must be space left for SD_DHCP_OPTION_END */
407 if (optoffset + opt_full_length < req->max_optlen) {
408 memcpy(packet->dhcp.options + optoffset, req->agent_info_option, opt_full_length);
409 optoffset += opt_full_length;
410 }
411 }
412
413 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0,
414 SD_DHCP_OPTION_END, 0, NULL);
415 if (r < 0)
416 return r;
417
418 /* RFC 2131 Section 4.1
419
420 If the ’giaddr’ field in a DHCP message from a client is non-zero,
421 the server sends any return messages to the ’DHCP server’ port on the
422 BOOTP relay agent whose address appears in ’giaddr’. If the ’giaddr’
423 field is zero and the ’ciaddr’ field is nonzero, then the server
424 unicasts DHCPOFFER and DHCPACK messages to the address in ’ciaddr’.
425 If ’giaddr’ is zero and ’ciaddr’ is zero, and the broadcast bit is
426 set, then the server broadcasts DHCPOFFER and DHCPACK messages to
427 0xffffffff. If the broadcast bit is not set and ’giaddr’ is zero and
428 ’ciaddr’ is zero, then the server unicasts DHCPOFFER and DHCPACK
429 messages to the client’s hardware address and ’yiaddr’ address. In
430 all cases, when ’giaddr’ is zero, the server broadcasts any DHCPNAK
431 messages to 0xffffffff.
432
433 Section 4.3.2
434
435 If ’giaddr’ is set in the DHCPREQUEST message, the client is on a
436 different subnet. The server MUST set the broadcast bit in the
437 DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
438 client, because the client may not have a correct network address
439 or subnet mask, and the client may not be answering ARP requests.
440 */
441 if (req->message->giaddr) {
442 destination = req->message->giaddr;
443 destination_port = DHCP_PORT_SERVER;
444 if (type == DHCP_NAK)
445 packet->dhcp.flags = htobe16(0x8000);
446 } else if (req->message->ciaddr && type != DHCP_NAK)
447 destination = req->message->ciaddr;
448
449 bool l2_broadcast = requested_broadcast(req->message) || type == DHCP_NAK;
450 return dhcp_server_send(server, destination, destination_port, packet, optoffset, l2_broadcast);
451 }
452
453 static int server_message_init(sd_dhcp_server *server, DHCPPacket **ret,
454 uint8_t type, size_t *_optoffset,
455 DHCPRequest *req) {
456 _cleanup_free_ DHCPPacket *packet = NULL;
457 size_t optoffset = 0;
458 int r;
459
460 assert(server);
461 assert(ret);
462 assert(_optoffset);
463 assert(IN_SET(type, DHCP_OFFER, DHCP_ACK, DHCP_NAK));
464
465 packet = malloc0(sizeof(DHCPPacket) + req->max_optlen);
466 if (!packet)
467 return -ENOMEM;
468
469 r = dhcp_message_init(&packet->dhcp, BOOTREPLY,
470 be32toh(req->message->xid), type, ARPHRD_ETHER,
471 req->max_optlen, &optoffset);
472 if (r < 0)
473 return r;
474
475 packet->dhcp.flags = req->message->flags;
476 packet->dhcp.giaddr = req->message->giaddr;
477 memcpy(&packet->dhcp.chaddr, &req->message->chaddr, ETH_ALEN);
478
479 *_optoffset = optoffset;
480 *ret = TAKE_PTR(packet);
481
482 return 0;
483 }
484
485 static int server_send_offer_or_ack(
486 sd_dhcp_server *server,
487 DHCPRequest *req,
488 be32_t address,
489 uint8_t type) {
490
491 _cleanup_free_ DHCPPacket *packet = NULL;
492 sd_dhcp_option *j;
493 be32_t lease_time;
494 size_t offset;
495 int r;
496
497 assert(server);
498 assert(req);
499 assert(IN_SET(type, DHCP_OFFER, DHCP_ACK));
500
501 r = server_message_init(server, &packet, type, &offset, req);
502 if (r < 0)
503 return r;
504
505 packet->dhcp.yiaddr = address;
506
507 lease_time = htobe32(req->lifetime);
508 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
509 SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4,
510 &lease_time);
511 if (r < 0)
512 return r;
513
514 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
515 SD_DHCP_OPTION_SUBNET_MASK, 4, &server->netmask);
516 if (r < 0)
517 return r;
518
519 if (server->emit_router) {
520 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
521 SD_DHCP_OPTION_ROUTER, 4, &server->address);
522 if (r < 0)
523 return r;
524 }
525
526 if (type == DHCP_ACK) {
527 static const uint8_t option_map[_SD_DHCP_LEASE_SERVER_TYPE_MAX] = {
528 [SD_DHCP_LEASE_DNS] = SD_DHCP_OPTION_DOMAIN_NAME_SERVER,
529 [SD_DHCP_LEASE_NTP] = SD_DHCP_OPTION_NTP_SERVER,
530 [SD_DHCP_LEASE_SIP] = SD_DHCP_OPTION_SIP_SERVER,
531 [SD_DHCP_LEASE_POP3] = SD_DHCP_OPTION_POP3_SERVER,
532 [SD_DHCP_LEASE_SMTP] = SD_DHCP_OPTION_SMTP_SERVER,
533 [SD_DHCP_LEASE_LPR] = SD_DHCP_OPTION_LPR_SERVER,
534 };
535
536 for (sd_dhcp_lease_server_type_t k = 0; k < _SD_DHCP_LEASE_SERVER_TYPE_MAX; k++) {
537 if (server->servers[k].size <= 0)
538 continue;
539
540 r = dhcp_option_append(
541 &packet->dhcp, req->max_optlen, &offset, 0,
542 option_map[k],
543 sizeof(struct in_addr) * server->servers[k].size,
544 server->servers[k].addr);
545 if (r < 0)
546 return r;
547 }
548
549
550 if (server->timezone) {
551 r = dhcp_option_append(
552 &packet->dhcp, req->max_optlen, &offset, 0,
553 SD_DHCP_OPTION_NEW_TZDB_TIMEZONE,
554 strlen(server->timezone), server->timezone);
555 if (r < 0)
556 return r;
557 }
558 }
559
560 ORDERED_SET_FOREACH(j, server->extra_options) {
561 r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
562 j->option, j->length, j->data);
563 if (r < 0)
564 return r;
565 }
566
567 if (!ordered_set_isempty(server->vendor_options)) {
568 r = dhcp_option_append(
569 &packet->dhcp, req->max_optlen, &offset, 0,
570 SD_DHCP_OPTION_VENDOR_SPECIFIC,
571 ordered_set_size(server->vendor_options), server->vendor_options);
572 if (r < 0)
573 return r;
574 }
575
576 r = dhcp_server_send_packet(server, req, packet, type, offset);
577 if (r < 0)
578 return r;
579
580 return 0;
581 }
582
583 static int server_send_nak(sd_dhcp_server *server, DHCPRequest *req) {
584 _cleanup_free_ DHCPPacket *packet = NULL;
585 size_t offset;
586 int r;
587
588 r = server_message_init(server, &packet, DHCP_NAK, &offset, req);
589 if (r < 0)
590 return r;
591
592 return dhcp_server_send_packet(server, req, packet, DHCP_NAK, offset);
593 }
594
595 static int server_send_forcerenew(sd_dhcp_server *server, be32_t address,
596 be32_t gateway, const uint8_t chaddr[]) {
597 _cleanup_free_ DHCPPacket *packet = NULL;
598 size_t optoffset = 0;
599 int r;
600
601 assert(server);
602 assert(address != INADDR_ANY);
603 assert(chaddr);
604
605 packet = malloc0(sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE);
606 if (!packet)
607 return -ENOMEM;
608
609 r = dhcp_message_init(&packet->dhcp, BOOTREPLY, 0,
610 DHCP_FORCERENEW, ARPHRD_ETHER,
611 DHCP_MIN_OPTIONS_SIZE, &optoffset);
612 if (r < 0)
613 return r;
614
615 r = dhcp_option_append(&packet->dhcp, DHCP_MIN_OPTIONS_SIZE,
616 &optoffset, 0, SD_DHCP_OPTION_END, 0, NULL);
617 if (r < 0)
618 return r;
619
620 memcpy(&packet->dhcp.chaddr, chaddr, ETH_ALEN);
621
622 r = dhcp_server_send_udp(server, address, DHCP_PORT_CLIENT,
623 &packet->dhcp,
624 sizeof(DHCPMessage) + optoffset);
625 if (r < 0)
626 return r;
627
628 return 0;
629 }
630
631 static int parse_request(uint8_t code, uint8_t len, const void *option, void *userdata) {
632 DHCPRequest *req = userdata;
633
634 assert(req);
635
636 switch(code) {
637 case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
638 if (len == 4)
639 req->lifetime = unaligned_read_be32(option);
640
641 break;
642 case SD_DHCP_OPTION_REQUESTED_IP_ADDRESS:
643 if (len == 4)
644 memcpy(&req->requested_ip, option, sizeof(be32_t));
645
646 break;
647 case SD_DHCP_OPTION_SERVER_IDENTIFIER:
648 if (len == 4)
649 memcpy(&req->server_id, option, sizeof(be32_t));
650
651 break;
652 case SD_DHCP_OPTION_CLIENT_IDENTIFIER:
653 if (len >= 2) {
654 uint8_t *data;
655
656 data = memdup(option, len);
657 if (!data)
658 return -ENOMEM;
659
660 free(req->client_id.data);
661 req->client_id.data = data;
662 req->client_id.length = len;
663 }
664
665 break;
666 case SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE:
667
668 if (len == 2 && unaligned_read_be16(option) >= sizeof(DHCPPacket))
669 req->max_optlen = unaligned_read_be16(option) - sizeof(DHCPPacket);
670
671 break;
672 case SD_DHCP_OPTION_RELAY_AGENT_INFORMATION:
673 req->agent_info_option = (uint8_t*)option - 2;
674
675 break;
676 }
677
678 return 0;
679 }
680
681 static DHCPRequest* dhcp_request_free(DHCPRequest *req) {
682 if (!req)
683 return NULL;
684
685 free(req->client_id.data);
686 return mfree(req);
687 }
688
689 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest*, dhcp_request_free);
690
691 static int ensure_sane_request(sd_dhcp_server *server, DHCPRequest *req, DHCPMessage *message) {
692 assert(req);
693 assert(message);
694
695 req->message = message;
696
697 /* set client id based on MAC address if client did not send an explicit
698 one */
699 if (!req->client_id.data) {
700 void *data;
701
702 data = malloc0(ETH_ALEN + 1);
703 if (!data)
704 return -ENOMEM;
705
706 ((uint8_t*) data)[0] = 0x01;
707 memcpy((uint8_t*) data + 1, &message->chaddr, ETH_ALEN);
708
709 req->client_id.length = ETH_ALEN + 1;
710 req->client_id.data = data;
711 }
712
713 if (req->max_optlen < DHCP_MIN_OPTIONS_SIZE)
714 req->max_optlen = DHCP_MIN_OPTIONS_SIZE;
715
716 if (req->lifetime <= 0)
717 req->lifetime = MAX(1ULL, server->default_lease_time);
718
719 if (server->max_lease_time > 0 && req->lifetime > server->max_lease_time)
720 req->lifetime = server->max_lease_time;
721
722 return 0;
723 }
724
725 static int get_pool_offset(sd_dhcp_server *server, be32_t requested_ip) {
726 assert(server);
727
728 if (!server->pool_size)
729 return -EINVAL;
730
731 if (be32toh(requested_ip) < (be32toh(server->subnet) | server->pool_offset) ||
732 be32toh(requested_ip) >= (be32toh(server->subnet) | (server->pool_offset + server->pool_size)))
733 return -ERANGE;
734
735 return be32toh(requested_ip & ~server->netmask) - server->pool_offset;
736 }
737
738 static int append_agent_information_option(sd_dhcp_server *server, DHCPMessage *message, size_t opt_length, size_t size) {
739 int r;
740 size_t offset;
741
742 assert(server);
743 assert(message);
744
745 r = dhcp_option_find_option(message->options, opt_length, SD_DHCP_OPTION_END, &offset);
746 if (r < 0)
747 return r;
748
749 r = dhcp_option_append(message, size, &offset, 0, SD_DHCP_OPTION_RELAY_AGENT_INFORMATION, 0, server);
750 if (r < 0)
751 return r;
752
753 r = dhcp_option_append(message, size, &offset, 0, SD_DHCP_OPTION_END, 0, NULL);
754 if (r < 0)
755 return r;
756 return offset;
757 }
758
759 static int dhcp_server_relay_message(sd_dhcp_server *server, DHCPMessage *message, size_t opt_length, size_t buflen) {
760 _cleanup_free_ DHCPPacket *packet = NULL;
761 int r;
762
763 assert(server);
764 assert(message);
765 assert(sd_dhcp_server_is_in_relay_mode(server));
766
767 if (message->op == BOOTREQUEST) {
768 log_dhcp_server(server, "(relay agent) BOOTREQUEST (0x%x)", be32toh(message->xid));
769 if (message->hops >= 16)
770 return -ETIME;
771 message->hops++;
772
773 /* https://tools.ietf.org/html/rfc1542#section-4.1.1 */
774 if (message->giaddr == 0)
775 message->giaddr = server->address;
776
777 if (server->agent_circuit_id || server->agent_remote_id) {
778 r = append_agent_information_option(server, message, opt_length, buflen - sizeof(DHCPMessage));
779 if (r < 0)
780 return log_dhcp_server_errno(server, r, "could not append relay option: %m");
781 opt_length = r;
782 }
783
784 return dhcp_server_send_udp(server, server->relay_target.s_addr, DHCP_PORT_SERVER, message, sizeof(DHCPMessage) + opt_length);
785 } else if (message->op == BOOTREPLY) {
786 log_dhcp_server(server, "(relay agent) BOOTREPLY (0x%x)", be32toh(message->xid));
787 if (message->giaddr != server->address)
788 return log_dhcp_server_errno(server, SYNTHETIC_ERRNO(EBADMSG),
789 "(relay agent) BOOTREPLY giaddr mismatch, discarding");
790
791 int message_type = dhcp_option_parse(message, sizeof(DHCPMessage) + opt_length, NULL, NULL, NULL);
792 if (message_type < 0)
793 return message_type;
794
795 packet = malloc0(sizeof(DHCPPacket) + opt_length);
796 if (!packet)
797 return -ENOMEM;
798 memcpy(&packet->dhcp, message, sizeof(DHCPMessage) + opt_length);
799
800 r = dhcp_option_remove_option(packet->dhcp.options, opt_length, SD_DHCP_OPTION_RELAY_AGENT_INFORMATION);
801 if (r > 0)
802 opt_length = r;
803
804 bool l2_broadcast = requested_broadcast(message) || message_type == DHCP_NAK;
805 const be32_t destination = message_type == DHCP_NAK ? INADDR_ANY : message->ciaddr;
806 return dhcp_server_send(server, destination, DHCP_PORT_CLIENT, packet, opt_length, l2_broadcast);
807 }
808 return -EBADMSG;
809 }
810
811 static int prepare_new_lease(
812 DHCPLease **ret_lease,
813 be32_t address,
814 const DHCPClientId *client_id,
815 const uint8_t chaddr[static ETH_ALEN],
816 be32_t gateway,
817 usec_t expiration) {
818
819 _cleanup_(dhcp_lease_freep) DHCPLease *lease = NULL;
820
821 lease = new(DHCPLease, 1);
822 if (!lease)
823 return -ENOMEM;
824
825 *lease = (DHCPLease) {
826 .address = address,
827 .client_id.length = client_id->length,
828 .gateway = gateway,
829 .expiration = expiration,
830 };
831 lease->client_id.data = memdup(client_id->data, client_id->length);
832 if (!lease->client_id.data)
833 return -ENOMEM;
834
835 memcpy(&lease->chaddr, chaddr, ETH_ALEN);
836
837 *ret_lease = TAKE_PTR(lease);
838
839 return 0;
840 }
841
842 static bool static_leases_have_address(sd_dhcp_server *server, be32_t address) {
843 DHCPLease *s;
844
845 assert(server);
846
847 HASHMAP_FOREACH(s, server->static_leases_by_client_id)
848 if (s->address == address)
849 return true;
850
851 return false;
852 }
853
854 #define HASH_KEY SD_ID128_MAKE(0d,1d,fe,bd,f1,24,bd,b3,47,f1,dd,6e,73,21,93,30)
855
856 int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, size_t length) {
857 _cleanup_(dhcp_request_freep) DHCPRequest *req = NULL;
858 _cleanup_free_ char *error_message = NULL;
859 DHCPLease *existing_lease, *static_lease;
860 int type, r;
861
862 assert(server);
863 assert(message);
864
865 if (message->op != BOOTREQUEST ||
866 message->htype != ARPHRD_ETHER ||
867 message->hlen != ETHER_ADDR_LEN)
868 return 0;
869
870 req = new0(DHCPRequest, 1);
871 if (!req)
872 return -ENOMEM;
873
874 type = dhcp_option_parse(message, length, parse_request, req, &error_message);
875 if (type < 0)
876 return 0;
877
878 r = ensure_sane_request(server, req, message);
879 if (r < 0)
880 /* this only fails on critical errors */
881 return r;
882
883 existing_lease = hashmap_get(server->leases_by_client_id, &req->client_id);
884 static_lease = hashmap_get(server->static_leases_by_client_id, &req->client_id);
885
886 switch(type) {
887
888 case DHCP_DISCOVER: {
889 be32_t address = INADDR_ANY;
890 unsigned i;
891
892 log_dhcp_server(server, "DISCOVER (0x%x)", be32toh(req->message->xid));
893
894 if (!server->pool_size)
895 /* no pool allocated */
896 return 0;
897
898 /* for now pick a random free address from the pool */
899 if (static_lease)
900 address = static_lease->address;
901 else if (existing_lease)
902 address = existing_lease->address;
903 else {
904 struct siphash state;
905 uint64_t hash;
906 uint32_t next_offer;
907
908 /* even with no persistence of leases, we try to offer the same client
909 the same IP address. we do this by using the hash of the client id
910 as the offset into the pool of leases when finding the next free one */
911
912 siphash24_init(&state, HASH_KEY.bytes);
913 client_id_hash_func(&req->client_id, &state);
914 hash = htole64(siphash24_finalize(&state));
915 next_offer = hash % server->pool_size;
916
917 for (i = 0; i < server->pool_size; i++) {
918 if (!server->bound_leases[next_offer]) {
919 be32_t tmp = server->subnet | htobe32(server->pool_offset + next_offer);
920 if (!static_leases_have_address(server, tmp)) {
921 address = tmp;
922 break;
923 }
924 }
925
926 next_offer = (next_offer + 1) % server->pool_size;
927 }
928 }
929
930 if (address == INADDR_ANY)
931 /* no free addresses left */
932 return 0;
933
934 r = server_send_offer_or_ack(server, req, address, DHCP_OFFER);
935 if (r < 0)
936 /* this only fails on critical errors */
937 return log_dhcp_server_errno(server, r, "Could not send offer: %m");
938
939 log_dhcp_server(server, "OFFER (0x%x)", be32toh(req->message->xid));
940 return DHCP_OFFER;
941 }
942 case DHCP_DECLINE:
943 log_dhcp_server(server, "DECLINE (0x%x): %s", be32toh(req->message->xid), strna(error_message));
944
945 /* TODO: make sure we don't offer this address again */
946
947 return 1;
948
949 case DHCP_REQUEST: {
950 be32_t address;
951 bool init_reboot = false;
952 int pool_offset;
953
954 /* see RFC 2131, section 4.3.2 */
955
956 if (req->server_id) {
957 log_dhcp_server(server, "REQUEST (selecting) (0x%x)",
958 be32toh(req->message->xid));
959
960 /* SELECTING */
961 if (req->server_id != server->address)
962 /* client did not pick us */
963 return 0;
964
965 if (req->message->ciaddr)
966 /* this MUST be zero */
967 return 0;
968
969 if (!req->requested_ip)
970 /* this must be filled in with the yiaddr
971 from the chosen OFFER */
972 return 0;
973
974 address = req->requested_ip;
975 } else if (req->requested_ip) {
976 log_dhcp_server(server, "REQUEST (init-reboot) (0x%x)",
977 be32toh(req->message->xid));
978
979 /* INIT-REBOOT */
980 if (req->message->ciaddr)
981 /* this MUST be zero */
982 return 0;
983
984 /* TODO: check more carefully if IP is correct */
985 address = req->requested_ip;
986 init_reboot = true;
987 } else {
988 log_dhcp_server(server, "REQUEST (rebinding/renewing) (0x%x)",
989 be32toh(req->message->xid));
990
991 /* REBINDING / RENEWING */
992 if (!req->message->ciaddr)
993 /* this MUST be filled in with clients IP address */
994 return 0;
995
996 address = req->message->ciaddr;
997 }
998
999 pool_offset = get_pool_offset(server, address);
1000
1001 /* verify that the requested address is from the pool, and either
1002 owned by the current client or free */
1003 if (pool_offset >= 0 && static_lease) {
1004 _cleanup_(dhcp_lease_freep) DHCPLease *lease = NULL, *old_lease = NULL;
1005 usec_t time_now, expiration;
1006
1007 r = sd_event_now(server->event, clock_boottime_or_monotonic(), &time_now);
1008 if (r < 0)
1009 return r;
1010
1011 expiration = usec_add(req->lifetime * USEC_PER_SEC, time_now);
1012
1013 r = prepare_new_lease(&lease, static_lease->address, &req->client_id,
1014 req->message->chaddr, req->message->giaddr, expiration);
1015 if (r < 0)
1016 return r;
1017
1018 r = server_send_offer_or_ack(server, req, address, DHCP_ACK);
1019 if (r < 0)
1020 /* this only fails on critical errors */
1021 return log_dhcp_server_errno(server, r, "Could not send ack: %m");
1022
1023 log_dhcp_server(server, "ACK (0x%x)", be32toh(req->message->xid));
1024
1025 server->bound_leases[pool_offset] = lease;
1026
1027 old_lease = hashmap_remove(server->leases_by_client_id, &lease->client_id);
1028 r = hashmap_put(server->leases_by_client_id, &lease->client_id, lease);
1029 if (r < 0)
1030 return log_dhcp_server_errno(server, r, "Could not save lease: %m");
1031 TAKE_PTR(lease);
1032
1033 if (server->callback)
1034 server->callback(server, SD_DHCP_SERVER_EVENT_LEASE_CHANGED, server->callback_userdata);
1035
1036 return DHCP_ACK;
1037
1038 } else if (pool_offset >= 0 && server->bound_leases[pool_offset] == existing_lease) {
1039 _cleanup_(dhcp_lease_freep) DHCPLease *new_lease = NULL;
1040 usec_t time_now, expiration;
1041 DHCPLease *lease;
1042
1043 r = sd_event_now(server->event, clock_boottime_or_monotonic(), &time_now);
1044 if (r < 0)
1045 return r;
1046
1047 expiration = usec_add(req->lifetime * USEC_PER_SEC, time_now);
1048
1049 if (!existing_lease) {
1050 r = prepare_new_lease(&new_lease, address, &req->client_id,
1051 req->message->chaddr, req->message->giaddr, expiration);
1052 if (r < 0)
1053 return r;
1054
1055 lease = new_lease;
1056 } else {
1057 existing_lease->expiration = expiration;
1058 lease = existing_lease;
1059 }
1060
1061 r = server_send_offer_or_ack(server, req, address, DHCP_ACK);
1062 if (r < 0)
1063 /* this only fails on critical errors */
1064 return log_dhcp_server_errno(server, r, "Could not send ack: %m");
1065
1066 log_dhcp_server(server, "ACK (0x%x)", be32toh(req->message->xid));
1067
1068 server->bound_leases[pool_offset] = lease;
1069 r = hashmap_put(server->leases_by_client_id, &lease->client_id, lease);
1070 if (r < 0)
1071 return log_dhcp_server_errno(server, r, "Could not save lease: %m");
1072 TAKE_PTR(new_lease);
1073
1074 if (server->callback)
1075 server->callback(server, SD_DHCP_SERVER_EVENT_LEASE_CHANGED, server->callback_userdata);
1076
1077 return DHCP_ACK;
1078
1079 } else if (init_reboot) {
1080 r = server_send_nak(server, req);
1081 if (r < 0)
1082 /* this only fails on critical errors */
1083 return log_dhcp_server_errno(server, r, "Could not send nak: %m");
1084
1085 log_dhcp_server(server, "NAK (0x%x)", be32toh(req->message->xid));
1086 return DHCP_NAK;
1087 }
1088
1089 break;
1090 }
1091
1092 case DHCP_RELEASE: {
1093 int pool_offset;
1094
1095 log_dhcp_server(server, "RELEASE (0x%x)",
1096 be32toh(req->message->xid));
1097
1098 if (!existing_lease)
1099 return 0;
1100
1101 if (existing_lease->address != req->message->ciaddr)
1102 return 0;
1103
1104 pool_offset = get_pool_offset(server, req->message->ciaddr);
1105 if (pool_offset < 0)
1106 return 0;
1107
1108 if (server->bound_leases[pool_offset] == existing_lease) {
1109 server->bound_leases[pool_offset] = NULL;
1110 hashmap_remove(server->leases_by_client_id, existing_lease);
1111 dhcp_lease_free(existing_lease);
1112
1113 if (server->callback)
1114 server->callback(server, SD_DHCP_SERVER_EVENT_LEASE_CHANGED, server->callback_userdata);
1115 }
1116
1117 return 0;
1118 }}
1119
1120 return 0;
1121 }
1122
1123 static size_t relay_agent_information_length(const char* agent_circuit_id, const char* agent_remote_id) {
1124 size_t sum = 0;
1125 if (agent_circuit_id)
1126 sum += 2 + strlen(agent_circuit_id);
1127 if (agent_remote_id)
1128 sum += 2 + strlen(agent_remote_id);
1129 return sum;
1130 }
1131
1132 static int server_receive_message(sd_event_source *s, int fd,
1133 uint32_t revents, void *userdata) {
1134 _cleanup_free_ DHCPMessage *message = NULL;
1135 CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct in_pktinfo))) control;
1136 sd_dhcp_server *server = userdata;
1137 struct iovec iov = {};
1138 struct msghdr msg = {
1139 .msg_iov = &iov,
1140 .msg_iovlen = 1,
1141 .msg_control = &control,
1142 .msg_controllen = sizeof(control),
1143 };
1144 struct cmsghdr *cmsg;
1145 ssize_t datagram_size, len;
1146 int r;
1147
1148 assert(server);
1149
1150 datagram_size = next_datagram_size_fd(fd);
1151 if (datagram_size < 0)
1152 return datagram_size;
1153
1154 size_t buflen = datagram_size;
1155 if (sd_dhcp_server_is_in_relay_mode(server))
1156 /* Preallocate the additional size for DHCP Relay Agent Information Option if needed */
1157 buflen += relay_agent_information_length(server->agent_circuit_id, server->agent_remote_id) + 2;
1158
1159 message = malloc(buflen);
1160 if (!message)
1161 return -ENOMEM;
1162
1163 iov = IOVEC_MAKE(message, datagram_size);
1164
1165 len = recvmsg_safe(fd, &msg, 0);
1166 if (IN_SET(len, -EAGAIN, -EINTR))
1167 return 0;
1168 if (len < 0)
1169 return len;
1170 if ((size_t) len < sizeof(DHCPMessage))
1171 return 0;
1172
1173 CMSG_FOREACH(cmsg, &msg) {
1174 if (cmsg->cmsg_level == IPPROTO_IP &&
1175 cmsg->cmsg_type == IP_PKTINFO &&
1176 cmsg->cmsg_len == CMSG_LEN(sizeof(struct in_pktinfo))) {
1177 struct in_pktinfo *info = (struct in_pktinfo*)CMSG_DATA(cmsg);
1178
1179 /* TODO figure out if this can be done as a filter on
1180 * the socket, like for IPv6 */
1181 if (server->ifindex != info->ipi_ifindex)
1182 return 0;
1183
1184 break;
1185 }
1186 }
1187
1188 if (sd_dhcp_server_is_in_relay_mode(server)) {
1189 r = dhcp_server_relay_message(server, message, len - sizeof(DHCPMessage), buflen);
1190 if (r < 0)
1191 log_dhcp_server_errno(server, r, "Couldn't relay message: %m");
1192 } else {
1193 r = dhcp_server_handle_message(server, message, (size_t) len);
1194 if (r < 0)
1195 log_dhcp_server_errno(server, r, "Couldn't process incoming message: %m");
1196 }
1197 return 0;
1198 }
1199
1200 int sd_dhcp_server_start(sd_dhcp_server *server) {
1201 int r;
1202
1203 assert_return(server, -EINVAL);
1204 assert_return(server->event, -EINVAL);
1205
1206 if (sd_dhcp_server_is_running(server))
1207 return 0;
1208
1209 assert_return(!server->receive_message, -EBUSY);
1210 assert_return(server->fd_raw < 0, -EBUSY);
1211 assert_return(server->fd < 0, -EBUSY);
1212 assert_return(server->address != htobe32(INADDR_ANY), -EUNATCH);
1213
1214 r = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
1215 if (r < 0) {
1216 r = -errno;
1217 goto on_error;
1218 }
1219 server->fd_raw = r;
1220
1221 if (server->bind_to_interface)
1222 r = dhcp_network_bind_udp_socket(server->ifindex, INADDR_ANY, DHCP_PORT_SERVER, -1);
1223 else
1224 r = dhcp_network_bind_udp_socket(0, server->address, DHCP_PORT_SERVER, -1);
1225 if (r < 0)
1226 goto on_error;
1227 server->fd = r;
1228
1229 r = sd_event_add_io(server->event, &server->receive_message,
1230 server->fd, EPOLLIN,
1231 server_receive_message, server);
1232 if (r < 0)
1233 goto on_error;
1234
1235 r = sd_event_source_set_priority(server->receive_message,
1236 server->event_priority);
1237 if (r < 0)
1238 goto on_error;
1239
1240 if (!server->bind_to_interface) {
1241 r = dhcp_network_bind_udp_socket(server->ifindex, INADDR_BROADCAST, DHCP_PORT_SERVER, -1);
1242 if (r < 0)
1243 goto on_error;
1244
1245 server->fd_broadcast = r;
1246
1247 r = sd_event_add_io(server->event, &server->receive_broadcast,
1248 server->fd_broadcast, EPOLLIN,
1249 server_receive_message, server);
1250 if (r < 0)
1251 goto on_error;
1252
1253 r = sd_event_source_set_priority(server->receive_broadcast,
1254 server->event_priority);
1255 if (r < 0)
1256 goto on_error;
1257 }
1258
1259 log_dhcp_server(server, "STARTED");
1260
1261 return 0;
1262
1263 on_error:
1264 sd_dhcp_server_stop(server);
1265 return r;
1266 }
1267
1268 int sd_dhcp_server_forcerenew(sd_dhcp_server *server) {
1269 int r = 0;
1270
1271 assert_return(server, -EINVAL);
1272 assert(server->bound_leases);
1273
1274 for (uint32_t i = 0; i < server->pool_size; i++) {
1275 DHCPLease *lease = server->bound_leases[i];
1276
1277 if (!lease || lease == &server->invalid_lease)
1278 continue;
1279
1280 r = server_send_forcerenew(server, lease->address,
1281 lease->gateway,
1282 lease->chaddr);
1283 if (r < 0)
1284 return r;
1285
1286 log_dhcp_server(server, "FORCERENEW");
1287 }
1288
1289 return r;
1290 }
1291
1292 int sd_dhcp_server_set_bind_to_interface(sd_dhcp_server *server, int enabled) {
1293 assert_return(server, -EINVAL);
1294 assert_return(!sd_dhcp_server_is_running(server), -EBUSY);
1295
1296 if (!!enabled == server->bind_to_interface)
1297 return 0;
1298
1299 server->bind_to_interface = enabled;
1300
1301 return 1;
1302 }
1303
1304 int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *tz) {
1305 int r;
1306
1307 assert_return(server, -EINVAL);
1308 assert_return(timezone_is_valid(tz, LOG_DEBUG), -EINVAL);
1309
1310 if (streq_ptr(tz, server->timezone))
1311 return 0;
1312
1313 r = free_and_strdup(&server->timezone, tz);
1314 if (r < 0)
1315 return r;
1316
1317 return 1;
1318 }
1319
1320 int sd_dhcp_server_set_max_lease_time(sd_dhcp_server *server, uint32_t t) {
1321 assert_return(server, -EINVAL);
1322
1323 if (t == server->max_lease_time)
1324 return 0;
1325
1326 server->max_lease_time = t;
1327 return 1;
1328 }
1329
1330 int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint32_t t) {
1331 assert_return(server, -EINVAL);
1332
1333 if (t == server->default_lease_time)
1334 return 0;
1335
1336 server->default_lease_time = t;
1337 return 1;
1338 }
1339
1340 int sd_dhcp_server_set_servers(
1341 sd_dhcp_server *server,
1342 sd_dhcp_lease_server_type_t what,
1343 const struct in_addr addresses[],
1344 size_t n_addresses) {
1345
1346 struct in_addr *c = NULL;
1347
1348 assert_return(server, -EINVAL);
1349 assert_return(addresses || n_addresses == 0, -EINVAL);
1350 assert_return(what >= 0, -EINVAL);
1351 assert_return(what < _SD_DHCP_LEASE_SERVER_TYPE_MAX, -EINVAL);
1352
1353 if (server->servers[what].size == n_addresses &&
1354 memcmp(server->servers[what].addr, addresses, sizeof(struct in_addr) * n_addresses) == 0)
1355 return 0;
1356
1357 if (n_addresses > 0) {
1358 c = newdup(struct in_addr, addresses, n_addresses);
1359 if (!c)
1360 return -ENOMEM;
1361 }
1362
1363 free(server->servers[what].addr);
1364 server->servers[what].addr = c;
1365 server->servers[what].size = n_addresses;
1366 return 1;
1367 }
1368
1369 int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr dns[], size_t n) {
1370 return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_DNS, dns, n);
1371 }
1372 int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr ntp[], size_t n) {
1373 return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_NTP, ntp, n);
1374 }
1375 int sd_dhcp_server_set_sip(sd_dhcp_server *server, const struct in_addr sip[], size_t n) {
1376 return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_SIP, sip, n);
1377 }
1378 int sd_dhcp_server_set_pop3(sd_dhcp_server *server, const struct in_addr pop3[], size_t n) {
1379 return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_POP3, pop3, n);
1380 }
1381 int sd_dhcp_server_set_smtp(sd_dhcp_server *server, const struct in_addr smtp[], size_t n) {
1382 return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_SMTP, smtp, n);
1383 }
1384 int sd_dhcp_server_set_lpr(sd_dhcp_server *server, const struct in_addr lpr[], size_t n) {
1385 return sd_dhcp_server_set_servers(server, SD_DHCP_LEASE_LPR, lpr, n);
1386 }
1387
1388 int sd_dhcp_server_set_emit_router(sd_dhcp_server *server, int enabled) {
1389 assert_return(server, -EINVAL);
1390
1391 if (enabled == server->emit_router)
1392 return 0;
1393
1394 server->emit_router = enabled;
1395
1396 return 1;
1397 }
1398
1399 int sd_dhcp_server_add_option(sd_dhcp_server *server, sd_dhcp_option *v) {
1400 int r;
1401
1402 assert_return(server, -EINVAL);
1403 assert_return(v, -EINVAL);
1404
1405 r = ordered_set_ensure_put(&server->extra_options, &dhcp_option_hash_ops, v);
1406 if (r < 0)
1407 return r;
1408
1409 sd_dhcp_option_ref(v);
1410 return 0;
1411 }
1412
1413 int sd_dhcp_server_add_vendor_option(sd_dhcp_server *server, sd_dhcp_option *v) {
1414 int r;
1415
1416 assert_return(server, -EINVAL);
1417 assert_return(v, -EINVAL);
1418
1419 r = ordered_set_ensure_put(&server->vendor_options, &dhcp_option_hash_ops, v);
1420 if (r < 0)
1421 return r;
1422
1423 sd_dhcp_option_ref(v);
1424
1425 return 1;
1426 }
1427
1428 int sd_dhcp_server_set_callback(sd_dhcp_server *server, sd_dhcp_server_callback_t cb, void *userdata) {
1429 assert_return(server, -EINVAL);
1430
1431 server->callback = cb;
1432 server->callback_userdata = userdata;
1433
1434 return 0;
1435 }
1436
1437 int sd_dhcp_server_set_relay_target(sd_dhcp_server *server, const struct in_addr *address) {
1438 assert_return(server, -EINVAL);
1439 assert_return(!sd_dhcp_server_is_running(server), -EBUSY);
1440
1441 if (memcmp(address, &server->relay_target, sizeof(struct in_addr)) == 0)
1442 return 0;
1443
1444 server->relay_target = *address;
1445 return 1;
1446 }
1447
1448 int sd_dhcp_server_set_relay_agent_information(
1449 sd_dhcp_server *server,
1450 const char *agent_circuit_id,
1451 const char *agent_remote_id) {
1452 _cleanup_free_ char *circuit_id_dup = NULL, *remote_id_dup = NULL;
1453
1454 assert_return(server, -EINVAL);
1455
1456 if (relay_agent_information_length(agent_circuit_id, agent_remote_id) > UINT8_MAX)
1457 return -ENOBUFS;
1458
1459 if (agent_circuit_id) {
1460 circuit_id_dup = strdup(agent_circuit_id);
1461 if (!circuit_id_dup)
1462 return -ENOMEM;
1463 }
1464
1465 if (agent_remote_id) {
1466 remote_id_dup = strdup(agent_remote_id);
1467 if (!remote_id_dup)
1468 return -ENOMEM;
1469 }
1470
1471 free_and_replace(server->agent_circuit_id, circuit_id_dup);
1472 free_and_replace(server->agent_remote_id, remote_id_dup);
1473 return 0;
1474 }
1475
1476 int sd_dhcp_server_set_static_lease(
1477 sd_dhcp_server *server,
1478 const struct in_addr *address,
1479 uint8_t *client_id,
1480 size_t client_id_size) {
1481
1482 _cleanup_(dhcp_lease_freep) DHCPLease *lease = NULL, *old = NULL;
1483 DHCPClientId c;
1484 int r;
1485
1486 assert_return(server, -EINVAL);
1487 assert_return(client_id, -EINVAL);
1488 assert_return(client_id_size == ETH_ALEN + 1, -EINVAL);
1489 assert_return(!sd_dhcp_server_is_running(server), -EBUSY);
1490
1491 /* Static lease with an empty or omitted address is a valid entry,
1492 * the server removes any static lease with the specified mac address. */
1493 if (!address || address->s_addr == 0) {
1494 _cleanup_free_ void *data = NULL;
1495
1496 data = memdup(client_id, client_id_size);
1497 if (!data)
1498 return -ENOMEM;
1499
1500 c = (DHCPClientId) {
1501 .length = client_id_size,
1502 .data = data,
1503 };
1504
1505 old = hashmap_remove(server->static_leases_by_client_id, &c);
1506 return 0;
1507 }
1508
1509 if (static_leases_have_address(server, address->s_addr))
1510 return -EEXIST;
1511
1512 lease = new(DHCPLease, 1);
1513 if (!lease)
1514 return -ENOMEM;
1515
1516 *lease = (DHCPLease) {
1517 .address = address->s_addr,
1518 .client_id.length = client_id_size,
1519 .gateway = 0,
1520 .expiration = 0,
1521 };
1522 lease->client_id.data = memdup(client_id, client_id_size);
1523 if (!lease->client_id.data)
1524 return -ENOMEM;
1525
1526 r = hashmap_ensure_put(&server->static_leases_by_client_id, &dhcp_lease_hash_ops, &lease->client_id, lease);
1527 if (r < 0)
1528 return r;
1529
1530 TAKE_PTR(lease);
1531 return 0;
1532 }