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