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