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