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;
93int poll_timeout = 30000;
94
95void 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
103int 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
116int sysctl_adjusted;
117
118void 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
151void 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
181int 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
241int 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
265int 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
289void 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
300int 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
429void load_initial_table(void)
430{
431	rtnl_wilddump_request(&rth, AF_INET, RTM_GETNEIGH);
432}
433
434void 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. */
480void 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
535void 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>
548sigjmp_buf env;
549volatile int in_poll;
550
551void sig_exit(int signo)
552{
553	do_exit = 1;
554	if (in_poll)
555		siglongjmp(env, 1);
556}
557
558void sig_sync(int signo)
559{
560	do_sync = 1;
561	if (in_poll)
562		siglongjmp(env, 1);
563}
564
565void sig_stats(int signo)
566{
567	do_sync = 1;
568	do_stats = 1;
569	if (in_poll)
570		siglongjmp(env, 1);
571}
572
573void 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
590int 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();
830out:
831	dbase->close(dbase);
832	exit(0);
833
834do_abort:
835	dbase->close(dbase);
836	exit(-1);
837}
838