]> rtime.felk.cvut.cz Git - lisovros/iproute2_canprio.git/blob - misc/arpd.c
csum action, fix typo
[lisovros/iproute2_canprio.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 int poll_timeout = 30000;
94
95 void usage(void)
96 {
97         fprintf(stderr,
98                 "Usage: arpd [ -lkh? ] [ -a N ] [ -b dbase ] [ -B number ]"
99                 " [ -f file ] [ -n time ] [-p interval ] [ -R rate ] [ interfaces ]\n");
100         exit(1);
101 }
102
103 int handle_if(int ifindex)
104 {
105         int i;
106
107         if (ifnum == 0)
108                 return 1;
109
110         for (i=0; i<ifnum; i++)
111                 if (ifvec[i] == ifindex)
112                         return 1;
113         return 0;
114 }
115
116 int sysctl_adjusted;
117
118 void do_sysctl_adjustments(void)
119 {
120         int i;
121
122         if (!ifnum)
123                 return;
124
125         for (i=0; i<ifnum; i++) {
126                 char buf[128];
127                 FILE *fp;
128
129                 if (active_probing) {
130                         sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/mcast_solicit", ifnames[i]);
131                         if ((fp = fopen(buf, "w")) != NULL) {
132                                 if (no_kernel_broadcasts)
133                                         strcpy(buf, "0\n");
134                                 else
135                                         sprintf(buf, "%d\n", active_probing>=2 ? 1 : 3-active_probing);
136                                 fputs(buf, fp);
137                                 fclose(fp);
138                         }
139                 }
140
141                 sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/app_solicit", ifnames[i]);
142                 if ((fp = fopen(buf, "w")) != NULL) {
143                         sprintf(buf, "%d\n", active_probing<=1 ? 1 : active_probing);
144                         fputs(buf, fp);
145                         fclose(fp);
146                 }
147         }
148         sysctl_adjusted = 1;
149 }
150
151 void undo_sysctl_adjustments(void)
152 {
153         int i;
154
155         if (!sysctl_adjusted)
156                 return;
157
158         for (i=0; i<ifnum; i++) {
159                 char buf[128];
160                 FILE *fp;
161
162                 if (active_probing) {
163                         sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/mcast_solicit", ifnames[i]);
164                         if ((fp = fopen(buf, "w")) != NULL) {
165                                 strcpy(buf, "3\n");
166                                 fputs(buf, fp);
167                                 fclose(fp);
168                         }
169                 }
170                 sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/app_solicit", ifnames[i]);
171                 if ((fp = fopen(buf, "w")) != NULL) {
172                         strcpy(buf, "0\n");
173                         fputs(buf, fp);
174                         fclose(fp);
175                 }
176         }
177         sysctl_adjusted = 0;
178 }
179
180
181 int send_probe(int ifindex, __u32 addr)
182 {
183         struct ifreq ifr;
184         struct sockaddr_in dst;
185         socklen_t len;
186         unsigned char buf[256];
187         struct arphdr *ah = (struct arphdr*)buf;
188         unsigned char *p = (unsigned char *)(ah+1);
189         struct sockaddr_ll sll;
190
191         memset(&ifr, 0, sizeof(ifr));
192         ifr.ifr_ifindex = ifindex;
193         if (ioctl(udp_sock, SIOCGIFNAME, &ifr))
194                 return -1;
195         if (ioctl(udp_sock, SIOCGIFHWADDR, &ifr))
196                 return -1;
197         if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
198                 return -1;
199         if (setsockopt(udp_sock, SOL_SOCKET, SO_BINDTODEVICE, ifr.ifr_name, strlen(ifr.ifr_name)+1) < 0)
200                 return -1;
201
202         dst.sin_family = AF_INET;
203         dst.sin_port = htons(1025);
204         dst.sin_addr.s_addr = addr;
205         if (connect(udp_sock, (struct sockaddr*)&dst, sizeof(dst)) < 0)
206                 return -1;
207         len = sizeof(dst);
208         if (getsockname(udp_sock, (struct sockaddr*)&dst, &len) < 0)
209                 return -1;
210
211         ah->ar_hrd = htons(ifr.ifr_hwaddr.sa_family);
212         ah->ar_pro = htons(ETH_P_IP);
213         ah->ar_hln = 6;
214         ah->ar_pln = 4;
215         ah->ar_op  = htons(ARPOP_REQUEST);
216
217         memcpy(p, ifr.ifr_hwaddr.sa_data, ah->ar_hln);
218         p += ah->ar_hln;
219
220         memcpy(p, &dst.sin_addr, 4);
221         p+=4;
222
223         sll.sll_family = AF_PACKET;
224         memset(sll.sll_addr, 0xFF, sizeof(sll.sll_addr));
225         sll.sll_ifindex = ifindex;
226         sll.sll_protocol = htons(ETH_P_ARP);
227         memcpy(p, &sll.sll_addr, ah->ar_hln);
228         p+=ah->ar_hln;
229
230         memcpy(p, &addr, 4);
231         p+=4;
232
233         if (sendto(pset[0].fd, buf, p-buf, 0, (struct sockaddr*)&sll, sizeof(sll)) < 0)
234                 return -1;
235         stats.probes_sent++;
236         return 0;
237 }
238
239 /* Be very tough on sending probes: 1 per second with burst of 3. */
240
241 int queue_active_probe(int ifindex, __u32 addr)
242 {
243         static struct timeval prev;
244         static int buckets;
245         struct timeval now;
246
247         gettimeofday(&now, NULL);
248         if (prev.tv_sec) {
249                 int diff = (now.tv_sec-prev.tv_sec)*1000+(now.tv_usec-prev.tv_usec)/1000;
250                 buckets += diff;
251         } else {
252                 buckets = broadcast_burst;
253         }
254         if (buckets > broadcast_burst)
255                 buckets = broadcast_burst;
256         if (buckets >= broadcast_rate && !send_probe(ifindex, addr)) {
257                 buckets -= broadcast_rate;
258                 prev = now;
259                 return 0;
260         }
261         stats.probes_suppressed++;
262         return -1;
263 }
264
265 int respond_to_kernel(int ifindex, __u32 addr, char *lla, int llalen)
266 {
267         struct {
268                 struct nlmsghdr         n;
269                 struct ndmsg            ndm;
270                 char                    buf[256];
271         } req;
272
273         memset(&req.n, 0, sizeof(req.n));
274         memset(&req.ndm, 0, sizeof(req.ndm));
275
276         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
277         req.n.nlmsg_flags = NLM_F_REQUEST;
278         req.n.nlmsg_type = RTM_NEWNEIGH;
279         req.ndm.ndm_family = AF_INET;
280         req.ndm.ndm_state = NUD_STALE;
281         req.ndm.ndm_ifindex = ifindex;
282         req.ndm.ndm_type = RTN_UNICAST;
283
284         addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4);
285         addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen);
286         return rtnl_send(&rth, &req, req.n.nlmsg_len) <= 0;
287 }
288
289 void prepare_neg_entry(__u8 *ndata, __u32 stamp)
290 {
291         ndata[0] = 0xFF;
292         ndata[1] = 0;
293         ndata[2] = stamp>>24;
294         ndata[3] = stamp>>16;
295         ndata[4] = stamp>>8;
296         ndata[5] = stamp;
297 }
298
299
300 int do_one_request(struct nlmsghdr *n)
301 {
302         struct ndmsg *ndm = NLMSG_DATA(n);
303         int len = n->nlmsg_len;
304         struct rtattr * tb[NDA_MAX+1];
305         struct dbkey key;
306         DBT dbkey, dbdat;
307         int do_acct = 0;
308
309         if (n->nlmsg_type == NLMSG_DONE) {
310                 dbase->sync(dbase, 0);
311
312                 /* Now we have at least mirror of kernel db, so that
313                  * may start real resolution.
314                  */
315                 do_sysctl_adjustments();
316                 return 0;
317         }
318
319         if (n->nlmsg_type != RTM_GETNEIGH && n->nlmsg_type != RTM_NEWNEIGH)
320                 return 0;
321
322         len -= NLMSG_LENGTH(sizeof(*ndm));
323         if (len < 0)
324                 return -1;
325
326         if (ndm->ndm_family != AF_INET ||
327             (ifnum && !handle_if(ndm->ndm_ifindex)) ||
328             ndm->ndm_flags ||
329             ndm->ndm_type != RTN_UNICAST ||
330             !(ndm->ndm_state&~NUD_NOARP))
331                 return 0;
332
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
429 void load_initial_table(void)
430 {
431         rtnl_wilddump_request(&rth, AF_INET, RTM_GETNEIGH);
432 }
433
434 void 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. */
480 void get_arp_pkt(void)
481 {
482         unsigned char buf[1024];
483         struct sockaddr_ll sll;
484         socklen_t 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,
491                      (struct sockaddr*)&sll, &sll_len);
492         if (n < 0) {
493                 if (errno != EINTR && errno != EAGAIN)
494                         syslog(LOG_ERR, "recvfrom: %m");
495                 return;
496         }
497
498         if (ifnum && !handle_if(sll.sll_ifindex))
499                 return;
500
501         /* Sanity checks */
502
503         if (n < sizeof(*a) ||
504             (a->ar_op != htons(ARPOP_REQUEST) &&
505              a->ar_op != htons(ARPOP_REPLY)) ||
506             a->ar_pln != 4 ||
507             a->ar_pro != htons(ETH_P_IP) ||
508             a->ar_hln != sll.sll_halen ||
509             sizeof(*a) + 2*4 + 2*a->ar_hln > n)
510                 return;
511
512         key.iface = sll.sll_ifindex;
513         memcpy(&key.addr, (char*)(a+1) + a->ar_hln, 4);
514
515         /* DAD message, ignore. */
516         if (key.addr == 0)
517                 return;
518
519         dbkey.data = &key;
520         dbkey.size = sizeof(key);
521
522         if (dbase->get(dbase, &dbkey, &dbdat, 0) == 0 && !IS_NEG(dbdat.data)) {
523                 if (memcmp(dbdat.data, a+1, dbdat.size) == 0)
524                         return;
525                 stats.arp_change++;
526         } else {
527                 stats.arp_new++;
528         }
529
530         dbdat.data = a+1;
531         dbdat.size = a->ar_hln;
532         dbase->put(dbase, &dbkey, &dbdat, 0);
533 }
534
535 void catch_signal(int sig, void (*handler)(int))
536 {
537         struct sigaction sa;
538
539         memset(&sa, 0, sizeof(sa));
540         sa.sa_handler = handler;
541 #ifdef SA_INTERRUPT
542         sa.sa_flags = SA_INTERRUPT;
543 #endif
544         sigaction(sig, &sa, NULL);
545 }
546
547 #include <setjmp.h>
548 sigjmp_buf env;
549 volatile int in_poll;
550
551 void sig_exit(int signo)
552 {
553         do_exit = 1;
554         if (in_poll)
555                 siglongjmp(env, 1);
556 }
557
558 void sig_sync(int signo)
559 {
560         do_sync = 1;
561         if (in_poll)
562                 siglongjmp(env, 1);
563 }
564
565 void sig_stats(int signo)
566 {
567         do_sync = 1;
568         do_stats = 1;
569         if (in_poll)
570                 siglongjmp(env, 1);
571 }
572
573 void send_stats(void)
574 {
575         syslog(LOG_INFO, "arp_rcv: n%lu c%lu app_rcv: tot %lu hits %lu bad %lu neg %lu sup %lu",
576                stats.arp_new, stats.arp_change,
577
578                stats.app_recv, stats.app_success,
579                stats.app_bad, stats.app_neg, stats.app_suppressed
580                );
581         syslog(LOG_INFO, "kern: n%lu c%lu neg %lu arp_send: %lu rlim %lu",
582                stats.kern_new, stats.kern_change, stats.kern_neg,
583
584                stats.probes_sent, stats.probes_suppressed
585                );
586         do_stats = 0;
587 }
588
589
590 int main(int argc, char **argv)
591 {
592         int opt;
593         int do_list = 0;
594         char *do_load = NULL;
595
596         while ((opt = getopt(argc, argv, "h?b:lf:a:n:p:kR:B:")) != EOF) {
597                 switch (opt) {
598                 case 'b':
599                         dbname = optarg;
600                         break;
601                 case 'f':
602                         if (do_load) {
603                                 fprintf(stderr, "Duplicate option -f\n");
604                                 usage();
605                         }
606                         do_load = optarg;
607                         break;
608                 case 'l':
609                         do_list = 1;
610                         break;
611                 case 'a':
612                         active_probing = atoi(optarg);
613                         break;
614                 case 'n':
615                         negative_timeout = atoi(optarg);
616                         break;
617                 case 'k':
618                         no_kernel_broadcasts = 1;
619                         break;
620                 case 'p':
621                         if ((poll_timeout = 1000 * strtod(optarg, NULL)) < 100) {
622                                 fprintf(stderr,"Invalid poll timeout\n");
623                                 exit(-1);
624                         }
625                         break;
626                 case 'R':
627                         if ((broadcast_rate = atoi(optarg)) <= 0 ||
628                             (broadcast_rate = 1000/broadcast_rate) <= 0) {
629                                 fprintf(stderr, "Invalid ARP rate\n");
630                                 exit(-1);
631                         }
632                         break;
633                 case 'B':
634                         if ((broadcast_burst = atoi(optarg)) <= 0 ||
635                             (broadcast_burst = 1000*broadcast_burst) <= 0) {
636                                 fprintf(stderr, "Invalid ARP burst\n");
637                                 exit(-1);
638                         }
639                         break;
640                 case 'h':
641                 case '?':
642                 default:
643                         usage();
644                 }
645         }
646         argc -= optind;
647         argv += optind;
648
649         if (argc > 0) {
650                 ifnum = argc;
651                 ifnames = argv;
652                 ifvec = malloc(argc*sizeof(int));
653                 if (!ifvec) {
654                         perror("malloc");
655                         exit(-1);
656                 }
657         }
658
659         if ((udp_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
660                 perror("socket");
661                 exit(-1);
662         }
663
664         if (ifnum) {
665                 int i;
666                 struct ifreq ifr;
667                 memset(&ifr, 0, sizeof(ifr));
668                 for (i=0; i<ifnum; i++) {
669                         strncpy(ifr.ifr_name, ifnames[i], IFNAMSIZ);
670                         if (ioctl(udp_sock, SIOCGIFINDEX, &ifr)) {
671                                 perror("ioctl(SIOCGIFINDEX)");
672                                 exit(-1);;
673                         }
674                         ifvec[i] = ifr.ifr_ifindex;
675                 }
676         }
677
678         dbase = dbopen(dbname, O_CREAT|O_RDWR, 0644, DB_HASH, NULL);
679         if (dbase == NULL) {
680                 perror("db_open");
681                 exit(-1);
682         }
683
684         if (do_load) {
685                 char buf[128];
686                 FILE *fp;
687                 struct dbkey k;
688                 DBT dbkey, dbdat;
689
690                 dbkey.data = &k;
691                 dbkey.size = sizeof(k);
692
693                 if (strcmp(do_load, "-") == 0 || strcmp(do_load, "--") == 0) {
694                         fp = stdin;
695                 } else if ((fp = fopen(do_load, "r")) == NULL) {
696                         perror("fopen");
697                         goto do_abort;
698                 }
699
700                 buf[sizeof(buf)-1] = 0;
701                 while (fgets(buf, sizeof(buf)-1, fp)) {
702                         __u8 b1[6];
703                         char ipbuf[128];
704                         char macbuf[128];
705
706                         if (buf[0] == '#')
707                                 continue;
708
709                         if (sscanf(buf, "%u%s%s", &k.iface, ipbuf, macbuf) != 3) {
710                                 fprintf(stderr, "Wrong format of input file \"%s\"\n", do_load);
711                                 goto do_abort;
712                         }
713                         if (strncmp(macbuf, "FAILED:", 7) == 0)
714                                 continue;
715                         if (!inet_aton(ipbuf, (struct in_addr*)&k.addr)) {
716                                 fprintf(stderr, "Invalid IP address: \"%s\"\n", ipbuf);
717                                 goto do_abort;
718                         }
719
720                         dbdat.data = hexstring_a2n(macbuf, b1, 6);
721                         if (dbdat.data == NULL)
722                                 goto do_abort;
723                         dbdat.size = 6;
724
725                         if (dbase->put(dbase, &dbkey, &dbdat, 0)) {
726                                 perror("hash->put");
727                                 goto do_abort;
728                         }
729                 }
730                 dbase->sync(dbase, 0);
731                 if (fp != stdin)
732                         fclose(fp);
733         }
734
735         if (do_list) {
736                 DBT dbkey, dbdat;
737                 printf("%-8s %-15s %s\n", "#Ifindex", "IP", "MAC");
738                 while (dbase->seq(dbase, &dbkey, &dbdat, R_NEXT) == 0) {
739                         struct dbkey *key = dbkey.data;
740                         if (handle_if(key->iface)) {
741                                 if (!IS_NEG(dbdat.data)) {
742                                         char b1[18];
743                                         printf("%-8d %-15s %s\n",
744                                                key->iface,
745                                                inet_ntoa(*(struct in_addr*)&key->addr),
746                                                hexstring_n2a(dbdat.data, 6, b1, 18));
747                                 } else {
748                                         printf("%-8d %-15s FAILED: %dsec ago\n",
749                                                key->iface,
750                                                inet_ntoa(*(struct in_addr*)&key->addr),
751                                                NEG_AGE(dbdat.data));
752                                 }
753                         }
754                 }
755         }
756
757         if (do_load || do_list)
758                 goto out;
759
760         pset[0].fd = socket(PF_PACKET, SOCK_DGRAM, 0);
761         if (pset[0].fd < 0) {
762                 perror("socket");
763                 exit(-1);
764         }
765
766         if (1) {
767                 struct sockaddr_ll sll;
768                 memset(&sll, 0, sizeof(sll));
769                 sll.sll_family = AF_PACKET;
770                 sll.sll_protocol = htons(ETH_P_ARP);
771                 sll.sll_ifindex = (ifnum == 1 ? ifvec[0] : 0);
772                 if (bind(pset[0].fd, (struct sockaddr*)&sll, sizeof(sll)) < 0) {
773                         perror("bind");
774                         goto do_abort;
775                 }
776         }
777
778         if (rtnl_open(&rth, RTMGRP_NEIGH) < 0) {
779                 perror("rtnl_open");
780                 goto do_abort;
781         }
782         pset[1].fd = rth.fd;
783
784         load_initial_table();
785
786         if (daemon(0, 0)) {
787                 perror("arpd: daemon");
788                 goto do_abort;
789         }
790
791         openlog("arpd", LOG_PID | LOG_CONS, LOG_DAEMON);
792         catch_signal(SIGINT, sig_exit);
793         catch_signal(SIGTERM, sig_exit);
794         catch_signal(SIGHUP, sig_sync);
795         catch_signal(SIGUSR1, sig_stats);
796
797 #define EVENTS (POLLIN|POLLPRI|POLLERR|POLLHUP)
798         pset[0].events = EVENTS;
799         pset[0].revents = 0;
800         pset[1].events = EVENTS;
801         pset[1].revents = 0;
802
803         sigsetjmp(env, 1);
804
805         for (;;) {
806                 in_poll = 1;
807
808                 if (do_exit)
809                         break;
810                 if (do_sync) {
811                         in_poll = 0;
812                         dbase->sync(dbase, 0);
813                         do_sync = 0;
814                         in_poll = 1;
815                 }
816                 if (do_stats)
817                         send_stats();
818                 if (poll(pset, 2, poll_timeout) > 0) {
819                         in_poll = 0;
820                         if (pset[0].revents&EVENTS)
821                                 get_arp_pkt();
822                         if (pset[1].revents&EVENTS)
823                                 get_kern_msg();
824                 } else {
825                         do_sync = 1;
826                 }
827         }
828
829         undo_sysctl_adjustments();
830 out:
831         dbase->close(dbase);
832         exit(0);
833
834 do_abort:
835         dbase->close(dbase);
836         exit(-1);
837 }