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