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