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