]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-ipv4acd.c
ff36f3eec1ee4e31ec828adbf6bb4537bdbad2da
[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 = 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 assert_return(acd, -EINVAL);
172
173 ipv4acd_reset(acd);
174
175 log_ipv4acd(acd, "STOPPED");
176
177 ipv4acd_client_notify(acd, SD_IPV4ACD_EVENT_STOP);
178
179 return 0;
180 }
181
182 static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata);
183
184 static int ipv4acd_set_next_wakeup(sd_ipv4acd *acd, usec_t usec, usec_t random_usec) {
185 _cleanup_(sd_event_source_unrefp) sd_event_source *timer = NULL;
186 usec_t next_timeout, time_now;
187 int r;
188
189 assert(acd);
190
191 next_timeout = usec;
192
193 if (random_usec > 0)
194 next_timeout += (usec_t) random_u64() % random_usec;
195
196 assert_se(sd_event_now(acd->event, clock_boottime_or_monotonic(), &time_now) >= 0);
197
198 r = sd_event_add_time(acd->event, &timer, clock_boottime_or_monotonic(), time_now + next_timeout, 0, ipv4acd_on_timeout, acd);
199 if (r < 0)
200 return r;
201
202 r = sd_event_source_set_priority(timer, acd->event_priority);
203 if (r < 0)
204 return r;
205
206 (void) sd_event_source_set_description(timer, "ipv4acd-timer");
207
208 sd_event_source_unref(acd->timer_event_source);
209 acd->timer_event_source = TAKE_PTR(timer);
210
211 return 0;
212 }
213
214 static bool ipv4acd_arp_conflict(sd_ipv4acd *acd, struct ether_arp *arp) {
215 assert(acd);
216 assert(arp);
217
218 /* see the BPF */
219 if (memcmp(arp->arp_spa, &acd->address, sizeof(acd->address)) == 0)
220 return true;
221
222 /* the TPA matched instead of the SPA, this is not a conflict */
223 return false;
224 }
225
226 static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
227 sd_ipv4acd *acd = userdata;
228 int r = 0;
229
230 assert(acd);
231
232 switch (acd->state) {
233
234 case IPV4ACD_STATE_STARTED:
235 ipv4acd_set_state(acd, IPV4ACD_STATE_WAITING_PROBE, true);
236
237 if (acd->n_conflict >= MAX_CONFLICTS) {
238 char ts[FORMAT_TIMESPAN_MAX];
239 log_ipv4acd(acd, "Max conflicts reached, delaying by %s", format_timespan(ts, sizeof(ts), RATE_LIMIT_INTERVAL_USEC, 0));
240
241 r = ipv4acd_set_next_wakeup(acd, RATE_LIMIT_INTERVAL_USEC, PROBE_WAIT_USEC);
242 if (r < 0)
243 goto fail;
244 } else {
245 r = ipv4acd_set_next_wakeup(acd, 0, PROBE_WAIT_USEC);
246 if (r < 0)
247 goto fail;
248 }
249
250 break;
251
252 case IPV4ACD_STATE_WAITING_PROBE:
253 case IPV4ACD_STATE_PROBING:
254 /* Send a probe */
255 r = arp_send_probe(acd->fd, acd->ifindex, acd->address, &acd->mac_addr);
256 if (r < 0) {
257 log_ipv4acd_errno(acd, r, "Failed to send ARP probe: %m");
258 goto fail;
259 } else {
260 _cleanup_free_ char *address = NULL;
261 union in_addr_union addr = { .in.s_addr = acd->address };
262
263 (void) in_addr_to_string(AF_INET, &addr, &address);
264 log_ipv4acd(acd, "Probing %s", strna(address));
265 }
266
267 if (acd->n_iteration < PROBE_NUM - 2) {
268 ipv4acd_set_state(acd, IPV4ACD_STATE_PROBING, false);
269
270 r = ipv4acd_set_next_wakeup(acd, PROBE_MIN_USEC, (PROBE_MAX_USEC-PROBE_MIN_USEC));
271 if (r < 0)
272 goto fail;
273 } else {
274 ipv4acd_set_state(acd, IPV4ACD_STATE_WAITING_ANNOUNCE, true);
275
276 r = ipv4acd_set_next_wakeup(acd, ANNOUNCE_WAIT_USEC, 0);
277 if (r < 0)
278 goto fail;
279 }
280
281 break;
282
283 case IPV4ACD_STATE_ANNOUNCING:
284 if (acd->n_iteration >= ANNOUNCE_NUM - 1) {
285 ipv4acd_set_state(acd, IPV4ACD_STATE_RUNNING, false);
286 break;
287 }
288
289 _fallthrough_;
290 case IPV4ACD_STATE_WAITING_ANNOUNCE:
291 /* Send announcement packet */
292 r = arp_send_announcement(acd->fd, acd->ifindex, acd->address, &acd->mac_addr);
293 if (r < 0) {
294 log_ipv4acd_errno(acd, r, "Failed to send ARP announcement: %m");
295 goto fail;
296 } else
297 log_ipv4acd(acd, "ANNOUNCE");
298
299 ipv4acd_set_state(acd, IPV4ACD_STATE_ANNOUNCING, false);
300
301 r = ipv4acd_set_next_wakeup(acd, ANNOUNCE_INTERVAL_USEC, 0);
302 if (r < 0)
303 goto fail;
304
305 if (acd->n_iteration == 0) {
306 acd->n_conflict = 0;
307 ipv4acd_client_notify(acd, SD_IPV4ACD_EVENT_BIND);
308 }
309
310 break;
311
312 default:
313 assert_not_reached("Invalid state.");
314 }
315
316 return 0;
317
318 fail:
319 sd_ipv4acd_stop(acd);
320 return 0;
321 }
322
323 static void ipv4acd_on_conflict(sd_ipv4acd *acd) {
324 _cleanup_free_ char *address = NULL;
325 union in_addr_union addr = { .in.s_addr = acd->address };
326
327 assert(acd);
328
329 acd->n_conflict++;
330
331 (void) in_addr_to_string(AF_INET, &addr, &address);
332 log_ipv4acd(acd, "Conflict on %s (%u)", strna(address), acd->n_conflict);
333
334 ipv4acd_reset(acd);
335 ipv4acd_client_notify(acd, SD_IPV4ACD_EVENT_CONFLICT);
336 }
337
338 static int ipv4acd_on_packet(
339 sd_event_source *s,
340 int fd,
341 uint32_t revents,
342 void *userdata) {
343
344 sd_ipv4acd *acd = userdata;
345 struct ether_arp packet;
346 ssize_t n;
347 int r;
348
349 assert(s);
350 assert(acd);
351 assert(fd >= 0);
352
353 n = recv(fd, &packet, sizeof(struct ether_arp), 0);
354 if (n < 0) {
355 if (IN_SET(errno, EAGAIN, EINTR))
356 return 0;
357
358 log_ipv4acd_errno(acd, errno, "Failed to read ARP packet: %m");
359 goto fail;
360 }
361 if ((size_t) n != sizeof(struct ether_arp)) {
362 log_ipv4acd(acd, "Ignoring too short ARP packet.");
363 return 0;
364 }
365
366 switch (acd->state) {
367
368 case IPV4ACD_STATE_ANNOUNCING:
369 case IPV4ACD_STATE_RUNNING:
370
371 if (ipv4acd_arp_conflict(acd, &packet)) {
372 usec_t ts;
373
374 assert_se(sd_event_now(acd->event, clock_boottime_or_monotonic(), &ts) >= 0);
375
376 /* Defend address */
377 if (ts > acd->defend_window) {
378 acd->defend_window = ts + DEFEND_INTERVAL_USEC;
379 r = arp_send_announcement(acd->fd, acd->ifindex, acd->address, &acd->mac_addr);
380 if (r < 0) {
381 log_ipv4acd_errno(acd, r, "Failed to send ARP announcement: %m");
382 goto fail;
383 } else
384 log_ipv4acd(acd, "DEFEND");
385
386 } else
387 ipv4acd_on_conflict(acd);
388 }
389 break;
390
391 case IPV4ACD_STATE_WAITING_PROBE:
392 case IPV4ACD_STATE_PROBING:
393 case IPV4ACD_STATE_WAITING_ANNOUNCE:
394 /* BPF ensures this packet indicates a conflict */
395 ipv4acd_on_conflict(acd);
396 break;
397
398 default:
399 assert_not_reached("Invalid state.");
400 }
401
402 return 0;
403
404 fail:
405 sd_ipv4acd_stop(acd);
406 return 0;
407 }
408
409 int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int ifindex) {
410 assert_return(acd, -EINVAL);
411 assert_return(ifindex > 0, -EINVAL);
412 assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY);
413
414 acd->ifindex = ifindex;
415
416 return 0;
417 }
418
419 int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr) {
420 assert_return(acd, -EINVAL);
421 assert_return(addr, -EINVAL);
422 assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY);
423
424 acd->mac_addr = *addr;
425
426 return 0;
427 }
428
429 int sd_ipv4acd_detach_event(sd_ipv4acd *acd) {
430 assert_return(acd, -EINVAL);
431
432 acd->event = sd_event_unref(acd->event);
433
434 return 0;
435 }
436
437 int sd_ipv4acd_attach_event(sd_ipv4acd *acd, sd_event *event, int64_t priority) {
438 int r;
439
440 assert_return(acd, -EINVAL);
441 assert_return(!acd->event, -EBUSY);
442
443 if (event)
444 acd->event = sd_event_ref(event);
445 else {
446 r = sd_event_default(&acd->event);
447 if (r < 0)
448 return r;
449 }
450
451 acd->event_priority = priority;
452
453 return 0;
454 }
455
456 int sd_ipv4acd_set_callback(sd_ipv4acd *acd, sd_ipv4acd_callback_t cb, void *userdata) {
457 assert_return(acd, -EINVAL);
458
459 acd->callback = cb;
460 acd->userdata = userdata;
461
462 return 0;
463 }
464
465 int sd_ipv4acd_set_address(sd_ipv4acd *acd, const struct in_addr *address) {
466 assert_return(acd, -EINVAL);
467 assert_return(address, -EINVAL);
468 assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY);
469
470 acd->address = address->s_addr;
471
472 return 0;
473 }
474
475 int sd_ipv4acd_is_running(sd_ipv4acd *acd) {
476 assert_return(acd, false);
477
478 return acd->state != IPV4ACD_STATE_INIT;
479 }
480
481 int sd_ipv4acd_start(sd_ipv4acd *acd) {
482 int r;
483
484 assert_return(acd, -EINVAL);
485 assert_return(acd->event, -EINVAL);
486 assert_return(acd->ifindex > 0, -EINVAL);
487 assert_return(acd->address != 0, -EINVAL);
488 assert_return(!ether_addr_is_null(&acd->mac_addr), -EINVAL);
489 assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY);
490
491 r = arp_network_bind_raw_socket(acd->ifindex, acd->address, &acd->mac_addr);
492 if (r < 0)
493 return r;
494
495 safe_close(acd->fd);
496 acd->fd = r;
497 acd->defend_window = 0;
498 acd->n_conflict = 0;
499
500 r = sd_event_add_io(acd->event, &acd->receive_message_event_source, acd->fd, EPOLLIN, ipv4acd_on_packet, acd);
501 if (r < 0)
502 goto fail;
503
504 r = sd_event_source_set_priority(acd->receive_message_event_source, acd->event_priority);
505 if (r < 0)
506 goto fail;
507
508 (void) sd_event_source_set_description(acd->receive_message_event_source, "ipv4acd-receive-message");
509
510 r = ipv4acd_set_next_wakeup(acd, 0, 0);
511 if (r < 0)
512 goto fail;
513
514 ipv4acd_set_state(acd, IPV4ACD_STATE_STARTED, true);
515 return 0;
516
517 fail:
518 ipv4acd_reset(acd);
519 return r;
520 }