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