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
40int resolve_hosts;
41
42DB	*dbase;
43char	*dbname = "/var/lib/arpd/arpd.db";
44
45int	ifnum;
46int	*ifvec;
47char	**ifnames;
48
49struct 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
61struct rtnl_handle rth;
62
63struct pollfd pset[2];
64int udp_sock = -1;
65
66volatile int do_exit;
67volatile int do_sync;
68volatile int do_stats;
69
70struct {
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
88int active_probing;
89int negative_timeout = 60;
90int no_kernel_broadcasts;
91int broadcast_rate = 1000;
92int broadcast_burst = 3000;
93
94void usage(void)
95{
96	fprintf(stderr,
97"Usage: arpd [ -lk ] [ -a N ] [ -b dbase ] [ -f file ] [ interfaces ]\n");
98	exit(1);
99}
100
101int 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
114int sysctl_adjusted;
115
116void 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
149void 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
179int 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
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	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
427void load_initial_table(void)
428{
429	rtnl_wilddump_request(&rth, AF_INET, RTM_GETNEIGH);
430}
431
432void 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. */
478void 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
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
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();
840out:
841	dbase->close(dbase);
842	exit(0);
843
844do_abort:
845	dbase->close(dbase);
846	exit(-1);
847}
848