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