OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / user / miniupnpd / miniupnpd.c
1 /* $Id: miniupnpd.c,v 1.1 2008-09-15 12:28:52 winfred 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 */
7
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
30
31 /* unix sockets */
32 #include "config.h"
33 #ifdef USE_MINIUPNPDCTL
34 #include <sys/un.h>
35 #endif
36
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"
53
54 #ifdef USE_MINIUPNPDCTL
55 struct ctlelem {
56         int socket;
57         LIST_ENTRY(ctlelem) entries;
58 };
59 #endif
60
61 /* MAX_LAN_ADDR : maximum number of interfaces
62  * to listen to SSDP traffic */
63 /*#define MAX_LAN_ADDR (4)*/
64
65 static volatile int quitting = 0;
66
67 /* OpenAndConfHTTPSocket() :
68  * setup the socket used to handle incoming HTTP connections. */
69 static int
70 OpenAndConfHTTPSocket(unsigned short port)
71 {
72         int s;
73         int i = 1;
74         struct sockaddr_in listenname;
75
76         if( (s = socket(PF_INET, SOCK_STREAM, 0)) < 0)
77         {
78                 syslog(LOG_ERR, "socket(http): %m");
79                 return -1;
80         }
81
82         if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0)
83         {
84                 syslog(LOG_WARNING, "setsockopt(http, SO_REUSEADDR): %m");
85         }
86
87         memset(&listenname, 0, sizeof(struct sockaddr_in));
88         listenname.sin_family = AF_INET;
89         listenname.sin_port = htons(port);
90         listenname.sin_addr.s_addr = htonl(INADDR_ANY);
91
92         if(bind(s, (struct sockaddr *)&listenname, sizeof(struct sockaddr_in)) < 0)
93         {
94                 syslog(LOG_ERR, "bind(http): %m");
95                 close(s);
96                 return -1;
97         }
98
99         if(listen(s, 6) < 0)
100         {
101                 syslog(LOG_ERR, "listen(http): %m");
102                 close(s);
103                 return -1;
104         }
105
106         return s;
107 }
108
109 /* Functions used to communicate with miniupnpdctl */
110 #ifdef USE_MINIUPNPDCTL
111 static int
112 OpenAndConfCtlUnixSocket(const char * path)
113 {
114         struct sockaddr_un localun;
115         int s;
116         s = socket(AF_UNIX, SOCK_STREAM, 0);
117         localun.sun_family = AF_UNIX;
118         strncpy(localun.sun_path, path,
119                   sizeof(localun.sun_path));
120         if(bind(s, (struct sockaddr *)&localun,
121                 sizeof(struct sockaddr_un)) < 0)
122         {
123                 syslog(LOG_ERR, "bind(sctl): %m");
124                 close(s);
125                 s = -1;
126         }
127         else if(listen(s, 5) < 0)
128         {
129                 syslog(LOG_ERR, "listen(sctl): %m");
130                 close(s);
131                 s = -1;
132         }
133         return s;
134 }
135
136 static void
137 write_upnphttp_details(int fd, struct upnphttp * e)
138 {
139         char buffer[256];
140         int len;
141         while(e)
142         {
143                 len = snprintf(buffer, sizeof(buffer),
144                                "%d %d %s req_buf=%p(%dbytes) res_buf=%p(%dbytes alloc)\n",
145                                e->socket, e->state, e->HttpVer,
146                                e->req_buf, e->req_buflen,
147                                e->res_buf, e->res_buf_alloclen);
148                 write(fd, buffer, len);
149                 e = e->entries.le_next;
150         }
151 }
152
153 static void
154 write_ctlsockets_list(int fd, struct ctlelem * e)
155 {
156         char buffer[256];
157         int len;
158         while(e)
159         {
160                 len = snprintf(buffer, sizeof(buffer),
161                                "struct ctlelem: socket=%d\n", e->socket);
162                 write(fd, buffer, len);
163                 e = e->entries.le_next;
164         }
165 }
166
167 static void
168 write_option_list(int fd)
169 {
170         char buffer[256];
171         int len;
172         int i;
173         for(i=0; i<num_options; i++)
174         {
175                 len = snprintf(buffer, sizeof(buffer),
176                                "opt=%02d %s\n",
177                                ary_options[i].id, ary_options[i].value);
178                 write(fd, buffer, len);
179         }
180 }
181
182 #endif
183
184 /* Handler for the SIGTERM signal (kill) 
185  * SIGINT is also handled */
186 static void
187 sigterm(int sig)
188 {
189         /*int save_errno = errno;*/
190         signal(sig, SIG_IGN);   /* Ignore this signal while we are quitting */
191
192         syslog(LOG_NOTICE, "received signal %d, good-bye", sig);
193
194         quitting = 1;
195         /*errno = save_errno;*/
196 }
197
198 /* record the startup time, for returning uptime */
199 static void
200 set_startup_time(int sysuptime)
201 {
202         startup_time = time(NULL);
203         if(sysuptime)
204         {
205                 /* use system uptime instead of daemon uptime */
206 #if defined(__linux__)
207                 char buff[64];
208                 int uptime, fd;
209                 fd = open("/proc/uptime", O_RDONLY);
210                 if(fd < 0)
211                 {
212                         syslog(LOG_ERR, "open(\"/proc/uptime\" : %m");
213                 }
214                 else
215                 {
216                         memset(buff, 0, sizeof(buff));
217                         read(fd, buff, sizeof(buff) - 1);
218                         uptime = atoi(buff);
219                         syslog(LOG_INFO, "system uptime is %d seconds", uptime);
220                         close(fd);
221                         startup_time -= uptime;
222                 }
223 #elif defined(SOLARIS_KSTATS)
224                 kstat_ctl_t *kc;
225                 kc = kstat_open();
226                 if(kc != NULL)
227                 {
228                         kstat_t *ksp;
229                         ksp = kstat_lookup(kc, "unix", 0, "system_misc");
230                         if(ksp && (kstat_read(kc, ksp, NULL) != -1))
231                         {
232                                 void *ptr = kstat_data_lookup(ksp, "boot_time");
233                                 if(ptr)
234                                         memcpy(&startup_time, ptr, sizeof(startup_time));
235                                 else
236                                         syslog(LOG_ERR, "cannot find boot_time kstat");
237                         }
238                         else
239                                 syslog(LOG_ERR, "cannot open kstats for unix/0/system_misc: %m");
240                         kstat_close(kc);
241                 }
242 #else
243                 struct timeval boottime;
244                 size_t size = sizeof(boottime);
245                 int name[2] = { CTL_KERN, KERN_BOOTTIME };
246                 if(sysctl(name, 2, &boottime, &size, NULL, 0) < 0)
247                 {
248                         syslog(LOG_ERR, "sysctl(\"kern.boottime\") failed");
249                 }
250                 else
251                 {
252                         startup_time = boottime.tv_sec;
253                 }
254 #endif
255         }
256 }
257
258 /* structure containing variables used during "main loop"
259  * that are filled during the init */
260 struct runtime_vars {
261         /* LAN IP addresses for SSDP traffic and HTTP */
262         /* moved to global vars */
263         /*int n_lan_addr;*/
264         /*struct lan_addr_s lan_addr[MAX_LAN_ADDR];*/
265         int port;       /* HTTP Port */
266         int notify_interval;    /* seconds between SSDP announces */
267         /* unused rules cleaning related variables : */
268         int clean_ruleset_threshold;    /* threshold for removing unused rules */
269         int clean_ruleset_interval;             /* (minimum) interval between checks */
270 };
271
272 /* parselanaddr()
273  * parse address with mask
274  * ex: 192.168.1.1/24
275  * return value : 
276  *    0 : ok
277  *   -1 : error */
278 static int
279 parselanaddr(struct lan_addr_s * lan_addr, const char * str)
280 {
281         const char * p;
282         int nbits = 24;
283         int n;
284         p = str;
285         while(*p && *p != '/' && !isspace(*p))
286                 p++;
287         n = p - str;
288         if(*p == '/')
289         {
290                 nbits = atoi(++p);
291                 while(*p && !isspace(*p))
292                         p++;
293         }
294         if(n>15)
295         {
296                 fprintf(stderr, "Error parsing address/mask : %s\n", str);
297                 return -1;
298         }
299         memcpy(lan_addr->str, str, n);
300         lan_addr->str[n] = '\0';
301         if(!inet_aton(lan_addr->str, &lan_addr->addr))
302         {
303                 fprintf(stderr, "Error parsing address/mask : %s\n", str);
304                 return -1;
305         }
306         lan_addr->mask.s_addr = htonl(nbits ? (0xffffffff << (32 - nbits)) : 0);
307 #ifdef MULTIPLE_EXTERNAL_IP
308         while(*p && isspace(*p))
309                 p++;
310         if(*p) {
311                 n = 0;
312                 while(p[n] && !isspace(*p))
313                         n++;
314                 if(n<=15) {
315                         memcpy(lan_addr->ext_ip_str, p, n);
316                         lan_addr->ext_ip_str[n] = '\0';
317                         if(!inet_aton(lan_addr->ext_ip_str, &lan_addr->ext_ip_addr)) {
318                                 /* error */
319                                 fprintf(stderr, "Error parsing address : %s\n", lan_addr->ext_ip_str);
320                         }
321                 }
322         }
323 #endif
324         return 0;
325 }
326
327 /* init phase :
328  * 1) read configuration file
329  * 2) read command line arguments
330  * 3) daemonize
331  * 4) open syslog
332  * 5) check and write pid file
333  * 6) set startup time stamp
334  * 7) compute presentation URL
335  * 8) set signal handlers */
336 static int
337 init(int argc, char * * argv, struct runtime_vars * v)
338 {
339         int i;
340         int pid;
341         int debug_flag = 0;
342         int options_flag = 0;
343         int openlog_option;
344         struct sigaction sa;
345         /*const char * logfilename = 0;*/
346         const char * presurl = 0;
347         const char * optionsfile = "/etc/miniupnpd.conf";
348
349         /* first check if "-f" option is used */
350         for(i=2; i<argc; i++)
351         {
352                 if(0 == strcmp(argv[i-1], "-f"))
353                 {
354                         optionsfile = argv[i];
355                         options_flag = 1;
356                         break;
357                 }
358         }
359
360         /* set initial values */
361         SETFLAG(ENABLEUPNPMASK);
362
363         /*v->n_lan_addr = 0;*/
364         v->port = -1;
365         v->notify_interval = 30;        /* seconds between SSDP announces */
366         v->clean_ruleset_threshold = 20;
367         v->clean_ruleset_interval = 0;  /* interval between ruleset check. 0=disabled */
368
369         /* read options file first since
370          * command line arguments have final say */
371         if(readoptionsfile(optionsfile) < 0)
372         {
373                 /* only error if file exists or using -f */
374                 if(access(optionsfile, F_OK) == 0 || options_flag)
375                         fprintf(stderr, "Error reading configuration file %s\n", optionsfile);
376         }
377         else
378         {
379                 for(i=0; i<num_options; i++)
380                 {
381                         switch(ary_options[i].id)
382                         {
383                         case UPNPEXT_IFNAME:
384                                 ext_if_name = ary_options[i].value;
385                                 break;
386                         case UPNPEXT_IP:
387                                 use_ext_ip_addr = ary_options[i].value;
388                                 break;
389                         case UPNPLISTENING_IP:
390                                 if(n_lan_addr < MAX_LAN_ADDR)/* if(v->n_lan_addr < MAX_LAN_ADDR)*/
391                                 {
392                                         /*if(parselanaddr(&v->lan_addr[v->n_lan_addr],*/
393                                         if(parselanaddr(&lan_addr[n_lan_addr],
394                                                      ary_options[i].value) == 0)
395                                                 n_lan_addr++; /*v->n_lan_addr++; */
396                                 }
397                                 else
398                                 {
399                                         fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n",
400                                             MAX_LAN_ADDR, ary_options[i].value);
401                                 }
402                                 break;
403                         case UPNPPORT:
404                                 v->port = atoi(ary_options[i].value);
405                                 break;
406                         case UPNPBITRATE_UP:
407                                 upstream_bitrate = strtoul(ary_options[i].value, 0, 0);
408                                 break;
409                         case UPNPBITRATE_DOWN:
410                                 downstream_bitrate = strtoul(ary_options[i].value, 0, 0);
411                                 break;
412                         case UPNPPRESENTATIONURL:
413                                 presurl = ary_options[i].value;
414                                 break;
415                         case UPNPNOTIFY_INTERVAL:
416                                 v->notify_interval = atoi(ary_options[i].value);
417                                 break;
418                         case UPNPSYSTEM_UPTIME:
419                                 if(strcmp(ary_options[i].value, "yes") == 0)
420                                         SETFLAG(SYSUPTIMEMASK); /*sysuptime = 1;*/
421                                 break;
422                         case UPNPPACKET_LOG:
423                                 if(strcmp(ary_options[i].value, "yes") == 0)
424                                         SETFLAG(LOGPACKETSMASK);        /*logpackets = 1;*/
425                                 break;
426                         case UPNPUUID:
427                                 strncpy(uuidvalue+5, ary_options[i].value,
428                                         strlen(uuidvalue+5) + 1);
429                                 break;
430                         case UPNPSERIAL:
431                                 strncpy(serialnumber, ary_options[i].value, SERIALNUMBER_MAX_LEN);
432                                 serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0';
433                                 break;                          
434                         case UPNPMODEL_NUMBER:
435                                 strncpy(modelnumber, ary_options[i].value, MODELNUMBER_MAX_LEN);
436                                 modelnumber[MODELNUMBER_MAX_LEN-1] = '\0';
437                                 break;
438                         case UPNPCLEANTHRESHOLD:
439                                 v->clean_ruleset_threshold = atoi(ary_options[i].value);
440                                 break;
441                         case UPNPCLEANINTERVAL:
442                                 v->clean_ruleset_interval = atoi(ary_options[i].value);
443                                 break;
444 #ifdef USE_PF
445                         case UPNPQUEUE:
446                                 queue = ary_options[i].value;
447                                 break;
448                         case UPNPTAG:
449                                 tag = ary_options[i].value;
450                                 break;
451 #endif
452 #ifdef ENABLE_NATPMP
453                         case UPNPENABLENATPMP:
454                                 if(strcmp(ary_options[i].value, "yes") == 0)
455                                         SETFLAG(ENABLENATPMPMASK);      /*enablenatpmp = 1;*/
456                                 else
457                                         if(atoi(ary_options[i].value))
458                                                 SETFLAG(ENABLENATPMPMASK);
459                                         /*enablenatpmp = atoi(ary_options[i].value);*/
460                                 break;
461 #endif
462 #ifdef PF_ENABLE_FILTER_RULES
463                         case UPNPQUICKRULES:
464                                 if(strcmp(ary_options[i].value, "no") == 0)
465                                         SETFLAG(PFNOQUICKRULESMASK);
466                                 break;
467 #endif
468                         case UPNPENABLE:
469                                 if(strcmp(ary_options[i].value, "yes") != 0)
470                                         CLEARFLAG(ENABLEUPNPMASK);
471                                 break;
472                         case UPNPSECUREMODE:
473                                 if(strcmp(ary_options[i].value, "yes") == 0)
474                                         SETFLAG(SECUREMODEMASK);
475                                 break;
476 #ifdef ENABLE_LEASEFILE
477                         case UPNPLEASEFILE:
478                                 lease_file = ary_options[i].value;
479                                 remove(lease_file);
480                                 break;
481 #endif
482                         default:
483                                 fprintf(stderr, "Unknown option in file %s\n",
484                                         optionsfile);
485                         }
486                 }
487         }
488
489         /* command line arguments processing */
490         for(i=1; i<argc; i++)
491         {
492                 if(argv[i][0]!='-')
493                 {
494                         fprintf(stderr, "Unknown option: %s\n", argv[i]);
495                 }
496                 else switch(argv[i][1])
497                 {
498                 case 'o':
499                         if(i+1 < argc)
500                                 use_ext_ip_addr = argv[++i];
501                         else
502                                 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
503                         break;
504                 case 't':
505                         if(i+1 < argc)
506                                 v->notify_interval = atoi(argv[++i]);
507                         else
508                                 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
509                         break;
510                 case 'u':
511                         if(i+1 < argc)
512                                 strncpy(uuidvalue+5, argv[++i], strlen(uuidvalue+5) + 1);
513                         else
514                                 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
515                         break;
516                 case 's':
517                         if(i+1 < argc)
518                                 strncpy(serialnumber, argv[++i], SERIALNUMBER_MAX_LEN);
519                         else
520                                 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
521                         serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0';
522                         break;
523                 case 'm':
524                         if(i+1 < argc)
525                                 strncpy(modelnumber, argv[++i], MODELNUMBER_MAX_LEN);
526                         else
527                                 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
528                         modelnumber[MODELNUMBER_MAX_LEN-1] = '\0';
529                         break;
530 #ifdef ENABLE_NATPMP
531                 case 'N':
532                         /*enablenatpmp = 1;*/
533                         SETFLAG(ENABLENATPMPMASK);
534                         break;
535 #endif
536                 case 'U':
537                         /*sysuptime = 1;*/
538                         SETFLAG(SYSUPTIMEMASK);
539                         break;
540                 /*case 'l':
541                         logfilename = argv[++i];
542                         break;*/
543                 case 'L':
544                         /*logpackets = 1;*/
545                         SETFLAG(LOGPACKETSMASK);
546                         break;
547                 case 'S':
548                         SETFLAG(SECUREMODEMASK);
549                         break;
550                 case 'i':
551                         if(i+1 < argc)
552                                 ext_if_name = argv[++i];
553                         else
554                                 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
555                         break;
556 #ifdef USE_PF
557                 case 'q':
558                         if(i+1 < argc)
559                                 queue = argv[++i];
560                         else
561                                 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
562                         break;
563                 case 'T':
564                         if(i+1 < argc)
565                                 tag = argv[++i];
566                         else
567                                 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
568                         break;
569 #endif
570                 case 'p':
571                         if(i+1 < argc)
572                                 v->port = atoi(argv[++i]);
573                         else
574                                 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
575                         break;
576                 case 'P':
577                         if(i+1 < argc)
578                                 pidfilename = argv[++i];
579                         else
580                                 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
581                         break;
582                 case 'd':
583                         debug_flag = 1;
584                         break;
585                 case 'w':
586                         if(i+1 < argc)
587                                 presurl = argv[++i];
588                         else
589                                 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
590                         break;
591                 case 'B':
592                         if(i+2<argc)
593                         {
594                                 downstream_bitrate = strtoul(argv[++i], 0, 0);
595                                 upstream_bitrate = strtoul(argv[++i], 0, 0);
596                         }
597                         else
598                                 fprintf(stderr, "Option -%c takes two arguments.\n", argv[i][1]);
599                         break;
600                 case 'a':
601                         if(i+1 < argc)
602                         {
603                                 int address_already_there = 0;
604                                 int j;
605                                 i++;
606                                 for(j=0; j<n_lan_addr; j++)/* for(j=0; j<v->n_lan_addr; j++)*/
607                                 {
608                                         struct lan_addr_s tmpaddr;
609                                         parselanaddr(&tmpaddr, argv[i]);
610                                         /*if(0 == strcmp(v->lan_addr[j].str, tmpaddr.str))*/
611                                         if(0 == strcmp(lan_addr[j].str, tmpaddr.str))
612                                                 address_already_there = 1;
613                                 }
614                                 if(address_already_there)
615                                         break;
616                                 if(n_lan_addr < MAX_LAN_ADDR) /*if(v->n_lan_addr < MAX_LAN_ADDR)*/
617                                 {
618                                         /*v->lan_addr[v->n_lan_addr++] = argv[i];*/
619                                         /*if(parselanaddr(&v->lan_addr[v->n_lan_addr], argv[i]) == 0)*/
620                                         if(parselanaddr(&lan_addr[n_lan_addr], argv[i]) == 0)
621                                                 n_lan_addr++; /*v->n_lan_addr++;*/
622                                 }
623                                 else
624                                 {
625                                         fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n",
626                                             MAX_LAN_ADDR, argv[i]);
627                                 }
628                         }
629                         else
630                                 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
631                         break;
632                 case 'f':
633                         i++;    /* discarding, the config file is already read */
634                         break;
635                 default:
636                         fprintf(stderr, "Unknown option: %s\n", argv[i]);
637                 }
638         }
639         if(!ext_if_name || (/*v->*/n_lan_addr==0) || v->port<=0)
640         {
641                 fprintf(stderr, "Usage:\n\t"
642                         "%s [-f config_file] [-i ext_ifname] [-o ext_ip]\n"
643 #ifndef ENABLE_NATPMP
644                                 "\t\t[-a listening_ip] [-p port] [-d] [-L] [-U] [-S]\n"
645 #else
646                                 "\t\t[-a listening_ip] [-p port] [-d] [-L] [-U] [-S] [-N]\n"
647 #endif
648                                 /*"[-l logfile] " not functionnal */
649                                 "\t\t[-u uuid] [-s serial] [-m model_number] \n"
650                                 "\t\t[-t notify_interval] [-P pid_filename]\n"
651 #ifdef USE_PF
652                                 "\t\t[-B down up] [-w url] [-q queue] [-T tag]\n"
653 #else
654                                 "\t\t[-B down up] [-w url]\n"
655 #endif
656                         "\nNotes:\n\tThere can be one or several listening_ips.\n"
657                         "\tNotify interval is in seconds. Default is 30 seconds.\n"
658                                 "\tDefault pid file is %s.\n"
659                                 "\tWith -d miniupnpd will run as a standard program.\n"
660                                 "\t-L sets packet log in pf and ipf on.\n"
661                                 "\t-S sets \"secure\" mode : clients can only add mappings to their own ip\n"
662                                 "\t-U causes miniupnpd to report system uptime instead "
663                                 "of daemon uptime.\n"
664                                 "\t-B sets bitrates reported by daemon in bits per second.\n"
665                                 "\t-w sets the presentation url. Default is http address on port 80\n"
666 #ifdef USE_PF
667                                 "\t-q sets the ALTQ queue in pf.\n"
668                                 "\t-T sets the tag name in pf.\n"
669 #endif
670                         "", argv[0], pidfilename);
671                 return 1;
672         }
673
674         if(debug_flag)
675         {
676                 pid = getpid();
677         }
678         else
679         {
680 #ifdef USE_DAEMON
681                 if(daemon(0, 0)<0) {
682                         perror("daemon()");
683                 }
684                 pid = getpid();
685 #else
686                 pid = daemonize();
687 #endif
688         }
689
690         openlog_option = LOG_PID|LOG_CONS;
691         if(debug_flag)
692         {
693                 openlog_option |= LOG_PERROR;   /* also log on stderr */
694         }
695
696         openlog("miniupnpd", openlog_option, LOG_MINIUPNPD);
697
698         if(!debug_flag)
699         {
700                 /* speed things up and ignore LOG_INFO and LOG_DEBUG */
701                 setlogmask(LOG_UPTO(LOG_NOTICE));
702         }
703
704         if(checkforrunning(pidfilename) < 0)
705         {
706                 syslog(LOG_ERR, "MiniUPnPd is already running. EXITING");
707                 return 1;
708         }       
709
710         set_startup_time(GETFLAG(SYSUPTIMEMASK)/*sysuptime*/);
711
712         /* presentation url */
713         if(presurl)
714         {
715                 strncpy(presentationurl, presurl, PRESENTATIONURL_MAX_LEN);
716                 presentationurl[PRESENTATIONURL_MAX_LEN-1] = '\0';
717         }
718         else
719         {
720                 snprintf(presentationurl, PRESENTATIONURL_MAX_LEN,
721                          "http://%s/", lan_addr[0].str);
722                          /*"http://%s:%d/", lan_addr[0].str, 80);*/
723                          /*"http://%s:%d/", v->lan_addr[0].str, 80);*/
724         }
725
726         /* set signal handler */
727         memset(&sa, 0, sizeof(struct sigaction));
728         sa.sa_handler = sigterm;
729
730         if (sigaction(SIGTERM, &sa, NULL))
731         {
732                 syslog(LOG_ERR, "Failed to set %s handler. EXITING", "SIGTERM");
733                 return 1;
734         }
735         if (sigaction(SIGINT, &sa, NULL))
736         {
737                 syslog(LOG_ERR, "Failed to set %s handler. EXITING", "SIGINT");
738                 return 1;
739         }
740
741         if(signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
742                 syslog(LOG_ERR, "Failed to ignore SIGPIPE signals");
743         }
744
745         if(init_redirect() < 0)
746         {
747                 syslog(LOG_ERR, "Failed to init redirection engine. EXITING");
748                 return 1;
749         }
750
751         writepidfile(pidfilename, pid);
752
753         return 0;
754 }
755
756 /* === main === */
757 /* process HTTP or SSDP requests */
758 int
759 main(int argc, char * * argv)
760 {
761         int i;
762         int sudp = -1, shttpl = -1;
763 #ifdef ENABLE_NATPMP
764         int snatpmp = -1;
765 #endif
766         int snotify[MAX_LAN_ADDR];
767         LIST_HEAD(httplisthead, upnphttp) upnphttphead;
768         struct upnphttp * e = 0;
769         struct upnphttp * next;
770         fd_set readset; /* for select() */
771 #ifdef ENABLE_EVENTS
772         fd_set writeset;
773 #endif
774         struct timeval timeout, timeofday, lasttimeofday = {0, 0};
775         int max_fd = -1;
776 #ifdef USE_MINIUPNPDCTL
777         int sctl = -1;
778         LIST_HEAD(ctlstructhead, ctlelem) ctllisthead;
779         struct ctlelem * ectl;
780         struct ctlelem * ectlnext;
781 #endif
782         struct runtime_vars v;
783         /* variables used for the unused-rule cleanup process */
784         struct rule_state * rule_list = 0;
785         struct timeval checktime = {0, 0};
786
787         if(init(argc, argv, &v) != 0)
788                 return 1;
789
790         LIST_INIT(&upnphttphead);
791 #ifdef USE_MINIUPNPDCTL
792         LIST_INIT(&ctllisthead);
793 #endif
794
795         if(
796 #ifdef ENABLE_NATPMP
797         !GETFLAG(ENABLENATPMPMASK) &&
798 #endif
799         !GETFLAG(ENABLEUPNPMASK) ) {
800                 syslog(LOG_ERR, "Why did you run me anyway?");
801                 return 0;
802         }
803
804         if(GETFLAG(ENABLEUPNPMASK)/*enableupnp*/)
805         {
806
807                 /* open socket for SSDP connections */
808                 /*sudp = OpenAndConfSSDPReceiveSocket(v.n_lan_addr, v.lan_addr);*/
809                 sudp = OpenAndConfSSDPReceiveSocket(n_lan_addr, lan_addr);
810                 if(sudp < 0)
811                 {
812                         syslog(LOG_ERR, "Failed to open socket for receiving SSDP. EXITING");
813                         return 1;
814                 }
815                 /* open socket for HTTP connections. Listen on the 1st LAN address */
816                 shttpl = OpenAndConfHTTPSocket(v.port);
817                 if(shttpl < 0)
818                 {
819                         syslog(LOG_ERR, "Failed to open socket for HTTP. EXITING");
820                         return 1;
821                 }
822                 syslog(LOG_NOTICE, "HTTP listening on port %d", v.port);
823
824                 /* open socket for sending notifications */
825                 if(OpenAndConfSSDPNotifySockets(snotify) < 0)
826                 {
827                         syslog(LOG_ERR, "Failed to open sockets for sending SSDP notify "
828                                 "messages. EXITING");
829                         return 1;
830                 }
831         }
832
833 #ifdef ENABLE_NATPMP
834         /* open socket for NAT PMP traffic */
835         if(GETFLAG(ENABLENATPMPMASK))
836         {
837                 snatpmp = OpenAndConfNATPMPSocket();
838                 if(snatpmp < 0)
839                 {
840                         syslog(LOG_ERR, "Failed to open socket for NAT PMP.");
841                         /*syslog(LOG_ERR, "Failed to open socket for NAT PMP. EXITING");
842                         return 1;*/
843                 } else {
844                         syslog(LOG_NOTICE, "Listening for NAT-PMP traffic on port %u",
845                                NATPMP_PORT);
846                 }
847                 ScanNATPMPforExpiration();
848         }
849 #endif
850
851         /* for miniupnpdctl */
852 #ifdef USE_MINIUPNPDCTL
853         sctl = OpenAndConfCtlUnixSocket("/var/run/miniupnpd.ctl");
854 #endif
855
856         /* main loop */
857         while(!quitting)
858         {
859                 /* Check if we need to send SSDP NOTIFY messages and do it if
860                  * needed */
861                 if(gettimeofday(&timeofday, 0) < 0)
862                 {
863                         syslog(LOG_ERR, "gettimeofday(): %m");
864                         timeout.tv_sec = v.notify_interval;
865                         timeout.tv_usec = 0;
866                 }
867                 else
868                 {
869                         /* the comparaison is not very precise but who cares ? */
870                         if(timeofday.tv_sec >= (lasttimeofday.tv_sec + v.notify_interval))
871                         {
872                                 if (GETFLAG(ENABLEUPNPMASK))
873                                         SendSSDPNotifies2(snotify,
874                                                   (unsigned short)v.port,
875                                                   v.notify_interval << 1);
876                                 memcpy(&lasttimeofday, &timeofday, sizeof(struct timeval));
877                                 timeout.tv_sec = v.notify_interval;
878                                 timeout.tv_usec = 0;
879                         }
880                         else
881                         {
882                                 timeout.tv_sec = lasttimeofday.tv_sec + v.notify_interval
883                                                  - timeofday.tv_sec;
884                                 if(timeofday.tv_usec > lasttimeofday.tv_usec)
885                                 {
886                                         timeout.tv_usec = 1000000 + lasttimeofday.tv_usec
887                                                           - timeofday.tv_usec;
888                                         timeout.tv_sec--;
889                                 }
890                                 else
891                                 {
892                                         timeout.tv_usec = lasttimeofday.tv_usec - timeofday.tv_usec;
893                                 }
894                         }
895                 }
896                 /* remove unused rules */
897                 if( v.clean_ruleset_interval
898                   && (timeofday.tv_sec >= checktime.tv_sec + v.clean_ruleset_interval))
899                 {
900                         if(rule_list)
901                         {
902                                 remove_unused_rules(rule_list);
903                                 rule_list = NULL;
904                         }
905                         else
906                         {
907                                 rule_list = get_upnp_rules_state_list(v.clean_ruleset_threshold);
908                         }
909                         memcpy(&checktime, &timeofday, sizeof(struct timeval));
910                 }
911 #ifdef ENABLE_NATPMP
912                 /* Remove expired NAT-PMP mappings */
913                 while( nextnatpmptoclean_timestamp && (timeofday.tv_sec >= nextnatpmptoclean_timestamp + startup_time))
914                 {
915                         /*syslog(LOG_DEBUG, "cleaning expired NAT-PMP mappings");*/
916                         if(CleanExpiredNATPMP() < 0) {
917                                 syslog(LOG_ERR, "CleanExpiredNATPMP() failed");
918                                 break;
919                         }
920                 }
921                 if(nextnatpmptoclean_timestamp && timeout.tv_sec >= (nextnatpmptoclean_timestamp + startup_time - timeofday.tv_sec))
922                 {
923                         /*syslog(LOG_DEBUG, "setting timeout to %d sec", nextnatpmptoclean_timestamp + startup_time - timeofday.tv_sec);*/
924                         timeout.tv_sec = nextnatpmptoclean_timestamp + startup_time - timeofday.tv_sec;
925                         timeout.tv_usec = 0;
926                 }
927 #endif
928
929                 /* select open sockets (SSDP, HTTP listen, and all HTTP soap sockets) */
930                 FD_ZERO(&readset);
931
932                 if (sudp >= 0) 
933                 {
934                         FD_SET(sudp, &readset);
935                         max_fd = MAX( max_fd, sudp);
936                 }
937                 
938                 if (shttpl >= 0) 
939                 {
940                         FD_SET(shttpl, &readset);
941                         max_fd = MAX( max_fd, shttpl);
942                 }
943
944                 i = 0;  /* active HTTP connections count */
945                 for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next)
946                 {
947                         if((e->socket >= 0) && (e->state <= 2))
948                         {
949                                 FD_SET(e->socket, &readset);
950                                 max_fd = MAX( max_fd, e->socket);
951                                 i++;
952                         }
953                 }
954                 /* for debug */
955 #ifdef DEBUG
956                 if(i > 1)
957                 {
958                         syslog(LOG_DEBUG, "%d active incoming HTTP connections", i);
959                 }
960 #endif
961 #ifdef ENABLE_NATPMP
962                 if(snatpmp >= 0) {
963                         FD_SET(snatpmp, &readset);
964                         max_fd = MAX( max_fd, snatpmp);
965                 }
966 #endif
967 #ifdef USE_MINIUPNPDCTL
968                 if(sctl >= 0) {
969                         FD_SET(sctl, &readset);
970                         max_fd = MAX( max_fd, sctl);
971                 }
972                 
973                 for(ectl = ctllisthead.lh_first; ectl; ectl = ectl->entries.le_next)
974                 {
975                         if(ectl->socket >= 0) {
976                                 FD_SET(ectl->socket, &readset);
977                                 max_fd = MAX( max_fd, ectl->socket);
978                         }
979                 }
980 #endif
981
982 #ifdef ENABLE_EVENTS
983                 FD_ZERO(&writeset);
984                 upnpevents_selectfds(&readset, &writeset, &max_fd);
985 #endif
986
987 #ifdef ENABLE_EVENTS
988                 if(select(max_fd+1, &readset, &writeset, 0, &timeout) < 0)
989 #else
990                 if(select(max_fd+1, &readset, 0, 0, &timeout) < 0)
991 #endif
992                 {
993                         if(quitting) goto shutdown;
994                         syslog(LOG_ERR, "select(all): %m");
995                         syslog(LOG_ERR, "Failed to select open sockets. EXITING");
996                         return 1;       /* very serious cause of error */
997                 }
998 #ifdef USE_MINIUPNPDCTL
999                 for(ectl = ctllisthead.lh_first; ectl;)
1000                 {
1001                         ectlnext =  ectl->entries.le_next;
1002                         if((ectl->socket >= 0) && FD_ISSET(ectl->socket, &readset))
1003                         {
1004                                 char buf[256];
1005                                 int l;
1006                                 l = read(ectl->socket, buf, sizeof(buf));
1007                                 if(l > 0)
1008                                 {
1009                                         /*write(ectl->socket, buf, l);*/
1010                                         write_option_list(ectl->socket);
1011                                         write_permlist(ectl->socket, upnppermlist, num_upnpperm);
1012                                         write_upnphttp_details(ectl->socket, upnphttphead.lh_first);
1013                                         write_ctlsockets_list(ectl->socket, ctllisthead.lh_first);
1014                                         write_ruleset_details(ectl->socket);
1015 #ifdef ENABLE_EVENTS
1016                                         write_events_details(ectl->socket);
1017 #endif
1018                                         /* close the socket */
1019                                         close(ectl->socket);
1020                                         ectl->socket = -1;
1021                                 }
1022                                 else
1023                                 {
1024                                         close(ectl->socket);
1025                                         ectl->socket = -1;
1026                                 }
1027                         }
1028                         if(ectl->socket < 0)
1029                         {
1030                                 LIST_REMOVE(ectl, entries);
1031                                 free(ectl);
1032                         }
1033                         ectl = ectlnext;
1034                 }
1035                 if((sctl >= 0) && FD_ISSET(sctl, &readset))
1036                 {
1037                         int s;
1038                         struct sockaddr_un clientname;
1039                         struct ctlelem * tmp;
1040                         socklen_t clientnamelen = sizeof(struct sockaddr_un);
1041                         //syslog(LOG_DEBUG, "sctl!");
1042                         s = accept(sctl, (struct sockaddr *)&clientname,
1043                                    &clientnamelen);
1044                         syslog(LOG_DEBUG, "sctl! : '%s'", clientname.sun_path);
1045                         tmp = malloc(sizeof(struct ctlelem));
1046                         tmp->socket = s;
1047                         LIST_INSERT_HEAD(&ctllisthead, tmp, entries);
1048                 }
1049 #endif
1050 #ifdef ENABLE_EVENTS
1051                 upnpevents_processfds(&readset, &writeset);
1052 #endif
1053 #ifdef ENABLE_NATPMP
1054                 /* process NAT-PMP packets */
1055                 if((snatpmp >= 0) && FD_ISSET(snatpmp, &readset))
1056                 {
1057                         ProcessIncomingNATPMPPacket(snatpmp);
1058                 }
1059 #endif
1060                 /* process SSDP packets */
1061                 if(sudp >= 0 && FD_ISSET(sudp, &readset))
1062                 {
1063                         /*syslog(LOG_INFO, "Received UDP Packet");*/
1064                         /*ProcessSSDPRequest(sudp, v.lan_addr, v.n_lan_addr,*/
1065                         ProcessSSDPRequest(sudp, (unsigned short)v.port);
1066                 }
1067                 /* process active HTTP connections */
1068                 /* LIST_FOREACH macro is not available under linux */
1069                 for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next)
1070                 {
1071                         if(  (e->socket >= 0) && (e->state <= 2)
1072                                 &&(FD_ISSET(e->socket, &readset)) )
1073                         {
1074                                 Process_upnphttp(e);
1075                         }
1076                 }
1077                 /* process incoming HTTP connections */
1078                 if(shttpl >= 0 && FD_ISSET(shttpl, &readset))
1079                 {
1080                         int shttp;
1081                         socklen_t clientnamelen;
1082                         struct sockaddr_in clientname;
1083                         clientnamelen = sizeof(struct sockaddr_in);
1084                         shttp = accept(shttpl, (struct sockaddr *)&clientname, &clientnamelen);
1085                         if(shttp<0)
1086                         {
1087                                 syslog(LOG_ERR, "accept(http): %m");
1088                         }
1089                         else
1090                         {
1091                                 struct upnphttp * tmp = 0;
1092                                 syslog(LOG_INFO, "HTTP connection from %s:%d",
1093                                         inet_ntoa(clientname.sin_addr),
1094                                         ntohs(clientname.sin_port) );
1095                                 /*if (fcntl(shttp, F_SETFL, O_NONBLOCK) < 0) {
1096                                         syslog(LOG_ERR, "fcntl F_SETFL, O_NONBLOCK");
1097                                 }*/
1098                                 /* Create a new upnphttp object and add it to
1099                                  * the active upnphttp object list */
1100                                 tmp = New_upnphttp(shttp);
1101                                 if(tmp)
1102                                 {
1103                                         tmp->clientaddr = clientname.sin_addr;
1104                                         LIST_INSERT_HEAD(&upnphttphead, tmp, entries);
1105                                 }
1106                                 else
1107                                 {
1108                                         syslog(LOG_ERR, "New_upnphttp() failed");
1109                                         close(shttp);
1110                                 }
1111                         }
1112                 }
1113                 /* delete finished HTTP connections */
1114                 for(e = upnphttphead.lh_first; e != NULL; )
1115                 {
1116                         next = e->entries.le_next;
1117                         if(e->state >= 100)
1118                         {
1119                                 LIST_REMOVE(e, entries);
1120                                 Delete_upnphttp(e);
1121                         }
1122                         e = next;
1123                 }
1124         }
1125
1126 shutdown:
1127         /* close out open sockets */
1128         while(upnphttphead.lh_first != NULL)
1129         {
1130                 e = upnphttphead.lh_first;
1131                 LIST_REMOVE(e, entries);
1132                 Delete_upnphttp(e);
1133         }
1134
1135         if (sudp >= 0) close(sudp);
1136         if (shttpl >= 0) close(shttpl);
1137 #ifdef ENABLE_NATPMP
1138         if(snatpmp>=0)
1139         {
1140                 close(snatpmp);
1141                 snatpmp = -1;
1142         }
1143 #endif
1144 #ifdef USE_MINIUPNPDCTL
1145         if(sctl>=0)
1146         {
1147                 close(sctl);
1148                 sctl = -1;
1149                 if(unlink("/var/run/miniupnpd.ctl") < 0)
1150                 {
1151                         syslog(LOG_ERR, "unlink() %m");
1152                 }
1153         }
1154 #endif
1155         
1156         /*if(SendSSDPGoodbye(snotify, v.n_lan_addr) < 0)*/
1157         if (GETFLAG(ENABLEUPNPMASK))
1158         {
1159                 if(SendSSDPGoodbye(snotify, n_lan_addr) < 0)
1160                 {
1161                         syslog(LOG_ERR, "Failed to broadcast good-bye notifications");
1162                 }
1163                 for(i=0; i<n_lan_addr; i++)/* for(i=0; i<v.n_lan_addr; i++)*/
1164                         close(snotify[i]);
1165         }
1166
1167         if(unlink(pidfilename) < 0)
1168         {
1169                 syslog(LOG_ERR, "Failed to remove pidfile %s: %m", pidfilename);
1170         }
1171
1172         closelog();     
1173         freeoptions();
1174         
1175         return 0;
1176 }
1177