📄 miniupnpd.c
字号:
break; case 'B': if(i+2<argc) { downstream_bitrate = strtoul(argv[++i], 0, 0); upstream_bitrate = strtoul(argv[++i], 0, 0); } else fprintf(stderr, "Option -%c takes two arguments.\n", argv[i][1]); break; case 'a': if(i+1 < argc) { int address_already_there = 0; int j; i++; for(j=0; j<n_lan_addr; j++)/* for(j=0; j<v->n_lan_addr; j++)*/ { struct lan_addr_s tmpaddr; parselanaddr(&tmpaddr, argv[i]); /*if(0 == strcmp(v->lan_addr[j].str, tmpaddr.str))*/ if(0 == strcmp(lan_addr[j].str, tmpaddr.str)) address_already_there = 1; } if(address_already_there) break; if(n_lan_addr < MAX_LAN_ADDR) /*if(v->n_lan_addr < MAX_LAN_ADDR)*/ { /*v->lan_addr[v->n_lan_addr++] = argv[i];*/ /*if(parselanaddr(&v->lan_addr[v->n_lan_addr], argv[i]) == 0)*/ if(parselanaddr(&lan_addr[n_lan_addr], argv[i]) == 0) n_lan_addr++; /*v->n_lan_addr++;*/ } else { fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n", MAX_LAN_ADDR, argv[i]); } } else fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); break; case 'f': i++; /* discarding, the config file is already read */ break; default: fprintf(stderr, "Unknown option: %s\n", argv[i]); } } if(!ext_if_name || (/*v->*/n_lan_addr==0) || v->port<=0) { fprintf(stderr, "Usage:\n\t" "%s [-f config_file] [-i ext_ifname] [-o ext_ip]\n"#ifndef ENABLE_NATPMP "\t\t[-a listening_ip] [-p port] [-d] [-L] [-U] [-S]\n"#else "\t\t[-a listening_ip] [-p port] [-d] [-L] [-U] [-S] [-N]\n"#endif /*"[-l logfile] " not functionnal */ "\t\t[-u uuid] [-s serial] [-m model_number] \n" "\t\t[-t notify_interval] [-P pid_filename]\n"#ifdef USE_PF "\t\t[-B down up] [-w url] [-q queue] [-T tag]\n"#else "\t\t[-B down up] [-w url]\n"#endif "\nNotes:\n\tThere can be one or several listening_ips.\n" "\tNotify interval is in seconds. Default is 30 seconds.\n" "\tDefault pid file is %s.\n" "\tWith -d miniupnpd will run as a standard program.\n" "\t-L sets packet log in pf and ipf on.\n" "\t-S sets \"secure\" mode : clients can only add mappings to their own ip\n" "\t-U causes miniupnpd to report system uptime instead " "of daemon uptime.\n" "\t-B sets bitrates reported by daemon in bits per second.\n" "\t-w sets the presentation url. Default is http address on port 80\n"#ifdef USE_PF "\t-q sets the ALTQ queue in pf.\n" "\t-T sets the tag name in pf.\n"#endif "", argv[0], pidfilename); return 1; } if(debug_flag) { pid = getpid(); } else {#ifdef USE_DAEMON if(daemon(0, 0)<0) { perror("daemon()"); } pid = getpid();#else pid = daemonize();#endif } openlog_option = LOG_PID|LOG_CONS; if(debug_flag) { openlog_option |= LOG_PERROR; /* also log on stderr */ } openlog("miniupnpd", openlog_option, LOG_MINIUPNPD); if(!debug_flag) { /* speed things up and ignore LOG_INFO and LOG_DEBUG */ setlogmask(LOG_UPTO(LOG_NOTICE)); } if(checkforrunning(pidfilename) < 0) { syslog(LOG_ERR, "MiniUPnPd is already running. EXITING"); return 1; } set_startup_time(GETFLAG(SYSUPTIMEMASK)/*sysuptime*/); /* presentation url */ if(presurl) { strncpy(presentationurl, presurl, PRESENTATIONURL_MAX_LEN); presentationurl[PRESENTATIONURL_MAX_LEN-1] = '\0'; } else { snprintf(presentationurl, PRESENTATIONURL_MAX_LEN, "http://%s/", lan_addr[0].str); /*"http://%s:%d/", lan_addr[0].str, 80);*/ /*"http://%s:%d/", v->lan_addr[0].str, 80);*/ } /* set signal handler */ memset(&sa, 0, sizeof(struct sigaction)); sa.sa_handler = sigterm; if (sigaction(SIGTERM, &sa, NULL)) { syslog(LOG_ERR, "Failed to set %s handler. EXITING", "SIGTERM"); return 1; } if (sigaction(SIGINT, &sa, NULL)) { syslog(LOG_ERR, "Failed to set %s handler. EXITING", "SIGINT"); return 1; } if(signal(SIGPIPE, SIG_IGN) == SIG_ERR) { syslog(LOG_ERR, "Failed to ignore SIGPIPE signals"); } if(init_redirect() < 0) { syslog(LOG_ERR, "Failed to init redirection engine. EXITING"); return 1; } writepidfile(pidfilename, pid); return 0;}/* === main === *//* process HTTP or SSDP requests */intmain(int argc, char * * argv){ int i; int sudp = -1, shttpl = -1;#ifdef ENABLE_NATPMP int snatpmp = -1;#endif int snotify[MAX_LAN_ADDR]; LIST_HEAD(httplisthead, upnphttp) upnphttphead; struct upnphttp * e = 0; struct upnphttp * next; fd_set readset; /* for select() */#ifdef ENABLE_EVENTS fd_set writeset;#endif struct timeval timeout, timeofday, lasttimeofday = {0, 0}; int max_fd = -1;#ifdef USE_MINIUPNPDCTL int sctl = -1; LIST_HEAD(ctlstructhead, ctlelem) ctllisthead; struct ctlelem * ectl; struct ctlelem * ectlnext;#endif struct runtime_vars v; /* variables used for the unused-rule cleanup process */ struct rule_state * rule_list = 0; struct timeval checktime = {0, 0}; if(init(argc, argv, &v) != 0) return 1; LIST_INIT(&upnphttphead);#ifdef USE_MINIUPNPDCTL LIST_INIT(&ctllisthead);#endif if(#ifdef ENABLE_NATPMP !GETFLAG(ENABLENATPMPMASK) &&#endif !GETFLAG(ENABLEUPNPMASK) ) { syslog(LOG_ERR, "Why did you run me anyway?"); return 0; } if(GETFLAG(ENABLEUPNPMASK)/*enableupnp*/) { /* open socket for SSDP connections */ /*sudp = OpenAndConfSSDPReceiveSocket(v.n_lan_addr, v.lan_addr);*/ sudp = OpenAndConfSSDPReceiveSocket(n_lan_addr, lan_addr); if(sudp < 0) { syslog(LOG_ERR, "Failed to open socket for receiving SSDP. EXITING"); return 1; } /* open socket for HTTP connections. Listen on the 1st LAN address */ shttpl = OpenAndConfHTTPSocket(v.port); if(shttpl < 0) { syslog(LOG_ERR, "Failed to open socket for HTTP. EXITING"); return 1; } syslog(LOG_NOTICE, "HTTP listening on port %d", v.port); /* open socket for sending notifications */ if(OpenAndConfSSDPNotifySockets(snotify) < 0) { syslog(LOG_ERR, "Failed to open sockets for sending SSDP notify " "messages. EXITING"); return 1; } }#ifdef ENABLE_NATPMP /* open socket for NAT PMP traffic */ if(GETFLAG(ENABLENATPMPMASK)) { snatpmp = OpenAndConfNATPMPSocket(); if(snatpmp < 0) { syslog(LOG_ERR, "Failed to open socket for NAT PMP."); /*syslog(LOG_ERR, "Failed to open socket for NAT PMP. EXITING"); return 1;*/ } else { syslog(LOG_NOTICE, "Listening for NAT-PMP traffic on port %u", NATPMP_PORT); } ScanNATPMPforExpiration(); }#endif /* for miniupnpdctl */#ifdef USE_MINIUPNPDCTL sctl = OpenAndConfCtlUnixSocket("/var/run/miniupnpd.ctl");#endif /* main loop */ while(!quitting) { /* Check if we need to send SSDP NOTIFY messages and do it if * needed */ if(gettimeofday(&timeofday, 0) < 0) { syslog(LOG_ERR, "gettimeofday(): %m"); timeout.tv_sec = v.notify_interval; timeout.tv_usec = 0; } else { /* the comparaison is not very precise but who cares ? */ if(timeofday.tv_sec >= (lasttimeofday.tv_sec + v.notify_interval)) { if (GETFLAG(ENABLEUPNPMASK)) SendSSDPNotifies2(snotify, (unsigned short)v.port, v.notify_interval << 1); memcpy(&lasttimeofday, &timeofday, sizeof(struct timeval)); timeout.tv_sec = v.notify_interval; timeout.tv_usec = 0; } else { timeout.tv_sec = lasttimeofday.tv_sec + v.notify_interval - timeofday.tv_sec; if(timeofday.tv_usec > lasttimeofday.tv_usec) { timeout.tv_usec = 1000000 + lasttimeofday.tv_usec - timeofday.tv_usec; timeout.tv_sec--; } else { timeout.tv_usec = lasttimeofday.tv_usec - timeofday.tv_usec; } } } /* remove unused rules */ if( v.clean_ruleset_interval && (timeofday.tv_sec >= checktime.tv_sec + v.clean_ruleset_interval)) { if(rule_list) { remove_unused_rules(rule_list); rule_list = NULL; } else { rule_list = get_upnp_rules_state_list(v.clean_ruleset_threshold); } memcpy(&checktime, &timeofday, sizeof(struct timeval)); }#ifdef ENABLE_NATPMP /* Remove expired NAT-PMP mappings */ while( nextnatpmptoclean_timestamp && (timeofday.tv_sec >= nextnatpmptoclean_timestamp + startup_time)) { /*syslog(LOG_DEBUG, "cleaning expired NAT-PMP mappings");*/ if(CleanExpiredNATPMP() < 0) { syslog(LOG_ERR, "CleanExpiredNATPMP() failed"); break; } } if(nextnatpmptoclean_timestamp && timeout.tv_sec >= (nextnatpmptoclean_timestamp + startup_time - timeofday.tv_sec)) { /*syslog(LOG_DEBUG, "setting timeout to %d sec", nextnatpmptoclean_timestamp + startup_time - timeofday.tv_sec);*/ timeout.tv_sec = nextnatpmptoclean_timestamp + startup_time - timeofday.tv_sec; timeout.tv_usec = 0; }#endif /* select open sockets (SSDP, HTTP listen, and all HTTP soap sockets) */ FD_ZERO(&readset); if (sudp >= 0) { FD_SET(sudp, &readset); max_fd = MAX( max_fd, sudp); } if (shttpl >= 0) { FD_SET(shttpl, &readset); max_fd = MAX( max_fd, shttpl); } i = 0; /* active HTTP connections count */ for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next) { if((e->socket >= 0) && (e->state <= 2)) { FD_SET(e->socket, &readset); max_fd = MAX( max_fd, e->socket); i++; } } /* for debug */#ifdef DEBUG if(i > 1) { syslog(LOG_DEBUG, "%d active incoming HTTP connections", i); }#endif#ifdef ENABLE_NATPMP if(snatpmp >= 0) { FD_SET(snatpmp, &readset); max_fd = MAX( max_fd, snatpmp); }#endif#ifdef USE_MINIUPNPDCTL if(sctl >= 0) { FD_SET(sctl, &readset); max_fd = MAX( max_fd, sctl); } for(ectl = ctllisthead.lh_first; ectl; ectl = ectl->entries.le_next) { if(ectl->socket >= 0) { FD_SET(ectl->socket, &readset); max_fd = MAX( max_fd, ectl->socket); } }#endif#ifdef ENABLE_EVENTS FD_ZERO(&writeset); upnpevents_selectfds(&readset, &writeset, &max_fd);#endif#ifdef ENABLE_EVENTS if(select(max_fd+1, &readset, &writeset, 0, &timeout) < 0)#else if(select(max_fd+1, &readset, 0, 0, &timeout) < 0)#endif { if(quitting) goto shutdown; syslog(LOG_ERR, "select(all): %m"); syslog(LOG_ERR, "Failed to select open sockets. EXITING"); return 1; /* very serious cause of error */ }#ifdef USE_MINIUPNPDCTL for(ectl = ctllisthead.lh_first; ectl;) { ectlnext = ectl->entries.le_next; if((ectl->socket >= 0) && FD_ISSET(ectl->socket, &readset)) { char buf[256]; int l; l = read(ectl->socket, buf, sizeof(buf)); if(l > 0) { /*write(ectl->socket, buf, l);*/ write_option_list(ectl->socket); write_permlist(ectl->socket, upnppermlist, num_upnpperm); write_upnphttp_details(ectl->socket, upnphttphead.lh_first); write_ctlsockets_list(ectl->socket, ctllisthead.lh_first); write_ruleset_details(ectl->socket);#ifdef ENABLE_EVENTS write_events_details(ectl->socket);#endif /* close the socket */ close(ectl->socket); ectl->socket = -1; } else { close(ectl->socket); ectl->socket = -1; } } if(ectl->socket < 0) { LIST_REMOVE(ectl, entries); free(ectl); } ectl = ectlnext; } if((sctl >= 0) && FD_ISSET(sctl, &readset)) { int s; struct sockaddr_un clientname; struct ctlelem * tmp; socklen_t clientnamelen = sizeof(struct sockaddr_un); //syslog(LOG_DEBUG, "sctl!"); s = accept(sctl, (struct sockaddr *)&clientname, &clientnamelen); syslog(LOG_DEBUG, "sctl! : '%s'", clientname.sun_path); tmp = malloc(sizeof(struct ctlelem)); tmp->socket = s; LIST_INSERT_HEAD(&ctllisthead, tmp, entries); }#endif#ifdef ENABLE_EVENTS upnpevents_processfds(&readset, &writeset);#endif#ifdef ENABLE_NATPMP /* process NAT-PMP packets */ if((snatpmp >= 0) && FD_ISSET(snatpmp, &readset)) { ProcessIncomingNATPMPPacket(snatpmp); }#endif /* process SSDP packets */ if(sudp >= 0 && FD_ISSET(sudp, &readset)) { /*syslog(LOG_INFO, "Received UDP Packet");*/ /*ProcessSSDPRequest(sudp, v.lan_addr, v.n_lan_addr,*/ ProcessSSDPRequest(sudp, (unsigned short)v.port); } /* process active HTTP connections */ /* LIST_FOREACH macro is not available under linux */ for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next) { if( (e->socket >= 0) && (e->state <= 2) &&(FD_ISSET(e->socket, &readset)) ) { Process_upnphttp(e); } } /* process incoming HTTP connections */ if(shttpl >= 0 && FD_ISSET(shttpl, &readset)) { int shttp; socklen_t clientnamelen; struct sockaddr_in clientname; clientnamelen = sizeof(struct sockaddr_in); shttp = accept(shttpl, (struct sockaddr *)&clientname, &clientnamelen); if(shttp<0) { syslog(LOG_ERR, "accept(http): %m"); } else { struct upnphttp * tmp = 0; syslog(LOG_INFO, "HTTP connection from %s:%d", inet_ntoa(clientname.sin_addr), ntohs(clientname.sin_port) ); /*if (fcntl(shttp, F_SETFL, O_NONBLOCK) < 0) { syslog(LOG_ERR, "fcntl F_SETFL, O_NONBLOCK"); }*/ /* Create a new upnphttp object and add it to * the active upnphttp object list */ tmp = New_upnphttp(shttp); if(tmp) { tmp->clientaddr = clientname.sin_addr; LIST_INSERT_HEAD(&upnphttphead, tmp, entries); } else { syslog(LOG_ERR, "New_upnphttp() failed"); close(shttp); } } } /* delete finished HTTP connections */ for(e = upnphttphead.lh_first; e != NULL; ) { next = e->entries.le_next; if(e->state >= 100) { LIST_REMOVE(e, entries); Delete_upnphttp(e); } e = next; } }shutdown: /* close out open sockets */ while(upnphttphead.lh_first != NULL) { e = upnphttphead.lh_first; LIST_REMOVE(e, entries); Delete_upnphttp(e); } if (sudp >= 0) close(sudp); if (shttpl >= 0) close(shttpl);#ifdef ENABLE_NATPMP if(snatpmp>=0) { close(snatpmp); snatpmp = -1; }#endif#ifdef USE_MINIUPNPDCTL if(sctl>=0) { close(sctl); sctl = -1; if(unlink("/var/run/miniupnpd.ctl") < 0) { syslog(LOG_ERR, "unlink() %m"); } }#endif /*if(SendSSDPGoodbye(snotify, v.n_lan_addr) < 0)*/ if (GETFLAG(ENABLEUPNPMASK)) { if(SendSSDPGoodbye(snotify, n_lan_addr) < 0) { syslog(LOG_ERR, "Failed to broadcast good-bye notifications"); } for(i=0; i<n_lan_addr; i++)/* for(i=0; i<v.n_lan_addr; i++)*/ close(snotify[i]); } if(unlink(pidfilename) < 0) { syslog(LOG_ERR, "Failed to remove pidfile %s: %m", pidfilename); } closelog(); freeoptions(); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -