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