1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 Copyright © 2014 Axis Communications AB. All rights reserved.
6 #include <netinet/if_ether.h>
9 #include "sd-ipv4acd.h"
11 #include "alloc-util.h"
13 #include "errno-util.h"
14 #include "ether-addr-util.h"
15 #include "event-util.h"
17 #include "in-addr-util.h"
18 #include "memory-util.h"
19 #include "network-common.h"
20 #include "random-util.h"
21 #include "socket-util.h"
22 #include "string-table.h"
23 #include "string-util.h"
24 #include "time-util.h"
26 /* Intervals from the RFC in seconds, need to be multiplied by the time unit */
30 #define ANNOUNCE_WAIT 2U
31 #define TOTAL_TIME_UNITS 7U
33 /* Intervals from the RFC not adjusted to the time unit */
34 #define ANNOUNCE_INTERVAL_USEC (2U * USEC_PER_SEC)
35 #define RATE_LIMIT_INTERVAL_USEC (60U * USEC_PER_SEC)
36 #define DEFEND_INTERVAL_USEC (10U * USEC_PER_SEC)
38 /* Other constants from the RFC */
40 #define ANNOUNCE_NUM 2U
41 #define MAX_CONFLICTS 10U
43 /* Default timeout from the RFC */
44 #define DEFAULT_ACD_TIMEOUT_USEC (200 * USEC_PER_MSEC)
46 typedef enum IPv4ACDState
{
48 IPV4ACD_STATE_STARTED
,
49 IPV4ACD_STATE_WAITING_PROBE
,
50 IPV4ACD_STATE_PROBING
,
51 IPV4ACD_STATE_WAITING_ANNOUNCE
,
52 IPV4ACD_STATE_ANNOUNCING
,
53 IPV4ACD_STATE_RUNNING
,
55 _IPV4ACD_STATE_INVALID
= -EINVAL
,
69 /* Indicates the duration of a "time unit", i.e. one second in the RFC but scaled to the
70 * chosen total duration. Represents 1/7 of the total conflict detection timeout. */
71 usec_t time_unit_usec
;
73 sd_event_source
*receive_message_event_source
;
74 sd_event_source
*timer_event_source
;
77 struct in_addr address
;
80 struct ether_addr mac_addr
;
84 sd_ipv4acd_callback_t callback
;
86 sd_ipv4acd_check_mac_callback_t check_mac_callback
;
87 void *check_mac_userdata
;
90 #define log_ipv4acd_errno(acd, error, fmt, ...) \
91 log_interface_prefix_full_errno( \
94 error, fmt, ##__VA_ARGS__)
95 #define log_ipv4acd(acd, fmt, ...) \
96 log_interface_prefix_full_errno_zerook( \
99 0, fmt, ##__VA_ARGS__)
101 static const char * const ipv4acd_state_table
[_IPV4ACD_STATE_MAX
] = {
102 [IPV4ACD_STATE_INIT
] = "init",
103 [IPV4ACD_STATE_STARTED
] = "started",
104 [IPV4ACD_STATE_WAITING_PROBE
] = "waiting-probe",
105 [IPV4ACD_STATE_PROBING
] = "probing",
106 [IPV4ACD_STATE_WAITING_ANNOUNCE
] = "waiting-announce",
107 [IPV4ACD_STATE_ANNOUNCING
] = "announcing",
108 [IPV4ACD_STATE_RUNNING
] = "running",
111 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(ipv4acd_state
, IPv4ACDState
);
113 static void ipv4acd_set_state(sd_ipv4acd
*acd
, IPv4ACDState st
, bool reset_counter
) {
115 assert(st
< _IPV4ACD_STATE_MAX
);
117 if (st
!= acd
->state
)
118 log_ipv4acd(acd
, "%s -> %s", ipv4acd_state_to_string(acd
->state
), ipv4acd_state_to_string(st
));
120 if (st
== acd
->state
&& !reset_counter
)
124 acd
->n_iteration
= 0;
128 static void ipv4acd_reset(sd_ipv4acd
*acd
) {
131 (void) event_source_disable(acd
->timer_event_source
);
132 acd
->receive_message_event_source
= sd_event_source_disable_unref(acd
->receive_message_event_source
);
134 acd
->fd
= safe_close(acd
->fd
);
136 ipv4acd_set_state(acd
, IPV4ACD_STATE_INIT
, true);
139 static sd_ipv4acd
*ipv4acd_free(sd_ipv4acd
*acd
) {
143 sd_event_source_unref(acd
->timer_event_source
);
144 sd_ipv4acd_detach_event(acd
);
149 DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_ipv4acd
, sd_ipv4acd
, ipv4acd_free
);
151 int sd_ipv4acd_new(sd_ipv4acd
**ret
) {
152 _cleanup_(sd_ipv4acd_unrefp
) sd_ipv4acd
*acd
= NULL
;
154 assert_return(ret
, -EINVAL
);
156 acd
= new(sd_ipv4acd
, 1);
160 *acd
= (sd_ipv4acd
) {
162 .state
= IPV4ACD_STATE_INIT
,
163 .time_unit_usec
= DEFAULT_ACD_TIMEOUT_USEC
/ TOTAL_TIME_UNITS
,
168 *ret
= TAKE_PTR(acd
);
173 static void ipv4acd_client_notify(sd_ipv4acd
*acd
, int event
) {
179 acd
->callback(acd
, event
, acd
->userdata
);
182 int sd_ipv4acd_stop(sd_ipv4acd
*acd
) {
183 IPv4ACDState old_state
;
188 old_state
= acd
->state
;
192 if (old_state
== IPV4ACD_STATE_INIT
)
195 log_ipv4acd(acd
, "STOPPED");
197 ipv4acd_client_notify(acd
, SD_IPV4ACD_EVENT_STOP
);
202 static int ipv4acd_on_timeout(sd_event_source
*s
, uint64_t usec
, void *userdata
);
204 static int ipv4acd_set_next_wakeup(sd_ipv4acd
*acd
, usec_t usec
, usec_t random_usec
) {
205 usec_t next_timeout
, time_now
;
212 next_timeout
+= (usec_t
) random_u64() % random_usec
;
214 assert_se(sd_event_now(acd
->event
, CLOCK_BOOTTIME
, &time_now
) >= 0);
216 return event_reset_time(acd
->event
, &acd
->timer_event_source
,
218 time_now
+ next_timeout
, 0,
219 ipv4acd_on_timeout
, acd
,
220 acd
->event_priority
, "ipv4acd-timer", true);
223 static int ipv4acd_on_timeout(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
224 sd_ipv4acd
*acd
= ASSERT_PTR(userdata
);
227 switch (acd
->state
) {
229 case IPV4ACD_STATE_STARTED
:
230 acd
->defend_window
= 0;
233 "Started on address " IPV4_ADDRESS_FMT_STR
" with a max timeout of %s",
234 IPV4_ADDRESS_FMT_VAL(acd
->address
),
235 FORMAT_TIMESPAN(TOTAL_TIME_UNITS
* acd
->time_unit_usec
, USEC_PER_MSEC
));
237 ipv4acd_set_state(acd
, IPV4ACD_STATE_WAITING_PROBE
, true);
239 if (acd
->n_conflict
>= MAX_CONFLICTS
) {
240 log_ipv4acd(acd
, "Max conflicts reached, delaying by %s",
241 FORMAT_TIMESPAN(RATE_LIMIT_INTERVAL_USEC
, 0));
242 r
= ipv4acd_set_next_wakeup(
243 acd
, RATE_LIMIT_INTERVAL_USEC
, PROBE_WAIT
* acd
->time_unit_usec
);
245 r
= ipv4acd_set_next_wakeup(acd
, 0, PROBE_WAIT
* acd
->time_unit_usec
);
251 case IPV4ACD_STATE_WAITING_PROBE
:
252 case IPV4ACD_STATE_PROBING
:
254 r
= arp_send_probe(acd
->fd
, acd
->ifindex
, &acd
->address
, &acd
->mac_addr
);
256 log_ipv4acd_errno(acd
, r
, "Failed to send ARP probe: %m");
260 log_ipv4acd(acd
, "Probing "IPV4_ADDRESS_FMT_STR
, IPV4_ADDRESS_FMT_VAL(acd
->address
));
262 if (acd
->n_iteration
< PROBE_NUM
- 2) {
263 ipv4acd_set_state(acd
, IPV4ACD_STATE_PROBING
, false);
265 r
= ipv4acd_set_next_wakeup(
267 PROBE_MIN
* acd
->time_unit_usec
,
268 (PROBE_MAX
- PROBE_MIN
) * acd
->time_unit_usec
);
272 ipv4acd_set_state(acd
, IPV4ACD_STATE_WAITING_ANNOUNCE
, true);
274 r
= ipv4acd_set_next_wakeup(acd
, ANNOUNCE_WAIT
* acd
->time_unit_usec
, 0);
281 case IPV4ACD_STATE_ANNOUNCING
:
282 if (acd
->n_iteration
>= ANNOUNCE_NUM
- 1) {
283 ipv4acd_set_state(acd
, IPV4ACD_STATE_RUNNING
, false);
288 case IPV4ACD_STATE_WAITING_ANNOUNCE
:
289 /* Send announcement packet */
290 r
= arp_send_announcement(acd
->fd
, acd
->ifindex
, &acd
->address
, &acd
->mac_addr
);
292 log_ipv4acd_errno(acd
, r
, "Failed to send ARP announcement: %m");
296 log_ipv4acd(acd
, "Announcing "IPV4_ADDRESS_FMT_STR
, IPV4_ADDRESS_FMT_VAL(acd
->address
));
298 ipv4acd_set_state(acd
, IPV4ACD_STATE_ANNOUNCING
, false);
300 r
= ipv4acd_set_next_wakeup(acd
, ANNOUNCE_INTERVAL_USEC
, 0);
304 if (acd
->n_iteration
== 0) {
306 ipv4acd_client_notify(acd
, SD_IPV4ACD_EVENT_BIND
);
312 assert_not_reached();
318 sd_ipv4acd_stop(acd
);
322 static bool ipv4acd_arp_conflict(sd_ipv4acd
*acd
, const struct ether_arp
*arp
, bool announced
) {
326 /* RFC 5227 section 2.1.1.
327 * "the host receives any ARP packet (Request *or* Reply) on the interface where the probe is
328 * being performed, where the packet's 'sender IP address' is the address being probed for,
329 * then the host MUST treat this address as being in use by some other host" */
330 if (memcmp(arp
->arp_spa
, &acd
->address
, sizeof(struct in_addr
)) == 0)
334 /* the TPA matched instead of SPA, this is not a conflict */
337 /* "any ARP Probe where the packet's 'target IP address' is the address being probed for, and
338 * the packet's 'sender hardware address' is not the hardware address of any of the host's
339 * interfaces, then the host SHOULD similarly treat this as an address conflict" */
340 if (arp
->ea_hdr
.ar_op
!= htobe16(ARPOP_REQUEST
))
341 return false; /* not ARP Request, ignoring. */
342 if (memeqzero(arp
->arp_spa
, sizeof(struct in_addr
)) == 0)
343 return false; /* not ARP Probe, ignoring. */
344 if (memcmp(arp
->arp_tpa
, &acd
->address
, sizeof(struct in_addr
)) != 0)
345 return false; /* target IP address does not match, BPF code is broken? */
347 if (acd
->check_mac_callback
&&
348 acd
->check_mac_callback(acd
, (const struct ether_addr
*) arp
->arp_sha
, acd
->check_mac_userdata
) > 0)
349 /* sender hardware is one of the host's interfaces, ignoring. */
352 return true; /* conflict! */
355 static void ipv4acd_on_conflict(sd_ipv4acd
*acd
) {
360 log_ipv4acd(acd
, "Conflict on "IPV4_ADDRESS_FMT_STR
" (%u)", IPV4_ADDRESS_FMT_VAL(acd
->address
), acd
->n_conflict
);
363 ipv4acd_client_notify(acd
, SD_IPV4ACD_EVENT_CONFLICT
);
366 static int ipv4acd_on_packet(
372 sd_ipv4acd
*acd
= ASSERT_PTR(userdata
);
373 struct ether_arp packet
;
380 n
= recv(fd
, &packet
, sizeof(struct ether_arp
), 0);
382 if (ERRNO_IS_TRANSIENT(errno
) || ERRNO_IS_DISCONNECT(errno
))
385 log_ipv4acd_errno(acd
, errno
, "Failed to read ARP packet: %m");
388 if ((size_t) n
!= sizeof(struct ether_arp
)) {
389 log_ipv4acd(acd
, "Ignoring too short ARP packet.");
393 switch (acd
->state
) {
395 case IPV4ACD_STATE_ANNOUNCING
:
396 case IPV4ACD_STATE_RUNNING
:
398 if (ipv4acd_arp_conflict(acd
, &packet
, true)) {
401 assert_se(sd_event_now(acd
->event
, CLOCK_BOOTTIME
, &ts
) >= 0);
404 if (ts
> acd
->defend_window
) {
405 acd
->defend_window
= ts
+ DEFEND_INTERVAL_USEC
;
406 r
= arp_send_announcement(acd
->fd
, acd
->ifindex
, &acd
->address
, &acd
->mac_addr
);
408 log_ipv4acd_errno(acd
, r
, "Failed to send ARP announcement: %m");
412 log_ipv4acd(acd
, "Defending "IPV4_ADDRESS_FMT_STR
, IPV4_ADDRESS_FMT_VAL(acd
->address
));
415 ipv4acd_on_conflict(acd
);
419 case IPV4ACD_STATE_STARTED
:
420 case IPV4ACD_STATE_WAITING_PROBE
:
421 case IPV4ACD_STATE_PROBING
:
422 case IPV4ACD_STATE_WAITING_ANNOUNCE
:
423 if (ipv4acd_arp_conflict(acd
, &packet
, false))
424 ipv4acd_on_conflict(acd
);
428 assert_not_reached();
434 sd_ipv4acd_stop(acd
);
438 int sd_ipv4acd_set_ifindex(sd_ipv4acd
*acd
, int ifindex
) {
439 assert_return(acd
, -EINVAL
);
440 assert_return(ifindex
> 0, -EINVAL
);
441 assert_return(acd
->state
== IPV4ACD_STATE_INIT
, -EBUSY
);
443 acd
->ifindex
= ifindex
;
448 int sd_ipv4acd_get_ifindex(sd_ipv4acd
*acd
) {
455 int sd_ipv4acd_set_ifname(sd_ipv4acd
*acd
, const char *ifname
) {
456 assert_return(acd
, -EINVAL
);
457 assert_return(ifname
, -EINVAL
);
459 if (!ifname_valid_full(ifname
, IFNAME_VALID_ALTERNATIVE
))
462 return free_and_strdup(&acd
->ifname
, ifname
);
465 int sd_ipv4acd_set_timeout(sd_ipv4acd
*acd
, uint64_t usec
) {
466 assert_return(acd
, -EINVAL
);
469 usec
= DEFAULT_ACD_TIMEOUT_USEC
;
471 /* Clamp the total duration to a value between 1ms and 1 minute */
472 acd
->time_unit_usec
= DIV_ROUND_UP(
473 CLAMP(usec
, 1U * USEC_PER_MSEC
, 1U * USEC_PER_MINUTE
), TOTAL_TIME_UNITS
);
478 int sd_ipv4acd_get_ifname(sd_ipv4acd
*acd
, const char **ret
) {
481 assert_return(acd
, -EINVAL
);
483 r
= get_ifname(acd
->ifindex
, &acd
->ifname
);
493 int sd_ipv4acd_set_mac(sd_ipv4acd
*acd
, const struct ether_addr
*addr
) {
496 assert_return(acd
, -EINVAL
);
497 assert_return(addr
, -EINVAL
);
498 assert_return(!ether_addr_is_null(addr
), -EINVAL
);
500 acd
->mac_addr
= *addr
;
502 if (!sd_ipv4acd_is_running(acd
))
505 assert(acd
->fd
>= 0);
506 r
= arp_update_filter(acd
->fd
, &acd
->address
, &acd
->mac_addr
);
515 int sd_ipv4acd_detach_event(sd_ipv4acd
*acd
) {
516 assert_return(acd
, -EINVAL
);
518 acd
->event
= sd_event_unref(acd
->event
);
523 int sd_ipv4acd_attach_event(sd_ipv4acd
*acd
, sd_event
*event
, int64_t priority
) {
526 assert_return(acd
, -EINVAL
);
527 assert_return(!acd
->event
, -EBUSY
);
530 acd
->event
= sd_event_ref(event
);
532 r
= sd_event_default(&acd
->event
);
537 acd
->event_priority
= priority
;
542 int sd_ipv4acd_set_callback(sd_ipv4acd
*acd
, sd_ipv4acd_callback_t cb
, void *userdata
) {
543 assert_return(acd
, -EINVAL
);
546 acd
->userdata
= userdata
;
551 int sd_ipv4acd_set_check_mac_callback(sd_ipv4acd
*acd
, sd_ipv4acd_check_mac_callback_t cb
, void *userdata
) {
552 assert_return(acd
, -EINVAL
);
554 acd
->check_mac_callback
= cb
;
555 acd
->check_mac_userdata
= userdata
;
559 int sd_ipv4acd_set_address(sd_ipv4acd
*acd
, const struct in_addr
*address
) {
562 assert_return(acd
, -EINVAL
);
563 assert_return(address
, -EINVAL
);
564 assert_return(in4_addr_is_set(address
), -EINVAL
);
566 if (in4_addr_equal(&acd
->address
, address
))
569 acd
->address
= *address
;
571 if (!sd_ipv4acd_is_running(acd
))
574 assert(acd
->fd
>= 0);
575 r
= arp_update_filter(acd
->fd
, &acd
->address
, &acd
->mac_addr
);
579 r
= ipv4acd_set_next_wakeup(acd
, 0, 0);
583 ipv4acd_set_state(acd
, IPV4ACD_STATE_STARTED
, true);
591 int sd_ipv4acd_get_address(sd_ipv4acd
*acd
, struct in_addr
*address
) {
592 assert_return(acd
, -EINVAL
);
593 assert_return(address
, -EINVAL
);
595 *address
= acd
->address
;
600 int sd_ipv4acd_is_running(sd_ipv4acd
*acd
) {
604 return acd
->state
!= IPV4ACD_STATE_INIT
;
607 int sd_ipv4acd_is_bound(sd_ipv4acd
*acd
) {
608 assert_return(acd
, false);
610 return IN_SET(acd
->state
, IPV4ACD_STATE_ANNOUNCING
, IPV4ACD_STATE_RUNNING
);
613 int sd_ipv4acd_start(sd_ipv4acd
*acd
, bool reset_conflicts
) {
616 assert_return(acd
, -EINVAL
);
617 assert_return(acd
->event
, -EINVAL
);
618 assert_return(acd
->ifindex
> 0, -EINVAL
);
619 assert_return(in4_addr_is_set(&acd
->address
), -EINVAL
);
620 assert_return(!ether_addr_is_null(&acd
->mac_addr
), -EINVAL
);
621 assert_return(acd
->state
== IPV4ACD_STATE_INIT
, -EBUSY
);
623 r
= sd_event_get_state(acd
->event
);
626 if (r
== SD_EVENT_FINISHED
)
629 r
= arp_network_bind_raw_socket(acd
->ifindex
, &acd
->address
, &acd
->mac_addr
);
633 close_and_replace(acd
->fd
, r
);
638 r
= sd_event_add_io(acd
->event
, &acd
->receive_message_event_source
, acd
->fd
, EPOLLIN
, ipv4acd_on_packet
, acd
);
642 r
= sd_event_source_set_priority(acd
->receive_message_event_source
, acd
->event_priority
);
646 (void) sd_event_source_set_description(acd
->receive_message_event_source
, "ipv4acd-receive-message");
648 r
= ipv4acd_set_next_wakeup(acd
, 0, 0);
652 ipv4acd_set_state(acd
, IPV4ACD_STATE_STARTED
, true);