1
2
3
4
5
6
7
8#include <stdio.h>
9#include <syslog.h>
10#include <malloc.h>
11#include <string.h>
12#include <unistd.h>
13#include <stdlib.h>
14#include <netdb.h>
15#include <db_185.h>
16#include <sys/ioctl.h>
17#include <poll.h>
18#include <errno.h>
19#include <fcntl.h>
20#include <sys/uio.h>
21#include <sys/socket.h>
22#include <sys/stat.h>
23#include <sys/time.h>
24#include <time.h>
25#include <signal.h>
26#include <linux/if.h>
27#include <linux/if_ether.h>
28#include <linux/if_arp.h>
29#include <netinet/in.h>
30#include <arpa/inet.h>
31#include <linux/if_packet.h>
32#include <linux/filter.h>
33
34#include "libnetlink.h"
35#include "utils.h"
36#include "rt_names.h"
37
38DB *dbase;
39char const default_dbname[] = ARPDDIR "/arpd.db";
40char const *dbname = default_dbname;
41
42int ifnum;
43int *ifvec;
44char **ifnames;
45
46struct dbkey {
47 __u32 iface;
48 __u32 addr;
49};
50
51#define IS_NEG(x) (((__u8 *)(x))[0] == 0xFF)
52#define NEG_TIME(x) (((x)[2]<<24)|((x)[3]<<16)|((x)[4]<<8)|(x)[5])
53#define NEG_AGE(x) ((__u32)time(NULL) - NEG_TIME((__u8 *)x))
54#define NEG_VALID(x) (NEG_AGE(x) < negative_timeout)
55#define NEG_CNT(x) (((__u8 *)(x))[1])
56
57struct rtnl_handle rth;
58
59struct pollfd pset[2];
60int udp_sock = -1;
61
62volatile int do_exit;
63volatile int do_sync;
64volatile int do_stats;
65
66struct {
67 unsigned long arp_new;
68 unsigned long arp_change;
69
70 unsigned long app_recv;
71 unsigned long app_success;
72 unsigned long app_bad;
73 unsigned long app_neg;
74 unsigned long app_suppressed;
75
76 unsigned long kern_neg;
77 unsigned long kern_new;
78 unsigned long kern_change;
79
80 unsigned long probes_sent;
81 unsigned long probes_suppressed;
82} stats;
83
84int active_probing;
85int negative_timeout = 60;
86int no_kernel_broadcasts;
87int broadcast_rate = 1000;
88int broadcast_burst = 3000;
89int poll_timeout = 30000;
90
91static void usage(void)
92{
93 fprintf(stderr,
94 "Usage: arpd [ -lkh? ] [ -a N ] [ -b dbase ] [ -B number ] [ -f file ] [ -n time ] [-p interval ] [ -R rate ] [ interfaces ]\n");
95 exit(1);
96}
97
98static int handle_if(int ifindex)
99{
100 int i;
101
102 if (ifnum == 0)
103 return 1;
104
105 for (i = 0; i < ifnum; i++)
106 if (ifvec[i] == ifindex)
107 return 1;
108 return 0;
109}
110
111int sysctl_adjusted;
112
113static void do_sysctl_adjustments(void)
114{
115 int i;
116
117 if (!ifnum)
118 return;
119
120 for (i = 0; i < ifnum; i++) {
121 char buf[128];
122 FILE *fp;
123
124 if (active_probing) {
125 sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/mcast_solicit", ifnames[i]);
126 if ((fp = fopen(buf, "w")) != NULL) {
127 if (no_kernel_broadcasts)
128 strcpy(buf, "0\n");
129 else
130 sprintf(buf, "%d\n", active_probing >= 2 ? 1 : 3-active_probing);
131 fputs(buf, fp);
132 fclose(fp);
133 }
134 }
135
136 sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/app_solicit", ifnames[i]);
137 if ((fp = fopen(buf, "w")) != NULL) {
138 sprintf(buf, "%d\n", active_probing <= 1 ? 1 : active_probing);
139 fputs(buf, fp);
140 fclose(fp);
141 }
142 }
143 sysctl_adjusted = 1;
144}
145
146static void undo_sysctl_adjustments(void)
147{
148 int i;
149
150 if (!sysctl_adjusted)
151 return;
152
153 for (i = 0; i < ifnum; i++) {
154 char buf[128];
155 FILE *fp;
156
157 if (active_probing) {
158 sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/mcast_solicit", ifnames[i]);
159 if ((fp = fopen(buf, "w")) != NULL) {
160 strcpy(buf, "3\n");
161 fputs(buf, fp);
162 fclose(fp);
163 }
164 }
165 sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/app_solicit", ifnames[i]);
166 if ((fp = fopen(buf, "w")) != NULL) {
167 strcpy(buf, "0\n");
168 fputs(buf, fp);
169 fclose(fp);
170 }
171 }
172 sysctl_adjusted = 0;
173}
174
175
176static int send_probe(int ifindex, __u32 addr)
177{
178 struct ifreq ifr = { .ifr_ifindex = ifindex };
179 struct sockaddr_in dst = {
180 .sin_family = AF_INET,
181 .sin_port = htons(1025),
182 .sin_addr.s_addr = addr,
183 };
184 socklen_t len;
185 unsigned char buf[256];
186 struct arphdr *ah = (struct arphdr *)buf;
187 unsigned char *p = (unsigned char *)(ah+1);
188 struct sockaddr_ll sll = {
189 .sll_family = AF_PACKET,
190 .sll_ifindex = ifindex,
191 .sll_protocol = htons(ETH_P_ARP),
192 };
193
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 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 memset(sll.sll_addr, 0xFF, sizeof(sll.sll_addr));
222 memcpy(p, &sll.sll_addr, ah->ar_hln);
223 p += ah->ar_hln;
224
225 memcpy(p, &addr, 4);
226 p += 4;
227
228 if (sendto(pset[0].fd, buf, p-buf, 0, (struct sockaddr *)&sll, sizeof(sll)) < 0)
229 return -1;
230 stats.probes_sent++;
231 return 0;
232}
233
234
235
236static int queue_active_probe(int ifindex, __u32 addr)
237{
238 static struct timeval prev;
239 static int buckets;
240 struct timeval now;
241
242 gettimeofday(&now, NULL);
243 if (prev.tv_sec) {
244 int diff = (now.tv_sec-prev.tv_sec)*1000+(now.tv_usec-prev.tv_usec)/1000;
245
246 buckets += diff;
247 } else {
248 buckets = broadcast_burst;
249 }
250 if (buckets > broadcast_burst)
251 buckets = broadcast_burst;
252 if (buckets >= broadcast_rate && !send_probe(ifindex, addr)) {
253 buckets -= broadcast_rate;
254 prev = now;
255 return 0;
256 }
257 stats.probes_suppressed++;
258 return -1;
259}
260
261static int respond_to_kernel(int ifindex, __u32 addr, char *lla, int llalen)
262{
263 struct {
264 struct nlmsghdr n;
265 struct ndmsg ndm;
266 char buf[256];
267 } req = {
268 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
269 .n.nlmsg_flags = NLM_F_REQUEST,
270 .n.nlmsg_type = RTM_NEWNEIGH,
271 .ndm.ndm_family = AF_INET,
272 .ndm.ndm_state = NUD_STALE,
273 .ndm.ndm_ifindex = ifindex,
274 .ndm.ndm_type = RTN_UNICAST,
275 };
276
277 addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4);
278 addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen);
279 return rtnl_send(&rth, &req, req.n.nlmsg_len) <= 0;
280}
281
282static void prepare_neg_entry(__u8 *ndata, __u32 stamp)
283{
284 ndata[0] = 0xFF;
285 ndata[1] = 0;
286 ndata[2] = stamp>>24;
287 ndata[3] = stamp>>16;
288 ndata[4] = stamp>>8;
289 ndata[5] = stamp;
290}
291
292
293static int do_one_request(struct nlmsghdr *n)
294{
295 struct ndmsg *ndm = NLMSG_DATA(n);
296 int len = n->nlmsg_len;
297 struct rtattr *tb[NDA_MAX+1];
298 struct dbkey key;
299 DBT dbkey, dbdat;
300 int do_acct = 0;
301
302 if (n->nlmsg_type == NLMSG_DONE) {
303 dbase->sync(dbase, 0);
304
305
306
307
308 do_sysctl_adjustments();
309 return 0;
310 }
311
312 if (n->nlmsg_type != RTM_GETNEIGH && n->nlmsg_type != RTM_NEWNEIGH)
313 return 0;
314
315 len -= NLMSG_LENGTH(sizeof(*ndm));
316 if (len < 0)
317 return -1;
318
319 if (ndm->ndm_family != AF_INET ||
320 (ifnum && !handle_if(ndm->ndm_ifindex)) ||
321 ndm->ndm_flags ||
322 ndm->ndm_type != RTN_UNICAST ||
323 !(ndm->ndm_state&~NUD_NOARP))
324 return 0;
325
326 parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len);
327
328 if (!tb[NDA_DST])
329 return 0;
330
331 key.iface = ndm->ndm_ifindex;
332 memcpy(&key.addr, RTA_DATA(tb[NDA_DST]), 4);
333 dbkey.data = &key;
334 dbkey.size = sizeof(key);
335
336 if (dbase->get(dbase, &dbkey, &dbdat, 0) != 0) {
337 dbdat.data = 0;
338 dbdat.size = 0;
339 }
340
341 if (n->nlmsg_type == RTM_GETNEIGH) {
342 if (!(n->nlmsg_flags&NLM_F_REQUEST))
343 return 0;
344
345 if (!(ndm->ndm_state&(NUD_PROBE|NUD_INCOMPLETE))) {
346 stats.app_bad++;
347 return 0;
348 }
349
350 if (ndm->ndm_state&NUD_PROBE) {
351
352
353
354
355
356
357 if (dbdat.data && !IS_NEG(dbdat.data))
358 stats.app_neg++;
359
360 dbase->del(dbase, &dbkey, 0);
361 } else {
362
363
364 stats.app_recv++;
365 if (dbdat.data && !IS_NEG(dbdat.data)) {
366 stats.app_success++;
367 respond_to_kernel(key.iface, key.addr, dbdat.data, dbdat.size);
368 return 0;
369 }
370
371
372
373 if (dbdat.data && NEG_VALID(dbdat.data)) {
374 if (NEG_CNT(dbdat.data) >= active_probing) {
375 stats.app_suppressed++;
376 return 0;
377 }
378 do_acct = 1;
379 }
380 }
381
382 if (active_probing &&
383 queue_active_probe(ndm->ndm_ifindex, key.addr) == 0 &&
384 do_acct) {
385 NEG_CNT(dbdat.data)++;
386 dbase->put(dbase, &dbkey, &dbdat, 0);
387 }
388 } else if (n->nlmsg_type == RTM_NEWNEIGH) {
389 if (n->nlmsg_flags&NLM_F_REQUEST)
390 return 0;
391
392 if (ndm->ndm_state&NUD_FAILED) {
393
394
395
396 if (!dbdat.data ||
397 !IS_NEG(dbdat.data) ||
398 !NEG_VALID(dbdat.data)) {
399 __u8 ndata[6];
400
401 stats.kern_neg++;
402 prepare_neg_entry(ndata, time(NULL));
403 dbdat.data = ndata;
404 dbdat.size = sizeof(ndata);
405 dbase->put(dbase, &dbkey, &dbdat, 0);
406 }
407 } else if (tb[NDA_LLADDR]) {
408 if (dbdat.data && !IS_NEG(dbdat.data)) {
409 if (memcmp(RTA_DATA(tb[NDA_LLADDR]), dbdat.data, dbdat.size) == 0)
410 return 0;
411 stats.kern_change++;
412 } else {
413 stats.kern_new++;
414 }
415 dbdat.data = RTA_DATA(tb[NDA_LLADDR]);
416 dbdat.size = RTA_PAYLOAD(tb[NDA_LLADDR]);
417 dbase->put(dbase, &dbkey, &dbdat, 0);
418 }
419 }
420 return 0;
421}
422
423static void load_initial_table(void)
424{
425 if (rtnl_neighdump_req(&rth, AF_INET, NULL) < 0) {
426 perror("dump request failed");
427 exit(1);
428 }
429
430}
431
432static 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 .msg_name = &nladdr,
441 .msg_namelen = sizeof(nladdr),
442 .msg_iov = &iov,
443 .msg_iovlen = 1,
444 };
445
446 iov.iov_base = buf;
447 iov.iov_len = sizeof(buf);
448
449 status = recvmsg(rth.fd, &msg, MSG_DONTWAIT);
450
451 if (status <= 0)
452 return;
453
454 if (msg.msg_namelen != sizeof(nladdr))
455 return;
456
457 if (nladdr.nl_pid)
458 return;
459
460 for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) {
461 int len = h->nlmsg_len;
462 int l = len - sizeof(*h);
463
464 if (l < 0 || len > status)
465 return;
466
467 if (do_one_request(h) < 0)
468 return;
469
470 status -= NLMSG_ALIGN(len);
471 h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
472 }
473}
474
475
476static void get_arp_pkt(void)
477{
478 unsigned char buf[1024];
479 struct sockaddr_ll sll;
480 socklen_t sll_len = sizeof(sll);
481 struct arphdr *a = (struct arphdr *)buf;
482 struct dbkey key;
483 DBT dbkey, dbdat;
484 int n;
485
486 n = recvfrom(pset[0].fd, buf, sizeof(buf), MSG_DONTWAIT,
487 (struct sockaddr *)&sll, &sll_len);
488 if (n < 0) {
489 if (errno != EINTR && errno != EAGAIN)
490 syslog(LOG_ERR, "recvfrom: %m");
491 return;
492 }
493
494 if (ifnum && !handle_if(sll.sll_ifindex))
495 return;
496
497
498 if (n < sizeof(*a) ||
499 (a->ar_op != htons(ARPOP_REQUEST) &&
500 a->ar_op != htons(ARPOP_REPLY)) ||
501 a->ar_pln != 4 ||
502 a->ar_pro != htons(ETH_P_IP) ||
503 a->ar_hln != sll.sll_halen ||
504 sizeof(*a) + 2*4 + 2*a->ar_hln > n)
505 return;
506
507 key.iface = sll.sll_ifindex;
508 memcpy(&key.addr, (char *)(a+1) + a->ar_hln, 4);
509
510
511 if (key.addr == 0)
512 return;
513
514 dbkey.data = &key;
515 dbkey.size = sizeof(key);
516
517 if (dbase->get(dbase, &dbkey, &dbdat, 0) == 0 && !IS_NEG(dbdat.data)) {
518 if (memcmp(dbdat.data, a+1, dbdat.size) == 0)
519 return;
520 stats.arp_change++;
521 } else {
522 stats.arp_new++;
523 }
524
525 dbdat.data = a+1;
526 dbdat.size = a->ar_hln;
527 dbase->put(dbase, &dbkey, &dbdat, 0);
528}
529
530static void catch_signal(int sig, void (*handler)(int))
531{
532 struct sigaction sa = { .sa_handler = handler };
533
534#ifdef SA_INTERRUPT
535 sa.sa_flags = SA_INTERRUPT;
536#endif
537 sigaction(sig, &sa, NULL);
538}
539
540#include <setjmp.h>
541sigjmp_buf env;
542volatile int in_poll;
543
544static void sig_exit(int signo)
545{
546 do_exit = 1;
547 if (in_poll)
548 siglongjmp(env, 1);
549}
550
551static void sig_sync(int signo)
552{
553 do_sync = 1;
554 if (in_poll)
555 siglongjmp(env, 1);
556}
557
558static void sig_stats(int signo)
559{
560 do_sync = 1;
561 do_stats = 1;
562 if (in_poll)
563 siglongjmp(env, 1);
564}
565
566static void send_stats(void)
567{
568 syslog(LOG_INFO, "arp_rcv: n%lu c%lu app_rcv: tot %lu hits %lu bad %lu neg %lu sup %lu",
569 stats.arp_new, stats.arp_change,
570
571 stats.app_recv, stats.app_success,
572 stats.app_bad, stats.app_neg, stats.app_suppressed
573 );
574 syslog(LOG_INFO, "kern: n%lu c%lu neg %lu arp_send: %lu rlim %lu",
575 stats.kern_new, stats.kern_change, stats.kern_neg,
576
577 stats.probes_sent, stats.probes_suppressed
578 );
579 do_stats = 0;
580}
581
582
583int main(int argc, char **argv)
584{
585 int opt;
586 int do_list = 0;
587 char *do_load = NULL;
588
589 while ((opt = getopt(argc, argv, "h?b:lf:a:n:p:kR:B:")) != EOF) {
590 switch (opt) {
591 case 'b':
592 dbname = optarg;
593 break;
594 case 'f':
595 if (do_load) {
596 fprintf(stderr, "Duplicate option -f\n");
597 usage();
598 }
599 do_load = optarg;
600 break;
601 case 'l':
602 do_list = 1;
603 break;
604 case 'a':
605 active_probing = atoi(optarg);
606 break;
607 case 'n':
608 negative_timeout = atoi(optarg);
609 break;
610 case 'k':
611 no_kernel_broadcasts = 1;
612 break;
613 case 'p':
614 if ((poll_timeout = 1000 * strtod(optarg, NULL)) < 100) {
615 fprintf(stderr, "Invalid poll timeout\n");
616 exit(-1);
617 }
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
661 for (i = 0; i < ifnum; i++) {
662 if (get_ifname(ifr.ifr_name, ifnames[i]))
663 invarg("not a valid ifname", ifnames[i]);
664 if (ioctl(udp_sock, SIOCGIFINDEX, &ifr)) {
665 perror("ioctl(SIOCGIFINDEX)");
666 exit(-1);
667 }
668 ifvec[i] = ifr.ifr_ifindex;
669 }
670 }
671
672 if (strcmp(default_dbname, dbname) == 0) {
673 if (mkdir(ARPDDIR, 0755) != 0 && errno != EEXIST) {
674 perror("create_db_dir");
675 exit(-1);
676 }
677 }
678
679 dbase = dbopen(dbname, O_CREAT|O_RDWR, 0644, DB_HASH, NULL);
680 if (dbase == NULL) {
681 perror("db_open");
682 exit(-1);
683 }
684
685 if (do_load) {
686 char buf[128];
687 FILE *fp;
688 struct dbkey k;
689 DBT dbkey, dbdat;
690
691 dbkey.data = &k;
692 dbkey.size = sizeof(k);
693
694 if (strcmp(do_load, "-") == 0 || strcmp(do_load, "--") == 0) {
695 fp = stdin;
696 } else if ((fp = fopen(do_load, "r")) == NULL) {
697 perror("fopen");
698 goto do_abort;
699 }
700
701 buf[sizeof(buf)-1] = 0;
702 while (fgets(buf, sizeof(buf), fp)) {
703 __u8 b1[6];
704 char ipbuf[128];
705 char macbuf[128];
706
707 if (buf[0] == '#')
708 continue;
709
710 if (sscanf(buf, "%u%s%s", &k.iface, ipbuf, macbuf) != 3) {
711 fprintf(stderr, "Wrong format of input file \"%s\"\n", do_load);
712 goto do_abort;
713 }
714 if (strncmp(macbuf, "FAILED:", 7) == 0)
715 continue;
716 if (!inet_aton(ipbuf, (struct in_addr *)&k.addr)) {
717 fprintf(stderr, "Invalid IP address: \"%s\"\n", ipbuf);
718 goto do_abort;
719 }
720
721 if (ll_addr_a2n((char *) b1, 6, macbuf) != 6)
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
738 printf("%-8s %-15s %s\n", "#Ifindex", "IP", "MAC");
739 while (dbase->seq(dbase, &dbkey, &dbdat, R_NEXT) == 0) {
740 struct dbkey *key = dbkey.data;
741
742 if (handle_if(key->iface)) {
743 if (!IS_NEG(dbdat.data)) {
744 char b1[18];
745
746 printf("%-8d %-15s %s\n",
747 key->iface,
748 inet_ntoa(*(struct in_addr *)&key->addr),
749 ll_addr_n2a(dbdat.data, 6, ARPHRD_ETHER, b1, 18));
750 } else {
751 printf("%-8d %-15s FAILED: %dsec ago\n",
752 key->iface,
753 inet_ntoa(*(struct in_addr *)&key->addr),
754 NEG_AGE(dbdat.data));
755 }
756 }
757 }
758 }
759
760 if (do_load || do_list)
761 goto out;
762
763 pset[0].fd = socket(PF_PACKET, SOCK_DGRAM, 0);
764 if (pset[0].fd < 0) {
765 perror("socket");
766 exit(-1);
767 }
768
769 if (1) {
770 struct sockaddr_ll sll = {
771 .sll_family = AF_PACKET,
772 .sll_protocol = htons(ETH_P_ARP),
773 .sll_ifindex = (ifnum == 1 ? ifvec[0] : 0),
774 };
775
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();
834out:
835 dbase->close(dbase);
836 exit(0);
837
838do_abort:
839 dbase->close(dbase);
840 exit(-1);
841}
842