void radvd_process() {
  unsigned char msg[MSG_SIZE];
  int len, hoplimit;
  struct sockaddr_in6 rcv_addr;
  struct in6_pktinfo *pkt_info = NULL;
  
  len = recv_rs_ra(sock, msg, &rcv_addr, &pkt_info, &hoplimit);
  if (len > 0)
    process(sock, iface, msg, len, 
            &rcv_addr, pkt_info, hoplimit);
  
}
Exemple #2
0
int
main(int argc, char *argv[])
{
	unsigned char msg[MSG_SIZE];
	char pidstr[16];
	ssize_t ret;
	int c, log_method;
	char *logfile, *pidfile;
	sigset_t oset, nset;
	int facility, fd;
	char *username = NULL;
	char *chrootdir = NULL;
	int singleprocess = 0;
#ifdef HAVE_GETOPT_LONG
	int opt_idx;
#endif
    /* BEGIN: Added by z67728, 2009/10/19 */
    FILE * pidfp = NULL;
    int    pid   = 0;
    /* END:   Added by z67728, 2009/10/19 */

    /*start: 用于查询组件版本号(dns atpv),请不要修改或删除*/
    /*if ((argc == 2) && (NULL != argv[1]) && (0 == strcmp(argv[1],ATP_VERSION_CMD_KEY)))
    {
       printf("\r\n%s.\n", RADVD_MODULE_VERSION);    	    		
       exit(0);
    }*/
    /*end */ 
    
	pname = ((pname=strrchr(argv[0],'/')) != NULL)?pname+1:argv[0];

	srand((unsigned int)time(NULL));

	log_method = L_STDERR_SYSLOG;
    /*BEGIN PN:2071008409 l00170266 for var problem modify 20120725 */
#define RADVD_LOG (ROUTER_VARPATH_PREFIX "/radvd/radvd.log")
#define RADVD_CONF (ROUTER_VARPATH_PREFIX "/radvd/radvd.conf")
#define RADVD_PID (ROUTER_VARPATH_PREFIX "/radvd/radvd.pid")
	logfile = RADVD_LOG;
	conf_file = RADVD_CONF;
	facility = LOG_FACILITY;
	pidfile = RADVD_PID;
    /*END PN:2071008409 l00170266 for var problem modify 20120725 */

	/* parse args */
#ifdef HAVE_GETOPT_LONG
	while ((c = getopt_long(argc, argv, "d:C:l:m:p:t:u:vhs", prog_opt, &opt_idx)) > 0)
#else
	while ((c = getopt(argc, argv, "d:C:l:m:p:t:u:vhs")) > 0)
#endif
	{
		switch (c) {
		case 'C':
			conf_file = optarg;
			break;
		case 'd':
			set_debuglevel(atoi(optarg));
			break;
		case 'f':
			facility = atoi(optarg);
			break;
		case 'l':
			logfile = optarg;
			break;
		case 'p':
			pidfile = optarg;
			break;
		case 'm':
			if (!strcmp(optarg, "syslog"))
			{
				log_method = L_SYSLOG;
			}
			else if (!strcmp(optarg, "stderr_syslog"))
			{
				log_method = L_STDERR_SYSLOG;
			}
			else if (!strcmp(optarg, "stderr"))
			{
				log_method = L_STDERR;
			}
			else if (!strcmp(optarg, "logfile"))
			{
				log_method = L_LOGFILE;
			}
			else if (!strcmp(optarg, "none"))
			{
				log_method = L_NONE;
			}
			else
			{
				fprintf(stderr, "%s: unknown log method: %s\n", pname, optarg);
				exit(1);
			}
			break;
		case 't':
			chrootdir = strdup(optarg);
			break;
		case 'u':
			username = strdup(optarg);
			break;
		case 'v':
            /* BEGIN 3061302357 y00188255 2013-6-28  Modified */
			//version();
			printf("%s\n", RADVD_MODULE_VERSION);
                    printf("BUILTTIME is: %s %s\n",__DATE__,__TIME__);
			exit(1);
			/* END 3061302357 y00188255 2013-6-28  Modified */
			break;
		case 's':
			singleprocess = 1;
			break;
		case 'h':
			usage();
#ifdef HAVE_GETOPT_LONG
		case ':':
			fprintf(stderr, "%s: option %s: parameter expected\n", pname,
				prog_opt[opt_idx].name);
			exit(1);
#endif
		case '?':
			exit(1);
		}
	}

	if (chrootdir) {
		if (!username) {
			fprintf(stderr, "Chroot as root is not safe, exiting\n");
			exit(1);
		}
		
		if (chroot(chrootdir) == -1) {
			perror("chroot");
			exit (1);
		}
		
		if (chdir("/") == -1) {
			perror("chdir");
			exit (1);
		}
		/* username will be switched later */
	}
	
	if (log_open(log_method, pname, logfile, facility) < 0)
		exit(1);

	flog(LOG_INFO, "version %s started", VERSION);

	/* get a raw socket for sending and receiving ICMPv6 messages */
	sock = open_icmpv6_socket();
	if (sock < 0)
		exit(1);

#if 0 
	/* check that 'other' cannot write the file
         * for non-root, also that self/own group can't either
         */
	if (check_conffile_perm(username, conf_file) < 0) {
		if (get_debuglevel() == 0)
			exit(1);
		else
			flog(LOG_WARNING, "Insecure file permissions, but continuing anyway");
	}
	
	/* if we know how to do it, check whether forwarding is enabled */
	if (check_ip6_forwarding()) {
		if (get_debuglevel() == 0) {
			flog(LOG_ERR, "IPv6 forwarding seems to be disabled, exiting");
			exit(1);
		}
		else
			flog(LOG_WARNING, "IPv6 forwarding seems to be disabled, but continuing anyway.");
	}
#endif

	/* parse config file */
	if (readin_config(conf_file) < 0){
        if ( 0 != unlink(pidfile) ){
            printf("\r\n Delete %s meet error. error : %s .",pidfile,strerror(errno));
        }
		exit(1);
    }   

	/* drop root privileges if requested. */
	if (username) {
		if (!singleprocess) {
		 	dlog(LOG_DEBUG, 3, "Initializing privsep");
		 	if (privsep_init() < 0)
				flog(LOG_WARNING, "Failed to initialize privsep.");
		}

		if (drop_root_privileges(username) < 0)
			exit(1);
	}
#if 0
	if ((fd = open(pidfile, O_RDONLY, 0)) > 0)
	{
		ret = read(fd, pidstr, sizeof(pidstr) - 1);
		if (ret < 0)
		{
			flog(LOG_ERR, "cannot read radvd pid file, terminating: %s", strerror(errno));
			exit(1);
		}
		pidstr[ret] = '\0';
		if (!kill((pid_t)atol(pidstr), 0))
		{
			flog(LOG_ERR, "radvd already running, terminating.");
			exit(1);
		}
		close(fd);
		fd = open(pidfile, O_CREAT|O_TRUNC|O_WRONLY, 0644);
	}
	else	/* FIXME: not atomic if pidfile is on an NFS mounted volume */
		fd = open(pidfile, O_CREAT|O_EXCL|O_WRONLY, 0644);

	if (fd < 0)
	{
		flog(LOG_ERR, "cannot create radvd pid file, terminating: %s", strerror(errno));
		exit(1);
	}
#endif	
	/*
	 * okay, config file is read in, socket and stuff is setup, so
	 * lets fork now...
	 */
#if 0 
	if (get_debuglevel() == 0) {

		/* Detach from controlling terminal */
		if (daemon(0, 0) < 0)
			perror("daemon");

		/* close old logfiles, including stderr */
		log_close();
		
		/* reopen logfiles, but don't log to stderr unless explicitly requested */
		if (log_method == L_STDERR_SYSLOG)
			log_method = L_SYSLOG;
		if (log_open(log_method, pname, logfile, facility) < 0)
			exit(1);

	}
#endif

	/*
	 *	config signal handlers, also make sure ALRM isn't blocked and raise a warning if so
	 *      (some stupid scripts/pppd appears to do this...)
	 */
	sigemptyset(&nset);
	sigaddset(&nset, SIGALRM);
	sigprocmask(SIG_UNBLOCK, &nset, &oset);
	if (sigismember(&oset, SIGALRM))
		flog(LOG_WARNING, "SIGALRM has been unblocked. Your startup environment might be wrong.");

	signal(SIGHUP, sighup_handler);
	signal(SIGTERM, sigterm_handler);
	signal(SIGINT, sigint_handler);
    /* BEGIN: Added by z67728, 2009/11/3 */    
    signal(SIGUSR1, sigdebug_handler);
    signal(SIGUSR2, sigprefixchg_handler);
    /* END:   Added by z67728, 2009/11/3 */
    
#if 0
	snprintf(pidstr, sizeof(pidstr), "%ld\n", (long)getpid());
	
	write(fd, pidstr, strlen(pidstr));
	
	close(fd);
#endif

    /*BEGIN PN:2071008409 l00170266 for var problem modify 20120725 */
#define RADVD_READTEST (ROUTER_VARPATH_PREFIX "/radvd/readtest")
    if ( 0 == access(RADVD_READTEST,F_OK) )
    /*END PN:2071008409 l00170266 for var problem modify 20120725 */
    {
        /* Ready test */
        g_iReadTestFlag = 1;
    }

    pid = getpid();
	if ((pidfp = fopen(pidfile, "w")) != NULL) {
		fwrite(&pid,1,4,pidfp);
		fclose(pidfp);
	}
    
	config_interface();
	kickoff_adverts();

	/* enter loop */

	for (;;)
	{
		int len = 0, hoplimit = 0;
		struct sockaddr_in6 rcv_addr;
		struct in6_pktinfo *pkt_info = NULL;
		
		len = recv_rs_ra(sock, msg, &rcv_addr, &pkt_info, &hoplimit);
		if (len > 0) {
			process(sock, IfaceList, msg, len, 
				&rcv_addr, pkt_info, hoplimit);
        }      

		if (sigterm_received || sigint_received) {
			stop_adverts();
			break;
		}

		if (sighup_received)
		{
		    if ( 1 == g_iPrefixChgeFlag )
		    {		        
    		    disable_oldprefix();
		    }

            reload_config();	
            
			sighup_received = 0;
            g_iPrefixChgeFlag = 0;
		}
	}

	unlink(pidfile);
	exit(0);
}
Exemple #3
0
int
main(int argc, char *argv[])
{
	unsigned char msg[MSG_SIZE];
	char pidstr[16];
	ssize_t ret;
	int c, log_method;
	char *logfile, *pidfile;
	sigset_t oset, nset;
	int facility, fd;
	char *username = NULL;
	char *chrootdir = NULL;
	int singleprocess = 0;
#ifdef HAVE_GETOPT_LONG
	int opt_idx;
#endif

	pname = ((pname=strrchr(argv[0],'/')) != NULL)?pname+1:argv[0];

	srand((unsigned int)time(NULL));

	log_method = L_STDERR_SYSLOG;
	logfile = PATH_RADVD_LOG;
	conf_file = PATH_RADVD_CONF;
	facility = LOG_FACILITY;
	pidfile = PATH_RADVD_PID;

	/* parse args */
#ifdef HAVE_GETOPT_LONG
	/* Add option to show advertise real lifetime */
	/* while ((c = getopt_long(argc, argv, "d:C:l:m:p:t:u:vhs", prog_opt, &opt_idx)) > 0) */
	while ((c = getopt_long(argc, argv, "d:C:l:m:p:t:u:vhsD", prog_opt, &opt_idx)) > 0)
#else
	/* Add option to show advertise real lifetime */
	/* while ((c = getopt(argc, argv, "d:C:l:m:p:t:u:vhs")) > 0) */
	while ((c = getopt(argc, argv, "d:C:l:m:p:t:u:vhsD")) > 0)
#endif
	{
		switch (c) {
		case 'C':
			conf_file = optarg;
			break;
		case 'd':
			set_debuglevel(atoi(optarg));
			break;
		case 'f':
			facility = atoi(optarg);
			break;
		case 'l':
			logfile = optarg;
			break;
		case 'p':
			pidfile = optarg;
			break;
		case 'm':
			if (!strcmp(optarg, "syslog"))
			{
				log_method = L_SYSLOG;
			}
			else if (!strcmp(optarg, "stderr_syslog"))
			{
				log_method = L_STDERR_SYSLOG;
			}
			else if (!strcmp(optarg, "stderr"))
			{
				log_method = L_STDERR;
			}
			else if (!strcmp(optarg, "logfile"))
			{
				log_method = L_LOGFILE;
			}
			else if (!strcmp(optarg, "none"))
			{
				log_method = L_NONE;
			}
			else
			{
				fprintf(stderr, "%s: unknown log method: %s\n", pname, optarg);
				exit(1);
			}
			break;
		case 't':
			chrootdir = strdup(optarg);
			break;
		case 'u':
			username = strdup(optarg);
			break;
		case 'v':
			version();
			break;
		case 's':
			singleprocess = 1;
			break;
		/* Add option to show advertise dynamic lifetime */
		case 'D':
			use_dynamic_lifetime = 1;
			break;
		case 'h':
			usage();
#ifdef HAVE_GETOPT_LONG
		case ':':
			fprintf(stderr, "%s: option %s: parameter expected\n", pname,
				prog_opt[opt_idx].name);
			exit(1);
#endif
		case '?':
			exit(1);
		}
	}

	if (chrootdir) {
		if (!username) {
			fprintf(stderr, "Chroot as root is not safe, exiting\n");
			exit(1);
		}
		
		if (chroot(chrootdir) == -1) {
			perror("chroot");
			exit (1);
		}
		
		if (chdir("/") == -1) {
			perror("chdir");
			exit (1);
		}
		/* username will be switched later */
	}
	
	if (log_open(log_method, pname, logfile, facility) < 0)
		exit(1);

	flog(LOG_INFO, "version %s started", VERSION);

	/* get a raw socket for sending and receiving ICMPv6 messages */
	sock = open_icmpv6_socket();
	if (sock < 0)
		exit(1);

	/* check that 'other' cannot write the file
         * for non-root, also that self/own group can't either
         */
	if (check_conffile_perm(username, conf_file) < 0) {
		if (get_debuglevel() == 0)
			exit(1);
		else
			flog(LOG_WARNING, "Insecure file permissions, but continuing anyway");
	}
	
	/* if we know how to do it, check whether forwarding is enabled */
	if (check_ip6_forwarding()) {
		if (get_debuglevel() == 0) {
			flog(LOG_ERR, "IPv6 forwarding seems to be disabled, exiting");
			exit(1);
		}
		else
			flog(LOG_WARNING, "IPv6 forwarding seems to be disabled, but continuing anyway.");
	}

	/* parse config file */
	if (readin_config(conf_file) < 0)
		exit(1);

	/* drop root privileges if requested. */
	if (username) {
		if (!singleprocess) {
		 	dlog(LOG_DEBUG, 3, "Initializing privsep");
		 	if (privsep_init() < 0)
				flog(LOG_WARNING, "Failed to initialize privsep.");
		}

		if (drop_root_privileges(username) < 0)
			exit(1);
	}

	if ((fd = open(pidfile, O_RDONLY, 0)) > 0)
	{
		ret = read(fd, pidstr, sizeof(pidstr) - 1);
		if (ret < 0)
		{
			flog(LOG_ERR, "cannot read radvd pid file, terminating: %s", strerror(errno));
			exit(1);
		}
		pidstr[ret] = '\0';
		if (!kill((pid_t)atol(pidstr), 0))
		{
			flog(LOG_ERR, "radvd already running, terminating.");
			exit(1);
		}
		close(fd);
		fd = open(pidfile, O_CREAT|O_TRUNC|O_WRONLY, 0644);
	}
	else	/* FIXME: not atomic if pidfile is on an NFS mounted volume */
		fd = open(pidfile, O_CREAT|O_EXCL|O_WRONLY, 0644);

	if (fd < 0)
	{
		flog(LOG_ERR, "cannot create radvd pid file, terminating: %s", strerror(errno));
		exit(1);
	}
	
	/*
	 * okay, config file is read in, socket and stuff is setup, so
	 * lets fork now...
	 */

	if (get_debuglevel() == 0) {

		/* Detach from controlling terminal */
		if (daemon(0, 0) < 0)
			perror("daemon");

		/* close old logfiles, including stderr */
		log_close();
		
		/* reopen logfiles, but don't log to stderr unless explicitly requested */
		if (log_method == L_STDERR_SYSLOG)
			log_method = L_SYSLOG;
		if (log_open(log_method, pname, logfile, facility) < 0)
			exit(1);

	}

	/*
	 *	config signal handlers, also make sure ALRM isn't blocked and raise a warning if so
	 *      (some stupid scripts/pppd appears to do this...)
	 */
	sigemptyset(&nset);
	sigaddset(&nset, SIGALRM);
	sigprocmask(SIG_UNBLOCK, &nset, &oset);
	if (sigismember(&oset, SIGALRM))
		flog(LOG_WARNING, "SIGALRM has been unblocked. Your startup environment might be wrong.");

	signal(SIGHUP, sighup_handler);
	signal(SIGTERM, sigterm_handler);
	signal(SIGINT, sigint_handler);
	signal(SIGUSR1, sigusr1_handler);	

	snprintf(pidstr, sizeof(pidstr), "%ld\n", (long)getpid());
	
	write(fd, pidstr, strlen(pidstr));
	
	close(fd);

	config_interface();
	/* Record the time for first advertisement */
	set_initial_advert_time();
	kickoff_adverts();

	/* enter loop */

	for (;;)
	{
		int len, hoplimit;
		struct sockaddr_in6 rcv_addr;
		struct in6_pktinfo *pkt_info = NULL;
		
		len = recv_rs_ra(sock, msg, &rcv_addr, &pkt_info, &hoplimit);
		if (len > 0)
			process(sock, IfaceList, msg, len, 
				&rcv_addr, pkt_info, hoplimit);

		if (sigterm_received || sigint_received) {
			stop_adverts();
			
			/* WNR3500L TD192, Per Netgear spec, 
			 * need to send RA for 3 times before termination.
			 */
			usleep(200000);
			stop_adverts();
			usleep(200000);
			stop_adverts();

			break;
		}

		if (sighup_received)
		{
			reload_config();		
			sighup_received = 0;
		}
		/* Reset the initial advertisement time to now */
		/* This should happen after a successful IADP renew */
		if (sigusr1_received)
		{
			set_initial_advert_time();
			sigusr1_received = 0;
		}
	}
	
	unlink(pidfile);
	exit(0);
}
Exemple #4
0
void main_loop(void)
{
	struct pollfd fds[2];

	memset(fds, 0, sizeof(fds));

	fds[0].fd = sock;
	fds[0].events = POLLIN;
	fds[0].revents = 0;

#if HAVE_NETLINK
	fds[1].fd = netlink_socket();
	fds[1].events = POLLIN;
	fds[1].revents = 0;
#else
	fds[1].fd = -1;
	fds[1].events = 0;
	fds[1].revents = 0;
#endif

	for (;;) {
		struct Interface *next = NULL;
		struct Interface *iface;
		int timeout = -1;
		int rc;

		if (IfaceList) {
			timeout = next_time_msec(IfaceList);
			next = IfaceList;
			for (iface = IfaceList; iface; iface = iface->next) {
				int t;
				t = next_time_msec(iface);
				if (timeout > t) {
					timeout = t;
					next = iface;
				}
			}
		}

		dlog(LOG_DEBUG, 5, "polling for %g seconds.", timeout/1000.0);

		rc = poll(fds, sizeof(fds)/sizeof(fds[0]), timeout);

		if (rc > 0) {
			if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
				flog(LOG_WARNING, "socket error on fds[0].fd");
			}
			else if (fds[0].revents & POLLIN) {
				int len, hoplimit;
				struct sockaddr_in6 rcv_addr;
				struct in6_pktinfo *pkt_info = NULL;
				unsigned char msg[MSG_SIZE_RECV];

				len = recv_rs_ra(msg, &rcv_addr, &pkt_info, &hoplimit);
				if (len > 0) {
					process(IfaceList, msg, len,
						&rcv_addr, pkt_info, hoplimit);
				}
			}
#ifdef HAVE_NETLINK
			if (fds[1].revents & (POLLERR | POLLHUP | POLLNVAL)) {
				flog(LOG_WARNING, "socket error on fds[1].fd");
			}
			else if (fds[1].revents & POLLIN) {
				process_netlink_msg(fds[1].fd);
			}
#endif
		}
		else if ( rc == 0 ) {
			if (next)
				timer_handler(next);
		}
		else if ( rc == -1 && errno != EINTR ) {
			flog(LOG_ERR, "poll error: %s", strerror(errno));
		}

		if (sigterm_received || sigint_received) {
			flog(LOG_WARNING, "Exiting, sigterm or sigint received.\n");
			break;
		}

		if (sighup_received)
		{
			reload_config();
			sighup_received = 0;
		}

		if (sigusr1_received)
		{
			reset_prefix_lifetimes();
			sigusr1_received = 0;
		}

	}
}
Exemple #5
0
int
main(int argc, char *argv[])
{
	unsigned char msg[MSG_SIZE];
	int c, len, hoplimit;
	int fform = 0;
	int edefs = 0;
	struct sockaddr_in6 rcv_addr;
        struct in6_pktinfo *pkt_info = NULL;
#ifdef HAVE_GETOPT_LONG
	int opt_idx;
#endif

	pname = ((pname=strrchr(argv[0],'/')) != NULL)?pname+1:argv[0];

	/* parse args */
#ifdef HAVE_GETOPT_LONG
	while ((c = getopt_long(argc, argv, "d:fehv", prog_opt, &opt_idx)) > 0)
#else
	while ((c = getopt(argc, argv, "d:fehv")) > 0)
#endif
	{
		switch (c) {
		case 'd':
			set_debuglevel(atoi(optarg));
			break;
		case 'f':
			fform = 1;
			break;
		case 'e':
			edefs = 1;
			break;
		case 'v':
			version();
			break;
		case 'h':
			usage();
#ifdef HAVE_GETOPT_LONG
		case ':':
			fprintf(stderr, "%s: option %s: parameter expected\n", pname,
				prog_opt[opt_idx].name);
			exit(1);
#endif
		case '?':
			exit(1);
		}
	}
	
	if (log_open(L_STDERR, pname, NULL, 0) < 0)
		exit(1);

	/* get a raw socket for sending and receiving ICMPv6 messages */
	sock = open_icmpv6_socket();
	if (sock < 0)
		exit(1);
		
	for(;;)
	{
	        len = recv_rs_ra(sock, msg, &rcv_addr, &pkt_info, &hoplimit);
   	     	if (len > 0)
       	 	{
			struct icmp6_hdr *icmph;
	
			/*
			 * can this happen?
			 */

			if (len < sizeof(struct icmp6_hdr))
			{
				log(LOG_WARNING, "received icmpv6 packet with invalid length: %d",
					len);
				exit(1);
			}

			icmph = (struct icmp6_hdr *) msg;

			if (icmph->icmp6_type != ND_ROUTER_SOLICIT &&
			    icmph->icmp6_type != ND_ROUTER_ADVERT)
			{
				/*
				 *	We just want to listen to RSs and RAs
				 */
			
				log(LOG_ERR, "icmpv6 filter failed");
				exit(1);
			}

			dlog(LOG_DEBUG, 4, "receiver if_index: %d", pkt_info->ipi6_ifindex);

			if (icmph->icmp6_type == ND_ROUTER_SOLICIT)
			{
				/* not yet */	
			}
			else if (icmph->icmp6_type == ND_ROUTER_ADVERT)
			{
				if (!fform)
					print_ra(msg, len, &rcv_addr, hoplimit, pkt_info->ipi6_ifindex);
				else
					print_ff(msg, len, &rcv_addr, hoplimit, pkt_info->ipi6_ifindex, edefs);
			}
        	}
		else if (len == 0)
       	 	{
       	 		log(LOG_ERR, "received zero lenght packet");
       	 		exit(1);
        	}
        	else
        	{
			log(LOG_ERR, "recv_rs_ra: %s", strerror(errno));
			exit(1);
        	}
        }                                                                                            

	exit(0);
}
Exemple #6
0
static struct Interface * main_loop(int sock, struct Interface *ifaces, char const *conf_path)
{
	struct pollfd fds[2];
	sigset_t sigmask;
	sigset_t sigempty;
	struct sigaction sa;

	sigemptyset(&sigempty);

	sigemptyset(&sigmask);
	sigaddset(&sigmask, SIGHUP);
	sigaddset(&sigmask, SIGTERM);
	sigaddset(&sigmask, SIGINT);
	sigaddset(&sigmask, SIGUSR1);
	sigprocmask(SIG_BLOCK, &sigmask, NULL);

	sa.sa_handler = sighup_handler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	sigaction(SIGHUP, &sa, 0);

	sa.sa_handler = sigterm_handler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	sigaction(SIGTERM, &sa, 0);

	sa.sa_handler = sigint_handler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	sigaction(SIGINT, &sa, 0);

	sa.sa_handler = sigusr1_handler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	sigaction(SIGUSR1, &sa, 0);

	memset(fds, 0, sizeof(fds));

	fds[0].fd = sock;
	fds[0].events = POLLIN;

#if HAVE_NETLINK
	fds[1].fd = netlink_socket();
	fds[1].events = POLLIN;
#else
	fds[1].fd = -1;
#endif

	for (;;) {
		struct timespec *tsp = 0;

		struct Interface *next_iface_to_expire = find_iface_by_time(ifaces);
		if (next_iface_to_expire) {
			static struct timespec ts;
			int timeout = next_time_msec(next_iface_to_expire);
			ts.tv_sec = timeout / 1000;
			ts.tv_nsec = (timeout - 1000 * ts.tv_sec) * 1000000;
			tsp = &ts;
			dlog(LOG_DEBUG, 1, "polling for %g second(s), next iface is %s", timeout / 1000.0,
			     next_iface_to_expire->props.name);
		} else {
			dlog(LOG_DEBUG, 1, "no iface is next. Polling indefinitely");
		}
#ifdef HAVE_PPOLL
		int rc = ppoll(fds, sizeof(fds) / sizeof(fds[0]), tsp, &sigempty);
#else
		int rc = poll(fds, sizeof(fds) / sizeof(fds[0]), 1000*tsp->tv_sec);
#endif

		if (rc > 0) {
#ifdef HAVE_NETLINK
			if (fds[1].revents & (POLLERR | POLLHUP | POLLNVAL)) {
				flog(LOG_WARNING, "socket error on fds[1].fd");
			} else if (fds[1].revents & POLLIN) {
				process_netlink_msg(fds[1].fd, ifaces);
			}
#endif

			if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
				flog(LOG_WARNING, "socket error on fds[0].fd");
			} else if (fds[0].revents & POLLIN) {
				int len, hoplimit;
				struct sockaddr_in6 rcv_addr;
				struct in6_pktinfo *pkt_info = NULL;
				unsigned char msg[MSG_SIZE_RECV];
				unsigned char chdr[CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int))];

				len = recv_rs_ra(sock, msg, &rcv_addr, &pkt_info, &hoplimit, chdr);
				if (len > 0 && pkt_info) {
					process(sock, ifaces, msg, len, &rcv_addr, pkt_info, hoplimit);
				} else if (!pkt_info) {
					dlog(LOG_INFO, 4, "recv_rs_ra returned null pkt_info");
				} else if (len <= 0) {
					dlog(LOG_INFO, 4, "recv_rs_ra returned len <= 0: %d", len);
				}
			}
		} else if (rc == 0) {
			if (next_iface_to_expire)
				timer_handler(sock, next_iface_to_expire);
		} else if (rc == -1) {
			dlog(LOG_INFO, 3, "poll returned early: %s", strerror(errno));
		}

		if (sigint_received) {
			flog(LOG_WARNING, "exiting, %d sigint(s) received", sigint_received);
			break;
		}

		if (sigterm_received) {
			flog(LOG_WARNING, "exiting, %d sigterm(s) received", sigterm_received);
			break;
		}

		if (sighup_received) {
			dlog(LOG_INFO, 3, "sig hup received");
			ifaces = reload_config(sock, ifaces, conf_path);
			sighup_received = 0;
		}

		if (sigusr1_received) {
			dlog(LOG_INFO, 3, "sig usr1 received");
			reset_prefix_lifetimes(ifaces);
			sigusr1_received = 0;
		}

	}

	return ifaces;
}