Home | History | Annotate | Download | only in ninfod
      1 /* $USAGI: ninfod.c,v 1.34 2003-01-15 06:41:23 mk Exp $ */
      2 /*
      3  * Copyright (C) 2002 USAGI/WIDE Project.
      4  * All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. Neither the name of the project nor the names of its contributors
     15  *    may be used to endorse or promote products derived from this software
     16  *    without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
     19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
     22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     28  * SUCH DAMAGE.
     29  */
     30 /*
     31  * Author:
     32  * 	YOSHIFUJI Hideaki <yoshfuji (at) linux-ipv6.org>
     33  */
     34 
     35 #if HAVE_CONFIG_H
     36 #include "config.h"
     37 #endif
     38 
     39 #if HAVE_SYS_TYPES_H
     40 # include <sys/types.h>
     41 #endif
     42 #if STDC_HEADERS
     43 # include <stdio.h>
     44 # include <stdlib.h>
     45 # include <stddef.h>
     46 # include <stdarg.h>
     47 #else
     48 # if HAVE_STDLIB_H
     49 #  include <stdlib.h>
     50 # endif
     51 #endif
     52 
     53 #if HAVE_STRING_H
     54 # if !STDC_HEADERS && HAVE_MEMORY_H
     55 #  include <memory.h>
     56 # endif
     57 # include <string.h>
     58 #endif
     59 #if HAVE_STRINGS_H
     60 # include <strings.h>
     61 #endif
     62 #if HAVE_INTTYPES_H
     63 # include <inttypes.h>
     64 #else
     65 # if HAVE_STDINT_H
     66 #  include <stdint.h>
     67 # endif
     68 #endif
     69 #if HAVE_LIMITS_H
     70 # include <limits.h>
     71 #endif
     72 #if HAVE_UNISTD_H
     73 # include <unistd.h>
     74 #endif
     75 
     76 #ifdef TIME_WITH_SYS_TIME
     77 # include <sys/time.h>
     78 # include <time.h>
     79 #else
     80 # ifdef HAVE_SYS_TIME_H
     81 #  include <sys/time.h>
     82 # else
     83 #  include <time.h>
     84 # endif
     85 #endif
     86 
     87 #if HAVE_SYS_UIO_H
     88 #include <sys/uio.h>
     89 #endif
     90 
     91 #include <sys/socket.h>
     92 
     93 #if HAVE_NETINET_IN_H
     94 # include <netinet/in.h>
     95 #endif
     96 
     97 #if HAVE_NETINET_ICMP6_H
     98 # include <netinet/icmp6.h>
     99 #endif
    100 #ifndef HAVE_STRUCT_ICMP6_NODEINFO
    101 # include "icmp6_nodeinfo.h"
    102 #endif
    103 
    104 #if HAVE_NETDB_H
    105 # include <netdb.h>
    106 #endif
    107 #include <errno.h>
    108 
    109 #include <signal.h>
    110 
    111 #if HAVE_SYSLOG_H
    112 # include <syslog.h>
    113 #endif
    114 
    115 #if HAVE_PWD_H
    116 # include <pwd.h>
    117 #endif
    118 
    119 #if HAVE_SYS_CAPABILITY_H
    120 # include <sys/prctl.h>
    121 # include <sys/capability.h>
    122 #endif
    123 
    124 #include "ninfod.h"
    125 
    126 #ifndef offsetof
    127 # define offsetof(aggregate,member)	((size_t)&((aggregate *)0)->member)
    128 #endif
    129 
    130 /* --------- */
    131 /* ID */
    132 static char *RCSID __attribute__ ((unused)) = "$USAGI: ninfod.c,v 1.34 2003-01-15 06:41:23 mk Exp $";
    133 
    134 /* Variables */
    135 int sock;
    136 int daemonized;
    137 
    138 char *appname;
    139 static int opt_d = 0;	/* debug */
    140 static int opt_h = 0;	/* help */
    141 static char *opt_p = NINFOD_PIDFILE;	/* pidfile */
    142 static int got_signal = 0;	/* loop unless true */
    143 int opt_v = 0;		/* verbose */
    144 static uid_t opt_u;
    145 
    146 static int ipv6_pktinfo = IPV6_PKTINFO;
    147 
    148 /* --------- */
    149 #if ENABLE_DEBUG
    150 static const __inline__ char * log_level(int priority) {
    151 	switch(priority) {
    152 	case LOG_EMERG:		return "EMERG";
    153 	case LOG_ALERT:		return "ALERT";
    154 	case LOG_CRIT:		return "CRIT";
    155 	case LOG_ERR:		return "ERR";
    156 	case LOG_WARNING:	return "WARNING";
    157 	case LOG_NOTICE:	return "NOTICE";
    158 	case LOG_INFO:		return "INFO";
    159 	case LOG_DEBUG:		return "DEBUG";
    160 	default:		return "???";
    161 	}
    162 }
    163 
    164 void stderrlog(int pri, char *fmt, ...)
    165 {
    166 	va_list ap;
    167 	char ebuf[512];
    168 	char *buf;
    169 	size_t buflen;
    170 
    171 	va_start(ap, fmt);
    172 
    173 	for (buf = ebuf, buflen = sizeof(ebuf);
    174 	     buflen < SIZE_MAX / 2;
    175 	     free(buf != ebuf ? buf : NULL), buf = NULL, buflen *= 2) {
    176 		size_t rem;
    177 		size_t res;
    178 
    179 		buf = malloc(buflen);
    180 		if (!buf)
    181 			break;	/*XXX*/
    182 
    183 		rem = buflen;
    184 
    185 		res = snprintf(buf, rem, "[%s] ", log_level(pri));
    186 		if (res >= rem)
    187 			continue;
    188 		rem -= res;
    189 
    190 		res = vsnprintf(buf + res, rem, fmt, ap);
    191 
    192 		if (res >= rem)
    193 			continue;
    194 		break;
    195 	}
    196 
    197 	if (buf) {
    198 		fputs(buf, stderr);
    199 		free(buf != ebuf ? buf : NULL);
    200 	}
    201 
    202 	va_end(ap);
    203 }
    204 #endif
    205 
    206 /* --------- */
    207 static int __inline__ open_sock(void)
    208 {
    209 	return socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
    210 }
    211 
    212 static int set_recvpktinfo(int sock)
    213 {
    214 	int on, ret;
    215 
    216 	on = 1;
    217 
    218 #if defined(IPV6_RECVPKTINFO)
    219 	ret = setsockopt(sock,
    220 			 IPPROTO_IPV6, IPV6_RECVPKTINFO,
    221 			 &on, sizeof(on));
    222 	if (!ret)
    223 		return 0;
    224 # if defined(IPV6_2292PKTINFO)
    225 	ret = setsockopt(sock,
    226 			 IPPROTO_IPV6, IPV6_2292PKTINFO,
    227 			 &on, sizeof(on));
    228 	if (!ret) {
    229 		ipv6_pktinfo = IPV6_2292PKTINFO;
    230 		return 0;
    231 	}
    232 
    233 	DEBUG(LOG_ERR, "setsockopt(IPV6_RECVPKTINFO/IPV6_2292PKTINFO): %s\n",
    234 	      strerror(errno));
    235 # else
    236 	DEBUG(LOG_ERR, "setsockopt(IPV6_RECVPKTINFO): %s\n",
    237 	      strerror(errno));
    238 # endif
    239 #else
    240 	ret = setsockopt(sock,
    241 			 IPPROTO_IPV6, IPV6_PKTINFO,
    242 			 &on, sizeof(on));
    243 	if (!ret)
    244 		return 0;
    245 
    246 	DEBUG(LOG_ERR, "setsockopt(IPV6_PKTINFO): %s\n",
    247 	      strerror(errno));
    248 #endif
    249 
    250 	return -1;
    251 }
    252 
    253 static int __inline__ init_sock(int sock)
    254 {
    255 	struct icmp6_filter filter;
    256 #if NEED_IPV6CHECKSUM
    257 	int i;
    258 
    259 	i = offsetof(struct icmp6_nodeinfo, ni_cksum);
    260 	if (setsockopt(sock,
    261 		       IPPROTO_IPV6, IPV6_CHECKSUM,
    262 		       &i, sizeof(i)) < 0) {
    263 		DEBUG(LOG_ERR, "setsockopt(IPV6_CHECKSUM): %s\n",
    264 		      strerror(errno));
    265 		return -1;
    266 	}
    267 #endif
    268 
    269 	ICMP6_FILTER_SETBLOCKALL(&filter);
    270 	ICMP6_FILTER_SETPASS(ICMP6_NI_QUERY, &filter);
    271 	if (setsockopt(sock,
    272 		       IPPROTO_ICMPV6, ICMP6_FILTER,
    273 		       &filter, sizeof(filter)) < 0) {
    274 		DEBUG(LOG_ERR, "setsockopt(ICMP6_FILTER): %s\n",
    275 		      strerror(errno));
    276 		return -1;
    277 	}
    278 
    279 	if (set_recvpktinfo(sock) < 0)
    280 		return -1;
    281 
    282 	return 0;
    283 }
    284 
    285 /* --------- */
    286 int ni_recv(struct packetcontext *p)
    287 {
    288 	int sock = p->sock;
    289 	struct iovec iov[1];
    290 	struct msghdr msgh;
    291 	char recvcbuf[CMSG_SPACE(sizeof(p->pktinfo))];
    292 	struct cmsghdr *cmsg;
    293 	int cc;
    294 
    295 	DEBUG(LOG_DEBUG, "%s()\n", __func__);
    296 
    297 	memset(&iov, 0, sizeof(iov));
    298 	iov[0].iov_base = p->query;
    299 	iov[0].iov_len = sizeof(p->query);
    300 
    301 	memset(&msgh, 0, sizeof(msgh));
    302 	msgh.msg_name = (struct sockaddr *)&p->addr;
    303 	msgh.msg_namelen = sizeof(p->addr);
    304 	msgh.msg_iov = iov;
    305 	msgh.msg_iovlen = 1;
    306 	msgh.msg_control = recvcbuf;
    307 	msgh.msg_controllen = sizeof(recvcbuf);
    308 
    309 	if ((cc = recvmsg(sock, &msgh, 0)) < 0)
    310 		return -1;
    311 
    312 	p->querylen = cc;
    313 	p->addrlen = msgh.msg_namelen;
    314 
    315 	for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg;
    316 	     cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
    317 		if (cmsg->cmsg_level == IPPROTO_IPV6 &&
    318 		    (cmsg->cmsg_type == IPV6_PKTINFO
    319 #if defined(IPV6_2292PKTINFO)
    320 		     || cmsg->cmsg_type == IPV6_2292PKTINFO
    321 #endif
    322 		    )) {
    323 			memcpy(&p->pktinfo, CMSG_DATA(cmsg), sizeof(p->pktinfo));
    324 			break;
    325 		}
    326 	}
    327 
    328 	return 0;
    329 }
    330 
    331 int ni_send(struct packetcontext *p)
    332 {
    333 	int sock = p->sock;
    334 	struct iovec iov[2];
    335 	char cbuf[CMSG_SPACE(sizeof(p->pktinfo))];
    336 	struct msghdr msgh;
    337 	struct cmsghdr *cmsg;
    338 	int cc;
    339 
    340 	DEBUG(LOG_DEBUG, "%s()\n", __func__);
    341 
    342 	memset(&iov, 0, sizeof(iov));
    343 	iov[0].iov_base = &p->reply;
    344 	iov[0].iov_len = sizeof(p->reply);
    345 	iov[1].iov_base = p->replydata;
    346 	iov[1].iov_len = p->replydatalen;
    347 
    348 	memset(&msgh, 0, sizeof(msgh));
    349 	msgh.msg_name = (struct sockaddr *)&p->addr;
    350 	msgh.msg_namelen = p->addrlen;
    351 	msgh.msg_iov = iov;
    352 	msgh.msg_iovlen = p->replydata ? 2 : 1;
    353 
    354 	msgh.msg_control = cbuf;
    355 	msgh.msg_controllen = sizeof(cbuf);
    356 
    357 	cmsg = CMSG_FIRSTHDR(&msgh);
    358 	cmsg->cmsg_level = IPPROTO_IPV6;
    359 	cmsg->cmsg_type = ipv6_pktinfo;
    360 	cmsg->cmsg_len = CMSG_LEN(sizeof(p->pktinfo));
    361 	memcpy(CMSG_DATA(cmsg), &p->pktinfo, sizeof(p->pktinfo));
    362 
    363 	msgh.msg_controllen = cmsg->cmsg_len;
    364 
    365 	if (p->delay) {
    366 #if HAVE_NANOSLEEP
    367 		struct timespec ts, rts;
    368 		int err = 0;
    369 
    370 		rts.tv_sec  = p->delay / 1000000;
    371 		rts.tv_nsec = (long)(p->delay % 1000000) * 1000;
    372 
    373 		do {
    374 			ts = rts;
    375 			err = nanosleep(&ts, &rts);
    376 		} while(err < 0);
    377 #else
    378 		usleep(p->delay);	/*XXX: signal*/
    379 #endif
    380 	}
    381 
    382 	cc = sendmsg(sock, &msgh, 0);
    383 	if (cc < 0)
    384 		DEBUG(LOG_DEBUG, "sendmsg(): %s\n", strerror(errno));
    385 
    386 	ni_free(p->replydata);
    387 	ni_free(p);
    388 
    389 	return cc;
    390 }
    391 
    392 /* --------- */
    393 static void sig_handler(int sig)
    394 {
    395 	if (!got_signal)
    396 		DEBUG(LOG_INFO, "singnal(%d) received, quitting.\n", sig);
    397 	got_signal = 1;
    398 }
    399 
    400 static void setup_sighandlers(void)
    401 {
    402 	struct sigaction act;
    403 	sigset_t smask;
    404 	sigemptyset(&smask);
    405 	sigaddset(&smask, SIGHUP);
    406 	sigaddset(&smask, SIGINT);
    407 	sigaddset(&smask, SIGQUIT);
    408 	sigaddset(&smask, SIGTERM);
    409 
    410 	memset(&act, 0, sizeof(act));
    411 	act.sa_handler = sig_handler;
    412 	act.sa_mask = smask;
    413 
    414 	sigaction(SIGHUP, &act, NULL);
    415 	sigaction(SIGINT, &act, NULL);
    416 	sigaction(SIGQUIT, &act, NULL);
    417 	sigaction(SIGTERM, &act, NULL);
    418 }
    419 
    420 static void set_logfile(void)
    421 {
    422 	setbuf(stderr, NULL);
    423 #if ENABLE_DEBUG
    424 	openlog(NINFOD, 0, LOG_USER);
    425 #endif
    426 }
    427 
    428 static void cleanup_pidfile(void)
    429 {
    430 	int err;
    431 
    432 	if (daemonized && opt_p) {
    433 		err = unlink(opt_p);
    434 		DEBUG(LOG_ERR, "failed to unlink file '%s' : %s\n",
    435 				opt_p, strerror(errno));
    436 	}
    437 }
    438 
    439 static FILE *fopen_excl(const char *file)
    440 {
    441 #ifndef __linux__
    442 	int fd;
    443 	FILE *fp;
    444 
    445 	fd = open(file, O_CREAT | O_RDWR | O_EXCL,
    446 		  S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
    447 	if (fd < 0)
    448 		return NULL;
    449 
    450 	return fdopen(file, "w+");
    451 #else
    452 	return fopen(file, "w+x");
    453 #endif
    454 }
    455 
    456 static void do_daemonize(void)
    457 {
    458 	FILE *fp = NULL;
    459 	pid_t pid;
    460 
    461 	if (opt_p) {
    462 		if (!access(opt_p, R_OK)) {
    463 			if ((fp = fopen(opt_p, "r"))) {
    464 				if (fscanf(fp, "%d", &pid) != 1) {
    465 					DEBUG(LOG_ERR, "pid file '%s' exists, but read failed.\n",
    466 					      opt_p);
    467 				} else {
    468 					DEBUG(LOG_ERR, "pid file '%s' exists : %d\n",
    469 					      opt_p, pid);
    470 				}
    471 				fclose(fp);
    472 				exit(1);
    473 			}
    474 		}
    475 
    476 		fp = fopen_excl(opt_p);
    477 		if (!fp) {
    478 			DEBUG(LOG_ERR, "failed to open file '%s': %s\n",
    479 			      opt_p, strerror(errno));
    480 			exit(1);
    481 		}
    482 	}
    483 
    484 	if (daemon(0, 0) < 0) {
    485 		DEBUG(LOG_ERR, "failed to daemon(): %s\n", strerror(errno));
    486 		unlink(opt_p);
    487 		exit(1);
    488 	}
    489 	daemonized = 1;
    490 
    491 	if (fp) {
    492 		fprintf(fp, "%d\n", getpid());
    493 		fclose(fp);
    494 	}
    495 }
    496 
    497 /* --------- */
    498 #ifdef HAVE_LIBCAP
    499 static const cap_value_t cap_net_raw = CAP_NET_RAW;
    500 static const cap_value_t cap_setuid =  CAP_SETUID;
    501 static cap_flag_value_t cap_ok;
    502 #else
    503 static uid_t euid;
    504 #endif
    505 
    506 static void limit_capabilities(void)
    507 {
    508 #ifdef HAVE_LIBCAP
    509 	cap_t cap_p, cap_cur_p;
    510 
    511 	cap_p = cap_init();
    512 	if (!cap_p) {
    513 		DEBUG(LOG_ERR, "cap_init: %s\n", strerror(errno));
    514 		exit(-1);
    515 	}
    516 
    517 	cap_cur_p = cap_get_proc();
    518 	if (!cap_cur_p) {
    519 		DEBUG(LOG_ERR, "cap_get_proc: %s\n", strerror(errno));
    520 		exit(-1);
    521         }
    522 
    523 	/* net_raw + setuid / net_raw */
    524 	cap_get_flag(cap_cur_p, CAP_NET_RAW, CAP_PERMITTED, &cap_ok);
    525 	if (cap_ok != CAP_CLEAR) {
    526 		cap_set_flag(cap_p, CAP_PERMITTED, 1, &cap_net_raw, CAP_SET);
    527 		cap_set_flag(cap_p, CAP_EFFECTIVE, 1, &cap_net_raw, CAP_SET);
    528 	}
    529 
    530 	cap_get_flag(cap_cur_p, CAP_SETUID, CAP_PERMITTED, &cap_ok);
    531 	if (cap_ok != CAP_CLEAR)
    532 		cap_set_flag(cap_p, CAP_PERMITTED, 1, &cap_setuid, CAP_SET);
    533 
    534 	if (cap_set_proc(cap_p) < 0) {
    535 		DEBUG(LOG_ERR, "cap_set_proc: %s\n", strerror(errno));
    536 		if (errno != EPERM)
    537 			exit(-1);
    538 	}
    539 
    540 	if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
    541 		DEBUG(LOG_ERR, "prctl: %s\n", strerror(errno));
    542 		exit(-1);
    543 	}
    544 
    545 	cap_free(cap_cur_p);
    546 	cap_free(cap_p);
    547 #else
    548 	euid = geteuid();
    549 #endif
    550 }
    551 
    552 static void drop_capabilities(void)
    553 {
    554 #ifdef HAVE_LIBCAP
    555 	cap_t cap_p;
    556 
    557 	cap_p = cap_init();
    558 	if (!cap_p) {
    559 		DEBUG(LOG_ERR, "cap_init: %s\n", strerror(errno));
    560 		exit(-1);
    561 	}
    562 
    563 	/* setuid / setuid */
    564 	if (cap_ok != CAP_CLEAR) {
    565 		cap_set_flag(cap_p, CAP_PERMITTED, 1, &cap_setuid, CAP_SET);
    566 		cap_set_flag(cap_p, CAP_EFFECTIVE, 1, &cap_setuid, CAP_SET);
    567 
    568 		if (cap_set_proc(cap_p) < 0) {
    569 			DEBUG(LOG_ERR, "cap_set_proc: %s\n", strerror(errno));
    570 			exit(-1);
    571 		}
    572 	}
    573 
    574 	if (seteuid(opt_u ? opt_u : getuid()) < 0) {
    575 		DEBUG(LOG_ERR, "setuid: %s\n", strerror(errno));
    576 		exit(-1);
    577 	}
    578 
    579 	if (prctl(PR_SET_KEEPCAPS, 0) < 0) {
    580 		DEBUG(LOG_ERR, "prctl: %s\n", strerror(errno));
    581 		exit(-1);
    582 	}
    583 
    584 	cap_clear(cap_p);
    585 	if (cap_set_proc(cap_p) < 0) {
    586 		DEBUG(LOG_ERR, "cap_set_proc: %s\n", strerror(errno));
    587 		exit(-1);
    588 	}
    589 
    590 	cap_free(cap_p);
    591 #else
    592 	if (setuid(getuid()) < 0) {
    593 		DEBUG(LOG_ERR, "setuid: %s\n", strerror(errno));
    594 		exit(-1);
    595 	}
    596 #endif
    597 }
    598 
    599 /* --------- */
    600 static void parse_args(int argc, char **argv)
    601 {
    602 	int c;
    603 	unsigned long val;
    604 	char *ep;
    605 
    606 	/* parse options */
    607 	while ((c = getopt(argc, argv, "dhvp:u:")) != -1) {
    608 		switch(c) {
    609 		case 'd':	/* debug */
    610 			opt_d = 1;
    611 			break;
    612 		case 'v':	/* verbose */
    613 			opt_v = 1;
    614 			break;
    615 		case 'p':
    616 			opt_p = optarg;
    617 			break;
    618 		case 'u':
    619 			val = strtoul(optarg, &ep, 10);
    620 			if (!optarg || *ep) {
    621 				struct passwd *pw = getpwnam(optarg);
    622 				if (!pw) {
    623 					DEBUG(LOG_ERR, "No such user: %s", optarg);
    624 					exit(1);
    625 				}
    626 				opt_u = pw->pw_uid;
    627 			} else
    628 				opt_u = val;
    629 			break;
    630 		case 'h':	/* help */
    631 		default:
    632 			opt_h = 1;
    633 			break;
    634 		}
    635 	}
    636 
    637 	argc -= optind;
    638 #if 0
    639 	argv += optind;
    640 #endif
    641 
    642 	if (argc)
    643 		opt_h = 1;
    644 }
    645 
    646 static void print_copying(void) {
    647 	fprintf(stderr,
    648 		"Node Information Daemon\n"
    649 		"Copyright (C)2002 USAGI/WIDE Project.  All Rights Reserved.\n"
    650 		"\n"
    651 	);
    652 }
    653 
    654 static void print_usage(void) {
    655 	fprintf(stderr,
    656 		"Usage: %s [-d] [-p pidfile] [-u user] [-h] [-v]\n\n",
    657 		appname
    658 	);
    659 }
    660 
    661 /* --------- */
    662 int main (int argc, char **argv)
    663 {
    664 	int sock_errno = 0;
    665 	int ret;
    666 
    667 	appname = argv[0];
    668 	set_logfile();
    669 
    670 	limit_capabilities();
    671 
    672 	sock = open_sock();
    673 	if (sock < 0)
    674 		sock_errno = errno;
    675 
    676 	parse_args(argc, argv);
    677 
    678 	drop_capabilities();
    679 
    680 	if (opt_h || opt_v)
    681 		print_copying();
    682 	if (opt_h) {
    683 		print_usage();
    684 		exit(1);
    685 	}
    686 
    687 	if (sock_errno) {
    688 		DEBUG(LOG_ERR, "socket: %s\n", strerror(sock_errno));
    689 		exit(1);
    690 	}
    691 
    692 	/* initialize */
    693 	if (init_sock(sock) < 0)
    694 		exit(1);
    695 
    696 	setup_sighandlers();
    697 	if (!opt_d)
    698 		do_daemonize();
    699 
    700 	init_core(1);
    701 
    702 	/* main loop */
    703 	while (!got_signal) {
    704 		struct packetcontext *p;
    705 		struct icmp6_hdr *icmph;
    706 #if ENABLE_DEBUG
    707 		char saddrbuf[NI_MAXHOST];
    708 		int gni;
    709 #endif
    710 
    711 		init_core(0);
    712 
    713 		p = ni_malloc(sizeof(*p));
    714 		if (!p) {
    715 			DEBUG(LOG_WARNING, "%s(): failed to allocate packet context; sleep 1 sec.\n",
    716 			      __func__);
    717 			sleep(1);
    718 			continue;
    719 		}
    720 
    721 		while (!got_signal) {
    722 			memset(p, 0, sizeof(*p));
    723 			p->sock = sock;
    724 
    725 			if (ni_recv(p) < 0) {
    726 				if (got_signal)
    727 					break;
    728 				if (errno == EAGAIN || errno == EINTR)
    729 					continue;
    730 				/* XXX: syslog */
    731 				continue;
    732 			}
    733 			break;
    734 		}
    735 
    736 #if ENABLE_DEBUG
    737 		gni = getnameinfo((struct sockaddr *)&p->addr,
    738 				  p->addrlen,
    739 				  saddrbuf, sizeof(saddrbuf),
    740 				  NULL, 0,
    741 				  NI_NUMERICHOST);
    742 		if (gni)
    743 			sprintf(saddrbuf, "???");
    744 #endif
    745 		init_core(0);
    746 
    747 		if (p->querylen < sizeof(struct icmp6_hdr)) {
    748 			ni_free(p);
    749 			DEBUG(LOG_WARNING, "Too short icmp message from %s\n", saddrbuf);
    750 			continue;
    751 		}
    752 
    753 		icmph = (struct icmp6_hdr *)p->query;
    754 
    755 		DEBUG(LOG_DEBUG,
    756 		      "type=%d, code=%d, cksum=0x%04x\n",
    757 		      icmph->icmp6_type, icmph->icmp6_code,
    758 		      ntohs(icmph->icmp6_cksum));
    759 
    760 		if (icmph->icmp6_type != ICMP6_NI_QUERY) {
    761 			DEBUG(LOG_WARNING,
    762 			      "Strange icmp type %d from %s\n",
    763 			      icmph->icmp6_type, saddrbuf);
    764 			ni_free(p);
    765 			continue;
    766 		}
    767 
    768 		pr_nodeinfo(p);	/* this frees p */
    769 	}
    770 
    771 	cleanup_pidfile();
    772 
    773 	exit(0);
    774 }
    775 
    776