1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 Copyright © 2013 Intel Corporation. All rights reserved.
6 #include <net/if_arp.h>
9 #include "sd-dhcp-server.h"
12 #include "alloc-util.h"
13 #include "dhcp-internal.h"
14 #include "dhcp-server-internal.h"
15 #include "dns-domain.h"
17 #include "in-addr-util.h"
19 #include "memory-util.h"
20 #include "network-common.h"
21 #include "ordered-set.h"
22 #include "siphash24.h"
23 #include "string-util.h"
24 #include "unaligned.h"
27 #define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR
28 #define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12)
30 DHCPLease
*dhcp_lease_free(DHCPLease
*lease
) {
35 hashmap_remove_value(lease
->server
->bound_leases_by_address
, UINT32_TO_PTR(lease
->address
), lease
);
36 hashmap_remove_value(lease
->server
->bound_leases_by_client_id
, &lease
->client_id
, lease
);
37 hashmap_remove_value(lease
->server
->static_leases_by_address
, UINT32_TO_PTR(lease
->address
), lease
);
38 hashmap_remove_value(lease
->server
->static_leases_by_client_id
, &lease
->client_id
, lease
);
41 free(lease
->client_id
.data
);
42 free(lease
->hostname
);
46 /* configures the server's address and subnet, and optionally the pool's size and offset into the subnet
47 * the whole pool must fit into the subnet, and may not contain the first (any) nor last (broadcast) address
48 * moreover, the server's own address may be in the pool, and is in that case reserved in order not to
49 * accidentally hand it out */
50 int sd_dhcp_server_configure_pool(
51 sd_dhcp_server
*server
,
52 const struct in_addr
*address
,
53 unsigned char prefixlen
,
57 struct in_addr netmask_addr
;
59 uint32_t server_off
, broadcast_off
, size_max
;
61 assert_return(server
, -EINVAL
);
62 assert_return(address
, -EINVAL
);
63 assert_return(address
->s_addr
!= INADDR_ANY
, -EINVAL
);
64 assert_return(prefixlen
<= 32, -ERANGE
);
66 assert_se(in4_addr_prefixlen_to_netmask(&netmask_addr
, prefixlen
));
67 netmask
= netmask_addr
.s_addr
;
69 server_off
= be32toh(address
->s_addr
& ~netmask
);
70 broadcast_off
= be32toh(~netmask
);
72 /* the server address cannot be the subnet address */
73 assert_return(server_off
!= 0, -ERANGE
);
75 /* nor the broadcast address */
76 assert_return(server_off
!= broadcast_off
, -ERANGE
);
78 /* 0 offset means we should set a default, we skip the first (subnet) address
79 and take the next one */
83 size_max
= (broadcast_off
+ 1) /* the number of addresses in the subnet */
84 - offset
/* exclude the addresses before the offset */
85 - 1; /* exclude the last (broadcast) address */
87 /* The pool must contain at least one address */
88 assert_return(size_max
>= 1, -ERANGE
);
91 assert_return(size
<= size_max
, -ERANGE
);
95 if (server
->address
!= address
->s_addr
|| server
->netmask
!= netmask
|| server
->pool_size
!= size
|| server
->pool_offset
!= offset
) {
97 server
->pool_offset
= offset
;
98 server
->pool_size
= size
;
100 server
->address
= address
->s_addr
;
101 server
->netmask
= netmask
;
102 server
->subnet
= address
->s_addr
& netmask
;
104 /* Drop any leases associated with the old address range */
105 hashmap_clear(server
->bound_leases_by_address
);
106 hashmap_clear(server
->bound_leases_by_client_id
);
108 if (server
->callback
)
109 server
->callback(server
, SD_DHCP_SERVER_EVENT_LEASE_CHANGED
, server
->callback_userdata
);
115 int sd_dhcp_server_is_running(sd_dhcp_server
*server
) {
116 assert_return(server
, false);
118 return !!server
->receive_message
;
121 int sd_dhcp_server_is_in_relay_mode(sd_dhcp_server
*server
) {
122 assert_return(server
, -EINVAL
);
124 return in4_addr_is_set(&server
->relay_target
);
127 void client_id_hash_func(const DHCPClientId
*id
, struct siphash
*state
) {
129 assert(id
->length
> 0);
132 siphash24_compress(&id
->length
, sizeof(id
->length
), state
);
133 siphash24_compress(id
->data
, id
->length
, state
);
136 int client_id_compare_func(const DHCPClientId
*a
, const DHCPClientId
*b
) {
139 assert(a
->length
> 0);
141 assert(b
->length
> 0);
144 r
= CMP(a
->length
, b
->length
);
148 return memcmp(a
->data
, b
->data
, a
->length
);
151 DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
155 client_id_compare_func
,
159 static sd_dhcp_server
*dhcp_server_free(sd_dhcp_server
*server
) {
162 sd_dhcp_server_stop(server
);
164 sd_event_unref(server
->event
);
166 free(server
->boot_server_name
);
167 free(server
->boot_filename
);
168 free(server
->timezone
);
170 for (sd_dhcp_lease_server_type_t i
= 0; i
< _SD_DHCP_LEASE_SERVER_TYPE_MAX
; i
++)
171 free(server
->servers
[i
].addr
);
173 server
->bound_leases_by_address
= hashmap_free(server
->bound_leases_by_address
);
174 server
->bound_leases_by_client_id
= hashmap_free(server
->bound_leases_by_client_id
);
175 server
->static_leases_by_address
= hashmap_free(server
->static_leases_by_address
);
176 server
->static_leases_by_client_id
= hashmap_free(server
->static_leases_by_client_id
);
178 ordered_set_free(server
->extra_options
);
179 ordered_set_free(server
->vendor_options
);
181 free(server
->agent_circuit_id
);
182 free(server
->agent_remote_id
);
184 free(server
->ifname
);
185 return mfree(server
);
188 DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_server
, sd_dhcp_server
, dhcp_server_free
);
190 int sd_dhcp_server_new(sd_dhcp_server
**ret
, int ifindex
) {
191 _cleanup_(sd_dhcp_server_unrefp
) sd_dhcp_server
*server
= NULL
;
193 assert_return(ret
, -EINVAL
);
194 assert_return(ifindex
> 0, -EINVAL
);
196 server
= new(sd_dhcp_server
, 1);
200 *server
= (sd_dhcp_server
) {
204 .fd_broadcast
= -EBADF
,
205 .address
= htobe32(INADDR_ANY
),
206 .netmask
= htobe32(INADDR_ANY
),
208 .bind_to_interface
= true,
209 .default_lease_time
= DIV_ROUND_UP(DHCP_DEFAULT_LEASE_TIME_USEC
, USEC_PER_SEC
),
210 .max_lease_time
= DIV_ROUND_UP(DHCP_MAX_LEASE_TIME_USEC
, USEC_PER_SEC
),
213 *ret
= TAKE_PTR(server
);
218 int sd_dhcp_server_set_ifname(sd_dhcp_server
*server
, const char *ifname
) {
219 assert_return(server
, -EINVAL
);
220 assert_return(ifname
, -EINVAL
);
222 if (!ifname_valid_full(ifname
, IFNAME_VALID_ALTERNATIVE
))
225 return free_and_strdup(&server
->ifname
, ifname
);
228 int sd_dhcp_server_get_ifname(sd_dhcp_server
*server
, const char **ret
) {
231 assert_return(server
, -EINVAL
);
233 r
= get_ifname(server
->ifindex
, &server
->ifname
);
238 *ret
= server
->ifname
;
243 int sd_dhcp_server_attach_event(sd_dhcp_server
*server
, sd_event
*event
, int64_t priority
) {
246 assert_return(server
, -EINVAL
);
247 assert_return(!server
->event
, -EBUSY
);
250 server
->event
= sd_event_ref(event
);
252 r
= sd_event_default(&server
->event
);
257 server
->event_priority
= priority
;
262 int sd_dhcp_server_detach_event(sd_dhcp_server
*server
) {
263 assert_return(server
, -EINVAL
);
265 server
->event
= sd_event_unref(server
->event
);
270 sd_event
*sd_dhcp_server_get_event(sd_dhcp_server
*server
) {
271 assert_return(server
, NULL
);
273 return server
->event
;
276 int sd_dhcp_server_set_boot_server_address(sd_dhcp_server
*server
, const struct in_addr
*address
) {
277 assert_return(server
, -EINVAL
);
280 server
->boot_server_address
= *address
;
282 server
->boot_server_address
= (struct in_addr
) {};
287 int sd_dhcp_server_set_boot_server_name(sd_dhcp_server
*server
, const char *name
) {
290 assert_return(server
, -EINVAL
);
293 r
= dns_name_is_valid(name
);
300 return free_and_strdup(&server
->boot_server_name
, name
);
303 int sd_dhcp_server_set_boot_filename(sd_dhcp_server
*server
, const char *filename
) {
304 assert_return(server
, -EINVAL
);
306 if (filename
&& (!string_is_safe(filename
) || !ascii_is_valid(filename
)))
309 return free_and_strdup(&server
->boot_filename
, filename
);
312 int sd_dhcp_server_stop(sd_dhcp_server
*server
) {
318 running
= sd_dhcp_server_is_running(server
);
320 server
->receive_message
= sd_event_source_disable_unref(server
->receive_message
);
321 server
->receive_broadcast
= sd_event_source_disable_unref(server
->receive_broadcast
);
323 server
->fd_raw
= safe_close(server
->fd_raw
);
324 server
->fd
= safe_close(server
->fd
);
325 server
->fd_broadcast
= safe_close(server
->fd_broadcast
);
328 log_dhcp_server(server
, "STOPPED");
333 static int dhcp_server_send_unicast_raw(
334 sd_dhcp_server
*server
,
336 const uint8_t *chaddr
,
340 union sockaddr_union link
= {
341 .ll
.sll_family
= AF_PACKET
,
342 .ll
.sll_protocol
= htobe16(ETH_P_IP
),
343 .ll
.sll_ifindex
= server
->ifindex
,
344 .ll
.sll_halen
= hlen
,
348 assert(server
->ifindex
> 0);
349 assert(server
->address
!= 0);
353 assert(len
> sizeof(DHCPPacket
));
355 memcpy(link
.ll
.sll_addr
, chaddr
, hlen
);
357 if (len
> UINT16_MAX
)
360 dhcp_packet_append_ip_headers(packet
, server
->address
, DHCP_PORT_SERVER
,
362 DHCP_PORT_CLIENT
, len
, -1);
364 return dhcp_network_send_raw_socket(server
->fd_raw
, &link
, packet
, len
);
367 static int dhcp_server_send_udp(sd_dhcp_server
*server
, be32_t destination
,
368 uint16_t destination_port
,
369 DHCPMessage
*message
, size_t len
) {
370 union sockaddr_union dest
= {
371 .in
.sin_family
= AF_INET
,
372 .in
.sin_port
= htobe16(destination_port
),
373 .in
.sin_addr
.s_addr
= destination
,
379 CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct in_pktinfo
))) control
= {};
380 struct msghdr msg
= {
382 .msg_namelen
= sizeof(dest
.in
),
386 struct cmsghdr
*cmsg
;
387 struct in_pktinfo
*pktinfo
;
390 assert(server
->fd
>= 0);
392 assert(len
>= sizeof(DHCPMessage
));
394 if (server
->bind_to_interface
) {
395 msg
.msg_control
= &control
;
396 msg
.msg_controllen
= sizeof(control
);
398 cmsg
= CMSG_FIRSTHDR(&msg
);
401 cmsg
->cmsg_level
= IPPROTO_IP
;
402 cmsg
->cmsg_type
= IP_PKTINFO
;
403 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct in_pktinfo
));
405 /* we attach source interface and address info to the message
406 rather than binding the socket. This will be mostly useful
407 when we gain support for arbitrary number of server addresses
409 pktinfo
= CMSG_TYPED_DATA(cmsg
, struct in_pktinfo
);
412 pktinfo
->ipi_ifindex
= server
->ifindex
;
413 pktinfo
->ipi_spec_dst
.s_addr
= server
->address
;
416 if (sendmsg(server
->fd
, &msg
, 0) < 0)
422 static bool requested_broadcast(DHCPMessage
*message
) {
424 return message
->flags
& htobe16(0x8000);
427 static int dhcp_server_send(
428 sd_dhcp_server
*server
,
430 const uint8_t *chaddr
,
432 uint16_t destination_port
,
437 if (destination
!= INADDR_ANY
)
438 return dhcp_server_send_udp(server
, destination
,
439 destination_port
, &packet
->dhcp
,
440 sizeof(DHCPMessage
) + optoffset
);
441 else if (l2_broadcast
)
442 return dhcp_server_send_udp(server
, INADDR_BROADCAST
,
443 destination_port
, &packet
->dhcp
,
444 sizeof(DHCPMessage
) + optoffset
);
446 /* we cannot send UDP packet to specific MAC address when the
447 address is not yet configured, so must fall back to raw
449 return dhcp_server_send_unicast_raw(server
, hlen
, chaddr
, packet
,
450 sizeof(DHCPPacket
) + optoffset
);
453 int dhcp_server_send_packet(sd_dhcp_server
*server
,
454 DHCPRequest
*req
, DHCPPacket
*packet
,
455 int type
, size_t optoffset
) {
456 be32_t destination
= INADDR_ANY
;
457 uint16_t destination_port
= DHCP_PORT_CLIENT
;
462 assert(req
->max_optlen
> 0);
463 assert(req
->message
);
464 assert(optoffset
<= req
->max_optlen
);
467 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &optoffset
, 0,
468 SD_DHCP_OPTION_SERVER_IDENTIFIER
,
469 4, &server
->address
);
473 if (req
->agent_info_option
) {
474 size_t opt_full_length
= *(req
->agent_info_option
+ 1) + 2;
475 /* there must be space left for SD_DHCP_OPTION_END */
476 if (optoffset
+ opt_full_length
< req
->max_optlen
) {
477 memcpy(packet
->dhcp
.options
+ optoffset
, req
->agent_info_option
, opt_full_length
);
478 optoffset
+= opt_full_length
;
482 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &optoffset
, 0,
483 SD_DHCP_OPTION_END
, 0, NULL
);
487 /* RFC 2131 Section 4.1
489 If the ’giaddr’ field in a DHCP message from a client is non-zero,
490 the server sends any return messages to the ’DHCP server’ port on the
491 BOOTP relay agent whose address appears in ’giaddr’. If the ’giaddr’
492 field is zero and the ’ciaddr’ field is nonzero, then the server
493 unicasts DHCPOFFER and DHCPACK messages to the address in ’ciaddr’.
494 If ’giaddr’ is zero and ’ciaddr’ is zero, and the broadcast bit is
495 set, then the server broadcasts DHCPOFFER and DHCPACK messages to
496 0xffffffff. If the broadcast bit is not set and ’giaddr’ is zero and
497 ’ciaddr’ is zero, then the server unicasts DHCPOFFER and DHCPACK
498 messages to the client’s hardware address and ’yiaddr’ address. In
499 all cases, when ’giaddr’ is zero, the server broadcasts any DHCPNAK
500 messages to 0xffffffff.
504 If ’giaddr’ is set in the DHCPREQUEST message, the client is on a
505 different subnet. The server MUST set the broadcast bit in the
506 DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
507 client, because the client may not have a correct network address
508 or subnet mask, and the client may not be answering ARP requests.
510 if (req
->message
->giaddr
!= 0) {
511 destination
= req
->message
->giaddr
;
512 destination_port
= DHCP_PORT_SERVER
;
513 if (type
== DHCP_NAK
)
514 packet
->dhcp
.flags
= htobe16(0x8000);
515 } else if (req
->message
->ciaddr
!= 0 && type
!= DHCP_NAK
)
516 destination
= req
->message
->ciaddr
;
518 bool l2_broadcast
= requested_broadcast(req
->message
) || type
== DHCP_NAK
;
519 return dhcp_server_send(server
, req
->message
->hlen
, req
->message
->chaddr
,
520 destination
, destination_port
, packet
, optoffset
, l2_broadcast
);
523 static int server_message_init(
524 sd_dhcp_server
*server
,
527 size_t *ret_optoffset
,
530 _cleanup_free_ DHCPPacket
*packet
= NULL
;
531 size_t optoffset
= 0;
536 assert(ret_optoffset
);
537 assert(IN_SET(type
, DHCP_OFFER
, DHCP_ACK
, DHCP_NAK
));
540 packet
= malloc0(sizeof(DHCPPacket
) + req
->max_optlen
);
544 r
= dhcp_message_init(&packet
->dhcp
, BOOTREPLY
,
545 be32toh(req
->message
->xid
), type
,
546 req
->message
->htype
, req
->message
->hlen
, req
->message
->chaddr
,
547 req
->max_optlen
, &optoffset
);
551 packet
->dhcp
.flags
= req
->message
->flags
;
552 packet
->dhcp
.giaddr
= req
->message
->giaddr
;
554 *ret_optoffset
= optoffset
;
555 *ret
= TAKE_PTR(packet
);
560 static int server_send_offer_or_ack(
561 sd_dhcp_server
*server
,
566 static const uint8_t option_map
[_SD_DHCP_LEASE_SERVER_TYPE_MAX
] = {
567 [SD_DHCP_LEASE_DNS
] = SD_DHCP_OPTION_DOMAIN_NAME_SERVER
,
568 [SD_DHCP_LEASE_NTP
] = SD_DHCP_OPTION_NTP_SERVER
,
569 [SD_DHCP_LEASE_SIP
] = SD_DHCP_OPTION_SIP_SERVER
,
570 [SD_DHCP_LEASE_POP3
] = SD_DHCP_OPTION_POP3_SERVER
,
571 [SD_DHCP_LEASE_SMTP
] = SD_DHCP_OPTION_SMTP_SERVER
,
572 [SD_DHCP_LEASE_LPR
] = SD_DHCP_OPTION_LPR_SERVER
,
575 _cleanup_free_ DHCPPacket
*packet
= NULL
;
583 assert(IN_SET(type
, DHCP_OFFER
, DHCP_ACK
));
585 r
= server_message_init(server
, &packet
, type
, &offset
, req
);
589 packet
->dhcp
.yiaddr
= address
;
590 packet
->dhcp
.siaddr
= server
->boot_server_address
.s_addr
;
592 lease_time
= htobe32(req
->lifetime
);
593 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
594 SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME
, 4,
599 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
600 SD_DHCP_OPTION_SUBNET_MASK
, 4, &server
->netmask
);
604 if (server
->emit_router
) {
605 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
606 SD_DHCP_OPTION_ROUTER
, 4,
607 in4_addr_is_set(&server
->router_address
) ?
608 &server
->router_address
.s_addr
:
614 if (server
->boot_server_name
) {
615 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
616 SD_DHCP_OPTION_BOOT_SERVER_NAME
,
617 strlen(server
->boot_server_name
), server
->boot_server_name
);
622 if (server
->boot_filename
) {
623 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
624 SD_DHCP_OPTION_BOOT_FILENAME
,
625 strlen(server
->boot_filename
), server
->boot_filename
);
630 for (sd_dhcp_lease_server_type_t k
= 0; k
< _SD_DHCP_LEASE_SERVER_TYPE_MAX
; k
++) {
631 if (server
->servers
[k
].size
<= 0)
634 r
= dhcp_option_append(
635 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
637 sizeof(struct in_addr
) * server
->servers
[k
].size
,
638 server
->servers
[k
].addr
);
643 if (server
->timezone
) {
644 r
= dhcp_option_append(
645 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
646 SD_DHCP_OPTION_TZDB_TIMEZONE
,
647 strlen(server
->timezone
), server
->timezone
);
652 ORDERED_SET_FOREACH(j
, server
->extra_options
) {
653 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
654 j
->option
, j
->length
, j
->data
);
659 if (!ordered_set_isempty(server
->vendor_options
)) {
660 r
= dhcp_option_append(
661 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
662 SD_DHCP_OPTION_VENDOR_SPECIFIC
,
663 ordered_set_size(server
->vendor_options
), server
->vendor_options
);
668 return dhcp_server_send_packet(server
, req
, packet
, type
, offset
);
671 static int server_send_nak_or_ignore(sd_dhcp_server
*server
, bool init_reboot
, DHCPRequest
*req
) {
672 _cleanup_free_ DHCPPacket
*packet
= NULL
;
676 /* When a request is refused, RFC 2131, section 4.3.2 mentioned we should send NAK when the
677 * client is in INITREBOOT. If the client is in other state, there is nothing mentioned in the
678 * RFC whether we should send NAK or not. Hence, let's silently ignore the request. */
683 r
= server_message_init(server
, &packet
, DHCP_NAK
, &offset
, req
);
685 return log_dhcp_server_errno(server
, r
, "Failed to create NAK message: %m");
687 r
= dhcp_server_send_packet(server
, req
, packet
, DHCP_NAK
, offset
);
689 return log_dhcp_server_errno(server
, r
, "Could not send NAK message: %m");
691 log_dhcp_server(server
, "NAK (0x%x)", be32toh(req
->message
->xid
));
695 static int server_send_forcerenew(
696 sd_dhcp_server
*server
,
701 const uint8_t *chaddr
) {
703 _cleanup_free_ DHCPPacket
*packet
= NULL
;
704 size_t optoffset
= 0;
708 assert(address
!= INADDR_ANY
);
711 packet
= malloc0(sizeof(DHCPPacket
) + DHCP_MIN_OPTIONS_SIZE
);
715 r
= dhcp_message_init(&packet
->dhcp
, BOOTREPLY
, 0,
716 DHCP_FORCERENEW
, htype
, hlen
, chaddr
,
717 DHCP_MIN_OPTIONS_SIZE
, &optoffset
);
721 r
= dhcp_option_append(&packet
->dhcp
, DHCP_MIN_OPTIONS_SIZE
,
722 &optoffset
, 0, SD_DHCP_OPTION_END
, 0, NULL
);
726 return dhcp_server_send_udp(server
, address
, DHCP_PORT_CLIENT
,
728 sizeof(DHCPMessage
) + optoffset
);
731 static int parse_request(uint8_t code
, uint8_t len
, const void *option
, void *userdata
) {
732 DHCPRequest
*req
= ASSERT_PTR(userdata
);
736 case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME
:
738 req
->lifetime
= unaligned_read_be32(option
);
741 case SD_DHCP_OPTION_REQUESTED_IP_ADDRESS
:
743 memcpy(&req
->requested_ip
, option
, sizeof(be32_t
));
746 case SD_DHCP_OPTION_SERVER_IDENTIFIER
:
748 memcpy(&req
->server_id
, option
, sizeof(be32_t
));
751 case SD_DHCP_OPTION_CLIENT_IDENTIFIER
:
755 data
= memdup(option
, len
);
759 free_and_replace(req
->client_id
.data
, data
);
760 req
->client_id
.length
= len
;
764 case SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE
:
766 if (len
== 2 && unaligned_read_be16(option
) >= sizeof(DHCPPacket
))
767 req
->max_optlen
= unaligned_read_be16(option
) - sizeof(DHCPPacket
);
770 case SD_DHCP_OPTION_RELAY_AGENT_INFORMATION
:
771 req
->agent_info_option
= (uint8_t*)option
- 2;
774 case SD_DHCP_OPTION_HOST_NAME
:
775 r
= dhcp_option_parse_string(option
, len
, &req
->hostname
);
777 log_debug_errno(r
, "Failed to parse hostname, ignoring: %m");
787 static DHCPRequest
* dhcp_request_free(DHCPRequest
*req
) {
791 free(req
->client_id
.data
);
796 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest
*, dhcp_request_free
);
798 static int ensure_sane_request(sd_dhcp_server
*server
, DHCPRequest
*req
, DHCPMessage
*message
) {
802 req
->message
= message
;
804 if (message
->hlen
> sizeof(message
->chaddr
))
807 /* set client id based on MAC address if client did not send an explicit one */
808 if (!req
->client_id
.data
) {
811 if (message
->hlen
== 0)
814 data
= new0(uint8_t, message
->hlen
+ 1);
819 memcpy(data
+ 1, message
->chaddr
, message
->hlen
);
821 req
->client_id
.length
= message
->hlen
+ 1;
822 req
->client_id
.data
= data
;
825 if (message
->hlen
== 0 || memeqzero(message
->chaddr
, message
->hlen
)) {
826 /* See RFC2131 section 4.1.1.
827 * hlen and chaddr may not be set for non-ethernet interface.
828 * Let's try to retrieve it from the client ID. */
830 if (!req
->client_id
.data
)
833 if (req
->client_id
.length
<= 1 || req
->client_id
.length
> sizeof(message
->chaddr
) + 1)
836 if (req
->client_id
.data
[0] != 0x01)
839 message
->hlen
= req
->client_id
.length
- 1;
840 memcpy(message
->chaddr
, req
->client_id
.data
+ 1, message
->hlen
);
843 if (req
->max_optlen
< DHCP_MIN_OPTIONS_SIZE
)
844 req
->max_optlen
= DHCP_MIN_OPTIONS_SIZE
;
846 if (req
->lifetime
<= 0)
847 req
->lifetime
= MAX(1ULL, server
->default_lease_time
);
849 if (server
->max_lease_time
> 0 && req
->lifetime
> server
->max_lease_time
)
850 req
->lifetime
= server
->max_lease_time
;
855 static bool address_is_in_pool(sd_dhcp_server
*server
, be32_t address
) {
858 if (server
->pool_size
== 0)
861 if (address
== server
->address
)
864 if (be32toh(address
) < (be32toh(server
->subnet
) | server
->pool_offset
) ||
865 be32toh(address
) >= (be32toh(server
->subnet
) | (server
->pool_offset
+ server
->pool_size
)))
868 if (hashmap_contains(server
->static_leases_by_address
, UINT32_TO_PTR(address
)))
874 static int append_agent_information_option(sd_dhcp_server
*server
, DHCPMessage
*message
, size_t opt_length
, size_t size
) {
881 r
= dhcp_option_find_option(message
->options
, opt_length
, SD_DHCP_OPTION_END
, &offset
);
885 r
= dhcp_option_append(message
, size
, &offset
, 0, SD_DHCP_OPTION_RELAY_AGENT_INFORMATION
, 0, server
);
889 r
= dhcp_option_append(message
, size
, &offset
, 0, SD_DHCP_OPTION_END
, 0, NULL
);
895 static int dhcp_server_relay_message(sd_dhcp_server
*server
, DHCPMessage
*message
, size_t opt_length
, size_t buflen
) {
896 _cleanup_free_ DHCPPacket
*packet
= NULL
;
901 assert(sd_dhcp_server_is_in_relay_mode(server
));
903 if (message
->hlen
== 0 || message
->hlen
> sizeof(message
->chaddr
) || memeqzero(message
->chaddr
, message
->hlen
))
904 return log_dhcp_server_errno(server
, SYNTHETIC_ERRNO(EBADMSG
),
905 "(relay agent) received message without/invalid hardware address, discarding.");
907 if (message
->op
== BOOTREQUEST
) {
908 log_dhcp_server(server
, "(relay agent) BOOTREQUEST (0x%x)", be32toh(message
->xid
));
909 if (message
->hops
>= 16)
913 /* https://tools.ietf.org/html/rfc1542#section-4.1.1 */
914 if (message
->giaddr
== 0)
915 message
->giaddr
= server
->address
;
917 if (server
->agent_circuit_id
|| server
->agent_remote_id
) {
918 r
= append_agent_information_option(server
, message
, opt_length
, buflen
- sizeof(DHCPMessage
));
920 return log_dhcp_server_errno(server
, r
, "could not append relay option: %m");
924 return dhcp_server_send_udp(server
, server
->relay_target
.s_addr
, DHCP_PORT_SERVER
, message
, sizeof(DHCPMessage
) + opt_length
);
925 } else if (message
->op
== BOOTREPLY
) {
926 log_dhcp_server(server
, "(relay agent) BOOTREPLY (0x%x)", be32toh(message
->xid
));
927 if (message
->giaddr
!= server
->address
)
928 return log_dhcp_server_errno(server
, SYNTHETIC_ERRNO(EBADMSG
),
929 "(relay agent) BOOTREPLY giaddr mismatch, discarding");
931 int message_type
= dhcp_option_parse(message
, sizeof(DHCPMessage
) + opt_length
, NULL
, NULL
, NULL
);
932 if (message_type
< 0)
935 packet
= malloc0(sizeof(DHCPPacket
) + opt_length
);
938 memcpy(&packet
->dhcp
, message
, sizeof(DHCPMessage
) + opt_length
);
940 r
= dhcp_option_remove_option(packet
->dhcp
.options
, opt_length
, SD_DHCP_OPTION_RELAY_AGENT_INFORMATION
);
944 bool l2_broadcast
= requested_broadcast(message
) || message_type
== DHCP_NAK
;
945 const be32_t destination
= message_type
== DHCP_NAK
? INADDR_ANY
: message
->ciaddr
;
946 return dhcp_server_send(server
, message
->hlen
, message
->chaddr
, destination
, DHCP_PORT_CLIENT
, packet
, opt_length
, l2_broadcast
);
951 static int prepare_new_lease(DHCPLease
**ret_lease
, be32_t address
, DHCPRequest
*req
, usec_t expiration
) {
952 _cleanup_(dhcp_lease_freep
) DHCPLease
*lease
= NULL
;
955 assert(address
!= 0);
957 assert(expiration
!= 0);
959 lease
= new(DHCPLease
, 1);
963 *lease
= (DHCPLease
) {
965 .client_id
.length
= req
->client_id
.length
,
966 .htype
= req
->message
->htype
,
967 .hlen
= req
->message
->hlen
,
968 .gateway
= req
->message
->giaddr
,
969 .expiration
= expiration
,
971 lease
->client_id
.data
= memdup(req
->client_id
.data
, req
->client_id
.length
);
972 if (!lease
->client_id
.data
)
975 memcpy(lease
->chaddr
, req
->message
->chaddr
, req
->message
->hlen
);
978 lease
->hostname
= strdup(req
->hostname
);
979 if (!lease
->hostname
)
983 *ret_lease
= TAKE_PTR(lease
);
988 static int server_ack_request(sd_dhcp_server
*server
, DHCPRequest
*req
, DHCPLease
*existing_lease
, be32_t address
) {
989 usec_t time_now
, expiration
;
994 assert(address
!= 0);
996 r
= sd_event_now(server
->event
, CLOCK_BOOTTIME
, &time_now
);
1000 expiration
= usec_add(req
->lifetime
* USEC_PER_SEC
, time_now
);
1002 if (existing_lease
) {
1003 assert(existing_lease
->server
);
1004 assert(existing_lease
->address
== address
);
1005 existing_lease
->expiration
= expiration
;
1008 _cleanup_(dhcp_lease_freep
) DHCPLease
*lease
= NULL
;
1010 r
= prepare_new_lease(&lease
, address
, req
, expiration
);
1012 return log_dhcp_server_errno(server
, r
, "Failed to create new lease: %m");
1014 lease
->server
= server
; /* This must be set just before hashmap_put(). */
1016 r
= hashmap_ensure_put(&server
->bound_leases_by_client_id
, &dhcp_lease_hash_ops
, &lease
->client_id
, lease
);
1018 return log_dhcp_server_errno(server
, r
, "Could not save lease: %m");
1020 r
= hashmap_ensure_put(&server
->bound_leases_by_address
, NULL
, UINT32_TO_PTR(lease
->address
), lease
);
1022 return log_dhcp_server_errno(server
, r
, "Could not save lease: %m");
1027 r
= server_send_offer_or_ack(server
, req
, address
, DHCP_ACK
);
1029 return log_dhcp_server_errno(server
, r
, "Could not send ACK: %m");
1031 log_dhcp_server(server
, "ACK (0x%x)", be32toh(req
->message
->xid
));
1033 if (server
->callback
)
1034 server
->callback(server
, SD_DHCP_SERVER_EVENT_LEASE_CHANGED
, server
->callback_userdata
);
1039 static int dhcp_server_cleanup_expired_leases(sd_dhcp_server
*server
) {
1046 r
= sd_event_now(server
->event
, CLOCK_BOOTTIME
, &time_now
);
1050 HASHMAP_FOREACH(lease
, server
->bound_leases_by_client_id
)
1051 if (lease
->expiration
< time_now
) {
1052 log_dhcp_server(server
, "CLEAN (0x%x)", be32toh(lease
->address
));
1053 dhcp_lease_free(lease
);
1059 static bool address_available(sd_dhcp_server
*server
, be32_t address
) {
1062 if (hashmap_contains(server
->bound_leases_by_address
, UINT32_TO_PTR(address
)) ||
1063 hashmap_contains(server
->static_leases_by_address
, UINT32_TO_PTR(address
)) ||
1064 address
== server
->address
)
1070 static int server_get_static_lease(sd_dhcp_server
*server
, const DHCPRequest
*req
, DHCPLease
**ret
) {
1071 DHCPLease
*static_lease
;
1072 _cleanup_free_
uint8_t *data
= NULL
;
1078 static_lease
= hashmap_get(server
->static_leases_by_client_id
, &req
->client_id
);
1080 *ret
= static_lease
;
1084 /* when no lease is found based on the client id fall back to chaddr */
1085 data
= new(uint8_t, req
->message
->hlen
+ 1);
1089 /* set client id type to 1: Ethernet Link-Layer (RFC 2132) */
1091 memcpy(data
+ 1, req
->message
->chaddr
, req
->message
->hlen
);
1093 static_lease
= hashmap_get(server
->static_leases_by_client_id
,
1095 .length
= req
->message
->hlen
+ 1,
1099 *ret
= static_lease
;
1104 #define HASH_KEY SD_ID128_MAKE(0d,1d,fe,bd,f1,24,bd,b3,47,f1,dd,6e,73,21,93,30)
1106 int dhcp_server_handle_message(sd_dhcp_server
*server
, DHCPMessage
*message
, size_t length
) {
1107 _cleanup_(dhcp_request_freep
) DHCPRequest
*req
= NULL
;
1108 _cleanup_free_
char *error_message
= NULL
;
1109 DHCPLease
*existing_lease
, *static_lease
;
1115 if (message
->op
!= BOOTREQUEST
)
1118 req
= new0(DHCPRequest
, 1);
1122 type
= dhcp_option_parse(message
, length
, parse_request
, req
, &error_message
);
1126 r
= ensure_sane_request(server
, req
, message
);
1130 r
= dhcp_server_cleanup_expired_leases(server
);
1134 existing_lease
= hashmap_get(server
->bound_leases_by_client_id
, &req
->client_id
);
1135 r
= server_get_static_lease(server
, req
, &static_lease
);
1141 case DHCP_DISCOVER
: {
1142 be32_t address
= INADDR_ANY
;
1144 log_dhcp_server(server
, "DISCOVER (0x%x)", be32toh(req
->message
->xid
));
1146 if (server
->pool_size
== 0)
1147 /* no pool allocated */
1150 /* for now pick a random free address from the pool */
1152 address
= static_lease
->address
;
1153 else if (existing_lease
)
1154 address
= existing_lease
->address
;
1156 struct siphash state
;
1159 /* even with no persistence of leases, we try to offer the same client
1160 the same IP address. we do this by using the hash of the client id
1161 as the offset into the pool of leases when finding the next free one */
1163 siphash24_init(&state
, HASH_KEY
.bytes
);
1164 client_id_hash_func(&req
->client_id
, &state
);
1165 hash
= htole64(siphash24_finalize(&state
));
1167 for (unsigned i
= 0; i
< server
->pool_size
; i
++) {
1170 tmp_address
= server
->subnet
| htobe32(server
->pool_offset
+ (hash
+ i
) % server
->pool_size
);
1171 if (address_available(server
, tmp_address
)) {
1172 address
= tmp_address
;
1178 if (address
== INADDR_ANY
)
1179 /* no free addresses left */
1182 r
= server_send_offer_or_ack(server
, req
, address
, DHCP_OFFER
);
1184 /* this only fails on critical errors */
1185 return log_dhcp_server_errno(server
, r
, "Could not send offer: %m");
1187 log_dhcp_server(server
, "OFFER (0x%x)", be32toh(req
->message
->xid
));
1191 log_dhcp_server(server
, "DECLINE (0x%x): %s", be32toh(req
->message
->xid
), strna(error_message
));
1193 /* TODO: make sure we don't offer this address again */
1197 case DHCP_REQUEST
: {
1199 bool init_reboot
= false;
1201 /* see RFC 2131, section 4.3.2 */
1203 if (req
->server_id
!= 0) {
1204 log_dhcp_server(server
, "REQUEST (selecting) (0x%x)",
1205 be32toh(req
->message
->xid
));
1208 if (req
->server_id
!= server
->address
)
1209 /* client did not pick us */
1212 if (req
->message
->ciaddr
!= 0)
1213 /* this MUST be zero */
1216 if (req
->requested_ip
== 0)
1217 /* this must be filled in with the yiaddr
1218 from the chosen OFFER */
1221 address
= req
->requested_ip
;
1222 } else if (req
->requested_ip
!= 0) {
1223 log_dhcp_server(server
, "REQUEST (init-reboot) (0x%x)",
1224 be32toh(req
->message
->xid
));
1227 if (req
->message
->ciaddr
!= 0)
1228 /* this MUST be zero */
1231 /* TODO: check more carefully if IP is correct */
1232 address
= req
->requested_ip
;
1235 log_dhcp_server(server
, "REQUEST (rebinding/renewing) (0x%x)",
1236 be32toh(req
->message
->xid
));
1238 /* REBINDING / RENEWING */
1239 if (req
->message
->ciaddr
== 0)
1240 /* this MUST be filled in with clients IP address */
1243 address
= req
->message
->ciaddr
;
1246 /* disallow our own address */
1247 if (address
== server
->address
)
1251 /* Found a static lease for the client ID. */
1253 if (static_lease
->address
!= address
)
1254 /* The client requested an address which is different from the static lease. Refuse. */
1255 return server_send_nak_or_ignore(server
, init_reboot
, req
);
1257 return server_ack_request(server
, req
, existing_lease
, address
);
1260 if (address_is_in_pool(server
, address
)) {
1261 /* The requested address is in the pool. */
1263 if (existing_lease
&& existing_lease
->address
!= address
)
1264 /* We previously assigned an address, but the client requested another one. Refuse. */
1265 return server_send_nak_or_ignore(server
, init_reboot
, req
);
1267 return server_ack_request(server
, req
, existing_lease
, address
);
1270 return server_send_nak_or_ignore(server
, init_reboot
, req
);
1273 case DHCP_RELEASE
: {
1274 log_dhcp_server(server
, "RELEASE (0x%x)",
1275 be32toh(req
->message
->xid
));
1277 if (!existing_lease
)
1280 if (existing_lease
->address
!= req
->message
->ciaddr
)
1283 dhcp_lease_free(existing_lease
);
1285 if (server
->callback
)
1286 server
->callback(server
, SD_DHCP_SERVER_EVENT_LEASE_CHANGED
, server
->callback_userdata
);
1294 static size_t relay_agent_information_length(const char* agent_circuit_id
, const char* agent_remote_id
) {
1296 if (agent_circuit_id
)
1297 sum
+= 2 + strlen(agent_circuit_id
);
1298 if (agent_remote_id
)
1299 sum
+= 2 + strlen(agent_remote_id
);
1303 static int server_receive_message(sd_event_source
*s
, int fd
,
1304 uint32_t revents
, void *userdata
) {
1305 _cleanup_free_ DHCPMessage
*message
= NULL
;
1306 CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct in_pktinfo
))) control
;
1307 sd_dhcp_server
*server
= ASSERT_PTR(userdata
);
1308 struct iovec iov
= {};
1309 struct msghdr msg
= {
1312 .msg_control
= &control
,
1313 .msg_controllen
= sizeof(control
),
1315 ssize_t datagram_size
, len
;
1318 datagram_size
= next_datagram_size_fd(fd
);
1319 if (ERRNO_IS_NEG_TRANSIENT(datagram_size
) || ERRNO_IS_NEG_DISCONNECT(datagram_size
))
1321 if (datagram_size
< 0) {
1322 log_dhcp_server_errno(server
, datagram_size
, "Failed to determine datagram size to read, ignoring: %m");
1326 size_t buflen
= datagram_size
;
1327 if (sd_dhcp_server_is_in_relay_mode(server
))
1328 /* Preallocate the additional size for DHCP Relay Agent Information Option if needed */
1329 buflen
+= relay_agent_information_length(server
->agent_circuit_id
, server
->agent_remote_id
) + 2;
1331 message
= malloc(buflen
);
1335 iov
= IOVEC_MAKE(message
, datagram_size
);
1337 len
= recvmsg_safe(fd
, &msg
, 0);
1338 if (ERRNO_IS_NEG_TRANSIENT(len
) || ERRNO_IS_NEG_DISCONNECT(len
))
1341 log_dhcp_server_errno(server
, len
, "Could not receive message, ignoring: %m");
1345 if ((size_t) len
< sizeof(DHCPMessage
))
1348 /* TODO figure out if this can be done as a filter on the socket, like for IPv6 */
1349 struct in_pktinfo
*info
= CMSG_FIND_DATA(&msg
, IPPROTO_IP
, IP_PKTINFO
, struct in_pktinfo
);
1350 if (info
&& info
->ipi_ifindex
!= server
->ifindex
)
1353 if (sd_dhcp_server_is_in_relay_mode(server
)) {
1354 r
= dhcp_server_relay_message(server
, message
, len
- sizeof(DHCPMessage
), buflen
);
1356 log_dhcp_server_errno(server
, r
, "Couldn't relay message, ignoring: %m");
1358 r
= dhcp_server_handle_message(server
, message
, (size_t) len
);
1360 log_dhcp_server_errno(server
, r
, "Couldn't process incoming message, ignoring: %m");
1365 static void dhcp_server_update_lease_servers(sd_dhcp_server
*server
) {
1367 assert(server
->address
!= 0);
1369 /* Convert null address -> server address */
1371 for (sd_dhcp_lease_server_type_t k
= 0; k
< _SD_DHCP_LEASE_SERVER_TYPE_MAX
; k
++)
1372 for (size_t i
= 0; i
< server
->servers
[k
].size
; i
++)
1373 if (in4_addr_is_null(&server
->servers
[k
].addr
[i
]))
1374 server
->servers
[k
].addr
[i
].s_addr
= server
->address
;
1377 int sd_dhcp_server_start(sd_dhcp_server
*server
) {
1380 assert_return(server
, -EINVAL
);
1381 assert_return(server
->event
, -EINVAL
);
1383 if (sd_dhcp_server_is_running(server
))
1386 assert_return(!server
->receive_message
, -EBUSY
);
1387 assert_return(server
->fd_raw
< 0, -EBUSY
);
1388 assert_return(server
->fd
< 0, -EBUSY
);
1389 assert_return(server
->address
!= htobe32(INADDR_ANY
), -EUNATCH
);
1391 dhcp_server_update_lease_servers(server
);
1393 r
= socket(AF_PACKET
, SOCK_DGRAM
| SOCK_CLOEXEC
| SOCK_NONBLOCK
, 0);
1400 if (server
->bind_to_interface
)
1401 r
= dhcp_network_bind_udp_socket(server
->ifindex
, INADDR_ANY
, DHCP_PORT_SERVER
, -1);
1403 r
= dhcp_network_bind_udp_socket(0, server
->address
, DHCP_PORT_SERVER
, -1);
1408 r
= sd_event_add_io(server
->event
, &server
->receive_message
,
1409 server
->fd
, EPOLLIN
,
1410 server_receive_message
, server
);
1414 r
= sd_event_source_set_priority(server
->receive_message
,
1415 server
->event_priority
);
1419 if (!server
->bind_to_interface
) {
1420 r
= dhcp_network_bind_udp_socket(server
->ifindex
, INADDR_BROADCAST
, DHCP_PORT_SERVER
, -1);
1424 server
->fd_broadcast
= r
;
1426 r
= sd_event_add_io(server
->event
, &server
->receive_broadcast
,
1427 server
->fd_broadcast
, EPOLLIN
,
1428 server_receive_message
, server
);
1432 r
= sd_event_source_set_priority(server
->receive_broadcast
,
1433 server
->event_priority
);
1438 log_dhcp_server(server
, "STARTED");
1443 sd_dhcp_server_stop(server
);
1447 int sd_dhcp_server_forcerenew(sd_dhcp_server
*server
) {
1451 assert_return(server
, -EINVAL
);
1453 log_dhcp_server(server
, "FORCERENEW");
1455 HASHMAP_FOREACH(lease
, server
->bound_leases_by_client_id
)
1457 server_send_forcerenew(server
, lease
->address
, lease
->gateway
,
1458 lease
->htype
, lease
->hlen
, lease
->chaddr
));
1462 int sd_dhcp_server_set_bind_to_interface(sd_dhcp_server
*server
, int enabled
) {
1463 assert_return(server
, -EINVAL
);
1464 assert_return(!sd_dhcp_server_is_running(server
), -EBUSY
);
1466 if (!!enabled
== server
->bind_to_interface
)
1469 server
->bind_to_interface
= enabled
;
1474 int sd_dhcp_server_set_timezone(sd_dhcp_server
*server
, const char *tz
) {
1477 assert_return(server
, -EINVAL
);
1478 assert_return(timezone_is_valid(tz
, LOG_DEBUG
), -EINVAL
);
1480 if (streq_ptr(tz
, server
->timezone
))
1483 r
= free_and_strdup(&server
->timezone
, tz
);
1490 int sd_dhcp_server_set_max_lease_time(sd_dhcp_server
*server
, uint32_t t
) {
1491 assert_return(server
, -EINVAL
);
1493 if (t
== server
->max_lease_time
)
1496 server
->max_lease_time
= t
;
1500 int sd_dhcp_server_set_default_lease_time(sd_dhcp_server
*server
, uint32_t t
) {
1501 assert_return(server
, -EINVAL
);
1503 if (t
== server
->default_lease_time
)
1506 server
->default_lease_time
= t
;
1510 int sd_dhcp_server_set_servers(
1511 sd_dhcp_server
*server
,
1512 sd_dhcp_lease_server_type_t what
,
1513 const struct in_addr addresses
[],
1514 size_t n_addresses
) {
1516 struct in_addr
*c
= NULL
;
1518 assert_return(server
, -EINVAL
);
1519 assert_return(!sd_dhcp_server_is_running(server
), -EBUSY
);
1520 assert_return(addresses
|| n_addresses
== 0, -EINVAL
);
1521 assert_return(what
>= 0, -EINVAL
);
1522 assert_return(what
< _SD_DHCP_LEASE_SERVER_TYPE_MAX
, -EINVAL
);
1524 if (server
->servers
[what
].size
== n_addresses
&&
1525 memcmp(server
->servers
[what
].addr
, addresses
, sizeof(struct in_addr
) * n_addresses
) == 0)
1528 if (n_addresses
> 0) {
1529 c
= newdup(struct in_addr
, addresses
, n_addresses
);
1534 free_and_replace(server
->servers
[what
].addr
, c
);
1535 server
->servers
[what
].size
= n_addresses
;
1539 int sd_dhcp_server_set_dns(sd_dhcp_server
*server
, const struct in_addr dns
[], size_t n
) {
1540 return sd_dhcp_server_set_servers(server
, SD_DHCP_LEASE_DNS
, dns
, n
);
1542 int sd_dhcp_server_set_ntp(sd_dhcp_server
*server
, const struct in_addr ntp
[], size_t n
) {
1543 return sd_dhcp_server_set_servers(server
, SD_DHCP_LEASE_NTP
, ntp
, n
);
1545 int sd_dhcp_server_set_sip(sd_dhcp_server
*server
, const struct in_addr sip
[], size_t n
) {
1546 return sd_dhcp_server_set_servers(server
, SD_DHCP_LEASE_SIP
, sip
, n
);
1548 int sd_dhcp_server_set_pop3(sd_dhcp_server
*server
, const struct in_addr pop3
[], size_t n
) {
1549 return sd_dhcp_server_set_servers(server
, SD_DHCP_LEASE_POP3
, pop3
, n
);
1551 int sd_dhcp_server_set_smtp(sd_dhcp_server
*server
, const struct in_addr smtp
[], size_t n
) {
1552 return sd_dhcp_server_set_servers(server
, SD_DHCP_LEASE_SMTP
, smtp
, n
);
1554 int sd_dhcp_server_set_lpr(sd_dhcp_server
*server
, const struct in_addr lpr
[], size_t n
) {
1555 return sd_dhcp_server_set_servers(server
, SD_DHCP_LEASE_LPR
, lpr
, n
);
1558 int sd_dhcp_server_set_router(sd_dhcp_server
*server
, const struct in_addr
*router
) {
1559 assert_return(server
, -EINVAL
);
1561 /* router is NULL: router option will not be appended.
1562 * router is null address (0.0.0.0): the server address will be used as the router address.
1563 * otherwise: the specified address will be used as the router address. */
1565 server
->emit_router
= router
;
1567 server
->router_address
= *router
;
1572 int sd_dhcp_server_add_option(sd_dhcp_server
*server
, sd_dhcp_option
*v
) {
1575 assert_return(server
, -EINVAL
);
1576 assert_return(v
, -EINVAL
);
1578 r
= ordered_set_ensure_put(&server
->extra_options
, &dhcp_option_hash_ops
, v
);
1582 sd_dhcp_option_ref(v
);
1586 int sd_dhcp_server_add_vendor_option(sd_dhcp_server
*server
, sd_dhcp_option
*v
) {
1589 assert_return(server
, -EINVAL
);
1590 assert_return(v
, -EINVAL
);
1592 r
= ordered_set_ensure_put(&server
->vendor_options
, &dhcp_option_hash_ops
, v
);
1596 sd_dhcp_option_ref(v
);
1601 int sd_dhcp_server_set_callback(sd_dhcp_server
*server
, sd_dhcp_server_callback_t cb
, void *userdata
) {
1602 assert_return(server
, -EINVAL
);
1604 server
->callback
= cb
;
1605 server
->callback_userdata
= userdata
;
1610 int sd_dhcp_server_set_relay_target(sd_dhcp_server
*server
, const struct in_addr
*address
) {
1611 assert_return(server
, -EINVAL
);
1612 assert_return(!sd_dhcp_server_is_running(server
), -EBUSY
);
1614 if (memcmp(address
, &server
->relay_target
, sizeof(struct in_addr
)) == 0)
1617 server
->relay_target
= *address
;
1621 int sd_dhcp_server_set_relay_agent_information(
1622 sd_dhcp_server
*server
,
1623 const char *agent_circuit_id
,
1624 const char *agent_remote_id
) {
1625 _cleanup_free_
char *circuit_id_dup
= NULL
, *remote_id_dup
= NULL
;
1627 assert_return(server
, -EINVAL
);
1629 if (relay_agent_information_length(agent_circuit_id
, agent_remote_id
) > UINT8_MAX
)
1632 if (agent_circuit_id
) {
1633 circuit_id_dup
= strdup(agent_circuit_id
);
1634 if (!circuit_id_dup
)
1638 if (agent_remote_id
) {
1639 remote_id_dup
= strdup(agent_remote_id
);
1644 free_and_replace(server
->agent_circuit_id
, circuit_id_dup
);
1645 free_and_replace(server
->agent_remote_id
, remote_id_dup
);
1649 int sd_dhcp_server_set_static_lease(
1650 sd_dhcp_server
*server
,
1651 const struct in_addr
*address
,
1653 size_t client_id_size
) {
1655 _cleanup_(dhcp_lease_freep
) DHCPLease
*lease
= NULL
;
1658 assert_return(server
, -EINVAL
);
1659 assert_return(client_id
, -EINVAL
);
1660 assert_return(client_id_size
> 0, -EINVAL
);
1661 assert_return(!sd_dhcp_server_is_running(server
), -EBUSY
);
1663 /* Static lease with an empty or omitted address is a valid entry,
1664 * the server removes any static lease with the specified mac address. */
1665 if (!address
|| address
->s_addr
== 0) {
1668 c
= (DHCPClientId
) {
1669 .length
= client_id_size
,
1673 dhcp_lease_free(hashmap_get(server
->static_leases_by_client_id
, &c
));
1677 lease
= new(DHCPLease
, 1);
1681 *lease
= (DHCPLease
) {
1682 .address
= address
->s_addr
,
1683 .client_id
.length
= client_id_size
,
1685 lease
->client_id
.data
= memdup(client_id
, client_id_size
);
1686 if (!lease
->client_id
.data
)
1689 lease
->server
= server
; /* This must be set just before hashmap_put(). */
1691 r
= hashmap_ensure_put(&server
->static_leases_by_client_id
, &dhcp_lease_hash_ops
, &lease
->client_id
, lease
);
1694 r
= hashmap_ensure_put(&server
->static_leases_by_address
, NULL
, UINT32_TO_PTR(lease
->address
), lease
);