File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / miniupnpd / miniupnpd.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:16:02 2012 UTC (12 years, 7 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

    1: /* $Id: miniupnpd.c,v 1.1 2012/02/21 23:16:02 misho Exp $ */
    2: /* MiniUPnP project
    3:  * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
    4:  * (c) 2006-2010 Thomas Bernard
    5:  * This software is subject to the conditions detailed
    6:  * in the LICENCE file provided within the distribution */
    7: 
    8: #include "config.h"
    9: 
   10: /* Experimental support for NFQUEUE interfaces */
   11: #ifdef ENABLE_NFQUEUE
   12: /* apt-get install libnetfilter-queue-dev */
   13: #include <netinet/ip.h>
   14: #include <netinet/udp.h>
   15: //#include <linux/netfilter_ipv4.h>  /* Defines verdicts (NF_ACCEPT, etc) */
   16: #include <linux/netfilter.h>
   17: #include <libnetfilter_queue/libnetfilter_queue.h>
   18: #include <linux/netfilter/nfnetlink_queue.h>
   19: #endif
   20: 
   21: #include <stdlib.h>
   22: #include <unistd.h>
   23: #include <string.h>
   24: #include <stdio.h>
   25: #include <ctype.h>
   26: #include <sys/types.h>
   27: #include <sys/socket.h>
   28: #include <netinet/in.h>
   29: #include <arpa/inet.h>
   30: #include <fcntl.h>
   31: #include <sys/file.h>
   32: #include <syslog.h>
   33: #include <sys/time.h>
   34: #include <time.h>
   35: #include <signal.h>
   36: #include <errno.h>
   37: #include <sys/param.h>
   38: #if defined(sun)
   39: #include <kstat.h>
   40: #else
   41: /* for BSD's sysctl */
   42: #include <sys/sysctl.h>
   43: #endif
   44: 
   45: /* unix sockets */
   46: #ifdef USE_MINIUPNPDCTL
   47: #include <sys/un.h>
   48: #endif
   49: 
   50: #include "upnpglobalvars.h"
   51: #include "upnphttp.h"
   52: #include "upnpdescgen.h"
   53: #include "miniupnpdpath.h"
   54: #include "getifaddr.h"
   55: #include "upnpsoap.h"
   56: #include "options.h"
   57: #include "minissdp.h"
   58: #include "upnpredirect.h"
   59: #include "miniupnpdtypes.h"
   60: #include "daemonize.h"
   61: #include "upnpevents.h"
   62: #ifdef ENABLE_NATPMP
   63: #include "natpmp.h"
   64: #endif
   65: #include "commonrdr.h"
   66: 
   67: #ifndef DEFAULT_CONFIG
   68: #define DEFAULT_CONFIG "/etc/miniupnpd.conf"
   69: #endif
   70: 
   71: #ifdef USE_MINIUPNPDCTL
   72: struct ctlelem {
   73: 	int socket;
   74: 	LIST_ENTRY(ctlelem) entries;
   75: };
   76: #endif
   77: 
   78: #ifdef ENABLE_NFQUEUE
   79: /* globals */
   80: static struct nfq_handle *nfqHandle;
   81: static struct sockaddr_in ssdp;
   82: 
   83: /* prototypes */
   84: void ProcessSSDPData(int s, char *bufr, struct sockaddr_in sendername, int n, unsigned short port);
   85: static int nfqueue_cb( struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data) ;
   86: int identify_ip_protocol (char *payload);
   87: int get_udp_dst_port (char *payload);
   88: #endif
   89: 
   90: 
   91: static int sudp = -1;
   92: 
   93: /* MAX_LAN_ADDR : maximum number of interfaces
   94:  * to listen to SSDP traffic */
   95: /*#define MAX_LAN_ADDR (4)*/
   96: 
   97: static volatile int quitting = 0;
   98: static volatile int should_send_public_address_change_notif = 0;
   99: 
  100: /* OpenAndConfHTTPSocket() :
  101:  * setup the socket used to handle incoming HTTP connections. */
  102: static int
  103: OpenAndConfHTTPSocket(unsigned short port)
  104: {
  105: 	int s;
  106: 	int i = 1;
  107: 	struct sockaddr_in listenname;
  108: 
  109: 	if( (s = socket(PF_INET, SOCK_STREAM, 0)) < 0)
  110: 	{
  111: 		syslog(LOG_ERR, "socket(http): %m");
  112: 		return -1;
  113: 	}
  114: 
  115: 	if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0)
  116: 	{
  117: 		syslog(LOG_WARNING, "setsockopt(http, SO_REUSEADDR): %m");
  118: 	}
  119: 
  120: 	memset(&listenname, 0, sizeof(struct sockaddr_in));
  121: 	listenname.sin_family = AF_INET;
  122: 	listenname.sin_port = htons(port);
  123: 	listenname.sin_addr.s_addr = htonl(INADDR_ANY);
  124: 
  125: 	if(bind(s, (struct sockaddr *)&listenname, sizeof(struct sockaddr_in)) < 0)
  126: 	{
  127: 		syslog(LOG_ERR, "bind(http): %m");
  128: 		close(s);
  129: 		return -1;
  130: 	}
  131: 
  132: 	if(listen(s, 6) < 0)
  133: 	{
  134: 		syslog(LOG_ERR, "listen(http): %m");
  135: 		close(s);
  136: 		return -1;
  137: 	}
  138: 
  139: 	return s;
  140: }
  141: #ifdef ENABLE_NFQUEUE
  142: 
  143: int identify_ip_protocol(char *payload) {
  144:     return payload[9];
  145: }
  146: 
  147: 
  148: /*
  149:  * This function returns the destination port of the captured packet UDP
  150:  */
  151: int get_udp_dst_port(char *payload) {
  152:         char *pkt_data_ptr = NULL;
  153:         pkt_data_ptr = payload + sizeof(struct ip);
  154: 
  155:     /* Cast the UDP Header from the raw packet */
  156:     struct udphdr *udp = (struct udphdr *) pkt_data_ptr;
  157: 
  158:     /* get the dst port of the packet */
  159:     return(ntohs(udp->dest));
  160: 
  161: }
  162: static int
  163: OpenAndConfNFqueue(){
  164: 
  165:         struct nfq_q_handle *myQueue;
  166:         struct nfnl_handle *netlinkHandle;
  167: 
  168:         int fd = 0, e = 0;
  169: 
  170: 	inet_pton(AF_INET, "239.255.255.250", &(ssdp.sin_addr));
  171: 
  172:         //Get a queue connection handle from the module
  173:         if (!(nfqHandle = nfq_open())) {
  174: 		syslog(LOG_ERR, "Error in nfq_open(): %m");
  175:                 return -1;
  176:         }
  177: 
  178:         //Unbind the handler from processing any IP packets
  179:         //      Not totally sure why this is done, or if it's necessary...
  180:         if ((e = nfq_unbind_pf(nfqHandle, AF_INET)) < 0) {
  181: 		syslog(LOG_ERR, "Error in nfq_unbind_pf(): %m");
  182:                 return -1;
  183:         }
  184: 
  185:         //Bind this handler to process IP packets...
  186:         if (nfq_bind_pf(nfqHandle, AF_INET) < 0) {
  187: 		syslog(LOG_ERR, "Error in nfq_bind_pf(): %m");
  188:                 return -1;
  189:         }
  190: 
  191:         //      Install a callback on queue -Q
  192:         if (!(myQueue = nfq_create_queue(nfqHandle,  nfqueue, &nfqueue_cb, NULL))) {
  193: 		syslog(LOG_ERR, "Error in nfq_create_queue(): %m");
  194:                 return -1;
  195:         }
  196: 
  197:         //      Turn on packet copy mode
  198:         if (nfq_set_mode(myQueue, NFQNL_COPY_PACKET, 0xffff) < 0) {
  199: 		syslog(LOG_ERR, "Error setting packet copy mode (): %m");
  200:                 return -1;
  201:         }
  202: 
  203:         netlinkHandle = nfq_nfnlh(nfqHandle);
  204:         fd = nfnl_fd(netlinkHandle);
  205: 
  206: 	return fd;
  207: 
  208: }
  209: 
  210: 
  211: static int nfqueue_cb(
  212:                 struct nfq_q_handle *qh,
  213:                 struct nfgenmsg *nfmsg,
  214:                 struct nfq_data *nfa,
  215:                 void *data) {
  216: 
  217: 	char	*pkt;
  218: 	struct nfqnl_msg_packet_hdr *ph;
  219: 	ph = nfq_get_msg_packet_hdr(nfa);
  220: 
  221: 	if ( ph ) {
  222: 
  223: 		int id = 0, size = 0;
  224: 		id = ntohl(ph->packet_id);
  225: 
  226: 		size = nfq_get_payload(nfa, &pkt);
  227: 
  228:     		struct ip *iph = (struct ip *) pkt;
  229: 
  230: 		int id_protocol = identify_ip_protocol(pkt);
  231: 
  232: 		int dport = get_udp_dst_port(pkt);
  233: 
  234: 		int x = sizeof (struct ip) + sizeof (struct udphdr);
  235: 	
  236: 		/* packets we are interested in are UDP multicast to 239.255.255.250:1900	
  237: 		 * and start with a data string M-SEARCH
  238: 		 */
  239: 		if ( (dport == 1900) && (id_protocol == IPPROTO_UDP) 
  240: 			&& (ssdp.sin_addr.s_addr == iph->ip_dst.s_addr) ) {
  241: 		
  242: 			/* get the index that the packet came in on */
  243: 			u_int32_t idx = nfq_get_indev(nfa);
  244: 			int i = 0;
  245: 			for ( ;i < n_nfqix ; i++) {
  246: 				if ( nfqix[i] == idx ) {
  247: 
  248: 					struct udphdr *udp = (struct udphdr *) (pkt + sizeof(struct ip));
  249: 
  250: 					char *dd = pkt + x;
  251: 					
  252: 					struct sockaddr_in sendername;
  253: 					sendername.sin_family = AF_INET;
  254: 					sendername.sin_port = udp->source;
  255: 					sendername.sin_addr.s_addr = iph->ip_src.s_addr;
  256: 
  257: 					/* printf("pkt found %s\n",dd);*/
  258: 					ProcessSSDPData (sudp, dd, sendername, size - x, (unsigned short) 5555);
  259: 				}
  260: 			}
  261: 		}
  262: 		
  263: 		nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL);
  264: 
  265: 	} else {
  266: 		syslog(LOG_ERR,"nfq_get_msg_packet_hdr failed");
  267: 		return 1; // from nfqueue source: 0 = ok, >0 = soft error, <0 hard error
  268: 	}
  269: 
  270: 	return 0;
  271: }
  272: 
  273: static void ProcessNFQUEUE(int fd){
  274: 	char buf[4096];
  275: 
  276: 	socklen_t len_r;
  277: 	struct sockaddr_in sendername;
  278: 	len_r = sizeof(struct sockaddr_in);
  279: 
  280:         int res = recvfrom(fd, buf, sizeof(buf), 0,
  281: 			(struct sockaddr *)&sendername, &len_r);
  282: 
  283: 	nfq_handle_packet(nfqHandle, buf, res);
  284: }
  285: #endif
  286: 
  287: /* Functions used to communicate with miniupnpdctl */
  288: #ifdef USE_MINIUPNPDCTL
  289: static int
  290: OpenAndConfCtlUnixSocket(const char * path)
  291: {
  292: 	struct sockaddr_un localun;
  293: 	int s;
  294: 	s = socket(AF_UNIX, SOCK_STREAM, 0);
  295: 	localun.sun_family = AF_UNIX;
  296: 	strncpy(localun.sun_path, path,
  297: 	          sizeof(localun.sun_path));
  298: 	if(bind(s, (struct sockaddr *)&localun,
  299: 	        sizeof(struct sockaddr_un)) < 0)
  300: 	{
  301: 		syslog(LOG_ERR, "bind(sctl): %m");
  302: 		close(s);
  303: 		s = -1;
  304: 	}
  305: 	else if(listen(s, 5) < 0)
  306: 	{
  307: 		syslog(LOG_ERR, "listen(sctl): %m");
  308: 		close(s);
  309: 		s = -1;
  310: 	}
  311: 	return s;
  312: }
  313: 
  314: static void
  315: write_upnphttp_details(int fd, struct upnphttp * e)
  316: {
  317: 	char buffer[256];
  318: 	int len;
  319: 	write(fd, "HTTP :\n", 7);
  320: 	while(e)
  321: 	{
  322: 		len = snprintf(buffer, sizeof(buffer),
  323: 		               "%d %d %s req_buf=%p(%dbytes) res_buf=%p(%dbytes alloc)\n",
  324: 		               e->socket, e->state, e->HttpVer,
  325: 		               e->req_buf, e->req_buflen,
  326: 		               e->res_buf, e->res_buf_alloclen);
  327: 		write(fd, buffer, len);
  328: 		e = e->entries.le_next;
  329: 	}
  330: }
  331: 
  332: static void
  333: write_ctlsockets_list(int fd, struct ctlelem * e)
  334: {
  335: 	char buffer[256];
  336: 	int len;
  337: 	write(fd, "CTL :\n", 6);
  338: 	while(e)
  339: 	{
  340: 		len = snprintf(buffer, sizeof(buffer),
  341: 		               "struct ctlelem: socket=%d\n", e->socket);
  342: 		write(fd, buffer, len);
  343: 		e = e->entries.le_next;
  344: 	}
  345: }
  346: 
  347: static void
  348: write_option_list(int fd)
  349: {
  350: 	char buffer[256];
  351: 	int len;
  352: 	int i;
  353: 	write(fd, "Options :\n", 10);
  354: 	for(i=0; i<num_options; i++)
  355: 	{
  356: 		len = snprintf(buffer, sizeof(buffer),
  357: 		               "opt=%02d %s\n",
  358: 		               ary_options[i].id, ary_options[i].value);
  359: 		write(fd, buffer, len);
  360: 	}
  361: }
  362: 
  363: static void
  364: write_command_line(int fd, int argc, char * * argv)
  365: {
  366: 	char buffer[256];
  367: 	int len;
  368: 	int i;
  369: 	write(fd, "Command Line :\n", 15);
  370: 	for(i=0; i<argc; i++)
  371: 	{
  372: 		len = snprintf(buffer, sizeof(buffer),
  373: 		               "argv[%02d]='%s'\n",
  374: 		                i, argv[i]);
  375: 		write(fd, buffer, len);
  376: 	}
  377: }
  378: 
  379: #endif
  380: 
  381: /* Handler for the SIGTERM signal (kill) 
  382:  * SIGINT is also handled */
  383: static void
  384: sigterm(int sig)
  385: {
  386: 	/*int save_errno = errno;*/
  387: 	signal(sig, SIG_IGN);	/* Ignore this signal while we are quitting */
  388: 
  389: 	syslog(LOG_NOTICE, "received signal %d, good-bye", sig);
  390: 
  391: 	quitting = 1;
  392: 	/*errno = save_errno;*/
  393: }
  394: 
  395: /* Handler for the SIGUSR1 signal indicating public IP address change. */
  396: static void
  397: sigusr1(int sig)
  398: {
  399: 	syslog(LOG_INFO, "received signal %d, public ip address change", sig);
  400: 
  401: 	should_send_public_address_change_notif = 1;
  402: }
  403: 
  404: /* record the startup time, for returning uptime */
  405: static void
  406: set_startup_time(int sysuptime)
  407: {
  408: 	startup_time = time(NULL);
  409: 	if(sysuptime)
  410: 	{
  411: 		/* use system uptime instead of daemon uptime */
  412: #if defined(__linux__)
  413: 		char buff[64];
  414: 		int uptime = 0, fd;
  415: 		fd = open("/proc/uptime", O_RDONLY);
  416: 		if(fd < 0)
  417: 		{
  418: 			syslog(LOG_ERR, "open(\"/proc/uptime\" : %m");
  419: 		}
  420: 		else
  421: 		{
  422: 			memset(buff, 0, sizeof(buff));
  423: 			if(read(fd, buff, sizeof(buff) - 1) < 0)
  424: 			{
  425: 				syslog(LOG_ERR, "read(\"/proc/uptime\" : %m");
  426: 			}
  427: 			else
  428: 			{
  429: 				uptime = atoi(buff);
  430: 				syslog(LOG_INFO, "system uptime is %d seconds", uptime);
  431: 			}
  432: 			close(fd);
  433: 			startup_time -= uptime;
  434: 		}
  435: #elif defined(SOLARIS_KSTATS)
  436: 		kstat_ctl_t *kc;
  437: 		kc = kstat_open();
  438: 		if(kc != NULL)
  439: 		{
  440: 			kstat_t *ksp;
  441: 			ksp = kstat_lookup(kc, "unix", 0, "system_misc");
  442: 			if(ksp && (kstat_read(kc, ksp, NULL) != -1))
  443: 			{
  444: 				void *ptr = kstat_data_lookup(ksp, "boot_time");
  445: 				if(ptr)
  446: 					memcpy(&startup_time, ptr, sizeof(startup_time));
  447: 				else
  448: 					syslog(LOG_ERR, "cannot find boot_time kstat");
  449: 			}
  450: 			else
  451: 				syslog(LOG_ERR, "cannot open kstats for unix/0/system_misc: %m");
  452: 			kstat_close(kc);
  453: 		}
  454: #else
  455: 		struct timeval boottime;
  456: 		size_t size = sizeof(boottime);
  457: 		int name[2] = { CTL_KERN, KERN_BOOTTIME };
  458: 		if(sysctl(name, 2, &boottime, &size, NULL, 0) < 0)
  459: 		{
  460: 			syslog(LOG_ERR, "sysctl(\"kern.boottime\") failed");
  461: 		}
  462: 		else
  463: 		{
  464: 			startup_time = boottime.tv_sec;
  465: 		}
  466: #endif
  467: 	}
  468: }
  469: 
  470: /* structure containing variables used during "main loop"
  471:  * that are filled during the init */
  472: struct runtime_vars {
  473: 	/* LAN IP addresses for SSDP traffic and HTTP */
  474: 	/* moved to global vars */
  475: 	/*int n_lan_addr;*/
  476: 	/*struct lan_addr_s lan_addr[MAX_LAN_ADDR];*/
  477: 	int port;	/* HTTP Port */
  478: 	int notify_interval;	/* seconds between SSDP announces */
  479: 	/* unused rules cleaning related variables : */
  480: 	int clean_ruleset_threshold;	/* threshold for removing unused rules */
  481: 	int clean_ruleset_interval;		/* (minimum) interval between checks */
  482: };
  483: 
  484: /* parselanaddr()
  485:  * parse address with mask
  486:  * ex: 192.168.1.1/24
  487:  * When MULTIPLE_EXTERNAL_IP is enabled, the ip address of the
  488:  * external interface associated with the lan subnet follows.
  489:  * ex : 192.168.1.1/24 81.21.41.11
  490:  *
  491:  * return value : 
  492:  *    0 : ok
  493:  *   -1 : error */
  494: static int
  495: parselanaddr(struct lan_addr_s * lan_addr, const char * str)
  496: {
  497: 	const char * p;
  498: 	int nbits = 24;	/* by default, networks are /24 */
  499: 	int n;
  500: 	p = str;
  501: 	while(*p && *p != '/' && !isspace(*p))
  502: 		p++;
  503: 	n = p - str;
  504: 	if(*p == '/')
  505: 	{
  506: 		nbits = atoi(++p);
  507: 		while(*p && !isspace(*p))
  508: 			p++;
  509: 	}
  510: 	if(n>15)
  511: 	{
  512: 		fprintf(stderr, "Error parsing address/mask : %s\n", str);
  513: 		return -1;
  514: 	}
  515: 	memcpy(lan_addr->str, str, n);
  516: 	lan_addr->str[n] = '\0';
  517: 	if(!inet_aton(lan_addr->str, &lan_addr->addr))
  518: 	{
  519: 		fprintf(stderr, "Error parsing address/mask : %s\n", str);
  520: 		return -1;
  521: 	}
  522: 	lan_addr->mask.s_addr = htonl(nbits ? (0xffffffff << (32 - nbits)) : 0);
  523: #ifdef MULTIPLE_EXTERNAL_IP
  524: 	/* skip spaces */
  525: 	while(*p && isspace(*p))
  526: 		p++;
  527: 	if(*p) {
  528: 		/* parse the exteral ip address to associate with this subnet */
  529: 		n = 0;
  530: 		while(p[n] && !isspace(*p))
  531: 			n++;
  532: 		if(n<=15) {
  533: 			memcpy(lan_addr->ext_ip_str, p, n);
  534: 			lan_addr->ext_ip_str[n] = '\0';
  535: 			if(!inet_aton(lan_addr->ext_ip_str, &lan_addr->ext_ip_addr)) {
  536: 				/* error */
  537: 				fprintf(stderr, "Error parsing address : %s\n", lan_addr->ext_ip_str);
  538: 			}
  539: 		}
  540: 	}
  541: #endif
  542: 	return 0;
  543: }
  544: 
  545: /* init phase :
  546:  * 1) read configuration file
  547:  * 2) read command line arguments
  548:  * 3) daemonize
  549:  * 4) open syslog
  550:  * 5) check and write pid file
  551:  * 6) set startup time stamp
  552:  * 7) compute presentation URL
  553:  * 8) set signal handlers */
  554: static int
  555: init(int argc, char * * argv, struct runtime_vars * v)
  556: {
  557: 	int i;
  558: 	int pid;
  559: 	int debug_flag = 0;
  560: 	int options_flag = 0;
  561: 	int openlog_option;
  562: 	struct sigaction sa;
  563: 	/*const char * logfilename = 0;*/
  564: 	const char * presurl = 0;
  565: 	const char * optionsfile = DEFAULT_CONFIG;
  566: 
  567: 	/* only print usage if -h is used */
  568: 	for(i=1; i<argc; i++)
  569: 	{
  570: 		if(0 == strcmp(argv[i], "-h"))
  571: 			goto print_usage;
  572: 	}
  573: 	/* first check if "-f" option is used */
  574: 	for(i=2; i<argc; i++)
  575: 	{
  576: 		if(0 == strcmp(argv[i-1], "-f"))
  577: 		{
  578: 			optionsfile = argv[i];
  579: 			options_flag = 1;
  580: 			break;
  581: 		}
  582: 	}
  583: 
  584: 	/* set initial values */
  585: 	SETFLAG(ENABLEUPNPMASK);
  586: 
  587: 	/*v->n_lan_addr = 0;*/
  588: 	v->port = -1;
  589: 	v->notify_interval = 30;	/* seconds between SSDP announces */
  590: 	v->clean_ruleset_threshold = 20;
  591: 	v->clean_ruleset_interval = 0;	/* interval between ruleset check. 0=disabled */
  592: 
  593: 	/* read options file first since
  594: 	 * command line arguments have final say */
  595: 	if(readoptionsfile(optionsfile) < 0)
  596: 	{
  597: 		/* only error if file exists or using -f */
  598: 		if(access(optionsfile, F_OK) == 0 || options_flag)
  599: 			fprintf(stderr, "Error reading configuration file %s\n", optionsfile);
  600: 	}
  601: 	else
  602: 	{
  603: 		for(i=0; i<num_options; i++)
  604: 		{
  605: 			switch(ary_options[i].id)
  606: 			{
  607: 			case UPNPEXT_IFNAME:
  608: 				ext_if_name = ary_options[i].value;
  609: 				break;
  610: 			case UPNPEXT_IP:
  611: 				use_ext_ip_addr = ary_options[i].value;
  612: 				break;
  613: 			case UPNPLISTENING_IP:
  614: 				if(n_lan_addr < MAX_LAN_ADDR)/* if(v->n_lan_addr < MAX_LAN_ADDR)*/
  615: 				{
  616: 					/*if(parselanaddr(&v->lan_addr[v->n_lan_addr],*/
  617: 					if(parselanaddr(&lan_addr[n_lan_addr],
  618: 					             ary_options[i].value) == 0)
  619: 						n_lan_addr++; /*v->n_lan_addr++; */
  620: 				}
  621: 				else
  622: 				{
  623: 					fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n",
  624: 			    		    MAX_LAN_ADDR, ary_options[i].value);
  625: 				}
  626: 				break;
  627: 			case UPNPPORT:
  628: 				v->port = atoi(ary_options[i].value);
  629: 				break;
  630: 			case UPNPBITRATE_UP:
  631: 				upstream_bitrate = strtoul(ary_options[i].value, 0, 0);
  632: 				break;
  633: 			case UPNPBITRATE_DOWN:
  634: 				downstream_bitrate = strtoul(ary_options[i].value, 0, 0);
  635: 				break;
  636: 			case UPNPPRESENTATIONURL:
  637: 				presurl = ary_options[i].value;
  638: 				break;
  639: #ifdef USE_NETFILTER
  640: 			case UPNPFORWARDCHAIN:
  641: 				miniupnpd_forward_chain = ary_options[i].value;
  642: 				break;
  643: 			case UPNPNATCHAIN:
  644: 				miniupnpd_nat_chain = ary_options[i].value;
  645: 				break;
  646: #endif
  647: 			case UPNPNOTIFY_INTERVAL:
  648: 				v->notify_interval = atoi(ary_options[i].value);
  649: 				break;
  650: 			case UPNPSYSTEM_UPTIME:
  651: 				if(strcmp(ary_options[i].value, "yes") == 0)
  652: 					SETFLAG(SYSUPTIMEMASK);	/*sysuptime = 1;*/
  653: 				break;
  654: 			case UPNPPACKET_LOG:
  655: 				if(strcmp(ary_options[i].value, "yes") == 0)
  656: 					SETFLAG(LOGPACKETSMASK);	/*logpackets = 1;*/
  657: 				break;
  658: 			case UPNPUUID:
  659: 				strncpy(uuidvalue+5, ary_options[i].value,
  660: 				        strlen(uuidvalue+5) + 1);
  661: 				break;
  662: 			case UPNPSERIAL:
  663: 				strncpy(serialnumber, ary_options[i].value, SERIALNUMBER_MAX_LEN);
  664: 				serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0';
  665: 				break;				
  666: 			case UPNPMODEL_NUMBER:
  667: 				strncpy(modelnumber, ary_options[i].value, MODELNUMBER_MAX_LEN);
  668: 				modelnumber[MODELNUMBER_MAX_LEN-1] = '\0';
  669: 				break;
  670: 			case UPNPCLEANTHRESHOLD:
  671: 				v->clean_ruleset_threshold = atoi(ary_options[i].value);
  672: 				break;
  673: 			case UPNPCLEANINTERVAL:
  674: 				v->clean_ruleset_interval = atoi(ary_options[i].value);
  675: 				break;
  676: #ifdef USE_PF
  677: 			case UPNPQUEUE:
  678: 				queue = ary_options[i].value;
  679: 				break;
  680: 			case UPNPTAG:
  681: 				tag = ary_options[i].value;
  682: 				break;
  683: #endif
  684: #ifdef ENABLE_NATPMP
  685: 			case UPNPENABLENATPMP:
  686: 				if(strcmp(ary_options[i].value, "yes") == 0)
  687: 					SETFLAG(ENABLENATPMPMASK);	/*enablenatpmp = 1;*/
  688: 				else
  689: 					if(atoi(ary_options[i].value))
  690: 						SETFLAG(ENABLENATPMPMASK);
  691: 					/*enablenatpmp = atoi(ary_options[i].value);*/
  692: 				break;
  693: #endif
  694: #ifdef PF_ENABLE_FILTER_RULES
  695: 			case UPNPQUICKRULES:
  696: 				if(strcmp(ary_options[i].value, "no") == 0)
  697: 					SETFLAG(PFNOQUICKRULESMASK);
  698: 				break;
  699: #endif
  700: 			case UPNPENABLE:
  701: 				if(strcmp(ary_options[i].value, "yes") != 0)
  702: 					CLEARFLAG(ENABLEUPNPMASK);
  703: 				break;
  704: 			case UPNPSECUREMODE:
  705: 				if(strcmp(ary_options[i].value, "yes") == 0)
  706: 					SETFLAG(SECUREMODEMASK);
  707: 				break;
  708: #ifdef ENABLE_LEASEFILE
  709: 			case UPNPLEASEFILE:
  710: 				lease_file = ary_options[i].value;
  711: 				break;
  712: #endif
  713: 			case UPNPMINISSDPDSOCKET:
  714: 				minissdpdsocketpath = ary_options[i].value;
  715: 				break;
  716: 			default:
  717: 				fprintf(stderr, "Unknown option in file %s\n",
  718: 				        optionsfile);
  719: 			}
  720: 		}
  721: 	}
  722: 
  723: 	/* command line arguments processing */
  724: 	for(i=1; i<argc; i++)
  725: 	{
  726: 		if(argv[i][0]!='-')
  727: 		{
  728: 			fprintf(stderr, "Unknown option: %s\n", argv[i]);
  729: 		}
  730: 		else switch(argv[i][1])
  731: 		{
  732: 		case 'o':
  733: 			if(i+1 < argc)
  734: 				use_ext_ip_addr = argv[++i];
  735: 			else
  736: 				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
  737: 			break;
  738: 		case 't':
  739: 			if(i+1 < argc)
  740: 				v->notify_interval = atoi(argv[++i]);
  741: 			else
  742: 				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
  743: 			break;
  744: 		case 'u':
  745: 			if(i+1 < argc)
  746: 				strncpy(uuidvalue+5, argv[++i], strlen(uuidvalue+5) + 1);
  747: 			else
  748: 				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
  749: 			break;
  750: 		case 's':
  751: 			if(i+1 < argc)
  752: 				strncpy(serialnumber, argv[++i], SERIALNUMBER_MAX_LEN);
  753: 			else
  754: 				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
  755: 			serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0';
  756: 			break;
  757: 		case 'm':
  758: 			if(i+1 < argc)
  759: 				strncpy(modelnumber, argv[++i], MODELNUMBER_MAX_LEN);
  760: 			else
  761: 				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
  762: 			modelnumber[MODELNUMBER_MAX_LEN-1] = '\0';
  763: 			break;
  764: #ifdef ENABLE_NATPMP
  765: 		case 'N':
  766: 			/*enablenatpmp = 1;*/
  767: 			SETFLAG(ENABLENATPMPMASK);
  768: 			break;
  769: #endif
  770: 		case 'U':
  771: 			/*sysuptime = 1;*/
  772: 			SETFLAG(SYSUPTIMEMASK);
  773: 			break;
  774: 		/*case 'l':
  775: 			logfilename = argv[++i];
  776: 			break;*/
  777: 		case 'L':
  778: 			/*logpackets = 1;*/
  779: 			SETFLAG(LOGPACKETSMASK);
  780: 			break;
  781: 		case 'S':
  782: 			SETFLAG(SECUREMODEMASK);
  783: 			break;
  784: 		case 'i':
  785: 			if(i+1 < argc)
  786: 				ext_if_name = argv[++i];
  787: 			else
  788: 				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
  789: 			break;
  790: #ifdef USE_PF
  791: 		case 'q':
  792: 			if(i+1 < argc)
  793: 				queue = argv[++i];
  794: 			else
  795: 				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
  796: 			break;
  797: 		case 'T':
  798: 			if(i+1 < argc)
  799: 				tag = argv[++i];
  800: 			else
  801: 				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
  802: 			break;
  803: #endif
  804: 		case 'p':
  805: 			if(i+1 < argc)
  806: 				v->port = atoi(argv[++i]);
  807: 			else
  808: #ifdef ENABLE_NFQUEUE
  809: 		case 'Q':
  810: 			if(i+1<argc)
  811: 			{
  812: 				nfqueue = atoi(argv[++i]);
  813: 			}
  814: 			else
  815: 				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
  816: 			break;
  817: 		case 'n':
  818: 			if (i+1 < argc) {
  819: 				i++;
  820: 				if(n_nfqix < MAX_LAN_ADDR) {
  821: 					nfqix[n_nfqix++] = if_nametoindex(argv[i]);
  822: 				} else {
  823: 					fprintf(stderr,"Too many nfq interfaces. Ignoring %s\n", argv[i]);
  824: 				}
  825: 			} else {
  826: 				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
  827: 			}
  828: 			break;
  829: #endif
  830: 				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
  831: 			break;
  832: 		case 'P':
  833: 			if(i+1 < argc)
  834: 				pidfilename = argv[++i];
  835: 			else
  836: 				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
  837: 			break;
  838: 		case 'd':
  839: 			debug_flag = 1;
  840: 			break;
  841: 		case 'w':
  842: 			if(i+1 < argc)
  843: 				presurl = argv[++i];
  844: 			else
  845: 				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
  846: 			break;
  847: 		case 'B':
  848: 			if(i+2<argc)
  849: 			{
  850: 				downstream_bitrate = strtoul(argv[++i], 0, 0);
  851: 				upstream_bitrate = strtoul(argv[++i], 0, 0);
  852: 			}
  853: 			else
  854: 				fprintf(stderr, "Option -%c takes two arguments.\n", argv[i][1]);
  855: 			break;
  856: 		case 'a':
  857: 			if(i+1 < argc)
  858: 			{
  859: 				int address_already_there = 0;
  860: 				int j;
  861: 				i++;
  862: 				for(j=0; j<n_lan_addr; j++)
  863: 				{
  864: 					struct lan_addr_s tmpaddr;
  865: 					parselanaddr(&tmpaddr, argv[i]);
  866: 					if(0 == strcmp(lan_addr[j].str, tmpaddr.str))
  867: 						address_already_there = 1;
  868: 				}
  869: 				if(address_already_there)
  870: 					break;
  871: 				if(n_lan_addr < MAX_LAN_ADDR)
  872: 				{
  873: 					if(parselanaddr(&lan_addr[n_lan_addr], argv[i]) == 0)
  874: 						n_lan_addr++;
  875: 				}
  876: 				else
  877: 				{
  878: 					fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n",
  879: 				    	    MAX_LAN_ADDR, argv[i]);
  880: 				}
  881: 			}
  882: 			else
  883: 				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
  884: 			break;
  885: 		case 'f':
  886: 			i++;	/* discarding, the config file is already read */
  887: 			break;
  888: 		default:
  889: 			fprintf(stderr, "Unknown option: %s\n", argv[i]);
  890: 		}
  891: 	}
  892: 	if(!ext_if_name || (n_lan_addr==0))
  893: 	{
  894: 		/* bad configuration */
  895: 		goto print_usage;
  896: 	}
  897: 
  898: 	if(debug_flag)
  899: 	{
  900: 		pid = getpid();
  901: 	}
  902: 	else
  903: 	{
  904: #ifdef USE_DAEMON
  905: 		if(daemon(0, 0)<0) {
  906: 			perror("daemon()");
  907: 		}
  908: 		pid = getpid();
  909: #else
  910: 		pid = daemonize();
  911: #endif
  912: 	}
  913: 
  914: 	openlog_option = LOG_PID|LOG_CONS;
  915: 	if(debug_flag)
  916: 	{
  917: 		openlog_option |= LOG_PERROR;	/* also log on stderr */
  918: 	}
  919: 
  920: 	openlog("miniupnpd", openlog_option, LOG_MINIUPNPD);
  921: 
  922: 	if(!debug_flag)
  923: 	{
  924: 		/* speed things up and ignore LOG_INFO and LOG_DEBUG */
  925: 		setlogmask(LOG_UPTO(LOG_NOTICE));
  926: 	}
  927: 
  928: 	if(checkforrunning(pidfilename) < 0)
  929: 	{
  930: 		syslog(LOG_ERR, "MiniUPnPd is already running. EXITING");
  931: 		return 1;
  932: 	}	
  933: 
  934: 	set_startup_time(GETFLAG(SYSUPTIMEMASK));
  935: 
  936: 	/* presentation url */
  937: 	if(presurl)
  938: 	{
  939: 		strncpy(presentationurl, presurl, PRESENTATIONURL_MAX_LEN);
  940: 		presentationurl[PRESENTATIONURL_MAX_LEN-1] = '\0';
  941: 	}
  942: 	else
  943: 	{
  944: 		snprintf(presentationurl, PRESENTATIONURL_MAX_LEN,
  945: 		         "http://%s/", lan_addr[0].str);
  946: 		         /*"http://%s:%d/", lan_addr[0].str, 80);*/
  947: 	}
  948: 
  949: 	/* set signal handler */
  950: 	memset(&sa, 0, sizeof(struct sigaction));
  951: 	sa.sa_handler = sigterm;
  952: 
  953: 	if (sigaction(SIGTERM, &sa, NULL))
  954: 	{
  955: 		syslog(LOG_ERR, "Failed to set %s handler. EXITING", "SIGTERM");
  956: 		return 1;
  957: 	}
  958: 	if (sigaction(SIGINT, &sa, NULL))
  959: 	{
  960: 		syslog(LOG_ERR, "Failed to set %s handler. EXITING", "SIGINT");
  961: 		return 1;
  962: 	}
  963: 
  964: 	if(signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
  965: 		syslog(LOG_ERR, "Failed to ignore SIGPIPE signals");
  966: 	}
  967: 
  968: 	sa.sa_handler = sigusr1;
  969: 	if (sigaction(SIGUSR1, &sa, NULL))
  970: 	{
  971: 		syslog(LOG_NOTICE, "Failed to set %s handler", "SIGUSR1");
  972: 	}
  973: 
  974: 	if(init_redirect() < 0)
  975: 	{
  976: 		syslog(LOG_ERR, "Failed to init redirection engine. EXITING");
  977: 		return 1;
  978: 	}
  979: 
  980: 	writepidfile(pidfilename, pid);
  981: 
  982: #ifdef ENABLE_LEASEFILE
  983: 	/*remove(lease_file);*/
  984: 	syslog(LOG_INFO, "Reloading rules from lease file");
  985: 	reload_from_lease_file();
  986: #endif
  987: 
  988: 	return 0;
  989: print_usage:
  990: 	fprintf(stderr, "Usage:\n\t"
  991: 	        "%s [-f config_file] [-i ext_ifname] [-o ext_ip]\n"
  992: #ifndef ENABLE_NATPMP
  993: 			"\t\t[-a listening_ip] [-p port] [-d] [-L] [-U] [-S]\n"
  994: #else
  995: 			"\t\t[-a listening_ip] [-p port] [-d] [-L] [-U] [-S] [-N]\n"
  996: #endif
  997: 			/*"[-l logfile] " not functionnal */
  998: 			"\t\t[-u uuid] [-s serial] [-m model_number] \n"
  999: 			"\t\t[-t notify_interval] [-P pid_filename]\n"
 1000: 			"\t\t[-B down up] [-w url]\n"
 1001: #ifdef USE_PF
 1002:                         "\t\t[-q queue] [-T tag]\n"
 1003: #endif
 1004: #ifdef ENABLE_NFQUEUE
 1005:                         "\t\t[-Q queue] [-n name]\n"
 1006: #endif
 1007: 	        "\nNotes:\n\tThere can be one or several listening_ips.\n"
 1008: 	        "\tNotify interval is in seconds. Default is 30 seconds.\n"
 1009: 			"\tDefault pid file is '%s'.\n"
 1010: 			"\tDefault config file is '%s'.\n"
 1011: 			"\tWith -d miniupnpd will run as a standard program.\n"
 1012: 			"\t-L sets packet log in pf and ipf on.\n"
 1013: 			"\t-S sets \"secure\" mode : clients can only add mappings to their own ip\n"
 1014: 			"\t-U causes miniupnpd to report system uptime instead "
 1015: 			"of daemon uptime.\n"
 1016: #ifdef ENABLE_NATPMP
 1017: 			"\t-N enable NAT-PMP functionnality.\n"
 1018: #endif
 1019: 			"\t-B sets bitrates reported by daemon in bits per second.\n"
 1020: 			"\t-w sets the presentation url. Default is http address on port 80\n"
 1021: #ifdef USE_PF
 1022: 			"\t-q sets the ALTQ queue in pf.\n"
 1023: 			"\t-T sets the tag name in pf.\n"
 1024: #endif
 1025: #ifdef ENABLE_NFQUEUE
 1026:                         "\t-Q sets the queue number that is used by NFQUEUE.\n"
 1027:                         "\t-n sets the name of the interface(s) that packets will arrive on.\n"
 1028: #endif
 1029: 			"\t-h prints this help and quits.\n"
 1030: 	        "", argv[0], pidfilename, DEFAULT_CONFIG);
 1031: 	return 1;
 1032: }
 1033: 
 1034: /* === main === */
 1035: /* process HTTP or SSDP requests */
 1036: int
 1037: main(int argc, char * * argv)
 1038: {
 1039: 	int i;
 1040: 	int shttpl = -1;
 1041: #ifdef ENABLE_NATPMP
 1042: 	int snatpmp[MAX_LAN_ADDR];
 1043: #ifdef ENABLE_NFQUEUE
 1044: 	int nfqh = -1;
 1045: #endif
 1046: #endif
 1047: 	int snotify[MAX_LAN_ADDR];
 1048: 	LIST_HEAD(httplisthead, upnphttp) upnphttphead;
 1049: 	struct upnphttp * e = 0;
 1050: 	struct upnphttp * next;
 1051: 	fd_set readset;	/* for select() */
 1052: #ifdef ENABLE_EVENTS
 1053: 	fd_set writeset;
 1054: #endif
 1055: 	struct timeval timeout, timeofday, lasttimeofday = {0, 0};
 1056: 	int max_fd = -1;
 1057: #ifdef USE_MINIUPNPDCTL
 1058: 	int sctl = -1;
 1059: 	LIST_HEAD(ctlstructhead, ctlelem) ctllisthead;
 1060: 	struct ctlelem * ectl;
 1061: 	struct ctlelem * ectlnext;
 1062: #endif
 1063: 	struct runtime_vars v;
 1064: 	/* variables used for the unused-rule cleanup process */
 1065: 	struct rule_state * rule_list = 0;
 1066: 	struct timeval checktime = {0, 0};
 1067: 	syslog(LOG_INFO, "SNet version started");
 1068: 
 1069: 
 1070: 	memset(snotify, 0, sizeof(snotify));
 1071: #ifdef ENABLE_NATPMP
 1072: 	for(i = 0; i < MAX_LAN_ADDR; i++)
 1073: 		snatpmp[i] = -1;
 1074: #endif
 1075: 	if(init(argc, argv, &v) != 0)
 1076: 		return 1;
 1077: 
 1078: 	LIST_INIT(&upnphttphead);
 1079: #ifdef USE_MINIUPNPDCTL
 1080: 	LIST_INIT(&ctllisthead);
 1081: #endif
 1082: 
 1083: 	if(
 1084: #ifdef ENABLE_NATPMP
 1085:         !GETFLAG(ENABLENATPMPMASK) &&
 1086: #endif
 1087:         !GETFLAG(ENABLEUPNPMASK) ) {
 1088: 		syslog(LOG_ERR, "Why did you run me anyway?");
 1089: 		return 0;
 1090: 	}
 1091: 
 1092: 	if(GETFLAG(ENABLEUPNPMASK))
 1093: 	{
 1094: 
 1095: 		/* open socket for HTTP connections. Listen on the 1st LAN address */
 1096: 		shttpl = OpenAndConfHTTPSocket((v.port > 0) ? v.port : 0);
 1097: 		if(shttpl < 0)
 1098: 		{
 1099: 			syslog(LOG_ERR, "Failed to open socket for HTTP. EXITING");
 1100: 			return 1;
 1101: 		}
 1102: 		if(v.port <= 0) {
 1103: 			struct sockaddr_in sockinfo;
 1104: 			socklen_t len = sizeof(struct sockaddr_in);
 1105: 			if (getsockname(shttpl, (struct sockaddr *)&sockinfo, &len) < 0) {
 1106: 				syslog(LOG_ERR, "getsockname(): %m");
 1107: 				return 1;
 1108: 			}
 1109: 			v.port = ntohs(sockinfo.sin_port);
 1110: 		}
 1111: 		syslog(LOG_NOTICE, "HTTP listening on port %d", v.port);
 1112: 
 1113: 		/* open socket for SSDP connections */
 1114: 		sudp = OpenAndConfSSDPReceiveSocket(n_lan_addr, lan_addr);
 1115: 		if(sudp < 0)
 1116: 		{
 1117: 			syslog(LOG_INFO, "Failed to open socket for receiving SSDP. Trying to use MiniSSDPd");
 1118: 			if(SubmitServicesToMiniSSDPD(lan_addr[0].str, v.port) < 0) {
 1119: 				syslog(LOG_ERR, "Failed to connect to MiniSSDPd. EXITING");
 1120: 				return 1;
 1121: 			}
 1122: 		}
 1123: 
 1124: 		/* open socket for sending notifications */
 1125: 		if(OpenAndConfSSDPNotifySockets(snotify) < 0)
 1126: 		{
 1127: 			syslog(LOG_ERR, "Failed to open sockets for sending SSDP notify "
 1128: 		                "messages. EXITING");
 1129: 			return 1;
 1130: 		}
 1131: 	}
 1132: 
 1133: #ifdef ENABLE_NATPMP
 1134: 	/* open socket for NAT PMP traffic */
 1135: 	if(GETFLAG(ENABLENATPMPMASK))
 1136: 	{
 1137: 		if(OpenAndConfNATPMPSockets(snatpmp) < 0)
 1138: 		{
 1139: 			syslog(LOG_ERR, "Failed to open sockets for NAT PMP.");
 1140: 		} else {
 1141: 			syslog(LOG_NOTICE, "Listening for NAT-PMP traffic on port %u",
 1142: 			       NATPMP_PORT);
 1143: 		}
 1144: 		ScanNATPMPforExpiration();
 1145: 	}
 1146: #endif
 1147: 
 1148: 	/* for miniupnpdctl */
 1149: #ifdef USE_MINIUPNPDCTL
 1150: 	sctl = OpenAndConfCtlUnixSocket("/var/run/miniupnpd.ctl");
 1151: #endif
 1152: 
 1153: #ifdef ENABLE_NFQUEUE
 1154: 	if ( nfqueue != -1 && n_nfqix > 0) {
 1155: 		nfqh = OpenAndConfNFqueue();
 1156: 		if(nfqh < 0) {
 1157: 			syslog(LOG_ERR, "Failed to open fd for NFQUEUE.");
 1158: 			return 1;
 1159: 		} else {
 1160: 			syslog(LOG_NOTICE, "Opened NFQUEUE %d",nfqueue);
 1161: 		}
 1162: 	}
 1163: #endif
 1164: 	/* main loop */
 1165: 	while(!quitting)
 1166: 	{
 1167: 		/* Correct startup_time if it was set with a RTC close to 0 */
 1168: 		if((startup_time<60*60*24) && (time(NULL)>60*60*24))
 1169: 		{
 1170: 			set_startup_time(GETFLAG(SYSUPTIMEMASK));
 1171: 		} 
 1172: 		/* Check if we need to send SSDP NOTIFY messages and do it if
 1173: 		 * needed */
 1174: 		if(gettimeofday(&timeofday, 0) < 0)
 1175: 		{
 1176: 			syslog(LOG_ERR, "gettimeofday(): %m");
 1177: 			timeout.tv_sec = v.notify_interval;
 1178: 			timeout.tv_usec = 0;
 1179: 		}
 1180: 		else
 1181: 		{
 1182: 			/* the comparaison is not very precise but who cares ? */
 1183: 			if(timeofday.tv_sec >= (lasttimeofday.tv_sec + v.notify_interval))
 1184: 			{
 1185: 				if (GETFLAG(ENABLEUPNPMASK))
 1186: 					SendSSDPNotifies2(snotify,
 1187: 				                  (unsigned short)v.port,
 1188: 				                  v.notify_interval << 1);
 1189: 				memcpy(&lasttimeofday, &timeofday, sizeof(struct timeval));
 1190: 				timeout.tv_sec = v.notify_interval;
 1191: 				timeout.tv_usec = 0;
 1192: 			}
 1193: 			else
 1194: 			{
 1195: 				timeout.tv_sec = lasttimeofday.tv_sec + v.notify_interval
 1196: 				                 - timeofday.tv_sec;
 1197: 				if(timeofday.tv_usec > lasttimeofday.tv_usec)
 1198: 				{
 1199: 					timeout.tv_usec = 1000000 + lasttimeofday.tv_usec
 1200: 					                  - timeofday.tv_usec;
 1201: 					timeout.tv_sec--;
 1202: 				}
 1203: 				else
 1204: 				{
 1205: 					timeout.tv_usec = lasttimeofday.tv_usec - timeofday.tv_usec;
 1206: 				}
 1207: 			}
 1208: 		}
 1209: 		/* remove unused rules */
 1210: 		if( v.clean_ruleset_interval
 1211: 		  && (timeofday.tv_sec >= checktime.tv_sec + v.clean_ruleset_interval))
 1212: 		{
 1213: 			if(rule_list)
 1214: 			{
 1215: 				remove_unused_rules(rule_list);
 1216: 				rule_list = NULL;
 1217: 			}
 1218: 			else
 1219: 			{
 1220: 				rule_list = get_upnp_rules_state_list(v.clean_ruleset_threshold);
 1221: 			}
 1222: 			memcpy(&checktime, &timeofday, sizeof(struct timeval));
 1223: 		}
 1224: #ifdef ENABLE_NATPMP
 1225: 		/* Remove expired NAT-PMP mappings */
 1226: 		while( nextnatpmptoclean_timestamp && (timeofday.tv_sec >= nextnatpmptoclean_timestamp + startup_time))
 1227: 		{
 1228: 			/*syslog(LOG_DEBUG, "cleaning expired NAT-PMP mappings");*/
 1229: 			if(CleanExpiredNATPMP() < 0) {
 1230: 				syslog(LOG_ERR, "CleanExpiredNATPMP() failed");
 1231: 				break;
 1232: 			}
 1233: 		}
 1234: 		if(nextnatpmptoclean_timestamp && timeout.tv_sec >= (nextnatpmptoclean_timestamp + startup_time - timeofday.tv_sec))
 1235: 		{
 1236: 			/*syslog(LOG_DEBUG, "setting timeout to %d sec", nextnatpmptoclean_timestamp + startup_time - timeofday.tv_sec);*/
 1237: #ifdef ENABLE_NFQUEUE
 1238: 		if (nfqh >= 0) 
 1239: 		{
 1240: 			FD_SET(nfqh, &readset);
 1241: 			max_fd = MAX( max_fd, nfqh);
 1242: 		}
 1243: #endif
 1244: 
 1245: 			timeout.tv_sec = nextnatpmptoclean_timestamp + startup_time - timeofday.tv_sec;
 1246: 			timeout.tv_usec = 0;
 1247: 		}
 1248: #endif
 1249: 
 1250: 		/* select open sockets (SSDP, HTTP listen, and all HTTP soap sockets) */
 1251: 		FD_ZERO(&readset);
 1252: 
 1253: 		if (sudp >= 0) 
 1254: 		{
 1255: 			FD_SET(sudp, &readset);
 1256: 			max_fd = MAX( max_fd, sudp);
 1257: 		}
 1258: 		
 1259: 		if (shttpl >= 0) 
 1260: 		{
 1261: 			FD_SET(shttpl, &readset);
 1262: 			max_fd = MAX( max_fd, shttpl);
 1263: 		}
 1264: 
 1265: 		i = 0;	/* active HTTP connections count */
 1266: 		for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next)
 1267: 		{
 1268: 			if((e->socket >= 0) && (e->state <= 2))
 1269: 			{
 1270: 				FD_SET(e->socket, &readset);
 1271: 				max_fd = MAX( max_fd, e->socket);
 1272: 				i++;
 1273: 			}
 1274: 		}
 1275: 		/* for debug */
 1276: #ifdef DEBUG
 1277: 		if(i > 1)
 1278: 		{
 1279: 			syslog(LOG_DEBUG, "%d active incoming HTTP connections", i);
 1280: 		}
 1281: #endif
 1282: #ifdef ENABLE_NATPMP
 1283: 		for(i=0; i<n_lan_addr; i++) {
 1284: 			if(snatpmp[i] >= 0) {
 1285: 				FD_SET(snatpmp[i], &readset);
 1286: 				max_fd = MAX( max_fd, snatpmp[i]);
 1287: 			}
 1288: 		}
 1289: #endif
 1290: #ifdef USE_MINIUPNPDCTL
 1291: 		if(sctl >= 0) {
 1292: 			FD_SET(sctl, &readset);
 1293: 			max_fd = MAX( max_fd, sctl);
 1294: 		}
 1295: 		
 1296: 		for(ectl = ctllisthead.lh_first; ectl; ectl = ectl->entries.le_next)
 1297: 		{
 1298: 			if(ectl->socket >= 0) {
 1299: 				FD_SET(ectl->socket, &readset);
 1300: 				max_fd = MAX( max_fd, ectl->socket);
 1301: 			}
 1302: 		}
 1303: #endif
 1304: 
 1305: #ifdef ENABLE_EVENTS
 1306: 		FD_ZERO(&writeset);
 1307: 		upnpevents_selectfds(&readset, &writeset, &max_fd);
 1308: #endif
 1309: 
 1310: #ifdef ENABLE_EVENTS
 1311: 		if(select(max_fd+1, &readset, &writeset, 0, &timeout) < 0)
 1312: #else
 1313: 		if(select(max_fd+1, &readset, 0, 0, &timeout) < 0)
 1314: #endif
 1315: 		{
 1316: 			if(quitting) goto shutdown;
 1317: 			if(errno == EINTR) continue; /* interrupted by a signal, start again */
 1318: 			syslog(LOG_ERR, "select(all): %m");
 1319: 			syslog(LOG_ERR, "Failed to select open sockets. EXITING");
 1320: 			return 1;	/* very serious cause of error */
 1321: 		}
 1322: #ifdef USE_MINIUPNPDCTL
 1323: 		for(ectl = ctllisthead.lh_first; ectl;)
 1324: 		{
 1325: 			ectlnext =  ectl->entries.le_next;
 1326: 			if((ectl->socket >= 0) && FD_ISSET(ectl->socket, &readset))
 1327: 			{
 1328: 				char buf[256];
 1329: 				int l;
 1330: 				l = read(ectl->socket, buf, sizeof(buf));
 1331: 				if(l > 0)
 1332: 				{
 1333: 					/*write(ectl->socket, buf, l);*/
 1334: 					write_command_line(ectl->socket, argc, argv);
 1335: 					write_option_list(ectl->socket);
 1336: 					write_permlist(ectl->socket, upnppermlist, num_upnpperm);
 1337: 					write_upnphttp_details(ectl->socket, upnphttphead.lh_first);
 1338: 					write_ctlsockets_list(ectl->socket, ctllisthead.lh_first);
 1339: 					write_ruleset_details(ectl->socket);
 1340: #ifdef ENABLE_EVENTS
 1341: 					write_events_details(ectl->socket);
 1342: #endif
 1343: 					/* close the socket */
 1344: 					close(ectl->socket);
 1345: 					ectl->socket = -1;
 1346: 				}
 1347: 				else
 1348: 				{
 1349: 					close(ectl->socket);
 1350: 					ectl->socket = -1;
 1351: 				}
 1352: 			}
 1353: 			if(ectl->socket < 0)
 1354: 			{
 1355: 				LIST_REMOVE(ectl, entries);
 1356: 				free(ectl);
 1357: 			}
 1358: 			ectl = ectlnext;
 1359: 		}
 1360: 		if((sctl >= 0) && FD_ISSET(sctl, &readset))
 1361: 		{
 1362: 			int s;
 1363: 			struct sockaddr_un clientname;
 1364: 			struct ctlelem * tmp;
 1365: 			socklen_t clientnamelen = sizeof(struct sockaddr_un);
 1366: 			//syslog(LOG_DEBUG, "sctl!");
 1367: 			s = accept(sctl, (struct sockaddr *)&clientname,
 1368: 			           &clientnamelen);
 1369: 			syslog(LOG_DEBUG, "sctl! : '%s'", clientname.sun_path);
 1370: 			tmp = malloc(sizeof(struct ctlelem));
 1371: 			tmp->socket = s;
 1372: 			LIST_INSERT_HEAD(&ctllisthead, tmp, entries);
 1373: 		}
 1374: #endif
 1375: #ifdef ENABLE_EVENTS
 1376: 		upnpevents_processfds(&readset, &writeset);
 1377: #endif
 1378: #ifdef ENABLE_NATPMP
 1379: 		/* process NAT-PMP packets */
 1380: 		for(i=0; i<n_lan_addr; i++)
 1381: 		{
 1382: 			if((snatpmp[i] >= 0) && FD_ISSET(snatpmp[i], &readset))
 1383: 			{
 1384: 				ProcessIncomingNATPMPPacket(snatpmp[i]);
 1385: 			}
 1386: 		}
 1387: #endif
 1388: 		/* process SSDP packets */
 1389: 		if(sudp >= 0 && FD_ISSET(sudp, &readset))
 1390: 		{
 1391: 			/*syslog(LOG_INFO, "Received UDP Packet");*/
 1392: 			ProcessSSDPRequest(sudp, (unsigned short)v.port);
 1393: 		}
 1394: 		/* process active HTTP connections */
 1395: 		/* LIST_FOREACH macro is not available under linux */
 1396: 		for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next)
 1397: 		{
 1398: 			if(  (e->socket >= 0) && (e->state <= 2)
 1399: 				&&(FD_ISSET(e->socket, &readset)) )
 1400: 			{
 1401: 				Process_upnphttp(e);
 1402: 			}
 1403: 		}
 1404: 		/* process incoming HTTP connections */
 1405: 		if(shttpl >= 0 && FD_ISSET(shttpl, &readset))
 1406: 		{
 1407: 			int shttp;
 1408: 			socklen_t clientnamelen;
 1409: 			struct sockaddr_in clientname;
 1410: 			clientnamelen = sizeof(struct sockaddr_in);
 1411: 			shttp = accept(shttpl, (struct sockaddr *)&clientname, &clientnamelen);
 1412: 			if(shttp<0)
 1413: 			{
 1414: 				syslog(LOG_ERR, "accept(http): %m");
 1415: 			}
 1416: 			else
 1417: 			{
 1418: 				struct upnphttp * tmp = 0;
 1419: 				syslog(LOG_INFO, "HTTP connection from %s:%d",
 1420: 					inet_ntoa(clientname.sin_addr),
 1421: 					ntohs(clientname.sin_port) );
 1422: 				/*if (fcntl(shttp, F_SETFL, O_NONBLOCK) < 0) {
 1423: 					syslog(LOG_ERR, "fcntl F_SETFL, O_NONBLOCK");
 1424: 				}*/
 1425: #ifdef ENABLE_NFQUEUE
 1426: 		/* process NFQ packets */
 1427: 		if(nfqh >= 0 && FD_ISSET(nfqh, &readset))
 1428: 		{
 1429: 			/* syslog(LOG_INFO, "Received NFQUEUE Packet");*/
 1430: 			ProcessNFQUEUE(nfqh);
 1431: 		}
 1432: #endif
 1433: 				/* Create a new upnphttp object and add it to
 1434: 				 * the active upnphttp object list */
 1435: 				tmp = New_upnphttp(shttp);
 1436: 				if(tmp)
 1437: 				{
 1438: 					tmp->clientaddr = clientname.sin_addr;
 1439: 					LIST_INSERT_HEAD(&upnphttphead, tmp, entries);
 1440: 				}
 1441: 				else
 1442: 				{
 1443: 					syslog(LOG_ERR, "New_upnphttp() failed");
 1444: 					close(shttp);
 1445: 				}
 1446: 			}
 1447: 		}
 1448: 		/* delete finished HTTP connections */
 1449: 		for(e = upnphttphead.lh_first; e != NULL; )
 1450: 		{
 1451: 			next = e->entries.le_next;
 1452: 			if(e->state >= 100)
 1453: 			{
 1454: 				LIST_REMOVE(e, entries);
 1455: 				Delete_upnphttp(e);
 1456: 			}
 1457: 			e = next;
 1458: 		}
 1459: 
 1460: 		/* send public address change notifications */
 1461: 		if(should_send_public_address_change_notif)
 1462: 		{
 1463: #ifdef ENABLE_NATPMP
 1464: 			if(GETFLAG(ENABLENATPMPMASK))
 1465: 				SendNATPMPPublicAddressChangeNotification(snatpmp/*snotify*/, n_lan_addr);
 1466: #endif
 1467: #ifdef ENABLE_EVENTS
 1468: 			if(GETFLAG(ENABLEUPNPMASK))
 1469: 			{
 1470: 				upnp_event_var_change_notify(EWanIPC);
 1471: 			}
 1472: #endif
 1473: 			should_send_public_address_change_notif = 0;
 1474: 		}
 1475: 	}	/* end of main loop */
 1476: 
 1477: shutdown:
 1478: 	/* close out open sockets */
 1479: 	while(upnphttphead.lh_first != NULL)
 1480: 	{
 1481: 		e = upnphttphead.lh_first;
 1482: 		LIST_REMOVE(e, entries);
 1483: 		Delete_upnphttp(e);
 1484: 	}
 1485: 
 1486: 	if (sudp >= 0) close(sudp);
 1487: 	if (shttpl >= 0) close(shttpl);
 1488: #ifdef ENABLE_NATPMP
 1489: 	for(i=0; i<n_lan_addr; i++) {
 1490: 		if(snatpmp[i]>=0)
 1491: 		{
 1492: 			close(snatpmp[i]);
 1493: 			snatpmp[i] = -1;
 1494: 		}
 1495: 	}
 1496: #endif
 1497: #ifdef USE_MINIUPNPDCTL
 1498: 	if(sctl>=0)
 1499: 	{
 1500: 		close(sctl);
 1501: 		sctl = -1;
 1502: 		if(unlink("/var/run/miniupnpd.ctl") < 0)
 1503: 		{
 1504: 			syslog(LOG_ERR, "unlink() %m");
 1505: 		}
 1506: 	}
 1507: #endif
 1508: 	
 1509: 	/*if(SendSSDPGoodbye(snotify, v.n_lan_addr) < 0)*/
 1510: 	if (GETFLAG(ENABLEUPNPMASK))
 1511: 	{
 1512: 		if(SendSSDPGoodbye(snotify, n_lan_addr) < 0)
 1513: 		{
 1514: 			syslog(LOG_ERR, "Failed to broadcast good-bye notifications");
 1515: 		}
 1516: 		for(i=0; i<n_lan_addr; i++)/* for(i=0; i<v.n_lan_addr; i++)*/
 1517: 			close(snotify[i]);
 1518: 	}
 1519: 
 1520: 	if(unlink(pidfilename) < 0)
 1521: 	{
 1522: 		syslog(LOG_ERR, "Failed to remove pidfile %s: %m", pidfilename);
 1523: 	}
 1524: 
 1525: 	closelog();	
 1526: 	freeoptions();
 1527: 	
 1528: 	return 0;
 1529: }
 1530: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>