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