]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-ipv4acd.c
Add SPDX license identifiers to source files under the LGPL
[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 /* fall through */
292
293 case IPV4ACD_STATE_WAITING_ANNOUNCE:
294 /* Send announcement packet */
295 r = arp_send_announcement(acd->fd, acd->ifindex, acd->address, &acd->mac_addr);
296 if (r < 0) {
297 log_ipv4acd_errno(acd, r, "Failed to send ARP announcement: %m");
298 goto fail;
299 } else
300 log_ipv4acd(acd, "ANNOUNCE");
301
302 ipv4acd_set_state(acd, IPV4ACD_STATE_ANNOUNCING, false);
303
304 r = ipv4acd_set_next_wakeup(acd, ANNOUNCE_INTERVAL_USEC, 0);
305 if (r < 0)
306 goto fail;
307
308 if (acd->n_iteration == 0) {
309 acd->n_conflict = 0;
310 ipv4acd_client_notify(acd, SD_IPV4ACD_EVENT_BIND);
311 }
312
313 break;
314
315 default:
316 assert_not_reached("Invalid state.");
317 }
318
319 return 0;
320
321 fail:
322 sd_ipv4acd_stop(acd);
323 return 0;
324 }
325
326 static void ipv4acd_on_conflict(sd_ipv4acd *acd) {
327 _cleanup_free_ char *address = NULL;
328 union in_addr_union addr = { .in.s_addr = acd->address };
329
330 assert(acd);
331
332 acd->n_conflict++;
333
334 (void) in_addr_to_string(AF_INET, &addr, &address);
335 log_ipv4acd(acd, "Conflict on %s (%u)", strna(address), acd->n_conflict);
336
337 ipv4acd_reset(acd);
338 ipv4acd_client_notify(acd, SD_IPV4ACD_EVENT_CONFLICT);
339 }
340
341 static int ipv4acd_on_packet(
342 sd_event_source *s,
343 int fd,
344 uint32_t revents,
345 void *userdata) {
346
347 sd_ipv4acd *acd = userdata;
348 struct ether_arp packet;
349 ssize_t n;
350 int r;
351
352 assert(s);
353 assert(acd);
354 assert(fd >= 0);
355
356 n = recv(fd, &packet, sizeof(struct ether_arp), 0);
357 if (n < 0) {
358 if (IN_SET(errno, EAGAIN, EINTR))
359 return 0;
360
361 log_ipv4acd_errno(acd, errno, "Failed to read ARP packet: %m");
362 goto fail;
363 }
364 if ((size_t) n != sizeof(struct ether_arp)) {
365 log_ipv4acd(acd, "Ignoring too short ARP packet.");
366 return 0;
367 }
368
369 switch (acd->state) {
370
371 case IPV4ACD_STATE_ANNOUNCING:
372 case IPV4ACD_STATE_RUNNING:
373
374 if (ipv4acd_arp_conflict(acd, &packet)) {
375 usec_t ts;
376
377 assert_se(sd_event_now(acd->event, clock_boottime_or_monotonic(), &ts) >= 0);
378
379 /* Defend address */
380 if (ts > acd->defend_window) {
381 acd->defend_window = ts + DEFEND_INTERVAL_USEC;
382 r = arp_send_announcement(acd->fd, acd->ifindex, acd->address, &acd->mac_addr);
383 if (r < 0) {
384 log_ipv4acd_errno(acd, r, "Failed to send ARP announcement: %m");
385 goto fail;
386 } else
387 log_ipv4acd(acd, "DEFEND");
388
389 } else
390 ipv4acd_on_conflict(acd);
391 }
392 break;
393
394 case IPV4ACD_STATE_WAITING_PROBE:
395 case IPV4ACD_STATE_PROBING:
396 case IPV4ACD_STATE_WAITING_ANNOUNCE:
397 /* BPF ensures this packet indicates a conflict */
398 ipv4acd_on_conflict(acd);
399 break;
400
401 default:
402 assert_not_reached("Invalid state.");
403 }
404
405 return 0;
406
407 fail:
408 sd_ipv4acd_stop(acd);
409 return 0;
410 }
411
412 int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int ifindex) {
413 assert_return(acd, -EINVAL);
414 assert_return(ifindex > 0, -EINVAL);
415 assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY);
416
417 acd->ifindex = ifindex;
418
419 return 0;
420 }
421
422 int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr) {
423 assert_return(acd, -EINVAL);
424 assert_return(addr, -EINVAL);
425 assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY);
426
427 acd->mac_addr = *addr;
428
429 return 0;
430 }
431
432 int sd_ipv4acd_detach_event(sd_ipv4acd *acd) {
433 assert_return(acd, -EINVAL);
434
435 acd->event = sd_event_unref(acd->event);
436
437 return 0;
438 }
439
440 int sd_ipv4acd_attach_event(sd_ipv4acd *acd, sd_event *event, int64_t priority) {
441 int r;
442
443 assert_return(acd, -EINVAL);
444 assert_return(!acd->event, -EBUSY);
445
446 if (event)
447 acd->event = sd_event_ref(event);
448 else {
449 r = sd_event_default(&acd->event);
450 if (r < 0)
451 return r;
452 }
453
454 acd->event_priority = priority;
455
456 return 0;
457 }
458
459 int sd_ipv4acd_set_callback(sd_ipv4acd *acd, sd_ipv4acd_callback_t cb, void *userdata) {
460 assert_return(acd, -EINVAL);
461
462 acd->callback = cb;
463 acd->userdata = userdata;
464
465 return 0;
466 }
467
468 int sd_ipv4acd_set_address(sd_ipv4acd *acd, const struct in_addr *address) {
469 assert_return(acd, -EINVAL);
470 assert_return(address, -EINVAL);
471 assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY);
472
473 acd->address = address->s_addr;
474
475 return 0;
476 }
477
478 int sd_ipv4acd_is_running(sd_ipv4acd *acd) {
479 assert_return(acd, false);
480
481 return acd->state != IPV4ACD_STATE_INIT;
482 }
483
484 int sd_ipv4acd_start(sd_ipv4acd *acd) {
485 int r;
486
487 assert_return(acd, -EINVAL);
488 assert_return(acd->event, -EINVAL);
489 assert_return(acd->ifindex > 0, -EINVAL);
490 assert_return(acd->address != 0, -EINVAL);
491 assert_return(!ether_addr_is_null(&acd->mac_addr), -EINVAL);
492 assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY);
493
494 r = arp_network_bind_raw_socket(acd->ifindex, acd->address, &acd->mac_addr);
495 if (r < 0)
496 return r;
497
498 safe_close(acd->fd);
499 acd->fd = r;
500 acd->defend_window = 0;
501 acd->n_conflict = 0;
502
503 r = sd_event_add_io(acd->event, &acd->receive_message_event_source, acd->fd, EPOLLIN, ipv4acd_on_packet, acd);
504 if (r < 0)
505 goto fail;
506
507 r = sd_event_source_set_priority(acd->receive_message_event_source, acd->event_priority);
508 if (r < 0)
509 goto fail;
510
511 (void) sd_event_source_set_description(acd->receive_message_event_source, "ipv4acd-receive-message");
512
513 r = ipv4acd_set_next_wakeup(acd, 0, 0);
514 if (r < 0)
515 goto fail;
516
517 ipv4acd_set_state(acd, IPV4ACD_STATE_STARTED, true);
518 return 0;
519
520 fail:
521 ipv4acd_reset(acd);
522 return r;
523 }