Home | History | Annotate | Download | only in misc
      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 (at) 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 
     40 int resolve_hosts;
     41 
     42 DB	*dbase;
     43 char	*dbname = "/var/lib/arpd/arpd.db";
     44 
     45 int	ifnum;
     46 int	*ifvec;
     47 char	**ifnames;
     48 
     49 struct 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 
     61 struct rtnl_handle rth;
     62 
     63 struct pollfd pset[2];
     64 int udp_sock = -1;
     65 
     66 volatile int do_exit;
     67 volatile int do_sync;
     68 volatile int do_stats;
     69 
     70 struct {
     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 
     88 int active_probing;
     89 int negative_timeout = 60;
     90 int no_kernel_broadcasts;
     91 int broadcast_rate = 1000;
     92 int broadcast_burst = 3000;
     93 int poll_timeout = 30000;
     94 
     95 void 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 
    103 int 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 
    116 int sysctl_adjusted;
    117 
    118 void 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 
    151 void 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 
    181 int 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 
    241 int 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 
    265 int 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 
    289 void 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 
    300 int 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 
    429 void load_initial_table(void)
    430 {
    431 	rtnl_wilddump_request(&rth, AF_INET, RTM_GETNEIGH);
    432 }
    433 
    434 void 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. */
    480 void 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 
    535 void 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>
    548 sigjmp_buf env;
    549 volatile int in_poll;
    550 
    551 void sig_exit(int signo)
    552 {
    553 	do_exit = 1;
    554 	if (in_poll)
    555 		siglongjmp(env, 1);
    556 }
    557 
    558 void sig_sync(int signo)
    559 {
    560 	do_sync = 1;
    561 	if (in_poll)
    562 		siglongjmp(env, 1);
    563 }
    564 
    565 void sig_stats(int signo)
    566 {
    567 	do_sync = 1;
    568 	do_stats = 1;
    569 	if (in_poll)
    570 		siglongjmp(env, 1);
    571 }
    572 
    573 void 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 
    590 int 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();
    830 out:
    831 	dbase->close(dbase);
    832 	exit(0);
    833 
    834 do_abort:
    835 	dbase->close(dbase);
    836 	exit(-1);
    837 }
    838