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