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 
     94 void usage(void)
     95 {
     96 	fprintf(stderr,
     97 "Usage: arpd [ -lk ] [ -a N ] [ -b dbase ] [ -f file ] [ interfaces ]\n");
     98 	exit(1);
     99 }
    100 
    101 int 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 
    114 int sysctl_adjusted;
    115 
    116 void 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 
    149 void 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 
    179 int 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 
    239 int 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 
    263 int 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 
    287 void 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 
    298 int 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 
    427 void load_initial_table(void)
    428 {
    429 	rtnl_wilddump_request(&rth, AF_INET, RTM_GETNEIGH);
    430 }
    431 
    432 void 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. */
    478 void 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 
    533 void 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>
    546 sigjmp_buf env;
    547 volatile int in_poll;
    548 
    549 void sig_exit(int signo)
    550 {
    551 	do_exit = 1;
    552 	if (in_poll)
    553 		siglongjmp(env, 1);
    554 }
    555 
    556 void sig_sync(int signo)
    557 {
    558 	do_sync = 1;
    559 	if (in_poll)
    560 		siglongjmp(env, 1);
    561 }
    562 
    563 void sig_stats(int signo)
    564 {
    565 	do_sync = 1;
    566 	do_stats = 1;
    567 	if (in_poll)
    568 		siglongjmp(env, 1);
    569 }
    570 
    571 void 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 
    588 int 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 (daemon(0, 0)) {
    779 		perror("arpd: daemon");
    780 		goto do_abort;
    781 	}
    782 
    783 	openlog("arpd", LOG_PID | LOG_CONS, LOG_DAEMON);
    784 	catch_signal(SIGINT, sig_exit);
    785 	catch_signal(SIGTERM, sig_exit);
    786 	catch_signal(SIGHUP, sig_sync);
    787 	catch_signal(SIGUSR1, sig_stats);
    788 
    789 #define EVENTS (POLLIN|POLLPRI|POLLERR|POLLHUP)
    790 	pset[0].events = EVENTS;
    791 	pset[0].revents = 0;
    792 	pset[1].events = EVENTS;
    793 	pset[1].revents = 0;
    794 
    795 	sigsetjmp(env, 1);
    796 
    797 	for (;;) {
    798 		in_poll = 1;
    799 
    800 		if (do_exit)
    801 			break;
    802 		if (do_sync) {
    803 			in_poll = 0;
    804 			dbase->sync(dbase, 0);
    805 			do_sync = 0;
    806 			in_poll = 1;
    807 		}
    808 		if (do_stats)
    809 			send_stats();
    810 		if (poll(pset, 2, 30000) > 0) {
    811 			in_poll = 0;
    812 			if (pset[0].revents&EVENTS)
    813 				get_arp_pkt();
    814 			if (pset[1].revents&EVENTS)
    815 				get_kern_msg();
    816 		} else {
    817 			do_sync = 1;
    818 		}
    819 	}
    820 
    821 	undo_sysctl_adjustments();
    822 out:
    823 	dbase->close(dbase);
    824 	exit(0);
    825 
    826 do_abort:
    827 	dbase->close(dbase);
    828 	exit(-1);
    829 }
    830