Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : /***
3 : Copyright © 2014 Axis Communications AB. All rights reserved.
4 : ***/
5 :
6 : #include <arpa/inet.h>
7 : #include <errno.h>
8 : #include <netinet/if_ether.h>
9 : #include <stdio.h>
10 : #include <stdlib.h>
11 : #include <string.h>
12 :
13 : #include "sd-ipv4acd.h"
14 :
15 : #include "alloc-util.h"
16 : #include "arp-util.h"
17 : #include "ether-addr-util.h"
18 : #include "event-util.h"
19 : #include "fd-util.h"
20 : #include "in-addr-util.h"
21 : #include "list.h"
22 : #include "random-util.h"
23 : #include "siphash24.h"
24 : #include "string-util.h"
25 : #include "time-util.h"
26 :
27 : /* Constants from the RFC */
28 : #define PROBE_WAIT_USEC (1U * USEC_PER_SEC)
29 : #define PROBE_NUM 3U
30 : #define PROBE_MIN_USEC (1U * USEC_PER_SEC)
31 : #define PROBE_MAX_USEC (2U * USEC_PER_SEC)
32 : #define ANNOUNCE_WAIT_USEC (2U * USEC_PER_SEC)
33 : #define ANNOUNCE_NUM 2U
34 : #define ANNOUNCE_INTERVAL_USEC (2U * USEC_PER_SEC)
35 : #define MAX_CONFLICTS 10U
36 : #define RATE_LIMIT_INTERVAL_USEC (60U * USEC_PER_SEC)
37 : #define DEFEND_INTERVAL_USEC (10U * USEC_PER_SEC)
38 :
39 : typedef enum IPv4ACDState {
40 : IPV4ACD_STATE_INIT,
41 : IPV4ACD_STATE_STARTED,
42 : IPV4ACD_STATE_WAITING_PROBE,
43 : IPV4ACD_STATE_PROBING,
44 : IPV4ACD_STATE_WAITING_ANNOUNCE,
45 : IPV4ACD_STATE_ANNOUNCING,
46 : IPV4ACD_STATE_RUNNING,
47 : _IPV4ACD_STATE_MAX,
48 : _IPV4ACD_STATE_INVALID = -1
49 : } IPv4ACDState;
50 :
51 : struct sd_ipv4acd {
52 : unsigned n_ref;
53 :
54 : IPv4ACDState state;
55 : int ifindex;
56 : int fd;
57 :
58 : unsigned n_iteration;
59 : unsigned n_conflict;
60 :
61 : sd_event_source *receive_message_event_source;
62 : sd_event_source *timer_event_source;
63 :
64 : usec_t defend_window;
65 : be32_t address;
66 :
67 : /* External */
68 : struct ether_addr mac_addr;
69 :
70 : sd_event *event;
71 : int event_priority;
72 : sd_ipv4acd_callback_t callback;
73 : void* userdata;
74 : };
75 :
76 : #define log_ipv4acd_errno(acd, error, fmt, ...) log_internal(LOG_DEBUG, error, PROJECT_FILE, __LINE__, __func__, "IPV4ACD: " fmt, ##__VA_ARGS__)
77 : #define log_ipv4acd(acd, fmt, ...) log_ipv4acd_errno(acd, 0, fmt, ##__VA_ARGS__)
78 :
79 6 : static void ipv4acd_set_state(sd_ipv4acd *acd, IPv4ACDState st, bool reset_counter) {
80 6 : assert(acd);
81 6 : assert(st < _IPV4ACD_STATE_MAX);
82 :
83 6 : if (st == acd->state && !reset_counter)
84 0 : acd->n_iteration++;
85 : else {
86 6 : acd->state = st;
87 6 : acd->n_iteration = 0;
88 : }
89 6 : }
90 :
91 3 : static void ipv4acd_reset(sd_ipv4acd *acd) {
92 3 : assert(acd);
93 :
94 3 : (void) event_source_disable(acd->timer_event_source);
95 3 : acd->receive_message_event_source = sd_event_source_unref(acd->receive_message_event_source);
96 :
97 3 : acd->fd = safe_close(acd->fd);
98 :
99 3 : ipv4acd_set_state(acd, IPV4ACD_STATE_INIT, true);
100 3 : }
101 :
102 2 : static sd_ipv4acd *ipv4acd_free(sd_ipv4acd *acd) {
103 2 : assert(acd);
104 :
105 2 : acd->timer_event_source = sd_event_source_unref(acd->timer_event_source);
106 :
107 2 : ipv4acd_reset(acd);
108 2 : sd_ipv4acd_detach_event(acd);
109 :
110 2 : return mfree(acd);
111 : }
112 :
113 2 : DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_ipv4acd, sd_ipv4acd, ipv4acd_free);
114 :
115 2 : int sd_ipv4acd_new(sd_ipv4acd **ret) {
116 2 : _cleanup_(sd_ipv4acd_unrefp) sd_ipv4acd *acd = NULL;
117 :
118 2 : assert_return(ret, -EINVAL);
119 :
120 2 : acd = new(sd_ipv4acd, 1);
121 2 : if (!acd)
122 0 : return -ENOMEM;
123 :
124 2 : *acd = (sd_ipv4acd) {
125 : .n_ref = 1,
126 : .state = IPV4ACD_STATE_INIT,
127 : .ifindex = -1,
128 : .fd = -1,
129 : };
130 :
131 2 : *ret = TAKE_PTR(acd);
132 :
133 2 : return 0;
134 : }
135 :
136 1 : static void ipv4acd_client_notify(sd_ipv4acd *acd, int event) {
137 1 : assert(acd);
138 :
139 1 : if (!acd->callback)
140 0 : return;
141 :
142 1 : acd->callback(acd, event, acd->userdata);
143 : }
144 :
145 1 : int sd_ipv4acd_stop(sd_ipv4acd *acd) {
146 1 : assert_return(acd, -EINVAL);
147 :
148 1 : ipv4acd_reset(acd);
149 :
150 1 : log_ipv4acd(acd, "STOPPED");
151 :
152 1 : ipv4acd_client_notify(acd, SD_IPV4ACD_EVENT_STOP);
153 :
154 1 : return 0;
155 : }
156 :
157 : static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata);
158 :
159 3 : static int ipv4acd_set_next_wakeup(sd_ipv4acd *acd, usec_t usec, usec_t random_usec) {
160 : usec_t next_timeout, time_now;
161 :
162 3 : assert(acd);
163 :
164 3 : next_timeout = usec;
165 :
166 3 : if (random_usec > 0)
167 2 : next_timeout += (usec_t) random_u64() % random_usec;
168 :
169 3 : assert_se(sd_event_now(acd->event, clock_boottime_or_monotonic(), &time_now) >= 0);
170 :
171 3 : return event_reset_time(acd->event, &acd->timer_event_source,
172 : clock_boottime_or_monotonic(),
173 : time_now + next_timeout, 0,
174 : ipv4acd_on_timeout, acd,
175 3 : acd->event_priority, "ipv4acd-timer", true);
176 : }
177 :
178 0 : static bool ipv4acd_arp_conflict(sd_ipv4acd *acd, struct ether_arp *arp) {
179 0 : assert(acd);
180 0 : assert(arp);
181 :
182 : /* see the BPF */
183 0 : if (memcmp(arp->arp_spa, &acd->address, sizeof(acd->address)) == 0)
184 0 : return true;
185 :
186 : /* the TPA matched instead of the SPA, this is not a conflict */
187 0 : return false;
188 : }
189 :
190 2 : static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
191 2 : sd_ipv4acd *acd = userdata;
192 2 : int r = 0;
193 :
194 2 : assert(acd);
195 :
196 2 : switch (acd->state) {
197 :
198 1 : case IPV4ACD_STATE_STARTED:
199 1 : ipv4acd_set_state(acd, IPV4ACD_STATE_WAITING_PROBE, true);
200 :
201 1 : if (acd->n_conflict >= MAX_CONFLICTS) {
202 : char ts[FORMAT_TIMESPAN_MAX];
203 0 : log_ipv4acd(acd, "Max conflicts reached, delaying by %s", format_timespan(ts, sizeof(ts), RATE_LIMIT_INTERVAL_USEC, 0));
204 :
205 0 : r = ipv4acd_set_next_wakeup(acd, RATE_LIMIT_INTERVAL_USEC, PROBE_WAIT_USEC);
206 0 : if (r < 0)
207 0 : goto fail;
208 : } else {
209 1 : r = ipv4acd_set_next_wakeup(acd, 0, PROBE_WAIT_USEC);
210 1 : if (r < 0)
211 0 : goto fail;
212 : }
213 :
214 1 : break;
215 :
216 1 : case IPV4ACD_STATE_WAITING_PROBE:
217 : case IPV4ACD_STATE_PROBING:
218 : /* Send a probe */
219 1 : r = arp_send_probe(acd->fd, acd->ifindex, acd->address, &acd->mac_addr);
220 1 : if (r < 0) {
221 0 : log_ipv4acd_errno(acd, r, "Failed to send ARP probe: %m");
222 0 : goto fail;
223 1 : } else {
224 1 : _cleanup_free_ char *address = NULL;
225 1 : union in_addr_union addr = { .in.s_addr = acd->address };
226 :
227 1 : (void) in_addr_to_string(AF_INET, &addr, &address);
228 1 : log_ipv4acd(acd, "Probing %s", strna(address));
229 : }
230 :
231 1 : if (acd->n_iteration < PROBE_NUM - 2) {
232 1 : ipv4acd_set_state(acd, IPV4ACD_STATE_PROBING, false);
233 :
234 1 : r = ipv4acd_set_next_wakeup(acd, PROBE_MIN_USEC, (PROBE_MAX_USEC-PROBE_MIN_USEC));
235 1 : if (r < 0)
236 0 : goto fail;
237 : } else {
238 0 : ipv4acd_set_state(acd, IPV4ACD_STATE_WAITING_ANNOUNCE, true);
239 :
240 0 : r = ipv4acd_set_next_wakeup(acd, ANNOUNCE_WAIT_USEC, 0);
241 0 : if (r < 0)
242 0 : goto fail;
243 : }
244 :
245 1 : break;
246 :
247 0 : case IPV4ACD_STATE_ANNOUNCING:
248 0 : if (acd->n_iteration >= ANNOUNCE_NUM - 1) {
249 0 : ipv4acd_set_state(acd, IPV4ACD_STATE_RUNNING, false);
250 0 : break;
251 : }
252 :
253 : _fallthrough_;
254 : case IPV4ACD_STATE_WAITING_ANNOUNCE:
255 : /* Send announcement packet */
256 0 : r = arp_send_announcement(acd->fd, acd->ifindex, acd->address, &acd->mac_addr);
257 0 : if (r < 0) {
258 0 : log_ipv4acd_errno(acd, r, "Failed to send ARP announcement: %m");
259 0 : goto fail;
260 : } else
261 0 : log_ipv4acd(acd, "ANNOUNCE");
262 :
263 0 : ipv4acd_set_state(acd, IPV4ACD_STATE_ANNOUNCING, false);
264 :
265 0 : r = ipv4acd_set_next_wakeup(acd, ANNOUNCE_INTERVAL_USEC, 0);
266 0 : if (r < 0)
267 0 : goto fail;
268 :
269 0 : if (acd->n_iteration == 0) {
270 0 : acd->n_conflict = 0;
271 0 : ipv4acd_client_notify(acd, SD_IPV4ACD_EVENT_BIND);
272 : }
273 :
274 0 : break;
275 :
276 0 : default:
277 0 : assert_not_reached("Invalid state.");
278 : }
279 :
280 2 : return 0;
281 :
282 0 : fail:
283 0 : sd_ipv4acd_stop(acd);
284 0 : return 0;
285 : }
286 :
287 0 : static void ipv4acd_on_conflict(sd_ipv4acd *acd) {
288 0 : _cleanup_free_ char *address = NULL;
289 0 : union in_addr_union addr = { .in.s_addr = acd->address };
290 :
291 0 : assert(acd);
292 :
293 0 : acd->n_conflict++;
294 :
295 0 : (void) in_addr_to_string(AF_INET, &addr, &address);
296 0 : log_ipv4acd(acd, "Conflict on %s (%u)", strna(address), acd->n_conflict);
297 :
298 0 : ipv4acd_reset(acd);
299 0 : ipv4acd_client_notify(acd, SD_IPV4ACD_EVENT_CONFLICT);
300 0 : }
301 :
302 0 : static int ipv4acd_on_packet(
303 : sd_event_source *s,
304 : int fd,
305 : uint32_t revents,
306 : void *userdata) {
307 :
308 0 : sd_ipv4acd *acd = userdata;
309 : struct ether_arp packet;
310 : ssize_t n;
311 : int r;
312 :
313 0 : assert(s);
314 0 : assert(acd);
315 0 : assert(fd >= 0);
316 :
317 0 : n = recv(fd, &packet, sizeof(struct ether_arp), 0);
318 0 : if (n < 0) {
319 0 : if (IN_SET(errno, EAGAIN, EINTR))
320 0 : return 0;
321 :
322 0 : log_ipv4acd_errno(acd, errno, "Failed to read ARP packet: %m");
323 0 : goto fail;
324 : }
325 0 : if ((size_t) n != sizeof(struct ether_arp)) {
326 0 : log_ipv4acd(acd, "Ignoring too short ARP packet.");
327 0 : return 0;
328 : }
329 :
330 0 : switch (acd->state) {
331 :
332 0 : case IPV4ACD_STATE_ANNOUNCING:
333 : case IPV4ACD_STATE_RUNNING:
334 :
335 0 : if (ipv4acd_arp_conflict(acd, &packet)) {
336 : usec_t ts;
337 :
338 0 : assert_se(sd_event_now(acd->event, clock_boottime_or_monotonic(), &ts) >= 0);
339 :
340 : /* Defend address */
341 0 : if (ts > acd->defend_window) {
342 0 : acd->defend_window = ts + DEFEND_INTERVAL_USEC;
343 0 : r = arp_send_announcement(acd->fd, acd->ifindex, acd->address, &acd->mac_addr);
344 0 : if (r < 0) {
345 0 : log_ipv4acd_errno(acd, r, "Failed to send ARP announcement: %m");
346 0 : goto fail;
347 : } else
348 0 : log_ipv4acd(acd, "DEFEND");
349 :
350 : } else
351 0 : ipv4acd_on_conflict(acd);
352 : }
353 0 : break;
354 :
355 0 : case IPV4ACD_STATE_WAITING_PROBE:
356 : case IPV4ACD_STATE_PROBING:
357 : case IPV4ACD_STATE_WAITING_ANNOUNCE:
358 : /* BPF ensures this packet indicates a conflict */
359 0 : ipv4acd_on_conflict(acd);
360 0 : break;
361 :
362 0 : default:
363 0 : assert_not_reached("Invalid state.");
364 : }
365 :
366 0 : return 0;
367 :
368 0 : fail:
369 0 : sd_ipv4acd_stop(acd);
370 0 : return 0;
371 : }
372 :
373 3 : int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int ifindex) {
374 3 : assert_return(acd, -EINVAL);
375 3 : assert_return(ifindex > 0, -EINVAL);
376 3 : assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY);
377 :
378 3 : acd->ifindex = ifindex;
379 :
380 3 : return 0;
381 : }
382 :
383 2 : int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr) {
384 2 : assert_return(acd, -EINVAL);
385 2 : assert_return(addr, -EINVAL);
386 2 : assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY);
387 :
388 2 : acd->mac_addr = *addr;
389 :
390 2 : return 0;
391 : }
392 :
393 2 : int sd_ipv4acd_detach_event(sd_ipv4acd *acd) {
394 2 : assert_return(acd, -EINVAL);
395 :
396 2 : acd->event = sd_event_unref(acd->event);
397 :
398 2 : return 0;
399 : }
400 :
401 3 : int sd_ipv4acd_attach_event(sd_ipv4acd *acd, sd_event *event, int64_t priority) {
402 : int r;
403 :
404 3 : assert_return(acd, -EINVAL);
405 3 : assert_return(!acd->event, -EBUSY);
406 :
407 2 : if (event)
408 2 : acd->event = sd_event_ref(event);
409 : else {
410 0 : r = sd_event_default(&acd->event);
411 0 : if (r < 0)
412 0 : return r;
413 : }
414 :
415 2 : acd->event_priority = priority;
416 :
417 2 : return 0;
418 : }
419 :
420 2 : int sd_ipv4acd_set_callback(sd_ipv4acd *acd, sd_ipv4acd_callback_t cb, void *userdata) {
421 2 : assert_return(acd, -EINVAL);
422 :
423 2 : acd->callback = cb;
424 2 : acd->userdata = userdata;
425 :
426 2 : return 0;
427 : }
428 :
429 4 : int sd_ipv4acd_set_address(sd_ipv4acd *acd, const struct in_addr *address) {
430 4 : assert_return(acd, -EINVAL);
431 4 : assert_return(address, -EINVAL);
432 4 : assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY);
433 :
434 4 : acd->address = address->s_addr;
435 :
436 4 : return 0;
437 : }
438 :
439 13 : int sd_ipv4acd_is_running(sd_ipv4acd *acd) {
440 13 : assert_return(acd, false);
441 :
442 13 : return acd->state != IPV4ACD_STATE_INIT;
443 : }
444 :
445 3 : int sd_ipv4acd_start(sd_ipv4acd *acd) {
446 : int r;
447 :
448 3 : assert_return(acd, -EINVAL);
449 3 : assert_return(acd->event, -EINVAL);
450 3 : assert_return(acd->ifindex > 0, -EINVAL);
451 1 : assert_return(acd->address != 0, -EINVAL);
452 1 : assert_return(!ether_addr_is_null(&acd->mac_addr), -EINVAL);
453 1 : assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY);
454 :
455 1 : r = arp_network_bind_raw_socket(acd->ifindex, acd->address, &acd->mac_addr);
456 1 : if (r < 0)
457 0 : return r;
458 :
459 1 : safe_close(acd->fd);
460 1 : acd->fd = r;
461 1 : acd->defend_window = 0;
462 1 : acd->n_conflict = 0;
463 :
464 1 : r = sd_event_add_io(acd->event, &acd->receive_message_event_source, acd->fd, EPOLLIN, ipv4acd_on_packet, acd);
465 1 : if (r < 0)
466 0 : goto fail;
467 :
468 1 : r = sd_event_source_set_priority(acd->receive_message_event_source, acd->event_priority);
469 1 : if (r < 0)
470 0 : goto fail;
471 :
472 1 : (void) sd_event_source_set_description(acd->receive_message_event_source, "ipv4acd-receive-message");
473 :
474 1 : r = ipv4acd_set_next_wakeup(acd, 0, 0);
475 1 : if (r < 0)
476 0 : goto fail;
477 :
478 1 : ipv4acd_set_state(acd, IPV4ACD_STATE_STARTED, true);
479 1 : return 0;
480 :
481 0 : fail:
482 0 : ipv4acd_reset(acd);
483 0 : return r;
484 : }
|