Tagging module iproute2 - iproute2-2.6.16-2
[iproute2.git] / misc / arpd.c
1 /*
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>
19 #include <db_185.h>
20 #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>
30 #include <linux/if_ether.h>
31 #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
40 int resolve_hosts;
41
42 DB      *dbase;
43 char    *dbname = "/var/lib/arpd/arpd.db";
44
45 int     ifnum;  
46 int     *ifvec;
47 char    **ifnames;
48
49 struct 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
61 struct rtnl_handle rth;
62
63 struct pollfd pset[2];
64 int udp_sock = -1;
65
66 volatile int do_exit;
67 volatile int do_sync;
68 volatile int do_stats;
69
70 struct {
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
88 int active_probing;
89 int negative_timeout = 60;
90 int no_kernel_broadcasts;
91 int broadcast_rate = 1000;
92 int broadcast_burst = 3000;
93
94 void usage(void)
95 {
96         fprintf(stderr,
97 "Usage: arpd [ -lk ] [ -a N ] [ -b dbase ] [ -f file ] [ interfaces ]\n");
98         exit(1);
99 }
100
101 int 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
114 int sysctl_adjusted;
115
116 void 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
149 void 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
179 int send_probe(int ifindex, __u32 addr)
180 {
181         struct ifreq ifr;
182         struct sockaddr_in dst;
183         socklen_t 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         if (sendto(pset[0].fd, buf, p-buf, 0, (struct sockaddr*)&sll, sizeof(sll)) < 0)
232                 return -1;
233         stats.probes_sent++;
234         return 0;
235 }
236
237 /* Be very tough on sending probes: 1 per second with burst of 3. */
238
239 int queue_active_probe(int ifindex, __u32 addr)
240 {
241         static struct timeval prev;
242         static int buckets;
243         struct timeval now;
244
245         gettimeofday(&now, NULL);
246         if (prev.tv_sec) {
247                 int diff = (now.tv_sec-prev.tv_sec)*1000+(now.tv_usec-prev.tv_usec)/1000;
248                 buckets += diff;
249         } else {
250                 buckets = broadcast_burst;
251         }
252         if (buckets > broadcast_burst)
253                 buckets = broadcast_burst;
254         if (buckets >= broadcast_rate && !send_probe(ifindex, addr)) {
255                 buckets -= broadcast_rate;
256                 prev = now;
257                 return 0;
258         }
259         stats.probes_suppressed++;
260         return -1;
261 }
262
263 int respond_to_kernel(int ifindex, __u32 addr, char *lla, int llalen)
264 {
265         struct {
266                 struct nlmsghdr         n;
267                 struct ndmsg            ndm;
268                 char                    buf[256];
269         } req;
270
271         memset(&req.n, 0, sizeof(req.n));
272         memset(&req.ndm, 0, sizeof(req.ndm));
273
274         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
275         req.n.nlmsg_flags = NLM_F_REQUEST;
276         req.n.nlmsg_type = RTM_NEWNEIGH;
277         req.ndm.ndm_family = AF_INET;
278         req.ndm.ndm_state = NUD_STALE;
279         req.ndm.ndm_ifindex = ifindex;
280         req.ndm.ndm_type = RTN_UNICAST;
281
282         addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4);
283         addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen);
284         return rtnl_send(&rth, (char*)&req, req.n.nlmsg_len) <= 0;
285 }
286
287 void prepare_neg_entry(__u8 *ndata, __u32 stamp)
288 {
289         ndata[0] = 0xFF;
290         ndata[1] = 0;
291         ndata[2] = stamp>>24;
292         ndata[3] = stamp>>16;
293         ndata[4] = stamp>>8;
294         ndata[5] = stamp;
295 }
296
297
298 int do_one_request(struct nlmsghdr *n)
299 {
300         struct ndmsg *ndm = NLMSG_DATA(n);
301         int len = n->nlmsg_len;
302         struct rtattr * tb[NDA_MAX+1];
303         struct dbkey key;
304         DBT dbkey, dbdat;
305         int do_acct = 0;
306
307         if (n->nlmsg_type == NLMSG_DONE) {
308                 dbase->sync(dbase, 0);
309
310                 /* Now we have at least mirror of kernel db, so that
311                  * may start real resolution.
312                  */
313                 do_sysctl_adjustments();
314                 return 0;
315         }
316
317         if (n->nlmsg_type != RTM_GETNEIGH && n->nlmsg_type != RTM_NEWNEIGH)
318                 return 0;
319
320         len -= NLMSG_LENGTH(sizeof(*ndm));
321         if (len < 0)
322                 return -1;
323
324         if (ndm->ndm_family != AF_INET ||
325             (ifnum && !handle_if(ndm->ndm_ifindex)) ||
326             ndm->ndm_flags ||
327             ndm->ndm_type != RTN_UNICAST ||
328             !(ndm->ndm_state&~NUD_NOARP))
329                 return 0;
330
331         parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len);
332
333         if (!tb[NDA_DST])
334                 return 0;
335
336         key.iface = ndm->ndm_ifindex;
337         memcpy(&key.addr, RTA_DATA(tb[NDA_DST]), 4);
338         dbkey.data = &key;
339         dbkey.size = sizeof(key);
340
341         if (dbase->get(dbase, &dbkey, &dbdat, 0) != 0) {
342                 dbdat.data = 0;
343                 dbdat.size = 0;
344         }
345
346         if (n->nlmsg_type == RTM_GETNEIGH) {
347                 if (!(n->nlmsg_flags&NLM_F_REQUEST))
348                         return 0;
349
350                 if (!(ndm->ndm_state&(NUD_PROBE|NUD_INCOMPLETE))) {
351                         stats.app_bad++;
352                         return 0;
353                 }
354
355                 if (ndm->ndm_state&NUD_PROBE) {
356                         /* If we get this, kernel still has some valid
357                          * address, but unicast probing failed and host
358                          * is either dead or changed its mac address.
359                          * Kernel is going to initiate broadcast resolution.
360                          * OK, we invalidate our information as well.
361                          */
362                         if (dbdat.data && !IS_NEG(dbdat.data))
363                                 stats.app_neg++;
364
365                         dbase->del(dbase, &dbkey, 0);
366                 } else {
367                         /* If we get this kernel does not have any information.
368                          * If we have something tell this to kernel. */
369                         stats.app_recv++;
370                         if (dbdat.data && !IS_NEG(dbdat.data)) {
371                                 stats.app_success++;
372                                 respond_to_kernel(key.iface, key.addr, dbdat.data, dbdat.size);
373                                 return 0;
374                         }
375
376                         /* Sheeit! We have nothing to tell. */
377                         /* If we have recent negative entry, be silent. */
378                         if (dbdat.data && NEG_VALID(dbdat.data)) {
379                                 if (NEG_CNT(dbdat.data) >= active_probing) {
380                                         stats.app_suppressed++;
381                                         return 0;
382                                 }
383                                 do_acct = 1;
384                         }
385                 }
386
387                 if (active_probing &&
388                     queue_active_probe(ndm->ndm_ifindex, key.addr) == 0 &&
389                     do_acct) {
390                         NEG_CNT(dbdat.data)++;
391                         dbase->put(dbase, &dbkey, &dbdat, 0);
392                 }
393         } else if (n->nlmsg_type == RTM_NEWNEIGH) {
394                 if (n->nlmsg_flags&NLM_F_REQUEST)
395                         return 0;
396
397                 if (ndm->ndm_state&NUD_FAILED) {
398                         /* Kernel was not able to resolve. Host is dead.
399                          * Create negative entry if it is not present
400                          * or renew it if it is too old. */
401                         if (!dbdat.data ||
402                             !IS_NEG(dbdat.data) ||
403                             !NEG_VALID(dbdat.data)) {
404                                 __u8 ndata[6];
405                                 stats.kern_neg++;
406                                 prepare_neg_entry(ndata, time(NULL));
407                                 dbdat.data = ndata;
408                                 dbdat.size = sizeof(ndata);
409                                 dbase->put(dbase, &dbkey, &dbdat, 0);
410                         }
411                 } else if (tb[NDA_LLADDR]) {
412                         if (dbdat.data && !IS_NEG(dbdat.data)) {
413                                 if (memcmp(RTA_DATA(tb[NDA_LLADDR]), dbdat.data, dbdat.size) == 0)
414                                         return 0;
415                                 stats.kern_change++;
416                         } else {
417                                 stats.kern_new++;
418                         }
419                         dbdat.data = RTA_DATA(tb[NDA_LLADDR]);
420                         dbdat.size = RTA_PAYLOAD(tb[NDA_LLADDR]);
421                         dbase->put(dbase, &dbkey, &dbdat, 0);
422                 }
423         }
424         return 0;
425 }
426
427 void load_initial_table(void)
428 {
429         rtnl_wilddump_request(&rth, AF_INET, RTM_GETNEIGH);
430 }
431
432 void get_kern_msg(void)
433 {
434         int status;
435         struct nlmsghdr *h;
436         struct sockaddr_nl nladdr;
437         struct iovec iov;
438         char   buf[8192];
439         struct msghdr msg = {
440                 (void*)&nladdr, sizeof(nladdr),
441                 &iov,   1,
442                 NULL,   0,
443                 0
444         };
445
446         memset(&nladdr, 0, sizeof(nladdr));
447
448         iov.iov_base = buf;
449         iov.iov_len = sizeof(buf);
450
451         status = recvmsg(rth.fd, &msg, MSG_DONTWAIT);
452
453         if (status <= 0)
454                 return;
455
456         if (msg.msg_namelen != sizeof(nladdr))
457                 return;
458
459         if (nladdr.nl_pid)
460                 return;
461
462         for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
463                 int len = h->nlmsg_len;
464                 int l = len - sizeof(*h);
465
466                 if (l < 0 || len > status)
467                         return;
468
469                 if (do_one_request(h) < 0)
470                         return;
471
472                 status -= NLMSG_ALIGN(len);
473                 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
474         }
475 }
476
477 /* Receive gratuitous ARP messages and store them, that's all. */
478 void get_arp_pkt(void)
479 {
480         unsigned char buf[1024];
481         struct sockaddr_ll sll;
482         socklen_t sll_len = sizeof(sll);
483         struct arphdr *a = (struct arphdr*)buf;
484         struct dbkey key;
485         DBT dbkey, dbdat;
486         int n;
487
488         n = recvfrom(pset[0].fd, buf, sizeof(buf), MSG_DONTWAIT, 
489                      (struct sockaddr*)&sll, &sll_len);
490         if (n < 0) {
491                 if (errno != EINTR && errno != EAGAIN)
492                         syslog(LOG_ERR, "recvfrom: %m");
493                 return;
494         }
495
496         if (ifnum && !handle_if(sll.sll_ifindex))
497                 return;
498
499         /* Sanity checks */
500
501         if (n < sizeof(*a) ||
502             (a->ar_op != htons(ARPOP_REQUEST) &&
503              a->ar_op != htons(ARPOP_REPLY)) ||
504             a->ar_pln != 4 ||
505             a->ar_pro != htons(ETH_P_IP) ||
506             a->ar_hln != sll.sll_halen ||
507             sizeof(*a) + 2*4 + 2*a->ar_hln > n)
508                 return;
509
510         key.iface = sll.sll_ifindex;
511         memcpy(&key.addr, (char*)(a+1) + a->ar_hln, 4);
512
513         /* DAD message, ignore. */ 
514         if (key.addr == 0)
515                 return;
516
517         dbkey.data = &key;
518         dbkey.size = sizeof(key);
519
520         if (dbase->get(dbase, &dbkey, &dbdat, 0) == 0 && !IS_NEG(dbdat.data)) {
521                 if (memcmp(dbdat.data, a+1, dbdat.size) == 0)
522                         return;
523                 stats.arp_change++;
524         } else {
525                 stats.arp_new++;
526         }
527
528         dbdat.data = a+1;
529         dbdat.size = a->ar_hln;
530         dbase->put(dbase, &dbkey, &dbdat, 0);
531 }
532
533 void catch_signal(int sig, void (*handler)(int))
534 {
535         struct sigaction sa;
536
537         memset(&sa, 0, sizeof(sa));
538         sa.sa_handler = handler;
539 #ifdef SA_INTERRUPT
540         sa.sa_flags = SA_INTERRUPT;
541 #endif  
542         sigaction(sig, &sa, NULL);
543 }
544
545 #include <setjmp.h>
546 sigjmp_buf env;
547 volatile int in_poll;
548
549 void sig_exit(int signo)
550 {
551         do_exit = 1;
552         if (in_poll)
553                 siglongjmp(env, 1);
554 }
555
556 void sig_sync(int signo)
557 {
558         do_sync = 1;
559         if (in_poll)
560                 siglongjmp(env, 1);
561 }
562
563 void sig_stats(int signo)
564 {
565         do_sync = 1;
566         do_stats = 1;
567         if (in_poll)
568                 siglongjmp(env, 1);
569 }
570
571 void send_stats(void)
572 {
573         syslog(LOG_INFO, "arp_rcv: n%lu c%lu app_rcv: tot %lu hits %lu bad %lu neg %lu sup %lu",
574                stats.arp_new, stats.arp_change,
575
576                stats.app_recv, stats.app_success,
577                stats.app_bad, stats.app_neg, stats.app_suppressed
578                );
579         syslog(LOG_INFO, "kern: n%lu c%lu neg %lu arp_send: %lu rlim %lu",
580                stats.kern_new, stats.kern_change, stats.kern_neg,
581
582                stats.probes_sent, stats.probes_suppressed
583                );
584         do_stats = 0;
585 }
586
587
588 int main(int argc, char **argv)
589 {
590         int opt;
591         int do_list = 0;
592         char *do_load = NULL;
593
594         while ((opt = getopt(argc, argv, "h?b:lf:a:n:kR:B:")) != EOF) {
595                 switch (opt) {
596                 case 'b':
597                         dbname = optarg;
598                         break;
599                 case 'f':
600                         if (do_load) {
601                                 fprintf(stderr, "Duplicate option -f\n");
602                                 usage();
603                         }
604                         do_load = optarg;
605                         break;
606                 case 'l':
607                         do_list = 1;
608                         break;
609                 case 'a':
610                         active_probing = atoi(optarg);
611                         break;
612                 case 'n':
613                         negative_timeout = atoi(optarg);
614                         break;
615                 case 'k':
616                         no_kernel_broadcasts = 1;
617                         break;
618                 case 'R':
619                         if ((broadcast_rate = atoi(optarg)) <= 0 ||
620                             (broadcast_rate = 1000/broadcast_rate) <= 0) {
621                                 fprintf(stderr, "Invalid ARP rate\n");
622                                 exit(-1);
623                         }
624                         break;
625                 case 'B':
626                         if ((broadcast_burst = atoi(optarg)) <= 0 ||
627                             (broadcast_burst = 1000*broadcast_burst) <= 0) {
628                                 fprintf(stderr, "Invalid ARP burst\n");
629                                 exit(-1);
630                         }
631                         break;
632                 case 'h':
633                 case '?':
634                 default:
635                         usage();
636                 }
637         }
638         argc -= optind;
639         argv += optind;
640
641         if (argc > 0) {
642                 ifnum = argc;
643                 ifnames = argv;
644                 ifvec = malloc(argc*sizeof(int));
645                 if (!ifvec) {
646                         perror("malloc");
647                         exit(-1);
648                 }
649         }
650
651         if ((udp_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
652                 perror("socket");
653                 exit(-1);
654         }
655
656         if (ifnum) {
657                 int i;
658                 struct ifreq ifr;
659                 memset(&ifr, 0, sizeof(ifr));
660                 for (i=0; i<ifnum; i++) {
661                         strncpy(ifr.ifr_name, ifnames[i], IFNAMSIZ);
662                         if (ioctl(udp_sock, SIOCGIFINDEX, &ifr)) {
663                                 perror("ioctl(SIOCGIFINDEX)");
664                                 exit(-1);;
665                         }
666                         ifvec[i] = ifr.ifr_ifindex;
667                 }
668         }
669
670         dbase = dbopen(dbname, O_CREAT|O_RDWR, 0644, DB_HASH, NULL);
671         if (dbase == NULL) {
672                 perror("db_open");
673                 exit(-1);
674         }
675
676         if (do_load) {
677                 char buf[128];
678                 FILE *fp;
679                 struct dbkey k;
680                 DBT dbkey, dbdat;
681
682                 dbkey.data = &k;
683                 dbkey.size = sizeof(k);
684
685                 if (strcmp(do_load, "-") == 0 || strcmp(do_load, "--") == 0) {
686                         fp = stdin;
687                 } else if ((fp = fopen(do_load, "r")) == NULL) {
688                         perror("fopen");
689                         goto do_abort;
690                 }
691
692                 buf[sizeof(buf)-1] = 0;
693                 while (fgets(buf, sizeof(buf)-1, fp)) {
694                         __u8 b1[6];
695                         char ipbuf[128];
696                         char macbuf[128];
697
698                         if (buf[0] == '#')
699                                 continue;
700
701                         if (sscanf(buf, "%u%s%s", &k.iface, ipbuf, macbuf) != 3) {
702                                 fprintf(stderr, "Wrong format of input file \"%s\"\n", do_load);
703                                 goto do_abort;
704                         }
705                         if (strncmp(macbuf, "FAILED:", 7) == 0)
706                                 continue;
707                         if (!inet_aton(ipbuf, (struct in_addr*)&k.addr)) {
708                                 fprintf(stderr, "Invalid IP address: \"%s\"\n", ipbuf);
709                                 goto do_abort;
710                         }
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                                         char 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();
840 out:
841         dbase->close(dbase);
842         exit(0);
843
844 do_abort:
845         dbase->close(dbase);
846         exit(-1);
847 }