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
41int resolve_hosts;
42
43DB	*dbase;
44char	*dbname = "/var/lib/arpd/arpd.db";
45
46int	ifnum;
47int	*ifvec;
48char	**ifnames;
49
50struct 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
62struct rtnl_handle rth;
63
64struct pollfd pset[2];
65int udp_sock = -1;
66
67volatile int do_exit;
68volatile int do_sync;
69volatile int do_stats;
70
71struct {
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
89int active_probing;
90int negative_timeout = 60;
91int no_kernel_broadcasts;
92int broadcast_rate = 1000;
93int broadcast_burst = 3000;
94int poll_timeout = 30000;
95
96static 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
104static 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
117int sysctl_adjusted;
118
119static 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
152static 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
182static 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
242static 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
266static 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
290static 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
301static 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
430static 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
439static 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. */
485static 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
540static 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>
553sigjmp_buf env;
554volatile int in_poll;
555
556static void sig_exit(int signo)
557{
558	do_exit = 1;
559	if (in_poll)
560		siglongjmp(env, 1);
561}
562
563static void sig_sync(int signo)
564{
565	do_sync = 1;
566	if (in_poll)
567		siglongjmp(env, 1);
568}
569
570static void sig_stats(int signo)
571{
572	do_sync = 1;
573	do_stats = 1;
574	if (in_poll)
575		siglongjmp(env, 1);
576}
577
578static 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
595int 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();
834out:
835	dbase->close(dbase);
836	exit(0);
837
838do_abort:
839	dbase->close(dbase);
840	exit(-1);
841}
842