1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42#include "libbb.h"
43#include <netinet/ether.h>
44#include <net/if.h>
45#include <net/if_arp.h>
46#include <linux/sockios.h>
47
48#include <syslog.h>
49
50
51#define MONOTONIC_US() ((unsigned)monotonic_us())
52
53struct arp_packet {
54 struct ether_header eth;
55 struct ether_arp arp;
56} PACKED;
57
58enum {
59
60 LINKLOCAL_ADDR = 0xa9fe0000,
61
62
63 PROBE_WAIT = 1,
64 PROBE_MIN = 1,
65 PROBE_MAX = 2,
66 PROBE_NUM = 3,
67 MAX_CONFLICTS = 10,
68 RATE_LIMIT_INTERVAL = 60,
69 ANNOUNCE_WAIT = 2,
70 ANNOUNCE_NUM = 2,
71 ANNOUNCE_INTERVAL = 2,
72 DEFEND_INTERVAL = 10
73};
74
75
76enum {
77 PROBE = 0,
78 RATE_LIMIT_PROBE,
79 ANNOUNCE,
80 MONITOR,
81 DEFEND
82};
83
84#define VDBG(...) do { } while (0)
85
86
87enum {
88 sock_fd = 3
89};
90
91struct globals {
92 struct sockaddr saddr;
93 struct ether_addr eth_addr;
94 uint32_t localnet_ip;
95} FIX_ALIASING;
96#define G (*(struct globals*)&bb_common_bufsiz1)
97#define saddr (G.saddr )
98#define eth_addr (G.eth_addr)
99#define INIT_G() do { } while (0)
100
101
102
103
104
105
106static uint32_t pick_nip(void)
107{
108 unsigned tmp;
109
110 do {
111 tmp = rand() & IN_CLASSB_HOST;
112 } while (tmp > (IN_CLASSB_HOST - 0x0200));
113 return htonl((G.localnet_ip + 0x0100) + tmp);
114}
115
116
117
118
119static void arp(
120
121
122 struct in_addr source_ip,
123 const struct ether_addr *target_eth, struct in_addr target_ip)
124{
125 enum { op = ARPOP_REQUEST };
126#define source_eth (ð_addr)
127
128 struct arp_packet p;
129 memset(&p, 0, sizeof(p));
130
131
132 p.eth.ether_type = htons(ETHERTYPE_ARP);
133 memcpy(p.eth.ether_shost, source_eth, ETH_ALEN);
134 memset(p.eth.ether_dhost, 0xff, ETH_ALEN);
135
136
137 p.arp.arp_hrd = htons(ARPHRD_ETHER);
138 p.arp.arp_pro = htons(ETHERTYPE_IP);
139 p.arp.arp_hln = ETH_ALEN;
140 p.arp.arp_pln = 4;
141 p.arp.arp_op = htons(op);
142 memcpy(&p.arp.arp_sha, source_eth, ETH_ALEN);
143 memcpy(&p.arp.arp_spa, &source_ip, sizeof(p.arp.arp_spa));
144 memcpy(&p.arp.arp_tha, target_eth, ETH_ALEN);
145 memcpy(&p.arp.arp_tpa, &target_ip, sizeof(p.arp.arp_tpa));
146
147
148
149
150
151
152
153
154 xsendto(sock_fd, &p, sizeof(p), &saddr, sizeof(saddr));
155#undef source_eth
156}
157
158
159
160
161
162static int run(char *argv[3], const char *param, struct in_addr *ip)
163{
164 int status;
165 char *addr = addr;
166 const char *fmt = "%s %s %s" + 3;
167
168 argv[2] = (char*)param;
169
170 VDBG("%s run %s %s\n", argv[0], argv[1], argv[2]);
171
172 if (ip) {
173 addr = inet_ntoa(*ip);
174 xsetenv("ip", addr);
175 fmt -= 3;
176 }
177 bb_info_msg(fmt, argv[2], argv[0], addr);
178
179 status = spawn_and_wait(argv + 1);
180 if (status < 0) {
181 bb_perror_msg("%s %s %s" + 3, argv[2], argv[0]);
182 return -errno;
183 }
184 if (status != 0)
185 bb_error_msg("script %s %s failed, exitcode=%d", argv[1], argv[2], status & 0xff);
186 return status;
187}
188
189
190
191
192static ALWAYS_INLINE unsigned random_delay_ms(unsigned secs)
193{
194 return rand() % (secs * 1000);
195}
196
197
198
199
200int zcip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
201int zcip_main(int argc UNUSED_PARAM, char **argv)
202{
203 int state;
204 char *r_opt;
205 const char *l_opt = "169.254.0.0";
206 unsigned opts;
207
208
209 struct {
210 const struct in_addr null_ip;
211 const struct ether_addr null_addr;
212 struct in_addr ip;
213 struct ifreq ifr;
214 int timeout_ms;
215 unsigned conflicts;
216 unsigned nprobes;
217 unsigned nclaims;
218 int ready;
219 int verbose;
220 } L;
221#define null_ip (L.null_ip )
222#define null_addr (L.null_addr )
223#define ip (L.ip )
224#define ifr (L.ifr )
225#define timeout_ms (L.timeout_ms)
226#define conflicts (L.conflicts )
227#define nprobes (L.nprobes )
228#define nclaims (L.nclaims )
229#define ready (L.ready )
230#define verbose (L.verbose )
231
232 memset(&L, 0, sizeof(L));
233 INIT_G();
234
235#define FOREGROUND (opts & 1)
236#define QUIT (opts & 2)
237
238
239 opt_complementary = "=2:vv:vf";
240 opts = getopt32(argv, "fqr:l:v", &r_opt, &l_opt, &verbose);
241#if !BB_MMU
242
243 if (!FOREGROUND)
244 bb_daemonize_or_rexec(0 , argv);
245#endif
246
247
248
249 xmove_fd(xsocket(AF_PACKET, SOCK_PACKET, htons(ETH_P_ARP)), sock_fd);
250 if (!FOREGROUND) {
251
252 openlog(applet_name, 0, LOG_DAEMON);
253 logmode |= LOGMODE_SYSLOG;
254 }
255 bb_logenv_override();
256
257 {
258 struct in_addr net;
259 if (inet_aton(l_opt, &net) == 0
260 || (net.s_addr & htonl(IN_CLASSB_NET)) != net.s_addr
261 ) {
262 bb_error_msg_and_die("invalid network address");
263 }
264 G.localnet_ip = ntohl(net.s_addr);
265 }
266 if (opts & 4) {
267 if (inet_aton(r_opt, &ip) == 0
268 || (ntohl(ip.s_addr) & IN_CLASSB_NET) != G.localnet_ip
269 ) {
270 bb_error_msg_and_die("invalid link address");
271 }
272 }
273 argv += optind - 1;
274
275
276
277 argv[0] = argv[1];
278 argv[1] = argv[2];
279
280#define argv_intf (argv[0])
281
282 xsetenv("interface", argv_intf);
283
284
285 if (run(argv, "init", NULL))
286 return EXIT_FAILURE;
287
288
289
290
291
292 safe_strncpy(saddr.sa_data, argv_intf, sizeof(saddr.sa_data));
293
294
295 xbind(sock_fd, &saddr, sizeof(saddr));
296
297
298
299 strncpy_IFNAMSIZ(ifr.ifr_name, argv_intf);
300 xioctl(sock_fd, SIOCGIFHWADDR, &ifr);
301 memcpy(ð_addr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN);
302
303
304
305
306
307
308
309 {
310 uint32_t t;
311 move_from_unaligned32(t, ((char *)ð_addr + 2));
312 srand(t);
313 }
314 if (ip.s_addr == 0)
315 ip.s_addr = pick_nip();
316
317
318
319
320
321
322 if (!FOREGROUND) {
323#if BB_MMU
324 bb_daemonize(0 );
325#endif
326 bb_info_msg("start, interface %s", argv_intf);
327 }
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344 state = PROBE;
345 while (1) {
346 struct pollfd fds[1];
347 unsigned deadline_us;
348 struct arp_packet p;
349 int source_ip_conflict;
350 int target_ip_conflict;
351
352 fds[0].fd = sock_fd;
353 fds[0].events = POLLIN;
354 fds[0].revents = 0;
355
356
357 if (!timeout_ms) {
358 timeout_ms = random_delay_ms(PROBE_WAIT);
359
360
361
362 }
363
364 deadline_us = MONOTONIC_US() + timeout_ms * 1000;
365
366 VDBG("...wait %d %s nprobes=%u, nclaims=%u\n",
367 timeout_ms, argv_intf, nprobes, nclaims);
368
369 switch (safe_poll(fds, 1, timeout_ms)) {
370
371 default:
372
373 return EXIT_FAILURE;
374
375
376 case 0:
377 VDBG("state = %d\n", state);
378 switch (state) {
379 case PROBE:
380
381
382 if (nprobes < PROBE_NUM) {
383 nprobes++;
384 VDBG("probe/%u %s@%s\n",
385 nprobes, argv_intf, inet_ntoa(ip));
386 timeout_ms = PROBE_MIN * 1000;
387 timeout_ms += random_delay_ms(PROBE_MAX - PROBE_MIN);
388 arp(
389 null_ip,
390 &null_addr, ip);
391 }
392 else {
393
394 state = ANNOUNCE;
395 nclaims = 0;
396 VDBG("announce/%u %s@%s\n",
397 nclaims, argv_intf, inet_ntoa(ip));
398 timeout_ms = ANNOUNCE_INTERVAL * 1000;
399 arp(
400 ip,
401 ð_addr, ip);
402 }
403 break;
404 case RATE_LIMIT_PROBE:
405
406
407 state = ANNOUNCE;
408 nclaims = 0;
409 VDBG("announce/%u %s@%s\n",
410 nclaims, argv_intf, inet_ntoa(ip));
411 timeout_ms = ANNOUNCE_INTERVAL * 1000;
412 arp(
413 ip,
414 ð_addr, ip);
415 break;
416 case ANNOUNCE:
417
418
419 if (nclaims < ANNOUNCE_NUM) {
420 nclaims++;
421 VDBG("announce/%u %s@%s\n",
422 nclaims, argv_intf, inet_ntoa(ip));
423 timeout_ms = ANNOUNCE_INTERVAL * 1000;
424 arp(
425 ip,
426 ð_addr, ip);
427 }
428 else {
429
430 state = MONITOR;
431
432
433 run(argv, "config", &ip);
434 ready = 1;
435 conflicts = 0;
436 timeout_ms = -1;
437
438
439
440 if (QUIT)
441 return EXIT_SUCCESS;
442 }
443 break;
444 case DEFEND:
445
446 state = MONITOR;
447 timeout_ms = -1;
448 conflicts = 0;
449 break;
450 default:
451
452 state = PROBE;
453 ip.s_addr = pick_nip();
454 timeout_ms = 0;
455 nprobes = 0;
456 nclaims = 0;
457 break;
458 }
459 break;
460
461
462 case 1:
463
464
465 if (timeout_ms > 0) {
466 unsigned diff = deadline_us - MONOTONIC_US();
467 if ((int)(diff) < 0) {
468
469
470 VDBG("missed an expected timeout\n");
471 timeout_ms = 0;
472 } else {
473 VDBG("adjusting timeout\n");
474 timeout_ms = (diff / 1000) | 1;
475 }
476 }
477
478 if ((fds[0].revents & POLLIN) == 0) {
479 if (fds[0].revents & POLLERR) {
480
481
482 bb_error_msg("iface %s is down", argv_intf);
483 if (ready) {
484 run(argv, "deconfig", &ip);
485 }
486 return EXIT_FAILURE;
487 }
488 continue;
489 }
490
491
492 if (safe_read(sock_fd, &p, sizeof(p)) < 0) {
493 bb_perror_msg_and_die(bb_msg_read_error);
494 }
495 if (p.eth.ether_type != htons(ETHERTYPE_ARP))
496 continue;
497#ifdef DEBUG
498 {
499 struct ether_addr *sha = (struct ether_addr *) p.arp.arp_sha;
500 struct ether_addr *tha = (struct ether_addr *) p.arp.arp_tha;
501 struct in_addr *spa = (struct in_addr *) p.arp.arp_spa;
502 struct in_addr *tpa = (struct in_addr *) p.arp.arp_tpa;
503 VDBG("%s recv arp type=%d, op=%d,\n",
504 argv_intf, ntohs(p.eth.ether_type),
505 ntohs(p.arp.arp_op));
506 VDBG("\tsource=%s %s\n",
507 ether_ntoa(sha),
508 inet_ntoa(*spa));
509 VDBG("\ttarget=%s %s\n",
510 ether_ntoa(tha),
511 inet_ntoa(*tpa));
512 }
513#endif
514 if (p.arp.arp_op != htons(ARPOP_REQUEST)
515 && p.arp.arp_op != htons(ARPOP_REPLY)
516 ) {
517 continue;
518 }
519
520 source_ip_conflict = 0;
521 target_ip_conflict = 0;
522
523 if (memcmp(&p.arp.arp_sha, ð_addr, ETH_ALEN) != 0) {
524 if (memcmp(p.arp.arp_spa, &ip.s_addr, sizeof(struct in_addr))) {
525
526 source_ip_conflict = 1;
527 }
528 if (p.arp.arp_op == htons(ARPOP_REQUEST)
529 && memcmp(p.arp.arp_spa, &null_ip, sizeof(struct in_addr)) == 0
530 && memcmp(p.arp.arp_tpa, &ip.s_addr, sizeof(struct in_addr)) == 0
531 ) {
532
533
534
535 target_ip_conflict = 1;
536 }
537 }
538
539 VDBG("state = %d, source ip conflict = %d, target ip conflict = %d\n",
540 state, source_ip_conflict, target_ip_conflict);
541 switch (state) {
542 case PROBE:
543 case ANNOUNCE:
544
545
546 if (source_ip_conflict || target_ip_conflict) {
547 conflicts++;
548 if (conflicts >= MAX_CONFLICTS) {
549 VDBG("%s ratelimit\n", argv_intf);
550 timeout_ms = RATE_LIMIT_INTERVAL * 1000;
551 state = RATE_LIMIT_PROBE;
552 }
553
554
555 ip.s_addr = pick_nip();
556 timeout_ms = 0;
557 nprobes = 0;
558 nclaims = 0;
559 }
560 break;
561 case MONITOR:
562
563 if (source_ip_conflict) {
564 VDBG("monitor conflict -- defending\n");
565 state = DEFEND;
566 timeout_ms = DEFEND_INTERVAL * 1000;
567 arp(
568 ip,
569 ð_addr, ip);
570 }
571 break;
572 case DEFEND:
573
574 if (source_ip_conflict) {
575 state = PROBE;
576 VDBG("defend conflict -- starting over\n");
577 ready = 0;
578 run(argv, "deconfig", &ip);
579
580
581 ip.s_addr = pick_nip();
582 timeout_ms = 0;
583 nprobes = 0;
584 nclaims = 0;
585 }
586 break;
587 default:
588
589 VDBG("invalid state -- starting over\n");
590 state = PROBE;
591 ip.s_addr = pick_nip();
592 timeout_ms = 0;
593 nprobes = 0;
594 nclaims = 0;
595 break;
596 }
597 break;
598 }
599 }
600#undef argv_intf
601}
602