Tomato 1.28
[tomato.git] / release / src / router / miniupnpd / miniupnpd.c
blob088327418ea66625b0a6276c1f3f059041776c88
1 /* $Id: miniupnpd.c,v 1.113 2009/09/04 16:14:04 nanard Exp $ */
2 /* MiniUPnP project
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * (c) 2006-2008 Thomas Bernard
5 * This software is subject to the conditions detailed
6 * in the LICENCE file provided within the distribution */
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <ctype.h>
13 #include <sys/types.h>
14 #include <sys/socket.h>
15 #include <netinet/in.h>
16 #include <arpa/inet.h>
17 #include <fcntl.h>
18 #include <sys/file.h>
19 #include <syslog.h>
20 #include <sys/time.h>
21 #include <time.h>
22 #include <signal.h>
23 #include <sys/param.h>
24 #if defined(sun)
25 #include <kstat.h>
26 #else
27 /* for BSD's sysctl */
28 #include <sys/sysctl.h>
29 #endif
31 /* unix sockets */
32 #include "config.h"
33 #ifdef USE_MINIUPNPDCTL
34 #include <sys/un.h>
35 #endif
37 #include "upnpglobalvars.h"
38 #include "upnphttp.h"
39 #include "upnpdescgen.h"
40 #include "miniupnpdpath.h"
41 #include "getifaddr.h"
42 #include "upnpsoap.h"
43 #include "options.h"
44 #include "minissdp.h"
45 #include "upnpredirect.h"
46 #include "miniupnpdtypes.h"
47 #include "daemonize.h"
48 #include "upnpevents.h"
49 #ifdef ENABLE_NATPMP
50 #include "natpmp.h"
51 #endif
52 #include "commonrdr.h"
54 #ifndef DEFAULT_CONFIG
55 #define DEFAULT_CONFIG "/etc/miniupnpd.conf"
56 #endif
58 #ifdef USE_MINIUPNPDCTL
59 struct ctlelem {
60 int socket;
61 LIST_ENTRY(ctlelem) entries;
63 #endif
65 /* MAX_LAN_ADDR : maximum number of interfaces
66 * to listen to SSDP traffic */
67 /*#define MAX_LAN_ADDR (4)*/
69 static volatile int quitting = 0;
72 #if 1
73 static volatile int gotusr2 = 0;
75 static void sigusr2(int sig)
77 gotusr2 = 1;
80 static void tomato_save(const char *fname)
82 unsigned short eport;
83 unsigned short iport;
84 char proto[4];
85 char iaddr[32];
86 char desc[64];
87 int n;
88 FILE *f;
89 int t;
90 char tmp[128];
92 strcpy(tmp, "/etc/upnp/saveXXXXXX");
93 if ((t = mkstemp(tmp)) != -1) {
94 if ((f = fdopen(t, "w")) != NULL) {
95 n = 0;
96 while (upnp_get_redirection_infos_by_index(n, &eport, proto, &iport, iaddr, sizeof(iaddr), desc, sizeof(desc)) == 0) {
97 fprintf(f, "%s %u %s %u [%s]\n", proto, eport, iaddr, iport, desc);
98 ++n;
100 fclose(f);
101 rename(tmp, fname);
103 else {
104 close(t);
106 unlink(tmp);
110 static void tomato_load(void)
112 FILE *f;
113 char s[256];
114 unsigned short eport;
115 unsigned short iport;
116 char proto[4];
117 char iaddr[32];
118 char desc[64];
119 char *a, *b;
121 if ((f = fopen("/etc/upnp/data", "r")) != NULL) {
122 s[sizeof(s) - 1] = 0;
123 while (fgets(s, sizeof(s) - 1, f)) {
124 if (sscanf(s, "%3s %hu %31s %hu ", proto, &eport, iaddr, &iport) == 4) {
125 if (((a = strchr(s, '[')) != NULL) && ((b = strrchr(a, ']')) != NULL) && ((b - a) <= sizeof(desc))) {
126 *b = 0;
127 upnp_redirect(eport, iaddr, iport, proto, a + 1);
131 fclose(f);
133 unlink("/etc/upnp/load");
136 static void tomato_delete(void)
138 FILE *f;
139 char s[128];
140 unsigned short eport;
141 unsigned short iport;
142 char proto[4];
143 char iaddr[32];
144 char desc[64];
145 int n;
147 if ((f = fopen("/etc/upnp/delete", "r")) != NULL) {
148 s[sizeof(s) - 1] = 0;
149 while (fgets(s, sizeof(s) - 1, f)) {
150 if (sscanf(s, "%3s %hu", proto, &eport) == 2) {
151 if (proto[0] == '*') {
152 n = upnp_get_portmapping_number_of_entries();
153 while (--n >= 0) {
154 if (upnp_get_redirection_infos_by_index(n, &eport, proto, &iport, iaddr, sizeof(iaddr), desc, sizeof(desc)) == 0) {
155 upnp_delete_redirection(eport, proto);
158 break;
160 else {
161 upnp_delete_redirection(eport, proto);
165 fclose(f);
166 unlink("/etc/upnp/delete");
170 static void tomato_helper(void)
172 struct stat st;
174 if (stat("/etc/upnp/delete", &st) == 0) {
175 tomato_delete();
178 if (stat("/etc/upnp/load", &st) == 0) {
179 tomato_load();
182 if (stat("/etc/upnp/save", &st) == 0) {
183 tomato_save("/etc/upnp/data");
184 unlink("/etc/upnp/save");
187 if (stat("/etc/upnp/info", &st) == 0) {
188 tomato_save("/etc/upnp/data.info");
189 unlink("/etc/upnp/info");
192 #endif /* 1 (tomato) */
195 /* OpenAndConfHTTPSocket() :
196 * setup the socket used to handle incoming HTTP connections. */
197 static int
198 OpenAndConfHTTPSocket(unsigned short port)
200 int s;
201 int i = 1;
202 struct sockaddr_in listenname;
204 if( (s = socket(PF_INET, SOCK_STREAM, 0)) < 0)
206 syslog(LOG_ERR, "socket(http): %m");
207 return -1;
210 if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0)
212 syslog(LOG_WARNING, "setsockopt(http, SO_REUSEADDR): %m");
215 memset(&listenname, 0, sizeof(struct sockaddr_in));
216 listenname.sin_family = AF_INET;
217 listenname.sin_port = htons(port);
218 listenname.sin_addr.s_addr = htonl(INADDR_ANY);
220 if(bind(s, (struct sockaddr *)&listenname, sizeof(struct sockaddr_in)) < 0)
222 syslog(LOG_ERR, "bind(http): %m");
223 close(s);
224 return -1;
227 if(listen(s, 6) < 0)
229 syslog(LOG_ERR, "listen(http): %m");
230 close(s);
231 return -1;
234 return s;
237 /* Functions used to communicate with miniupnpdctl */
238 #ifdef USE_MINIUPNPDCTL
239 static int
240 OpenAndConfCtlUnixSocket(const char * path)
242 struct sockaddr_un localun;
243 int s;
244 s = socket(AF_UNIX, SOCK_STREAM, 0);
245 localun.sun_family = AF_UNIX;
246 strncpy(localun.sun_path, path,
247 sizeof(localun.sun_path));
248 if(bind(s, (struct sockaddr *)&localun,
249 sizeof(struct sockaddr_un)) < 0)
251 syslog(LOG_ERR, "bind(sctl): %m");
252 close(s);
253 s = -1;
255 else if(listen(s, 5) < 0)
257 syslog(LOG_ERR, "listen(sctl): %m");
258 close(s);
259 s = -1;
261 return s;
264 static void
265 write_upnphttp_details(int fd, struct upnphttp * e)
267 char buffer[256];
268 int len;
269 while(e)
271 len = snprintf(buffer, sizeof(buffer),
272 "%d %d %s req_buf=%p(%dbytes) res_buf=%p(%dbytes alloc)\n",
273 e->socket, e->state, e->HttpVer,
274 e->req_buf, e->req_buflen,
275 e->res_buf, e->res_buf_alloclen);
276 write(fd, buffer, len);
277 e = e->entries.le_next;
281 static void
282 write_ctlsockets_list(int fd, struct ctlelem * e)
284 char buffer[256];
285 int len;
286 while(e)
288 len = snprintf(buffer, sizeof(buffer),
289 "struct ctlelem: socket=%d\n", e->socket);
290 write(fd, buffer, len);
291 e = e->entries.le_next;
295 static void
296 write_option_list(int fd)
298 char buffer[256];
299 int len;
300 int i;
301 for(i=0; i<num_options; i++)
303 len = snprintf(buffer, sizeof(buffer),
304 "opt=%02d %s\n",
305 ary_options[i].id, ary_options[i].value);
306 write(fd, buffer, len);
310 #endif
312 /* Handler for the SIGTERM signal (kill)
313 * SIGINT is also handled */
314 static void
315 sigterm(int sig)
317 /*int save_errno = errno;*/
318 signal(sig, SIG_IGN); /* Ignore this signal while we are quitting */
320 syslog(LOG_NOTICE, "received signal %d, good-bye", sig);
322 quitting = 1;
323 /*errno = save_errno;*/
326 /* record the startup time, for returning uptime */
327 static void
328 set_startup_time(int sysuptime)
330 startup_time = time(NULL);
331 if(sysuptime)
333 /* use system uptime instead of daemon uptime */
334 #if defined(__linux__)
335 char buff[64];
336 int uptime, fd;
337 fd = open("/proc/uptime", O_RDONLY);
338 if(fd < 0)
340 syslog(LOG_ERR, "open(\"/proc/uptime\" : %m");
342 else
344 memset(buff, 0, sizeof(buff));
345 read(fd, buff, sizeof(buff) - 1);
346 uptime = atoi(buff);
347 syslog(LOG_INFO, "system uptime is %d seconds", uptime);
348 close(fd);
349 startup_time -= uptime;
351 #elif defined(SOLARIS_KSTATS)
352 kstat_ctl_t *kc;
353 kc = kstat_open();
354 if(kc != NULL)
356 kstat_t *ksp;
357 ksp = kstat_lookup(kc, "unix", 0, "system_misc");
358 if(ksp && (kstat_read(kc, ksp, NULL) != -1))
360 void *ptr = kstat_data_lookup(ksp, "boot_time");
361 if(ptr)
362 memcpy(&startup_time, ptr, sizeof(startup_time));
363 else
364 syslog(LOG_ERR, "cannot find boot_time kstat");
366 else
367 syslog(LOG_ERR, "cannot open kstats for unix/0/system_misc: %m");
368 kstat_close(kc);
370 #else
371 struct timeval boottime;
372 size_t size = sizeof(boottime);
373 int name[2] = { CTL_KERN, KERN_BOOTTIME };
374 if(sysctl(name, 2, &boottime, &size, NULL, 0) < 0)
376 syslog(LOG_ERR, "sysctl(\"kern.boottime\") failed");
378 else
380 startup_time = boottime.tv_sec;
382 #endif
386 /* structure containing variables used during "main loop"
387 * that are filled during the init */
388 struct runtime_vars {
389 /* LAN IP addresses for SSDP traffic and HTTP */
390 /* moved to global vars */
391 /*int n_lan_addr;*/
392 /*struct lan_addr_s lan_addr[MAX_LAN_ADDR];*/
393 int port; /* HTTP Port */
394 int notify_interval; /* seconds between SSDP announces */
395 /* unused rules cleaning related variables : */
396 int clean_ruleset_threshold; /* threshold for removing unused rules */
397 int clean_ruleset_interval; /* (minimum) interval between checks */
400 /* parselanaddr()
401 * parse address with mask
402 * ex: 192.168.1.1/24
403 * return value :
404 * 0 : ok
405 * -1 : error */
406 static int
407 parselanaddr(struct lan_addr_s * lan_addr, const char * str)
409 const char * p;
410 int nbits = 24;
411 int n;
412 p = str;
413 while(*p && *p != '/' && !isspace(*p))
414 p++;
415 n = p - str;
416 if(*p == '/')
418 nbits = atoi(++p);
419 while(*p && !isspace(*p))
420 p++;
422 if(n>15)
424 fprintf(stderr, "Error parsing address/mask : %s\n", str);
425 return -1;
427 memcpy(lan_addr->str, str, n);
428 lan_addr->str[n] = '\0';
429 if(!inet_aton(lan_addr->str, &lan_addr->addr))
431 fprintf(stderr, "Error parsing address/mask : %s\n", str);
432 return -1;
434 lan_addr->mask.s_addr = htonl(nbits ? (0xffffffff << (32 - nbits)) : 0);
435 #ifdef MULTIPLE_EXTERNAL_IP
436 while(*p && isspace(*p))
437 p++;
438 if(*p) {
439 n = 0;
440 while(p[n] && !isspace(*p))
441 n++;
442 if(n<=15) {
443 memcpy(lan_addr->ext_ip_str, p, n);
444 lan_addr->ext_ip_str[n] = '\0';
445 if(!inet_aton(lan_addr->ext_ip_str, &lan_addr->ext_ip_addr)) {
446 /* error */
447 fprintf(stderr, "Error parsing address : %s\n", lan_addr->ext_ip_str);
451 #endif
452 return 0;
455 /* init phase :
456 * 1) read configuration file
457 * 2) read command line arguments
458 * 3) daemonize
459 * 4) open syslog
460 * 5) check and write pid file
461 * 6) set startup time stamp
462 * 7) compute presentation URL
463 * 8) set signal handlers */
464 static int
465 init(int argc, char * * argv, struct runtime_vars * v)
467 int i;
468 int pid;
469 int debug_flag = 0;
470 int options_flag = 0;
471 int openlog_option;
472 struct sigaction sa;
473 /*const char * logfilename = 0;*/
474 const char * presurl = 0;
475 const char * optionsfile = DEFAULT_CONFIG;
477 /* first check if "-f" option is used */
478 for(i=2; i<argc; i++)
480 if(0 == strcmp(argv[i-1], "-f"))
482 optionsfile = argv[i];
483 options_flag = 1;
484 break;
488 /* set initial values */
489 SETFLAG(ENABLEUPNPMASK);
491 /*v->n_lan_addr = 0;*/
492 v->port = -1;
493 v->notify_interval = 30; /* seconds between SSDP announces */
494 v->clean_ruleset_threshold = 20;
495 v->clean_ruleset_interval = 0; /* interval between ruleset check. 0=disabled */
497 /* read options file first since
498 * command line arguments have final say */
499 if(readoptionsfile(optionsfile) < 0)
501 /* only error if file exists or using -f */
502 if(access(optionsfile, F_OK) == 0 || options_flag)
503 fprintf(stderr, "Error reading configuration file %s\n", optionsfile);
505 else
507 for(i=0; i<num_options; i++)
509 switch(ary_options[i].id)
511 case UPNPEXT_IFNAME:
512 ext_if_name = ary_options[i].value;
513 break;
514 case UPNPEXT_IP:
515 use_ext_ip_addr = ary_options[i].value;
516 break;
517 case UPNPLISTENING_IP:
518 if(n_lan_addr < MAX_LAN_ADDR)/* if(v->n_lan_addr < MAX_LAN_ADDR)*/
520 /*if(parselanaddr(&v->lan_addr[v->n_lan_addr],*/
521 if(parselanaddr(&lan_addr[n_lan_addr],
522 ary_options[i].value) == 0)
523 n_lan_addr++; /*v->n_lan_addr++; */
525 else
527 fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n",
528 MAX_LAN_ADDR, ary_options[i].value);
530 break;
531 case UPNPPORT:
532 v->port = atoi(ary_options[i].value);
533 break;
534 case UPNPBITRATE_UP:
535 upstream_bitrate = strtoul(ary_options[i].value, 0, 0);
536 break;
537 case UPNPBITRATE_DOWN:
538 downstream_bitrate = strtoul(ary_options[i].value, 0, 0);
539 break;
540 case UPNPPRESENTATIONURL:
541 presurl = ary_options[i].value;
542 break;
543 #ifdef USE_NETFILTER
544 case UPNPFORWARDCHAIN:
545 miniupnpd_forward_chain = ary_options[i].value;
546 break;
547 case UPNPNATCHAIN:
548 miniupnpd_nat_chain = ary_options[i].value;
549 break;
550 #endif
551 case UPNPNOTIFY_INTERVAL:
552 v->notify_interval = atoi(ary_options[i].value);
553 break;
554 case UPNPSYSTEM_UPTIME:
555 if(strcmp(ary_options[i].value, "yes") == 0)
556 SETFLAG(SYSUPTIMEMASK); /*sysuptime = 1;*/
557 break;
558 case UPNPPACKET_LOG:
559 if(strcmp(ary_options[i].value, "yes") == 0)
560 SETFLAG(LOGPACKETSMASK); /*logpackets = 1;*/
561 break;
562 case UPNPUUID:
563 strncpy(uuidvalue+5, ary_options[i].value,
564 strlen(uuidvalue+5) + 1);
565 break;
566 case UPNPSERIAL:
567 strncpy(serialnumber, ary_options[i].value, SERIALNUMBER_MAX_LEN);
568 serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0';
569 break;
570 case UPNPMODEL_NUMBER:
571 strncpy(modelnumber, ary_options[i].value, MODELNUMBER_MAX_LEN);
572 modelnumber[MODELNUMBER_MAX_LEN-1] = '\0';
573 break;
574 case UPNPCLEANTHRESHOLD:
575 v->clean_ruleset_threshold = atoi(ary_options[i].value);
576 break;
577 case UPNPCLEANINTERVAL:
578 v->clean_ruleset_interval = atoi(ary_options[i].value);
579 break;
580 #ifdef USE_PF
581 case UPNPQUEUE:
582 queue = ary_options[i].value;
583 break;
584 case UPNPTAG:
585 tag = ary_options[i].value;
586 break;
587 #endif
588 #ifdef ENABLE_NATPMP
589 case UPNPENABLENATPMP:
590 if(strcmp(ary_options[i].value, "yes") == 0)
591 SETFLAG(ENABLENATPMPMASK); /*enablenatpmp = 1;*/
592 else
593 if(atoi(ary_options[i].value))
594 SETFLAG(ENABLENATPMPMASK);
595 /*enablenatpmp = atoi(ary_options[i].value);*/
596 break;
597 #endif
598 #ifdef PF_ENABLE_FILTER_RULES
599 case UPNPQUICKRULES:
600 if(strcmp(ary_options[i].value, "no") == 0)
601 SETFLAG(PFNOQUICKRULESMASK);
602 break;
603 #endif
604 case UPNPENABLE:
605 if(strcmp(ary_options[i].value, "yes") != 0)
606 CLEARFLAG(ENABLEUPNPMASK);
607 break;
608 case UPNPSECUREMODE:
609 if(strcmp(ary_options[i].value, "yes") == 0)
610 SETFLAG(SECUREMODEMASK);
611 break;
612 #ifdef ENABLE_LEASEFILE
613 case UPNPLEASEFILE:
614 lease_file = ary_options[i].value;
615 break;
616 #endif
617 case UPNPMINISSDPDSOCKET:
618 minissdpdsocketpath = ary_options[i].value;
619 break;
620 default:
621 fprintf(stderr, "Unknown option in file %s\n",
622 optionsfile);
627 /* command line arguments processing */
628 for(i=1; i<argc; i++)
630 if(argv[i][0]!='-')
632 fprintf(stderr, "Unknown option: %s\n", argv[i]);
634 else switch(argv[i][1])
636 case 'o':
637 if(i+1 < argc)
638 use_ext_ip_addr = argv[++i];
639 else
640 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
641 break;
642 case 't':
643 if(i+1 < argc)
644 v->notify_interval = atoi(argv[++i]);
645 else
646 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
647 break;
648 case 'u':
649 if(i+1 < argc)
650 strncpy(uuidvalue+5, argv[++i], strlen(uuidvalue+5) + 1);
651 else
652 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
653 break;
654 case 's':
655 if(i+1 < argc)
656 strncpy(serialnumber, argv[++i], SERIALNUMBER_MAX_LEN);
657 else
658 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
659 serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0';
660 break;
661 case 'm':
662 if(i+1 < argc)
663 strncpy(modelnumber, argv[++i], MODELNUMBER_MAX_LEN);
664 else
665 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
666 modelnumber[MODELNUMBER_MAX_LEN-1] = '\0';
667 break;
668 #ifdef ENABLE_NATPMP
669 case 'N':
670 /*enablenatpmp = 1;*/
671 SETFLAG(ENABLENATPMPMASK);
672 break;
673 #endif
674 case 'U':
675 /*sysuptime = 1;*/
676 SETFLAG(SYSUPTIMEMASK);
677 break;
678 /*case 'l':
679 logfilename = argv[++i];
680 break;*/
681 case 'L':
682 /*logpackets = 1;*/
683 SETFLAG(LOGPACKETSMASK);
684 break;
685 case 'S':
686 SETFLAG(SECUREMODEMASK);
687 break;
688 case 'i':
689 if(i+1 < argc)
690 ext_if_name = argv[++i];
691 else
692 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
693 break;
694 #ifdef USE_PF
695 case 'q':
696 if(i+1 < argc)
697 queue = argv[++i];
698 else
699 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
700 break;
701 case 'T':
702 if(i+1 < argc)
703 tag = argv[++i];
704 else
705 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
706 break;
707 #endif
708 case 'p':
709 if(i+1 < argc)
710 v->port = atoi(argv[++i]);
711 else
712 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
713 break;
714 case 'P':
715 if(i+1 < argc)
716 pidfilename = argv[++i];
717 else
718 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
719 break;
720 case 'd':
721 debug_flag = 1;
722 break;
723 case 'w':
724 if(i+1 < argc)
725 presurl = argv[++i];
726 else
727 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
728 break;
729 case 'B':
730 if(i+2<argc)
732 downstream_bitrate = strtoul(argv[++i], 0, 0);
733 upstream_bitrate = strtoul(argv[++i], 0, 0);
735 else
736 fprintf(stderr, "Option -%c takes two arguments.\n", argv[i][1]);
737 break;
738 case 'a':
739 if(i+1 < argc)
741 int address_already_there = 0;
742 int j;
743 i++;
744 for(j=0; j<n_lan_addr; j++)/* for(j=0; j<v->n_lan_addr; j++)*/
746 struct lan_addr_s tmpaddr;
747 parselanaddr(&tmpaddr, argv[i]);
748 /*if(0 == strcmp(v->lan_addr[j].str, tmpaddr.str))*/
749 if(0 == strcmp(lan_addr[j].str, tmpaddr.str))
750 address_already_there = 1;
752 if(address_already_there)
753 break;
754 if(n_lan_addr < MAX_LAN_ADDR) /*if(v->n_lan_addr < MAX_LAN_ADDR)*/
756 /*v->lan_addr[v->n_lan_addr++] = argv[i];*/
757 /*if(parselanaddr(&v->lan_addr[v->n_lan_addr], argv[i]) == 0)*/
758 if(parselanaddr(&lan_addr[n_lan_addr], argv[i]) == 0)
759 n_lan_addr++; /*v->n_lan_addr++;*/
761 else
763 fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n",
764 MAX_LAN_ADDR, argv[i]);
767 else
768 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
769 break;
770 case 'f':
771 i++; /* discarding, the config file is already read */
772 break;
773 default:
774 fprintf(stderr, "Unknown option: %s\n", argv[i]);
777 if(!ext_if_name || (/*v->*/n_lan_addr==0))
779 fprintf(stderr, "Usage:\n\t"
780 "%s [-f config_file] [-i ext_ifname] [-o ext_ip]\n"
781 #ifndef ENABLE_NATPMP
782 "\t\t[-a listening_ip] [-p port] [-d] [-L] [-U] [-S]\n"
783 #else
784 "\t\t[-a listening_ip] [-p port] [-d] [-L] [-U] [-S] [-N]\n"
785 #endif
786 /*"[-l logfile] " not functionnal */
787 "\t\t[-u uuid] [-s serial] [-m model_number] \n"
788 "\t\t[-t notify_interval] [-P pid_filename]\n"
789 #ifdef USE_PF
790 "\t\t[-B down up] [-w url] [-q queue] [-T tag]\n"
791 #else
792 "\t\t[-B down up] [-w url]\n"
793 #endif
794 "\nNotes:\n\tThere can be one or several listening_ips.\n"
795 "\tNotify interval is in seconds. Default is 30 seconds.\n"
796 "\tDefault pid file is %s.\n"
797 "\tWith -d miniupnpd will run as a standard program.\n"
798 "\t-L sets packet log in pf and ipf on.\n"
799 "\t-S sets \"secure\" mode : clients can only add mappings to their own ip\n"
800 "\t-U causes miniupnpd to report system uptime instead "
801 "of daemon uptime.\n"
802 "\t-B sets bitrates reported by daemon in bits per second.\n"
803 "\t-w sets the presentation url. Default is http address on port 80\n"
804 #ifdef USE_PF
805 "\t-q sets the ALTQ queue in pf.\n"
806 "\t-T sets the tag name in pf.\n"
807 #endif
808 "", argv[0], pidfilename);
809 return 1;
812 if(debug_flag)
814 pid = getpid();
816 else
818 #ifdef USE_DAEMON
819 if(daemon(0, 0)<0) {
820 perror("daemon()");
822 pid = getpid();
823 #else
824 pid = daemonize();
825 #endif
828 openlog_option = LOG_PID|LOG_CONS;
829 if(debug_flag)
831 openlog_option |= LOG_PERROR; /* also log on stderr */
834 openlog("miniupnpd", openlog_option, LOG_MINIUPNPD);
836 if(!debug_flag)
838 /* speed things up and ignore LOG_INFO and LOG_DEBUG */
839 setlogmask(LOG_UPTO(LOG_NOTICE));
842 if(checkforrunning(pidfilename) < 0)
844 syslog(LOG_ERR, "MiniUPnPd is already running. EXITING");
845 return 1;
848 set_startup_time(GETFLAG(SYSUPTIMEMASK)/*sysuptime*/);
850 /* presentation url */
851 if(presurl)
853 strncpy(presentationurl, presurl, PRESENTATIONURL_MAX_LEN);
854 presentationurl[PRESENTATIONURL_MAX_LEN-1] = '\0';
856 else
858 snprintf(presentationurl, PRESENTATIONURL_MAX_LEN,
859 "http://%s/", lan_addr[0].str);
860 /*"http://%s:%d/", lan_addr[0].str, 80);*/
861 /*"http://%s:%d/", v->lan_addr[0].str, 80);*/
864 /* set signal handler */
865 memset(&sa, 0, sizeof(struct sigaction));
866 sa.sa_handler = sigterm;
868 if (sigaction(SIGTERM, &sa, NULL))
870 syslog(LOG_ERR, "Failed to set %s handler. EXITING", "SIGTERM");
871 return 1;
873 if (sigaction(SIGINT, &sa, NULL))
875 syslog(LOG_ERR, "Failed to set %s handler. EXITING", "SIGINT");
876 return 1;
879 // zzz
880 sa.sa_handler = sigusr2;
881 sigaction(SIGUSR2, &sa, NULL);
883 if(signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
884 syslog(LOG_ERR, "Failed to ignore SIGPIPE signals");
887 if(init_redirect() < 0)
889 syslog(LOG_ERR, "Failed to init redirection engine. EXITING");
890 return 1;
893 writepidfile(pidfilename, pid);
895 #ifdef ENABLE_LEASEFILE
896 /*remove(lease_file);*/
897 syslog(LOG_INFO, "Reloading rules from lease file");
898 reload_from_lease_file();
899 #endif
901 return 0;
904 /* === main === */
905 /* process HTTP or SSDP requests */
907 main(int argc, char * * argv)
909 int i;
910 int sudp = -1, shttpl = -1;
911 #ifdef ENABLE_NATPMP
912 int snatpmp = -1;
913 #endif
914 int snotify[MAX_LAN_ADDR];
915 LIST_HEAD(httplisthead, upnphttp) upnphttphead;
916 struct upnphttp * e = 0;
917 struct upnphttp * next;
918 fd_set readset; /* for select() */
919 #ifdef ENABLE_EVENTS
920 fd_set writeset;
921 #endif
922 struct timeval timeout, timeofday, lasttimeofday = {0, 0};
923 int max_fd = -1;
924 #ifdef USE_MINIUPNPDCTL
925 int sctl = -1;
926 LIST_HEAD(ctlstructhead, ctlelem) ctllisthead;
927 struct ctlelem * ectl;
928 struct ctlelem * ectlnext;
929 #endif
930 struct runtime_vars v;
931 /* variables used for the unused-rule cleanup process */
932 struct rule_state * rule_list = 0;
933 struct timeval checktime = {0, 0};
935 if(init(argc, argv, &v) != 0)
936 return 1;
938 LIST_INIT(&upnphttphead);
939 #ifdef USE_MINIUPNPDCTL
940 LIST_INIT(&ctllisthead);
941 #endif
944 #ifdef ENABLE_NATPMP
945 !GETFLAG(ENABLENATPMPMASK) &&
946 #endif
947 !GETFLAG(ENABLEUPNPMASK) ) {
948 syslog(LOG_ERR, "Why did you run me anyway?");
949 return 0;
952 if(GETFLAG(ENABLEUPNPMASK)/*enableupnp*/)
955 /* open socket for HTTP connections. Listen on the 1st LAN address */
956 shttpl = OpenAndConfHTTPSocket((v.port > 0) ? v.port : 0);
957 if(shttpl < 0)
959 syslog(LOG_ERR, "Failed to open socket for HTTP. EXITING");
960 return 1;
962 if(v.port <= 0) {
963 struct sockaddr_in sockinfo;
964 socklen_t len = sizeof(struct sockaddr_in);
965 if (getsockname(shttpl, (struct sockaddr *)&sockinfo, &len) < 0) {
966 syslog(LOG_ERR, "getsockname(): %m");
967 return 1;
969 v.port = ntohs(sockinfo.sin_port);
971 syslog(LOG_NOTICE, "HTTP listening on port %d", v.port);
973 /* open socket for SSDP connections */
974 sudp = OpenAndConfSSDPReceiveSocket(n_lan_addr, lan_addr);
975 if(sudp < 0)
977 /*syslog(LOG_ERR, "Failed to open socket for receiving SSDP. EXITING");
978 return 1;*/
979 syslog(LOG_INFO, "Failed to open socket for receiving SSDP. Trying to use MiniSSDPd");
980 if(SubmitServicesToMiniSSDPD(lan_addr[0].str, v.port) < 0) {
981 syslog(LOG_ERR, "Failed to connect to MiniSSDPd. EXITING");
982 return 1;
986 /* open socket for sending notifications */
987 if(OpenAndConfSSDPNotifySockets(snotify) < 0)
989 syslog(LOG_ERR, "Failed to open sockets for sending SSDP notify "
990 "messages. EXITING");
991 return 1;
995 #ifdef ENABLE_NATPMP
996 /* open socket for NAT PMP traffic */
997 if(GETFLAG(ENABLENATPMPMASK))
999 snatpmp = OpenAndConfNATPMPSocket();
1000 if(snatpmp < 0)
1002 syslog(LOG_ERR, "Failed to open socket for NAT PMP.");
1003 /*syslog(LOG_ERR, "Failed to open socket for NAT PMP. EXITING");
1004 return 1;*/
1005 } else {
1006 syslog(LOG_NOTICE, "Listening for NAT-PMP traffic on port %u",
1007 NATPMP_PORT);
1009 ScanNATPMPforExpiration();
1011 #endif
1013 /* for miniupnpdctl */
1014 #ifdef USE_MINIUPNPDCTL
1015 sctl = OpenAndConfCtlUnixSocket("/var/run/miniupnpd.ctl");
1016 #endif
1018 tomato_helper(); // zzz
1020 /* main loop */
1021 while(!quitting)
1023 /* Check if we need to send SSDP NOTIFY messages and do it if
1024 * needed */
1025 if(gettimeofday(&timeofday, 0) < 0)
1027 syslog(LOG_ERR, "gettimeofday(): %m");
1028 timeout.tv_sec = v.notify_interval;
1029 timeout.tv_usec = 0;
1031 else
1033 /* the comparaison is not very precise but who cares ? */
1034 if(timeofday.tv_sec >= (lasttimeofday.tv_sec + v.notify_interval))
1036 if (GETFLAG(ENABLEUPNPMASK))
1037 SendSSDPNotifies2(snotify,
1038 (unsigned short)v.port,
1039 v.notify_interval << 1);
1040 memcpy(&lasttimeofday, &timeofday, sizeof(struct timeval));
1041 timeout.tv_sec = v.notify_interval;
1042 timeout.tv_usec = 0;
1044 else
1046 timeout.tv_sec = lasttimeofday.tv_sec + v.notify_interval
1047 - timeofday.tv_sec;
1048 if(timeofday.tv_usec > lasttimeofday.tv_usec)
1050 timeout.tv_usec = 1000000 + lasttimeofday.tv_usec
1051 - timeofday.tv_usec;
1052 timeout.tv_sec--;
1054 else
1056 timeout.tv_usec = lasttimeofday.tv_usec - timeofday.tv_usec;
1060 /* remove unused rules */
1061 if( v.clean_ruleset_interval
1062 && (timeofday.tv_sec >= checktime.tv_sec + v.clean_ruleset_interval))
1064 if(rule_list)
1066 remove_unused_rules(rule_list);
1067 rule_list = NULL;
1069 else
1071 rule_list = get_upnp_rules_state_list(v.clean_ruleset_threshold);
1073 memcpy(&checktime, &timeofday, sizeof(struct timeval));
1075 #ifdef ENABLE_NATPMP
1076 /* Remove expired NAT-PMP mappings */
1077 while( nextnatpmptoclean_timestamp && (timeofday.tv_sec >= nextnatpmptoclean_timestamp + startup_time))
1079 /*syslog(LOG_DEBUG, "cleaning expired NAT-PMP mappings");*/
1080 if(CleanExpiredNATPMP() < 0) {
1081 syslog(LOG_ERR, "CleanExpiredNATPMP() failed");
1082 break;
1085 if(nextnatpmptoclean_timestamp && timeout.tv_sec >= (nextnatpmptoclean_timestamp + startup_time - timeofday.tv_sec))
1087 /*syslog(LOG_DEBUG, "setting timeout to %d sec", nextnatpmptoclean_timestamp + startup_time - timeofday.tv_sec);*/
1088 timeout.tv_sec = nextnatpmptoclean_timestamp + startup_time - timeofday.tv_sec;
1089 timeout.tv_usec = 0;
1091 #endif
1093 /* select open sockets (SSDP, HTTP listen, and all HTTP soap sockets) */
1094 FD_ZERO(&readset);
1096 if (sudp >= 0)
1098 FD_SET(sudp, &readset);
1099 max_fd = MAX( max_fd, sudp);
1102 if (shttpl >= 0)
1104 FD_SET(shttpl, &readset);
1105 max_fd = MAX( max_fd, shttpl);
1108 i = 0; /* active HTTP connections count */
1109 for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next)
1111 if((e->socket >= 0) && (e->state <= 2))
1113 FD_SET(e->socket, &readset);
1114 max_fd = MAX( max_fd, e->socket);
1115 i++;
1118 /* for debug */
1119 #ifdef DEBUG
1120 if(i > 1)
1122 syslog(LOG_DEBUG, "%d active incoming HTTP connections", i);
1124 #endif
1125 #ifdef ENABLE_NATPMP
1126 if(snatpmp >= 0) {
1127 FD_SET(snatpmp, &readset);
1128 max_fd = MAX( max_fd, snatpmp);
1130 #endif
1131 #ifdef USE_MINIUPNPDCTL
1132 if(sctl >= 0) {
1133 FD_SET(sctl, &readset);
1134 max_fd = MAX( max_fd, sctl);
1137 for(ectl = ctllisthead.lh_first; ectl; ectl = ectl->entries.le_next)
1139 if(ectl->socket >= 0) {
1140 FD_SET(ectl->socket, &readset);
1141 max_fd = MAX( max_fd, ectl->socket);
1144 #endif
1146 #ifdef ENABLE_EVENTS
1147 FD_ZERO(&writeset);
1148 upnpevents_selectfds(&readset, &writeset, &max_fd);
1149 #endif
1151 #ifdef ENABLE_EVENTS
1152 if(select(max_fd+1, &readset, &writeset, 0, &timeout) < 0)
1153 #else
1154 if(select(max_fd+1, &readset, 0, 0, &timeout) < 0)
1155 #endif
1157 if(quitting) goto shutdown;
1158 if (gotusr2) { // zzz
1159 gotusr2 = 0;
1160 tomato_helper();
1161 continue;
1163 syslog(LOG_ERR, "select(all): %m");
1164 syslog(LOG_ERR, "Failed to select open sockets. EXITING");
1165 return 1; /* very serious cause of error */
1167 #ifdef USE_MINIUPNPDCTL
1168 for(ectl = ctllisthead.lh_first; ectl;)
1170 ectlnext = ectl->entries.le_next;
1171 if((ectl->socket >= 0) && FD_ISSET(ectl->socket, &readset))
1173 char buf[256];
1174 int l;
1175 l = read(ectl->socket, buf, sizeof(buf));
1176 if(l > 0)
1178 /*write(ectl->socket, buf, l);*/
1179 write_option_list(ectl->socket);
1180 write_permlist(ectl->socket, upnppermlist, num_upnpperm);
1181 write_upnphttp_details(ectl->socket, upnphttphead.lh_first);
1182 write_ctlsockets_list(ectl->socket, ctllisthead.lh_first);
1183 write_ruleset_details(ectl->socket);
1184 #ifdef ENABLE_EVENTS
1185 write_events_details(ectl->socket);
1186 #endif
1187 /* close the socket */
1188 close(ectl->socket);
1189 ectl->socket = -1;
1191 else
1193 close(ectl->socket);
1194 ectl->socket = -1;
1197 if(ectl->socket < 0)
1199 LIST_REMOVE(ectl, entries);
1200 free(ectl);
1202 ectl = ectlnext;
1204 if((sctl >= 0) && FD_ISSET(sctl, &readset))
1206 int s;
1207 struct sockaddr_un clientname;
1208 struct ctlelem * tmp;
1209 socklen_t clientnamelen = sizeof(struct sockaddr_un);
1210 //syslog(LOG_DEBUG, "sctl!");
1211 s = accept(sctl, (struct sockaddr *)&clientname,
1212 &clientnamelen);
1213 syslog(LOG_DEBUG, "sctl! : '%s'", clientname.sun_path);
1214 tmp = malloc(sizeof(struct ctlelem));
1215 tmp->socket = s;
1216 LIST_INSERT_HEAD(&ctllisthead, tmp, entries);
1218 #endif
1219 #ifdef ENABLE_EVENTS
1220 upnpevents_processfds(&readset, &writeset);
1221 #endif
1222 #ifdef ENABLE_NATPMP
1223 /* process NAT-PMP packets */
1224 if((snatpmp >= 0) && FD_ISSET(snatpmp, &readset))
1226 ProcessIncomingNATPMPPacket(snatpmp);
1228 #endif
1229 /* process SSDP packets */
1230 if(sudp >= 0 && FD_ISSET(sudp, &readset))
1232 /*syslog(LOG_INFO, "Received UDP Packet");*/
1233 ProcessSSDPRequest(sudp, (unsigned short)v.port);
1235 /* process active HTTP connections */
1236 /* LIST_FOREACH macro is not available under linux */
1237 for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next)
1239 if( (e->socket >= 0) && (e->state <= 2)
1240 &&(FD_ISSET(e->socket, &readset)) )
1242 Process_upnphttp(e);
1245 /* process incoming HTTP connections */
1246 if(shttpl >= 0 && FD_ISSET(shttpl, &readset))
1248 int shttp;
1249 socklen_t clientnamelen;
1250 struct sockaddr_in clientname;
1251 clientnamelen = sizeof(struct sockaddr_in);
1252 shttp = accept(shttpl, (struct sockaddr *)&clientname, &clientnamelen);
1253 if(shttp<0)
1255 syslog(LOG_ERR, "accept(http): %m");
1257 else
1259 struct upnphttp * tmp = 0;
1260 syslog(LOG_INFO, "HTTP connection from %s:%d",
1261 inet_ntoa(clientname.sin_addr),
1262 ntohs(clientname.sin_port) );
1263 /*if (fcntl(shttp, F_SETFL, O_NONBLOCK) < 0) {
1264 syslog(LOG_ERR, "fcntl F_SETFL, O_NONBLOCK");
1266 /* Create a new upnphttp object and add it to
1267 * the active upnphttp object list */
1268 tmp = New_upnphttp(shttp);
1269 if(tmp)
1271 tmp->clientaddr = clientname.sin_addr;
1272 LIST_INSERT_HEAD(&upnphttphead, tmp, entries);
1274 else
1276 syslog(LOG_ERR, "New_upnphttp() failed");
1277 close(shttp);
1281 /* delete finished HTTP connections */
1282 for(e = upnphttphead.lh_first; e != NULL; )
1284 next = e->entries.le_next;
1285 if(e->state >= 100)
1287 LIST_REMOVE(e, entries);
1288 Delete_upnphttp(e);
1290 e = next;
1294 shutdown:
1295 tomato_save("/etc/upnp/data"); // zzz
1297 /* close out open sockets */
1298 while(upnphttphead.lh_first != NULL)
1300 e = upnphttphead.lh_first;
1301 LIST_REMOVE(e, entries);
1302 Delete_upnphttp(e);
1305 if (sudp >= 0) close(sudp);
1306 if (shttpl >= 0) close(shttpl);
1307 #ifdef ENABLE_NATPMP
1308 if(snatpmp>=0)
1310 close(snatpmp);
1311 snatpmp = -1;
1313 #endif
1314 #ifdef USE_MINIUPNPDCTL
1315 if(sctl>=0)
1317 close(sctl);
1318 sctl = -1;
1319 if(unlink("/var/run/miniupnpd.ctl") < 0)
1321 syslog(LOG_ERR, "unlink() %m");
1324 #endif
1326 /*if(SendSSDPGoodbye(snotify, v.n_lan_addr) < 0)*/
1327 if (GETFLAG(ENABLEUPNPMASK))
1329 if(SendSSDPGoodbye(snotify, n_lan_addr) < 0)
1331 syslog(LOG_ERR, "Failed to broadcast good-bye notifications");
1333 for(i=0; i<n_lan_addr; i++)/* for(i=0; i<v.n_lan_addr; i++)*/
1334 close(snotify[i]);
1337 if(unlink(pidfilename) < 0)
1339 syslog(LOG_ERR, "Failed to remove pidfile %s: %m", pidfilename);
1342 closelog();
1343 freeoptions();
1345 return 0;