Annotation of embedaddon/miniupnpd/miniupnpd.c, revision 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>