1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright (C) 2013 Intel Corporation. All rights reserved.
7 Copyright (C) 2014 Tom Gundersen
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <sys/ioctl.h>
25 #include "siphash24.h"
27 #include "sd-dhcp-server.h"
28 #include "dhcp-server-internal.h"
29 #include "dhcp-internal.h"
31 #define DHCP_DEFAULT_LEASE_TIME 3600 /* one hour */
33 int sd_dhcp_server_set_lease_pool(sd_dhcp_server
*server
,
34 struct in_addr
*address
,
36 assert_return(server
, -EINVAL
);
37 assert_return(address
, -EINVAL
);
38 assert_return(address
->s_addr
, -EINVAL
);
39 assert_return(size
, -EINVAL
);
40 assert_return(server
->pool_start
== htobe32(INADDR_ANY
), -EBUSY
);
41 assert_return(!server
->pool_size
, -EBUSY
);
42 assert_return(!server
->bound_leases
, -EBUSY
);
44 server
->bound_leases
= new0(DHCPLease
*, size
);
45 if (!server
->bound_leases
)
48 server
->pool_start
= address
->s_addr
;
49 server
->pool_size
= size
;
54 int sd_dhcp_server_set_address(sd_dhcp_server
*server
, struct in_addr
*address
,
55 unsigned char prefixlen
) {
56 assert_return(server
, -EINVAL
);
57 assert_return(address
, -EINVAL
);
58 assert_return(address
->s_addr
, -EINVAL
);
59 assert_return(prefixlen
<= 32, -ERANGE
);
60 assert_return(server
->address
== htobe32(INADDR_ANY
), -EBUSY
);
61 assert_return(server
->netmask
== htobe32(INADDR_ANY
), -EBUSY
);
63 server
->address
= address
->s_addr
;
64 server
->netmask
= htobe32(0xfffffffflu
<< (32 - prefixlen
));
69 bool sd_dhcp_server_is_running(sd_dhcp_server
*server
) {
70 assert_return(server
, false);
72 return !!server
->receive_message
;
75 sd_dhcp_server
*sd_dhcp_server_ref(sd_dhcp_server
*server
) {
80 assert(server
->n_ref
>= 1);
86 unsigned long client_id_hash_func(const void *p
,
87 const uint8_t hash_key
[HASH_KEY_SIZE
]) {
89 const DHCPClientId
*id
= p
;
95 siphash24((uint8_t*) &u
, id
->data
, id
->length
, hash_key
);
97 return (unsigned long) u
;
100 int client_id_compare_func(const void *_a
, const void *_b
) {
101 const DHCPClientId
*a
, *b
;
106 assert(!a
->length
|| a
->data
);
107 assert(!b
->length
|| b
->data
);
109 if (a
->length
!= b
->length
)
110 return a
->length
< b
->length
? -1 : 1;
112 return memcmp(a
->data
, b
->data
, a
->length
);
115 static const struct hash_ops client_id_hash_ops
= {
116 .hash
= client_id_hash_func
,
117 .compare
= client_id_compare_func
120 static void dhcp_lease_free(DHCPLease
*lease
) {
124 free(lease
->client_id
.data
);
128 sd_dhcp_server
*sd_dhcp_server_unref(sd_dhcp_server
*server
) {
134 assert(server
->n_ref
>= 1);
137 if (server
->n_ref
> 0)
140 log_dhcp_server(server
, "UNREF");
142 sd_dhcp_server_stop(server
);
144 sd_event_unref(server
->event
);
146 free(server
->timezone
);
148 while ((lease
= hashmap_steal_first(server
->leases_by_client_id
)))
149 dhcp_lease_free(lease
);
150 hashmap_free(server
->leases_by_client_id
);
152 free(server
->bound_leases
);
158 int sd_dhcp_server_new(sd_dhcp_server
**ret
, int ifindex
) {
159 _cleanup_dhcp_server_unref_ sd_dhcp_server
*server
= NULL
;
161 assert_return(ret
, -EINVAL
);
162 assert_return(ifindex
> 0, -EINVAL
);
164 server
= new0(sd_dhcp_server
, 1);
171 server
->address
= htobe32(INADDR_ANY
);
172 server
->netmask
= htobe32(INADDR_ANY
);
173 server
->index
= ifindex
;
174 server
->leases_by_client_id
= hashmap_new(&client_id_hash_ops
);
182 int sd_dhcp_server_attach_event(sd_dhcp_server
*server
, sd_event
*event
,
186 assert_return(server
, -EINVAL
);
187 assert_return(!server
->event
, -EBUSY
);
190 server
->event
= sd_event_ref(event
);
192 r
= sd_event_default(&server
->event
);
197 server
->event_priority
= priority
;
202 int sd_dhcp_server_detach_event(sd_dhcp_server
*server
) {
203 assert_return(server
, -EINVAL
);
205 server
->event
= sd_event_unref(server
->event
);
210 sd_event
*sd_dhcp_server_get_event(sd_dhcp_server
*server
) {
211 assert_return(server
, NULL
);
213 return server
->event
;
216 int sd_dhcp_server_stop(sd_dhcp_server
*server
) {
217 assert_return(server
, -EINVAL
);
219 server
->receive_message
=
220 sd_event_source_unref(server
->receive_message
);
222 server
->fd_raw
= safe_close(server
->fd_raw
);
223 server
->fd
= safe_close(server
->fd
);
225 log_dhcp_server(server
, "STOPPED");
230 static int dhcp_server_send_unicast_raw(sd_dhcp_server
*server
,
231 DHCPPacket
*packet
, size_t len
) {
232 union sockaddr_union link
= {
233 .ll
.sll_family
= AF_PACKET
,
234 .ll
.sll_protocol
= htons(ETH_P_IP
),
235 .ll
.sll_ifindex
= server
->index
,
236 .ll
.sll_halen
= ETH_ALEN
,
241 assert(server
->index
> 0);
242 assert(server
->address
);
244 assert(len
> sizeof(DHCPPacket
));
246 memcpy(&link
.ll
.sll_addr
, &packet
->dhcp
.chaddr
, ETH_ALEN
);
248 dhcp_packet_append_ip_headers(packet
, server
->address
, DHCP_PORT_SERVER
,
250 DHCP_PORT_CLIENT
, len
);
252 r
= dhcp_network_send_raw_socket(server
->fd_raw
, &link
, packet
, len
);
259 static int dhcp_server_send_udp(sd_dhcp_server
*server
, be32_t destination
,
260 DHCPMessage
*message
, size_t len
) {
261 union sockaddr_union dest
= {
262 .in
.sin_family
= AF_INET
,
263 .in
.sin_port
= htobe16(DHCP_PORT_CLIENT
),
264 .in
.sin_addr
.s_addr
= destination
,
270 uint8_t cmsgbuf
[CMSG_LEN(sizeof(struct in_pktinfo
))] = {};
271 struct msghdr msg
= {
273 .msg_namelen
= sizeof(dest
.in
),
276 .msg_control
= cmsgbuf
,
277 .msg_controllen
= sizeof(cmsgbuf
),
279 struct cmsghdr
*cmsg
;
280 struct in_pktinfo
*pktinfo
;
284 assert(server
->fd
> 0);
286 assert(len
> sizeof(DHCPMessage
));
288 cmsg
= CMSG_FIRSTHDR(&msg
);
291 cmsg
->cmsg_level
= IPPROTO_IP
;
292 cmsg
->cmsg_type
= IP_PKTINFO
;
293 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct in_pktinfo
));
295 /* we attach source interface and address info to the message
296 rather than binding the socket. This will be mostly useful
297 when we gain support for arbitrary number of server addresses
299 pktinfo
= (struct in_pktinfo
*) CMSG_DATA(cmsg
);
302 pktinfo
->ipi_ifindex
= server
->index
;
303 pktinfo
->ipi_spec_dst
.s_addr
= server
->address
;
305 r
= sendmsg(server
->fd
, &msg
, 0);
312 static bool requested_broadcast(DHCPRequest
*req
) {
315 return req
->message
->flags
& htobe16(0x8000);
318 int dhcp_server_send_packet(sd_dhcp_server
*server
,
319 DHCPRequest
*req
, DHCPPacket
*packet
,
320 int type
, size_t optoffset
) {
321 be32_t destination
= INADDR_ANY
;
326 assert(req
->max_optlen
);
327 assert(optoffset
<= req
->max_optlen
);
330 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &optoffset
, 0,
331 DHCP_OPTION_SERVER_IDENTIFIER
,
332 4, &server
->address
);
336 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &optoffset
, 0,
337 DHCP_OPTION_END
, 0, NULL
);
341 /* RFC 2131 Section 4.1
343 If the ’giaddr’ field in a DHCP message from a client is non-zero,
344 the server sends any return messages to the ’DHCP server’ port on the
345 BOOTP relay agent whose address appears in ’giaddr’. If the ’giaddr’
346 field is zero and the ’ciaddr’ field is nonzero, then the server
347 unicasts DHCPOFFER and DHCPACK messages to the address in ’ciaddr’.
348 If ’giaddr’ is zero and ’ciaddr’ is zero, and the broadcast bit is
349 set, then the server broadcasts DHCPOFFER and DHCPACK messages to
350 0xffffffff. If the broadcast bit is not set and ’giaddr’ is zero and
351 ’ciaddr’ is zero, then the server unicasts DHCPOFFER and DHCPACK
352 messages to the client’s hardware address and ’yiaddr’ address. In
353 all cases, when ’giaddr’ is zero, the server broadcasts any DHCPNAK
354 messages to 0xffffffff.
358 If ’giaddr’ is set in the DHCPREQUEST message, the client is on a
359 different subnet. The server MUST set the broadcast bit in the
360 DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
361 client, because the client may not have a correct network address
362 or subnet mask, and the client may not be answering ARP requests.
364 if (req
->message
->giaddr
) {
365 destination
= req
->message
->giaddr
;
366 if (type
== DHCP_NAK
)
367 packet
->dhcp
.flags
= htobe16(0x8000);
368 } else if (req
->message
->ciaddr
&& type
!= DHCP_NAK
)
369 destination
= req
->message
->ciaddr
;
371 if (destination
!= INADDR_ANY
)
372 return dhcp_server_send_udp(server
, destination
, &packet
->dhcp
,
373 sizeof(DHCPMessage
) + optoffset
);
374 else if (requested_broadcast(req
) || type
== DHCP_NAK
)
375 return dhcp_server_send_udp(server
, INADDR_BROADCAST
,
377 sizeof(DHCPMessage
) + optoffset
);
379 /* we cannot send UDP packet to specific MAC address when the
380 address is not yet configured, so must fall back to raw
382 return dhcp_server_send_unicast_raw(server
, packet
,
383 sizeof(DHCPPacket
) + optoffset
);
386 static int server_message_init(sd_dhcp_server
*server
, DHCPPacket
**ret
,
387 uint8_t type
, size_t *_optoffset
,
389 _cleanup_free_ DHCPPacket
*packet
= NULL
;
390 size_t optoffset
= 0;
396 assert(IN_SET(type
, DHCP_OFFER
, DHCP_ACK
, DHCP_NAK
));
398 packet
= malloc0(sizeof(DHCPPacket
) + req
->max_optlen
);
402 r
= dhcp_message_init(&packet
->dhcp
, BOOTREPLY
,
403 be32toh(req
->message
->xid
), type
, ARPHRD_ETHER
,
404 req
->max_optlen
, &optoffset
);
408 packet
->dhcp
.flags
= req
->message
->flags
;
409 packet
->dhcp
.giaddr
= req
->message
->giaddr
;
410 memcpy(&packet
->dhcp
.chaddr
, &req
->message
->chaddr
, ETH_ALEN
);
412 *_optoffset
= optoffset
;
419 static int server_send_offer(sd_dhcp_server
*server
, DHCPRequest
*req
,
421 _cleanup_free_ DHCPPacket
*packet
= NULL
;
426 r
= server_message_init(server
, &packet
, DHCP_OFFER
, &offset
, req
);
430 packet
->dhcp
.yiaddr
= address
;
432 lease_time
= htobe32(req
->lifetime
);
433 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
434 DHCP_OPTION_IP_ADDRESS_LEASE_TIME
, 4,
439 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
440 DHCP_OPTION_SUBNET_MASK
, 4, &server
->netmask
);
444 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
445 DHCP_OPTION_ROUTER
, 4, &server
->address
);
449 r
= dhcp_server_send_packet(server
, req
, packet
, DHCP_OFFER
, offset
);
456 static int server_send_ack(sd_dhcp_server
*server
, DHCPRequest
*req
,
458 _cleanup_free_ DHCPPacket
*packet
= NULL
;
463 r
= server_message_init(server
, &packet
, DHCP_ACK
, &offset
, req
);
467 packet
->dhcp
.yiaddr
= address
;
469 lease_time
= htobe32(req
->lifetime
);
470 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
471 DHCP_OPTION_IP_ADDRESS_LEASE_TIME
, 4,
476 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
477 DHCP_OPTION_SUBNET_MASK
, 4, &server
->netmask
);
481 r
= dhcp_option_append(&packet
->dhcp
, req
->max_optlen
, &offset
, 0,
482 DHCP_OPTION_ROUTER
, 4, &server
->address
);
486 if (server
->timezone
) {
487 r
= dhcp_option_append(
488 &packet
->dhcp
, req
->max_optlen
, &offset
, 0,
489 DHCP_OPTION_NEW_TZDB_TIMEZONE
,
490 strlen(server
->timezone
), server
->timezone
);
495 r
= dhcp_server_send_packet(server
, req
, packet
, DHCP_ACK
, offset
);
502 static int server_send_nak(sd_dhcp_server
*server
, DHCPRequest
*req
) {
503 _cleanup_free_ DHCPPacket
*packet
= NULL
;
507 r
= server_message_init(server
, &packet
, DHCP_NAK
, &offset
, req
);
511 r
= dhcp_server_send_packet(server
, req
, packet
, DHCP_NAK
, offset
);
518 static int server_send_forcerenew(sd_dhcp_server
*server
, be32_t address
,
519 be32_t gateway
, uint8_t chaddr
[]) {
520 _cleanup_free_ DHCPPacket
*packet
= NULL
;
521 size_t optoffset
= 0;
525 assert(address
!= INADDR_ANY
);
528 packet
= malloc0(sizeof(DHCPPacket
) + DHCP_MIN_OPTIONS_SIZE
);
532 r
= dhcp_message_init(&packet
->dhcp
, BOOTREPLY
, 0,
533 DHCP_FORCERENEW
, ARPHRD_ETHER
,
534 DHCP_MIN_OPTIONS_SIZE
, &optoffset
);
538 r
= dhcp_option_append(&packet
->dhcp
, DHCP_MIN_OPTIONS_SIZE
,
539 &optoffset
, 0, DHCP_OPTION_END
, 0, NULL
);
543 memcpy(&packet
->dhcp
.chaddr
, chaddr
, ETH_ALEN
);
545 r
= dhcp_server_send_udp(server
, address
, &packet
->dhcp
,
546 sizeof(DHCPMessage
) + optoffset
);
553 static int parse_request(uint8_t code
, uint8_t len
, const void *option
,
555 DHCPRequest
*req
= userdata
;
560 case DHCP_OPTION_IP_ADDRESS_LEASE_TIME
:
562 req
->lifetime
= be32toh(*(be32_t
*)option
);
565 case DHCP_OPTION_REQUESTED_IP_ADDRESS
:
567 req
->requested_ip
= *(be32_t
*)option
;
570 case DHCP_OPTION_SERVER_IDENTIFIER
:
572 req
->server_id
= *(be32_t
*)option
;
575 case DHCP_OPTION_CLIENT_IDENTIFIER
:
579 data
= memdup(option
, len
);
583 free(req
->client_id
.data
);
584 req
->client_id
.data
= data
;
585 req
->client_id
.length
= len
;
589 case DHCP_OPTION_MAXIMUM_MESSAGE_SIZE
:
591 req
->max_optlen
= be16toh(*(be16_t
*)option
) -
592 - sizeof(DHCPPacket
);
600 static void dhcp_request_free(DHCPRequest
*req
) {
604 free(req
->client_id
.data
);
608 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest
*, dhcp_request_free
);
609 #define _cleanup_dhcp_request_free_ _cleanup_(dhcp_request_freep)
611 static int ensure_sane_request(DHCPRequest
*req
, DHCPMessage
*message
) {
615 req
->message
= message
;
617 /* set client id based on MAC address if client did not send an explicit
619 if (!req
->client_id
.data
) {
622 data
= new0(uint8_t, ETH_ALEN
+ 1);
626 req
->client_id
.length
= ETH_ALEN
+ 1;
627 req
->client_id
.data
= data
;
628 req
->client_id
.data
[0] = 0x01;
629 memcpy(&req
->client_id
.data
[1], &message
->chaddr
, ETH_ALEN
);
632 if (req
->max_optlen
< DHCP_MIN_OPTIONS_SIZE
)
633 req
->max_optlen
= DHCP_MIN_OPTIONS_SIZE
;
636 req
->lifetime
= DHCP_DEFAULT_LEASE_TIME
;
641 static int get_pool_offset(sd_dhcp_server
*server
, be32_t requested_ip
) {
644 if (!server
->pool_size
)
647 if (be32toh(requested_ip
) < be32toh(server
->pool_start
) ||
648 be32toh(requested_ip
) >= be32toh(server
->pool_start
) +
652 return be32toh(requested_ip
) - be32toh(server
->pool_start
);
655 int dhcp_server_handle_message(sd_dhcp_server
*server
, DHCPMessage
*message
,
657 _cleanup_dhcp_request_free_ DHCPRequest
*req
= NULL
;
658 DHCPLease
*existing_lease
;
664 if (message
->op
!= BOOTREQUEST
||
665 message
->htype
!= ARPHRD_ETHER
||
666 message
->hlen
!= ETHER_ADDR_LEN
)
669 req
= new0(DHCPRequest
, 1);
673 type
= dhcp_option_parse(message
, length
, parse_request
, req
);
677 r
= ensure_sane_request(req
, message
);
679 /* this only fails on critical errors */
682 existing_lease
= hashmap_get(server
->leases_by_client_id
,
688 be32_t address
= INADDR_ANY
;
691 log_dhcp_server(server
, "DISCOVER (0x%x)",
692 be32toh(req
->message
->xid
));
694 if (!server
->pool_size
)
695 /* no pool allocated */
698 /* for now pick a random free address from the pool */
700 address
= existing_lease
->address
;
702 for (i
= 0; i
< server
->pool_size
; i
++) {
703 if (!server
->bound_leases
[server
->next_offer
]) {
704 address
= htobe32(be32toh(server
->pool_start
) + server
->next_offer
);
707 server
->next_offer
= (server
->next_offer
+ 1) % server
->pool_size
;
711 if (address
== INADDR_ANY
)
712 /* no free addresses left */
715 r
= server_send_offer(server
, req
, address
);
717 /* this only fails on critical errors */
718 log_dhcp_server(server
, "could not send offer: %s",
722 log_dhcp_server(server
, "OFFER (0x%x)",
723 be32toh(req
->message
->xid
));
730 log_dhcp_server(server
, "DECLINE (0x%x)",
731 be32toh(req
->message
->xid
));
733 /* TODO: make sure we don't offer this address again */
741 bool init_reboot
= false;
744 /* see RFC 2131, section 4.3.2 */
746 if (req
->server_id
) {
747 log_dhcp_server(server
, "REQUEST (selecting) (0x%x)",
748 be32toh(req
->message
->xid
));
751 if (req
->server_id
!= server
->address
)
752 /* client did not pick us */
755 if (req
->message
->ciaddr
)
756 /* this MUST be zero */
759 if (!req
->requested_ip
)
760 /* this must be filled in with the yiaddr
761 from the chosen OFFER */
764 address
= req
->requested_ip
;
765 } else if (req
->requested_ip
) {
766 log_dhcp_server(server
, "REQUEST (init-reboot) (0x%x)",
767 be32toh(req
->message
->xid
));
770 if (req
->message
->ciaddr
)
771 /* this MUST be zero */
774 /* TODO: check more carefully if IP is correct */
775 address
= req
->requested_ip
;
778 log_dhcp_server(server
, "REQUEST (rebinding/renewing) (0x%x)",
779 be32toh(req
->message
->xid
));
781 /* REBINDING / RENEWING */
782 if (!req
->message
->ciaddr
)
783 /* this MUST be filled in with clients IP address */
786 address
= req
->message
->ciaddr
;
789 pool_offset
= get_pool_offset(server
, address
);
791 /* verify that the requested address is from the pool, and either
792 owned by the current client or free */
793 if (pool_offset
>= 0 &&
794 server
->bound_leases
[pool_offset
] == existing_lease
) {
798 if (!existing_lease
) {
799 lease
= new0(DHCPLease
, 1);
800 lease
->address
= req
->requested_ip
;
801 lease
->client_id
.data
= memdup(req
->client_id
.data
,
802 req
->client_id
.length
);
803 if (!lease
->client_id
.data
) {
807 lease
->client_id
.length
= req
->client_id
.length
;
808 memcpy(&lease
->chaddr
, &req
->message
->chaddr
,
810 lease
->gateway
= req
->message
->giaddr
;
812 lease
= existing_lease
;
814 r
= sd_event_now(server
->event
,
815 clock_boottime_or_monotonic(),
819 dhcp_lease_free(lease
);
823 lease
->expiration
= req
->lifetime
* USEC_PER_SEC
+ time_now
;
825 r
= server_send_ack(server
, req
, address
);
827 /* this only fails on critical errors */
828 log_dhcp_server(server
, "could not send ack: %s",
832 dhcp_lease_free(lease
);
836 log_dhcp_server(server
, "ACK (0x%x)",
837 be32toh(req
->message
->xid
));
839 server
->bound_leases
[pool_offset
] = lease
;
840 hashmap_put(server
->leases_by_client_id
,
841 &lease
->client_id
, lease
);
845 } else if (init_reboot
) {
846 r
= server_send_nak(server
, req
);
848 /* this only fails on critical errors */
849 log_dhcp_server(server
, "could not send nak: %s",
853 log_dhcp_server(server
, "NAK (0x%x)",
854 be32toh(req
->message
->xid
));
864 log_dhcp_server(server
, "RELEASE (0x%x)",
865 be32toh(req
->message
->xid
));
870 if (existing_lease
->address
!= req
->message
->ciaddr
)
873 pool_offset
= get_pool_offset(server
, req
->message
->ciaddr
);
877 if (server
->bound_leases
[pool_offset
] == existing_lease
) {
878 server
->bound_leases
[pool_offset
] = NULL
;
879 hashmap_remove(server
->leases_by_client_id
, existing_lease
);
880 dhcp_lease_free(existing_lease
);
891 static int server_receive_message(sd_event_source
*s
, int fd
,
892 uint32_t revents
, void *userdata
) {
893 _cleanup_free_ DHCPMessage
*message
= NULL
;
894 uint8_t cmsgbuf
[CMSG_LEN(sizeof(struct in_pktinfo
))];
895 sd_dhcp_server
*server
= userdata
;
896 struct iovec iov
= {};
897 struct msghdr msg
= {
900 .msg_control
= cmsgbuf
,
901 .msg_controllen
= sizeof(cmsgbuf
),
903 struct cmsghdr
*cmsg
;
908 if (ioctl(fd
, FIONREAD
, &buflen
) < 0)
913 message
= malloc0(buflen
);
917 iov
.iov_base
= message
;
918 iov
.iov_len
= buflen
;
920 len
= recvmsg(fd
, &msg
, 0);
923 else if ((size_t)len
< sizeof(DHCPMessage
))
926 CMSG_FOREACH(cmsg
, &msg
) {
927 if (cmsg
->cmsg_level
== IPPROTO_IP
&&
928 cmsg
->cmsg_type
== IP_PKTINFO
&&
929 cmsg
->cmsg_len
== CMSG_LEN(sizeof(struct in_pktinfo
))) {
930 struct in_pktinfo
*info
= (struct in_pktinfo
*)CMSG_DATA(cmsg
);
932 /* TODO figure out if this can be done as a filter on
933 * the socket, like for IPv6 */
934 if (server
->index
!= info
->ipi_ifindex
)
941 return dhcp_server_handle_message(server
, message
, (size_t)len
);
944 int sd_dhcp_server_start(sd_dhcp_server
*server
) {
947 assert_return(server
, -EINVAL
);
948 assert_return(server
->event
, -EINVAL
);
949 assert_return(!server
->receive_message
, -EBUSY
);
950 assert_return(server
->fd_raw
== -1, -EBUSY
);
951 assert_return(server
->fd
== -1, -EBUSY
);
952 assert_return(server
->address
!= htobe32(INADDR_ANY
), -EUNATCH
);
954 r
= socket(AF_PACKET
, SOCK_DGRAM
| SOCK_NONBLOCK
, 0);
957 sd_dhcp_server_stop(server
);
962 r
= dhcp_network_bind_udp_socket(INADDR_ANY
, DHCP_PORT_SERVER
);
964 sd_dhcp_server_stop(server
);
969 r
= sd_event_add_io(server
->event
, &server
->receive_message
,
971 server_receive_message
, server
);
973 sd_dhcp_server_stop(server
);
977 r
= sd_event_source_set_priority(server
->receive_message
,
978 server
->event_priority
);
980 sd_dhcp_server_stop(server
);
984 log_dhcp_server(server
, "STARTED");
989 int sd_dhcp_server_forcerenew(sd_dhcp_server
*server
) {
993 assert_return(server
, -EINVAL
);
994 assert(server
->bound_leases
);
996 for (i
= 0; i
< server
->pool_size
; i
++) {
997 DHCPLease
*lease
= server
->bound_leases
[i
];
1002 r
= server_send_forcerenew(server
, lease
->address
,
1008 log_dhcp_server(server
, "FORCERENEW");
1014 int sd_dhcp_server_set_timezone(sd_dhcp_server
*server
, const char *timezone
) {
1017 assert_return(server
, -EINVAL
);
1018 assert_return(timezone_is_valid(timezone
), -EINVAL
);
1020 if (streq_ptr(timezone
, server
->timezone
))
1023 r
= free_and_strdup(&server
->timezone
, timezone
);