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