blob: 7858ab04b70d3c388f76ac0880a001014820fd5c [file] [log] [blame]
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001/*
2 * arpd.c ARP helper daemon.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 */
11
12#include <stdio.h>
13#include <syslog.h>
14#include <malloc.h>
15#include <string.h>
16#include <unistd.h>
17#include <stdlib.h>
18#include <netdb.h>
osdl.org!shemminger16efac52004-06-09 21:28:46 +000019#include <db_185.h>
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000020#include <sys/ioctl.h>
21#include <sys/poll.h>
22#include <errno.h>
23#include <fcntl.h>
24#include <sys/uio.h>
25#include <sys/socket.h>
26#include <sys/time.h>
27#include <time.h>
28#include <signal.h>
29#include <linux/if.h>
osdl.net!shemminger17ce7fd2004-07-06 21:01:44 +000030#include <linux/if_ether.h>
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000031#include <linux/if_arp.h>
32#include <netinet/in.h>
33#include <arpa/inet.h>
34#include <linux/if_packet.h>
35#include <linux/filter.h>
36
37#include "libnetlink.h"
38#include "utils.h"
39
40int resolve_hosts;
41
42DB *dbase;
43char *dbname = "/var/lib/arpd/arpd.db";
44
45int ifnum;
46int *ifvec;
47char **ifnames;
48
49struct dbkey
50{
51 __u32 iface;
52 __u32 addr;
53};
54
55#define IS_NEG(x) (((__u8*)(x))[0] == 0xFF)
56#define NEG_TIME(x) (((x)[2]<<24)|((x)[3]<<16)|((x)[4]<<8)|(x)[5])
57#define NEG_AGE(x) ((__u32)time(NULL) - NEG_TIME((__u8*)x))
58#define NEG_VALID(x) (NEG_AGE(x) < negative_timeout)
59#define NEG_CNT(x) (((__u8*)(x))[1])
60
61struct rtnl_handle rth;
62
63struct pollfd pset[2];
64int udp_sock = -1;
65
66volatile int do_exit;
67volatile int do_sync;
68volatile int do_stats;
69
70struct {
71 unsigned long arp_new;
72 unsigned long arp_change;
73
74 unsigned long app_recv;
75 unsigned long app_success;
76 unsigned long app_bad;
77 unsigned long app_neg;
78 unsigned long app_suppressed;
79
80 unsigned long kern_neg;
81 unsigned long kern_new;
82 unsigned long kern_change;
83
84 unsigned long probes_sent;
85 unsigned long probes_suppressed;
86} stats;
87
88int active_probing;
89int negative_timeout = 60;
90int no_kernel_broadcasts;
91int broadcast_rate = 1000;
92int broadcast_burst = 3000;
93
94void usage(void)
95{
96 fprintf(stderr,
97"Usage: arpd [ -lk ] [ -a N ] [ -b dbase ] [ -f file ] [ interfaces ]\n");
98 exit(1);
99}
100
101int handle_if(int ifindex)
102{
103 int i;
104
105 if (ifnum == 0)
106 return 1;
107
108 for (i=0; i<ifnum; i++)
109 if (ifvec[i] == ifindex)
110 return 1;
111 return 0;
112}
113
114int sysctl_adjusted;
115
116void do_sysctl_adjustments(void)
117{
118 int i;
119
120 if (!ifnum)
121 return;
122
123 for (i=0; i<ifnum; i++) {
124 char buf[128];
125 FILE *fp;
126
127 if (active_probing) {
128 sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/mcast_solicit", ifnames[i]);
129 if ((fp = fopen(buf, "w")) != NULL) {
130 if (no_kernel_broadcasts)
131 strcpy(buf, "0\n");
132 else
133 sprintf(buf, "%d\n", active_probing>=2 ? 1 : 3-active_probing);
134 fputs(buf, fp);
135 fclose(fp);
136 }
137 }
138
139 sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/app_solicit", ifnames[i]);
140 if ((fp = fopen(buf, "w")) != NULL) {
141 sprintf(buf, "%d\n", active_probing<=1 ? 1 : active_probing);
142 fputs(buf, fp);
143 fclose(fp);
144 }
145 }
146 sysctl_adjusted = 1;
147}
148
149void undo_sysctl_adjustments(void)
150{
151 int i;
152
153 if (!sysctl_adjusted)
154 return;
155
156 for (i=0; i<ifnum; i++) {
157 char buf[128];
158 FILE *fp;
159
160 if (active_probing) {
161 sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/mcast_solicit", ifnames[i]);
162 if ((fp = fopen(buf, "w")) != NULL) {
163 strcpy(buf, "3\n");
164 fputs(buf, fp);
165 fclose(fp);
166 }
167 }
168 sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/app_solicit", ifnames[i]);
169 if ((fp = fopen(buf, "w")) != NULL) {
170 strcpy(buf, "0\n");
171 fputs(buf, fp);
172 fclose(fp);
173 }
174 }
175 sysctl_adjusted = 0;
176}
177
178
179int send_probe(int ifindex, __u32 addr)
180{
181 struct ifreq ifr;
182 struct sockaddr_in dst;
183 int len;
184 unsigned char buf[256];
185 struct arphdr *ah = (struct arphdr*)buf;
186 unsigned char *p = (unsigned char *)(ah+1);
187 struct sockaddr_ll sll;
188
189 memset(&ifr, 0, sizeof(ifr));
190 ifr.ifr_ifindex = ifindex;
191 if (ioctl(udp_sock, SIOCGIFNAME, &ifr))
192 return -1;
193 if (ioctl(udp_sock, SIOCGIFHWADDR, &ifr))
194 return -1;
195 if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
196 return -1;
197 if (setsockopt(udp_sock, SOL_SOCKET, SO_BINDTODEVICE, ifr.ifr_name, strlen(ifr.ifr_name)+1) < 0)
198 return -1;
199
200 dst.sin_family = AF_INET;
201 dst.sin_port = htons(1025);
202 dst.sin_addr.s_addr = addr;
203 if (connect(udp_sock, (struct sockaddr*)&dst, sizeof(dst)) < 0)
204 return -1;
205 len = sizeof(dst);
206 if (getsockname(udp_sock, (struct sockaddr*)&dst, &len) < 0)
207 return -1;
208
209 ah->ar_hrd = htons(ifr.ifr_hwaddr.sa_family);
210 ah->ar_pro = htons(ETH_P_IP);
211 ah->ar_hln = 6;
212 ah->ar_pln = 4;
213 ah->ar_op = htons(ARPOP_REQUEST);
214
215 memcpy(p, ifr.ifr_hwaddr.sa_data, ah->ar_hln);
216 p += ah->ar_hln;
217
218 memcpy(p, &dst.sin_addr, 4);
219 p+=4;
220
221 sll.sll_family = AF_PACKET;
222 memset(sll.sll_addr, 0xFF, sizeof(sll.sll_addr));
223 sll.sll_ifindex = ifindex;
224 sll.sll_protocol = htons(ETH_P_ARP);
225 memcpy(p, &sll.sll_addr, ah->ar_hln);
226 p+=ah->ar_hln;
227
228 memcpy(p, &addr, 4);
229 p+=4;
230
231 len = sendto(pset[0].fd, buf, p-buf, 0, (struct sockaddr*)&sll, sizeof(sll));
232 if (len < 0)
233 return -1;
234 stats.probes_sent++;
235 return 0;
236}
237
238/* Be very tough on sending probes: 1 per second with burst of 3. */
239
240int queue_active_probe(int ifindex, __u32 addr)
241{
242 static struct timeval prev;
243 static int buckets;
244 struct timeval now;
245
246 gettimeofday(&now, NULL);
247 if (prev.tv_sec) {
248 int diff = (now.tv_sec-prev.tv_sec)*1000+(now.tv_usec-prev.tv_usec)/1000;
249 buckets += diff;
250 } else {
251 buckets = broadcast_burst;
252 }
253 if (buckets > broadcast_burst)
254 buckets = broadcast_burst;
255 if (buckets >= broadcast_rate && !send_probe(ifindex, addr)) {
256 buckets -= broadcast_rate;
257 prev = now;
258 return 0;
259 }
260 stats.probes_suppressed++;
261 return -1;
262}
263
264int respond_to_kernel(int ifindex, __u32 addr, char *lla, int llalen)
265{
266 struct {
267 struct nlmsghdr n;
268 struct ndmsg ndm;
269 char buf[256];
270 } req;
271
272 memset(&req.n, 0, sizeof(req.n));
273 memset(&req.ndm, 0, sizeof(req.ndm));
274
275 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
276 req.n.nlmsg_flags = NLM_F_REQUEST;
277 req.n.nlmsg_type = RTM_NEWNEIGH;
278 req.ndm.ndm_family = AF_INET;
279 req.ndm.ndm_state = NUD_STALE;
280 req.ndm.ndm_ifindex = ifindex;
281 req.ndm.ndm_type = RTN_UNICAST;
282
283 addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4);
284 addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen);
285 return rtnl_send(&rth, (char*)&req, req.n.nlmsg_len) <= 0;
286}
287
288void prepare_neg_entry(__u8 *ndata, __u32 stamp)
289{
290 ndata[0] = 0xFF;
291 ndata[1] = 0;
292 ndata[2] = stamp>>24;
293 ndata[3] = stamp>>16;
294 ndata[4] = stamp>>8;
295 ndata[5] = stamp;
296}
297
298
299int do_one_request(struct nlmsghdr *n)
300{
301 struct ndmsg *ndm = NLMSG_DATA(n);
302 int len = n->nlmsg_len;
303 struct rtattr * tb[NDA_MAX+1];
304 struct dbkey key;
305 DBT dbkey, dbdat;
306 int do_acct = 0;
307
308 if (n->nlmsg_type == NLMSG_DONE) {
309 dbase->sync(dbase, 0);
310
311 /* Now we have at least mirror of kernel db, so that
312 * may start real resolution.
313 */
314 do_sysctl_adjustments();
315 return 0;
316 }
317
318 if (n->nlmsg_type != RTM_GETNEIGH && n->nlmsg_type != RTM_NEWNEIGH)
319 return 0;
320
321 len -= NLMSG_LENGTH(sizeof(*ndm));
322 if (len < 0)
323 return -1;
324
325 if (ndm->ndm_family != AF_INET ||
326 (ifnum && !handle_if(ndm->ndm_ifindex)) ||
327 ndm->ndm_flags ||
328 ndm->ndm_type != RTN_UNICAST ||
329 !(ndm->ndm_state&~NUD_NOARP))
330 return 0;
331
332 memset(tb, 0, sizeof(tb));
333 parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len);
334
335 if (!tb[NDA_DST])
336 return 0;
337
338 key.iface = ndm->ndm_ifindex;
339 memcpy(&key.addr, RTA_DATA(tb[NDA_DST]), 4);
340 dbkey.data = &key;
341 dbkey.size = sizeof(key);
342
343 if (dbase->get(dbase, &dbkey, &dbdat, 0) != 0) {
344 dbdat.data = 0;
345 dbdat.size = 0;
346 }
347
348 if (n->nlmsg_type == RTM_GETNEIGH) {
349 if (!(n->nlmsg_flags&NLM_F_REQUEST))
350 return 0;
351
352 if (!(ndm->ndm_state&(NUD_PROBE|NUD_INCOMPLETE))) {
353 stats.app_bad++;
354 return 0;
355 }
356
357 if (ndm->ndm_state&NUD_PROBE) {
358 /* If we get this, kernel still has some valid
359 * address, but unicast probing failed and host
360 * is either dead or changed its mac address.
361 * Kernel is going to initiate broadcast resolution.
362 * OK, we invalidate our information as well.
363 */
364 if (dbdat.data && !IS_NEG(dbdat.data))
365 stats.app_neg++;
366
367 dbase->del(dbase, &dbkey, 0);
368 } else {
369 /* If we get this kernel does not have any information.
370 * If we have something tell this to kernel. */
371 stats.app_recv++;
372 if (dbdat.data && !IS_NEG(dbdat.data)) {
373 stats.app_success++;
374 respond_to_kernel(key.iface, key.addr, dbdat.data, dbdat.size);
375 return 0;
376 }
377
378 /* Sheeit! We have nothing to tell. */
379 /* If we have recent negative entry, be silent. */
380 if (dbdat.data && NEG_VALID(dbdat.data)) {
381 if (NEG_CNT(dbdat.data) >= active_probing) {
382 stats.app_suppressed++;
383 return 0;
384 }
385 do_acct = 1;
386 }
387 }
388
389 if (active_probing &&
390 queue_active_probe(ndm->ndm_ifindex, key.addr) == 0 &&
391 do_acct) {
392 NEG_CNT(dbdat.data)++;
393 dbase->put(dbase, &dbkey, &dbdat, 0);
394 }
395 } else if (n->nlmsg_type == RTM_NEWNEIGH) {
396 if (n->nlmsg_flags&NLM_F_REQUEST)
397 return 0;
398
399 if (ndm->ndm_state&NUD_FAILED) {
400 /* Kernel was not able to resolve. Host is dead.
401 * Create negative entry if it is not present
402 * or renew it if it is too old. */
403 if (!dbdat.data ||
404 !IS_NEG(dbdat.data) ||
405 !NEG_VALID(dbdat.data)) {
406 __u8 ndata[6];
407 stats.kern_neg++;
408 prepare_neg_entry(ndata, time(NULL));
409 dbdat.data = ndata;
410 dbdat.size = sizeof(ndata);
411 dbase->put(dbase, &dbkey, &dbdat, 0);
412 }
413 } else if (tb[NDA_LLADDR]) {
414 if (dbdat.data && !IS_NEG(dbdat.data)) {
415 if (memcmp(RTA_DATA(tb[NDA_LLADDR]), dbdat.data, dbdat.size) == 0)
416 return 0;
417 stats.kern_change++;
418 } else {
419 stats.kern_new++;
420 }
421 dbdat.data = RTA_DATA(tb[NDA_LLADDR]);
422 dbdat.size = RTA_PAYLOAD(tb[NDA_LLADDR]);
423 dbase->put(dbase, &dbkey, &dbdat, 0);
424 }
425 }
426 return 0;
427}
428
429void load_initial_table(void)
430{
431 rtnl_wilddump_request(&rth, AF_INET, RTM_GETNEIGH);
432}
433
434void get_kern_msg(void)
435{
436 int status;
437 struct nlmsghdr *h;
438 struct sockaddr_nl nladdr;
439 struct iovec iov;
440 char buf[8192];
441 struct msghdr msg = {
442 (void*)&nladdr, sizeof(nladdr),
443 &iov, 1,
444 NULL, 0,
445 0
446 };
447
448 memset(&nladdr, 0, sizeof(nladdr));
449
450 iov.iov_base = buf;
451 iov.iov_len = sizeof(buf);
452
453 status = recvmsg(rth.fd, &msg, MSG_DONTWAIT);
454
455 if (status <= 0)
456 return;
457
458 if (msg.msg_namelen != sizeof(nladdr))
459 return;
460
461 if (nladdr.nl_pid)
462 return;
463
464 for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
465 int len = h->nlmsg_len;
466 int l = len - sizeof(*h);
467
468 if (l < 0 || len > status)
469 return;
470
471 if (do_one_request(h) < 0)
472 return;
473
474 status -= NLMSG_ALIGN(len);
475 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
476 }
477}
478
479/* Receive gratuitous ARP messages and store them, that's all. */
480void get_arp_pkt(void)
481{
482 unsigned char buf[1024];
483 struct sockaddr_ll sll;
484 int sll_len = sizeof(sll);
485 struct arphdr *a = (struct arphdr*)buf;
486 struct dbkey key;
487 DBT dbkey, dbdat;
488 int n;
489
490 n = recvfrom(pset[0].fd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr*)&sll, &sll_len);
491 if (n < 0) {
492 if (errno != EINTR && errno != EAGAIN)
493 syslog(LOG_ERR, "recvfrom: %m");
494 return;
495 }
496
497 if (ifnum && !handle_if(sll.sll_ifindex))
498 return;
499
500 /* Sanity checks */
501
502 if (n < sizeof(*a) ||
503 (a->ar_op != htons(ARPOP_REQUEST) &&
504 a->ar_op != htons(ARPOP_REPLY)) ||
505 a->ar_pln != 4 ||
506 a->ar_pro != htons(ETH_P_IP) ||
507 a->ar_hln != sll.sll_halen ||
508 sizeof(*a) + 2*4 + 2*a->ar_hln > n)
509 return;
510
511 key.iface = sll.sll_ifindex;
512 memcpy(&key.addr, (char*)(a+1) + a->ar_hln, 4);
513
514 /* DAD message, ignore. */
515 if (key.addr == 0)
516 return;
517
518 dbkey.data = &key;
519 dbkey.size = sizeof(key);
520
521 if (dbase->get(dbase, &dbkey, &dbdat, 0) == 0 && !IS_NEG(dbdat.data)) {
522 if (memcmp(dbdat.data, a+1, dbdat.size) == 0)
523 return;
524 stats.arp_change++;
525 } else {
526 stats.arp_new++;
527 }
528
529 dbdat.data = a+1;
530 dbdat.size = a->ar_hln;
531 dbase->put(dbase, &dbkey, &dbdat, 0);
532}
533
534void catch_signal(int sig, void (*handler)(int))
535{
536 struct sigaction sa;
537
538 memset(&sa, 0, sizeof(sa));
539 sa.sa_handler = handler;
540#ifdef SA_INTERRUPT
541 sa.sa_flags = SA_INTERRUPT;
542#endif
543 sigaction(sig, &sa, NULL);
544}
545
546#include <setjmp.h>
547sigjmp_buf env;
548volatile int in_poll;
549
550void sig_exit(int signo)
551{
552 do_exit = 1;
553 if (in_poll)
554 siglongjmp(env, 1);
555}
556
557void sig_sync(int signo)
558{
559 do_sync = 1;
560 if (in_poll)
561 siglongjmp(env, 1);
562}
563
564void sig_stats(int signo)
565{
566 do_sync = 1;
567 do_stats = 1;
568 if (in_poll)
569 siglongjmp(env, 1);
570}
571
572void send_stats(void)
573{
574 syslog(LOG_INFO, "arp_rcv: n%lu c%lu app_rcv: tot %lu hits %lu bad %lu neg %lu sup %lu",
575 stats.arp_new, stats.arp_change,
576
577 stats.app_recv, stats.app_success,
578 stats.app_bad, stats.app_neg, stats.app_suppressed
579 );
580 syslog(LOG_INFO, "kern: n%lu c%lu neg %lu arp_send: %lu rlim %lu",
581 stats.kern_new, stats.kern_change, stats.kern_neg,
582
583 stats.probes_sent, stats.probes_suppressed
584 );
585 do_stats = 0;
586}
587
588
589int main(int argc, char **argv)
590{
591 int opt;
592 int do_list = 0;
593 char *do_load = NULL;
594
595 while ((opt = getopt(argc, argv, "h?b:lf:a:n:kR:B:")) != EOF) {
596 switch (opt) {
597 case 'b':
598 dbname = optarg;
599 break;
600 case 'f':
601 if (do_load) {
602 fprintf(stderr, "Duplicate option -f\n");
603 usage();
604 }
605 do_load = optarg;
606 break;
607 case 'l':
608 do_list = 1;
609 break;
610 case 'a':
611 active_probing = atoi(optarg);
612 break;
613 case 'n':
614 negative_timeout = atoi(optarg);
615 break;
616 case 'k':
617 no_kernel_broadcasts = 1;
618 break;
619 case 'R':
620 if ((broadcast_rate = atoi(optarg)) <= 0 ||
621 (broadcast_rate = 1000/broadcast_rate) <= 0) {
622 fprintf(stderr, "Invalid ARP rate\n");
623 exit(-1);
624 }
625 break;
626 case 'B':
627 if ((broadcast_burst = atoi(optarg)) <= 0 ||
628 (broadcast_burst = 1000*broadcast_burst) <= 0) {
629 fprintf(stderr, "Invalid ARP burst\n");
630 exit(-1);
631 }
632 break;
633 case 'h':
634 case '?':
635 default:
636 usage();
637 }
638 }
639 argc -= optind;
640 argv += optind;
641
642 if (argc > 0) {
643 ifnum = argc;
644 ifnames = argv;
645 ifvec = malloc(argc*sizeof(int));
646 if (!ifvec) {
647 perror("malloc");
648 exit(-1);
649 }
650 }
651
652 if ((udp_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
653 perror("socket");
654 exit(-1);
655 }
656
657 if (ifnum) {
658 int i;
659 struct ifreq ifr;
660 memset(&ifr, 0, sizeof(ifr));
661 for (i=0; i<ifnum; i++) {
662 strncpy(ifr.ifr_name, ifnames[i], IFNAMSIZ);
663 if (ioctl(udp_sock, SIOCGIFINDEX, &ifr)) {
664 perror("ioctl(SIOCGIFINDEX)");
665 exit(-1);;
666 }
667 ifvec[i] = ifr.ifr_ifindex;
668 }
669 }
670
671 dbase = dbopen(dbname, O_CREAT|O_RDWR, 0644, DB_HASH, NULL);
672 if (dbase == NULL) {
673 perror("db_open");
674 exit(-1);
675 }
676
677 if (do_load) {
678 char buf[128];
679 FILE *fp;
680 struct dbkey k;
681 DBT dbkey, dbdat;
682
683 dbkey.data = &k;
684 dbkey.size = sizeof(k);
685
686 if (strcmp(do_load, "-") == 0 || strcmp(do_load, "--") == 0) {
687 fp = stdin;
688 } else if ((fp = fopen(do_load, "r")) == NULL) {
689 perror("fopen");
690 goto do_abort;
691 }
692
693 buf[sizeof(buf)-1] = 0;
694 while (fgets(buf, sizeof(buf)-1, fp)) {
695 __u8 b1[6];
696 char ipbuf[128];
697 char macbuf[128];
698
699 if (buf[0] == '#')
700 continue;
701
702 if (sscanf(buf, "%u%s%s", &k.iface, ipbuf, macbuf) != 3) {
703 fprintf(stderr, "Wrong format of input file \"%s\"\n", do_load);
704 goto do_abort;
705 }
706 if (strncmp(macbuf, "FAILED:", 7) == 0)
707 continue;
708 if (!inet_aton(ipbuf, (struct in_addr*)&k.addr)) {
709 fprintf(stderr, "Invalid IP address: \"%s\"\n", ipbuf);
710 goto do_abort;
711 }
712 dbdat.data = hexstring_a2n(macbuf, b1, 6);
713 if (dbdat.data == NULL)
714 goto do_abort;
715 dbdat.size = 6;
716
717 if (dbase->put(dbase, &dbkey, &dbdat, 0)) {
718 perror("hash->put");
719 goto do_abort;
720 }
721 }
722 dbase->sync(dbase, 0);
723 if (fp != stdin)
724 fclose(fp);
725 }
726
727 if (do_list) {
728 DBT dbkey, dbdat;
729 printf("%-8s %-15s %s\n", "#Ifindex", "IP", "MAC");
730 while (dbase->seq(dbase, &dbkey, &dbdat, R_NEXT) == 0) {
731 struct dbkey *key = dbkey.data;
732 if (handle_if(key->iface)) {
733 if (!IS_NEG(dbdat.data)) {
734 __u8 b1[18];
735 printf("%-8d %-15s %s\n",
736 key->iface,
737 inet_ntoa(*(struct in_addr*)&key->addr),
738 hexstring_n2a(dbdat.data, 6, b1, 18));
739 } else {
740 printf("%-8d %-15s FAILED: %dsec ago\n",
741 key->iface,
742 inet_ntoa(*(struct in_addr*)&key->addr),
743 NEG_AGE(dbdat.data));
744 }
745 }
746 }
747 }
748
749 if (do_load || do_list)
750 goto out;
751
752 pset[0].fd = socket(PF_PACKET, SOCK_DGRAM, 0);
753 if (pset[0].fd < 0) {
754 perror("socket");
755 exit(-1);
756 }
757
758 if (1) {
759 struct sockaddr_ll sll;
760 memset(&sll, 0, sizeof(sll));
761 sll.sll_family = AF_PACKET;
762 sll.sll_protocol = htons(ETH_P_ARP);
763 sll.sll_ifindex = (ifnum == 1 ? ifvec[0] : 0);
764 if (bind(pset[0].fd, (struct sockaddr*)&sll, sizeof(sll)) < 0) {
765 perror("bind");
766 goto do_abort;
767 }
768 }
769
770 if (rtnl_open(&rth, RTMGRP_NEIGH) < 0) {
771 perror("rtnl_open");
772 goto do_abort;
773 }
774 pset[1].fd = rth.fd;
775
776 load_initial_table();
777
778 if (1) {
779 int fd;
780 pid_t pid = fork();
781
782 if (pid > 0)
783 _exit(0);
784 if (pid < 0) {
785 perror("arpd: fork");
786 goto do_abort;
787 }
788
789 chdir("/");
790 fd = open("/dev/null", O_RDWR);
791 if (fd >= 0) {
792 dup2(fd, 0);
793 dup2(fd, 1);
794 dup2(fd, 2);
795 if (fd > 2)
796 close(fd);
797 }
798 setsid();
799 }
800
801 openlog("arpd", LOG_PID | LOG_CONS, LOG_DAEMON);
802 catch_signal(SIGINT, sig_exit);
803 catch_signal(SIGTERM, sig_exit);
804 catch_signal(SIGHUP, sig_sync);
805 catch_signal(SIGUSR1, sig_stats);
806
807#define EVENTS (POLLIN|POLLPRI|POLLERR|POLLHUP)
808 pset[0].events = EVENTS;
809 pset[0].revents = 0;
810 pset[1].events = EVENTS;
811 pset[1].revents = 0;
812
813 sigsetjmp(env, 1);
814
815 for (;;) {
816 in_poll = 1;
817
818 if (do_exit)
819 break;
820 if (do_sync) {
821 in_poll = 0;
822 dbase->sync(dbase, 0);
823 do_sync = 0;
824 in_poll = 1;
825 }
826 if (do_stats)
827 send_stats();
828 if (poll(pset, 2, 30000) > 0) {
829 in_poll = 0;
830 if (pset[0].revents&EVENTS)
831 get_arp_pkt();
832 if (pset[1].revents&EVENTS)
833 get_kern_msg();
834 } else {
835 do_sync = 1;
836 }
837 }
838
839 undo_sysctl_adjustments();
840out:
841 dbase->close(dbase);
842 exit(0);
843
844do_abort:
845 dbase->close(dbase);
846 exit(-1);
847}