]> git.proxmox.com Git - mirror_iproute2.git/blame - misc/arpd.c
(Logical change 1.3)
[mirror_iproute2.git] / misc / arpd.c
CommitLineData
aba5acdf
SH
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.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_arp.h>
31#include <netinet/in.h>
32#include <arpa/inet.h>
33#include <linux/if_packet.h>
34#include <linux/filter.h>
35
36#include "libnetlink.h"
37#include "utils.h"
38
39int resolve_hosts;
40
41DB *dbase;
42char *dbname = "/var/lib/arpd/arpd.db";
43
44int ifnum;
45int *ifvec;
46char **ifnames;
47
48struct dbkey
49{
50 __u32 iface;
51 __u32 addr;
52};
53
54#define IS_NEG(x) (((__u8*)(x))[0] == 0xFF)
55#define NEG_TIME(x) (((x)[2]<<24)|((x)[3]<<16)|((x)[4]<<8)|(x)[5])
56#define NEG_AGE(x) ((__u32)time(NULL) - NEG_TIME((__u8*)x))
57#define NEG_VALID(x) (NEG_AGE(x) < negative_timeout)
58#define NEG_CNT(x) (((__u8*)(x))[1])
59
60struct rtnl_handle rth;
61
62struct pollfd pset[2];
63int udp_sock = -1;
64
65volatile int do_exit;
66volatile int do_sync;
67volatile int do_stats;
68
69struct {
70 unsigned long arp_new;
71 unsigned long arp_change;
72
73 unsigned long app_recv;
74 unsigned long app_success;
75 unsigned long app_bad;
76 unsigned long app_neg;
77 unsigned long app_suppressed;
78
79 unsigned long kern_neg;
80 unsigned long kern_new;
81 unsigned long kern_change;
82
83 unsigned long probes_sent;
84 unsigned long probes_suppressed;
85} stats;
86
87int active_probing;
88int negative_timeout = 60;
89int no_kernel_broadcasts;
90int broadcast_rate = 1000;
91int broadcast_burst = 3000;
92
93void usage(void)
94{
95 fprintf(stderr,
96"Usage: arpd [ -lk ] [ -a N ] [ -b dbase ] [ -f file ] [ interfaces ]\n");
97 exit(1);
98}
99
100int handle_if(int ifindex)
101{
102 int i;
103
104 if (ifnum == 0)
105 return 1;
106
107 for (i=0; i<ifnum; i++)
108 if (ifvec[i] == ifindex)
109 return 1;
110 return 0;
111}
112
113int sysctl_adjusted;
114
115void do_sysctl_adjustments(void)
116{
117 int i;
118
119 if (!ifnum)
120 return;
121
122 for (i=0; i<ifnum; i++) {
123 char buf[128];
124 FILE *fp;
125
126 if (active_probing) {
127 sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/mcast_solicit", ifnames[i]);
128 if ((fp = fopen(buf, "w")) != NULL) {
129 if (no_kernel_broadcasts)
130 strcpy(buf, "0\n");
131 else
132 sprintf(buf, "%d\n", active_probing>=2 ? 1 : 3-active_probing);
133 fputs(buf, fp);
134 fclose(fp);
135 }
136 }
137
138 sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/app_solicit", ifnames[i]);
139 if ((fp = fopen(buf, "w")) != NULL) {
140 sprintf(buf, "%d\n", active_probing<=1 ? 1 : active_probing);
141 fputs(buf, fp);
142 fclose(fp);
143 }
144 }
145 sysctl_adjusted = 1;
146}
147
148void undo_sysctl_adjustments(void)
149{
150 int i;
151
152 if (!sysctl_adjusted)
153 return;
154
155 for (i=0; i<ifnum; i++) {
156 char buf[128];
157 FILE *fp;
158
159 if (active_probing) {
160 sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/mcast_solicit", ifnames[i]);
161 if ((fp = fopen(buf, "w")) != NULL) {
162 strcpy(buf, "3\n");
163 fputs(buf, fp);
164 fclose(fp);
165 }
166 }
167 sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/app_solicit", ifnames[i]);
168 if ((fp = fopen(buf, "w")) != NULL) {
169 strcpy(buf, "0\n");
170 fputs(buf, fp);
171 fclose(fp);
172 }
173 }
174 sysctl_adjusted = 0;
175}
176
177
178int send_probe(int ifindex, __u32 addr)
179{
180 struct ifreq ifr;
181 struct sockaddr_in dst;
182 int len;
183 unsigned char buf[256];
184 struct arphdr *ah = (struct arphdr*)buf;
185 unsigned char *p = (unsigned char *)(ah+1);
186 struct sockaddr_ll sll;
187
188 memset(&ifr, 0, sizeof(ifr));
189 ifr.ifr_ifindex = ifindex;
190 if (ioctl(udp_sock, SIOCGIFNAME, &ifr))
191 return -1;
192 if (ioctl(udp_sock, SIOCGIFHWADDR, &ifr))
193 return -1;
194 if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
195 return -1;
196 if (setsockopt(udp_sock, SOL_SOCKET, SO_BINDTODEVICE, ifr.ifr_name, strlen(ifr.ifr_name)+1) < 0)
197 return -1;
198
199 dst.sin_family = AF_INET;
200 dst.sin_port = htons(1025);
201 dst.sin_addr.s_addr = addr;
202 if (connect(udp_sock, (struct sockaddr*)&dst, sizeof(dst)) < 0)
203 return -1;
204 len = sizeof(dst);
205 if (getsockname(udp_sock, (struct sockaddr*)&dst, &len) < 0)
206 return -1;
207
208 ah->ar_hrd = htons(ifr.ifr_hwaddr.sa_family);
209 ah->ar_pro = htons(ETH_P_IP);
210 ah->ar_hln = 6;
211 ah->ar_pln = 4;
212 ah->ar_op = htons(ARPOP_REQUEST);
213
214 memcpy(p, ifr.ifr_hwaddr.sa_data, ah->ar_hln);
215 p += ah->ar_hln;
216
217 memcpy(p, &dst.sin_addr, 4);
218 p+=4;
219
220 sll.sll_family = AF_PACKET;
221 memset(sll.sll_addr, 0xFF, sizeof(sll.sll_addr));
222 sll.sll_ifindex = ifindex;
223 sll.sll_protocol = htons(ETH_P_ARP);
224 memcpy(p, &sll.sll_addr, ah->ar_hln);
225 p+=ah->ar_hln;
226
227 memcpy(p, &addr, 4);
228 p+=4;
229
230 len = sendto(pset[0].fd, buf, p-buf, 0, (struct sockaddr*)&sll, sizeof(sll));
231 if (len < 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
239int 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
263int 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
287void 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
298int 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 memset(tb, 0, sizeof(tb));
332 parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len);
333
334 if (!tb[NDA_DST])
335 return 0;
336
337 key.iface = ndm->ndm_ifindex;
338 memcpy(&key.addr, RTA_DATA(tb[NDA_DST]), 4);
339 dbkey.data = &key;
340 dbkey.size = sizeof(key);
341
342 if (dbase->get(dbase, &dbkey, &dbdat, 0) != 0) {
343 dbdat.data = 0;
344 dbdat.size = 0;
345 }
346
347 if (n->nlmsg_type == RTM_GETNEIGH) {
348 if (!(n->nlmsg_flags&NLM_F_REQUEST))
349 return 0;
350
351 if (!(ndm->ndm_state&(NUD_PROBE|NUD_INCOMPLETE))) {
352 stats.app_bad++;
353 return 0;
354 }
355
356 if (ndm->ndm_state&NUD_PROBE) {
357 /* If we get this, kernel still has some valid
358 * address, but unicast probing failed and host
359 * is either dead or changed its mac address.
360 * Kernel is going to initiate broadcast resolution.
361 * OK, we invalidate our information as well.
362 */
363 if (dbdat.data && !IS_NEG(dbdat.data))
364 stats.app_neg++;
365
366 dbase->del(dbase, &dbkey, 0);
367 } else {
368 /* If we get this kernel does not have any information.
369 * If we have something tell this to kernel. */
370 stats.app_recv++;
371 if (dbdat.data && !IS_NEG(dbdat.data)) {
372 stats.app_success++;
373 respond_to_kernel(key.iface, key.addr, dbdat.data, dbdat.size);
374 return 0;
375 }
376
377 /* Sheeit! We have nothing to tell. */
378 /* If we have recent negative entry, be silent. */
379 if (dbdat.data && NEG_VALID(dbdat.data)) {
380 if (NEG_CNT(dbdat.data) >= active_probing) {
381 stats.app_suppressed++;
382 return 0;
383 }
384 do_acct = 1;
385 }
386 }
387
388 if (active_probing &&
389 queue_active_probe(ndm->ndm_ifindex, key.addr) == 0 &&
390 do_acct) {
391 NEG_CNT(dbdat.data)++;
392 dbase->put(dbase, &dbkey, &dbdat, 0);
393 }
394 } else if (n->nlmsg_type == RTM_NEWNEIGH) {
395 if (n->nlmsg_flags&NLM_F_REQUEST)
396 return 0;
397
398 if (ndm->ndm_state&NUD_FAILED) {
399 /* Kernel was not able to resolve. Host is dead.
400 * Create negative entry if it is not present
401 * or renew it if it is too old. */
402 if (!dbdat.data ||
403 !IS_NEG(dbdat.data) ||
404 !NEG_VALID(dbdat.data)) {
405 __u8 ndata[6];
406 stats.kern_neg++;
407 prepare_neg_entry(ndata, time(NULL));
408 dbdat.data = ndata;
409 dbdat.size = sizeof(ndata);
410 dbase->put(dbase, &dbkey, &dbdat, 0);
411 }
412 } else if (tb[NDA_LLADDR]) {
413 if (dbdat.data && !IS_NEG(dbdat.data)) {
414 if (memcmp(RTA_DATA(tb[NDA_LLADDR]), dbdat.data, dbdat.size) == 0)
415 return 0;
416 stats.kern_change++;
417 } else {
418 stats.kern_new++;
419 }
420 dbdat.data = RTA_DATA(tb[NDA_LLADDR]);
421 dbdat.size = RTA_PAYLOAD(tb[NDA_LLADDR]);
422 dbase->put(dbase, &dbkey, &dbdat, 0);
423 }
424 }
425 return 0;
426}
427
428void load_initial_table(void)
429{
430 rtnl_wilddump_request(&rth, AF_INET, RTM_GETNEIGH);
431}
432
433void get_kern_msg(void)
434{
435 int status;
436 struct nlmsghdr *h;
437 struct sockaddr_nl nladdr;
438 struct iovec iov;
439 char buf[8192];
440 struct msghdr msg = {
441 (void*)&nladdr, sizeof(nladdr),
442 &iov, 1,
443 NULL, 0,
444 0
445 };
446
447 memset(&nladdr, 0, sizeof(nladdr));
448
449 iov.iov_base = buf;
450 iov.iov_len = sizeof(buf);
451
452 status = recvmsg(rth.fd, &msg, MSG_DONTWAIT);
453
454 if (status <= 0)
455 return;
456
457 if (msg.msg_namelen != sizeof(nladdr))
458 return;
459
460 if (nladdr.nl_pid)
461 return;
462
463 for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
464 int len = h->nlmsg_len;
465 int l = len - sizeof(*h);
466
467 if (l < 0 || len > status)
468 return;
469
470 if (do_one_request(h) < 0)
471 return;
472
473 status -= NLMSG_ALIGN(len);
474 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
475 }
476}
477
478/* Receive gratuitous ARP messages and store them, that's all. */
479void get_arp_pkt(void)
480{
481 unsigned char buf[1024];
482 struct sockaddr_ll sll;
483 int sll_len = sizeof(sll);
484 struct arphdr *a = (struct arphdr*)buf;
485 struct dbkey key;
486 DBT dbkey, dbdat;
487 int n;
488
489 n = recvfrom(pset[0].fd, buf, sizeof(buf), MSG_DONTWAIT, (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
533void 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>
546sigjmp_buf env;
547volatile int in_poll;
548
549void sig_exit(int signo)
550{
551 do_exit = 1;
552 if (in_poll)
553 siglongjmp(env, 1);
554}
555
556void sig_sync(int signo)
557{
558 do_sync = 1;
559 if (in_poll)
560 siglongjmp(env, 1);
561}
562
563void sig_stats(int signo)
564{
565 do_sync = 1;
566 do_stats = 1;
567 if (in_poll)
568 siglongjmp(env, 1);
569}
570
571void 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
588int 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 dbdat.data = hexstring_a2n(macbuf, b1, 6);
712 if (dbdat.data == NULL)
713 goto do_abort;
714 dbdat.size = 6;
715
716 if (dbase->put(dbase, &dbkey, &dbdat, 0)) {
717 perror("hash->put");
718 goto do_abort;
719 }
720 }
721 dbase->sync(dbase, 0);
722 if (fp != stdin)
723 fclose(fp);
724 }
725
726 if (do_list) {
727 DBT dbkey, dbdat;
728 printf("%-8s %-15s %s\n", "#Ifindex", "IP", "MAC");
729 while (dbase->seq(dbase, &dbkey, &dbdat, R_NEXT) == 0) {
730 struct dbkey *key = dbkey.data;
731 if (handle_if(key->iface)) {
732 if (!IS_NEG(dbdat.data)) {
733 __u8 b1[18];
734 printf("%-8d %-15s %s\n",
735 key->iface,
736 inet_ntoa(*(struct in_addr*)&key->addr),
737 hexstring_n2a(dbdat.data, 6, b1, 18));
738 } else {
739 printf("%-8d %-15s FAILED: %dsec ago\n",
740 key->iface,
741 inet_ntoa(*(struct in_addr*)&key->addr),
742 NEG_AGE(dbdat.data));
743 }
744 }
745 }
746 }
747
748 if (do_load || do_list)
749 goto out;
750
751 pset[0].fd = socket(PF_PACKET, SOCK_DGRAM, 0);
752 if (pset[0].fd < 0) {
753 perror("socket");
754 exit(-1);
755 }
756
757 if (1) {
758 struct sockaddr_ll sll;
759 memset(&sll, 0, sizeof(sll));
760 sll.sll_family = AF_PACKET;
761 sll.sll_protocol = htons(ETH_P_ARP);
762 sll.sll_ifindex = (ifnum == 1 ? ifvec[0] : 0);
763 if (bind(pset[0].fd, (struct sockaddr*)&sll, sizeof(sll)) < 0) {
764 perror("bind");
765 goto do_abort;
766 }
767 }
768
769 if (rtnl_open(&rth, RTMGRP_NEIGH) < 0) {
770 perror("rtnl_open");
771 goto do_abort;
772 }
773 pset[1].fd = rth.fd;
774
775 load_initial_table();
776
777 if (1) {
778 int fd;
779 pid_t pid = fork();
780
781 if (pid > 0)
782 _exit(0);
783 if (pid < 0) {
784 perror("arpd: fork");
785 goto do_abort;
786 }
787
788 chdir("/");
789 fd = open("/dev/null", O_RDWR);
790 if (fd >= 0) {
791 dup2(fd, 0);
792 dup2(fd, 1);
793 dup2(fd, 2);
794 if (fd > 2)
795 close(fd);
796 }
797 setsid();
798 }
799
800 openlog("arpd", LOG_PID | LOG_CONS, LOG_DAEMON);
801 catch_signal(SIGINT, sig_exit);
802 catch_signal(SIGTERM, sig_exit);
803 catch_signal(SIGHUP, sig_sync);
804 catch_signal(SIGUSR1, sig_stats);
805
806#define EVENTS (POLLIN|POLLPRI|POLLERR|POLLHUP)
807 pset[0].events = EVENTS;
808 pset[0].revents = 0;
809 pset[1].events = EVENTS;
810 pset[1].revents = 0;
811
812 sigsetjmp(env, 1);
813
814 for (;;) {
815 in_poll = 1;
816
817 if (do_exit)
818 break;
819 if (do_sync) {
820 in_poll = 0;
821 dbase->sync(dbase, 0);
822 do_sync = 0;
823 in_poll = 1;
824 }
825 if (do_stats)
826 send_stats();
827 if (poll(pset, 2, 30000) > 0) {
828 in_poll = 0;
829 if (pset[0].revents&EVENTS)
830 get_arp_pkt();
831 if (pset[1].revents&EVENTS)
832 get_kern_msg();
833 } else {
834 do_sync = 1;
835 }
836 }
837
838 undo_sysctl_adjustments();
839out:
840 dbase->close(dbase);
841 exit(0);
842
843do_abort:
844 dbase->close(dbase);
845 exit(-1);
846}