--- embedaddon/miniupnpd/miniupnpd.c 2012/05/29 12:55:57 1.1.1.2 +++ embedaddon/miniupnpd/miniupnpd.c 2013/07/22 00:32:35 1.1.1.3 @@ -1,7 +1,7 @@ -/* $Id: miniupnpd.c,v 1.1.1.2 2012/05/29 12:55:57 misho Exp $ */ +/* $Id: miniupnpd.c,v 1.1.1.3 2013/07/22 00:32:35 misho Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2011 Thomas Bernard + * (c) 2006-2013 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -12,7 +12,9 @@ /* apt-get install libnetfilter-queue-dev */ #include #include -//#include /* Defines verdicts (NF_ACCEPT, etc) */ +#if 0 +#include /* Defines verdicts (NF_ACCEPT, etc) */ +#endif #include #include #include @@ -47,6 +49,7 @@ #include #endif +#include "macros.h" #include "upnpglobalvars.h" #include "upnphttp.h" #include "upnpdescgen.h" @@ -56,6 +59,7 @@ #include "options.h" #include "minissdp.h" #include "upnpredirect.h" +#include "upnppinhole.h" #include "miniupnpdtypes.h" #include "daemonize.h" #include "upnpevents.h" @@ -67,6 +71,11 @@ #ifdef USE_IFACEWATCHER #include "ifacewatcher.h" #endif +#ifdef ENABLE_6FC_SERVICE +#ifdef USE_NETFILTER +void init_iptpinhole(void); +#endif +#endif #ifndef DEFAULT_CONFIG #define DEFAULT_CONFIG "/etc/miniupnpd.conf" @@ -91,8 +100,8 @@ int get_udp_dst_port (char *payload); #endif /* variables used by signals */ -static volatile int quitting = 0; -volatile int should_send_public_address_change_notif = 0; +static volatile sig_atomic_t quitting = 0; +volatile sig_atomic_t should_send_public_address_change_notif = 0; /* OpenAndConfHTTPSocket() : * setup the socket used to handle incoming HTTP connections. */ @@ -133,6 +142,11 @@ OpenAndConfHTTPSocket(unsigned short port) } #endif + if(!set_non_blocking(s)) + { + syslog(LOG_WARNING, "set_non_blocking(http): %m"); + } + #ifdef ENABLE_IPV6 memset(&listenname, 0, sizeof(struct sockaddr_in6)); listenname.sin6_family = AF_INET6; @@ -193,32 +207,32 @@ OpenAndConfNFqueue(){ inet_pton(AF_INET, "239.255.255.250", &(ssdp.sin_addr)); - //Get a queue connection handle from the module + /* Get a queue connection handle from the module */ if (!(nfqHandle = nfq_open())) { syslog(LOG_ERR, "Error in nfq_open(): %m"); return -1; } - //Unbind the handler from processing any IP packets - // Not totally sure why this is done, or if it's necessary... + /* Unbind the handler from processing any IP packets + Not totally sure why this is done, or if it's necessary... */ if ((e = nfq_unbind_pf(nfqHandle, AF_INET)) < 0) { syslog(LOG_ERR, "Error in nfq_unbind_pf(): %m"); return -1; } - //Bind this handler to process IP packets... + /* Bind this handler to process IP packets... */ if (nfq_bind_pf(nfqHandle, AF_INET) < 0) { syslog(LOG_ERR, "Error in nfq_bind_pf(): %m"); return -1; } - // Install a callback on queue -Q + /* Install a callback on queue -Q */ if (!(myQueue = nfq_create_queue(nfqHandle, nfqueue, &nfqueue_cb, NULL))) { syslog(LOG_ERR, "Error in nfq_create_queue(): %m"); return -1; } - // Turn on packet copy mode + /* Turn on packet copy mode */ if (nfq_set_mode(myQueue, NFQNL_COPY_PACKET, 0xffff) < 0) { syslog(LOG_ERR, "Error setting packet copy mode (): %m"); return -1; @@ -256,13 +270,13 @@ static int nfqueue_cb( int dport = get_udp_dst_port(pkt); int x = sizeof (struct ip) + sizeof (struct udphdr); - - /* packets we are interested in are UDP multicast to 239.255.255.250:1900 + + /* packets we are interested in are UDP multicast to 239.255.255.250:1900 * and start with a data string M-SEARCH */ - if ( (dport == 1900) && (id_protocol == IPPROTO_UDP) + if ( (dport == 1900) && (id_protocol == IPPROTO_UDP) && (ssdp.sin_addr.s_addr == iph->ip_dst.s_addr) ) { - + /* get the index that the packet came in on */ u_int32_t idx = nfq_get_indev(nfa); int i = 0; @@ -272,7 +286,7 @@ static int nfqueue_cb( struct udphdr *udp = (struct udphdr *) (pkt + sizeof(struct ip)); char *dd = pkt + x; - + struct sockaddr_in sendername; sendername.sin_family = AF_INET; sendername.sin_port = udp->source; @@ -284,12 +298,13 @@ static int nfqueue_cb( } } } - + nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL); } else { syslog(LOG_ERR,"nfq_get_msg_packet_hdr failed"); - return 1; // from nfqueue source: 0 = ok, >0 = soft error, <0 hard error + return 1; + /* from nfqueue source: 0 = ok, >0 = soft error, <0 hard error */ } return 0; @@ -369,12 +384,13 @@ write_ctlsockets_list(int fd, struct ctlelem * e) } } +#ifndef DISABLE_CONFIG_FILE static void write_option_list(int fd) { char buffer[256]; int len; - int i; + unsigned int i; write(fd, "Options :\n", 10); for(i=0; iifname)) { - nbits = atoi(++p); - while(*p && !isspace(*p)) - p++; + /* not starting with a digit : suppose it is an interface name */ + memcpy(lan_addr->ifname, str, n); + lan_addr->ifname[n] = '\0'; + if(getifaddr(lan_addr->ifname, lan_addr->str, sizeof(lan_addr->str)) < 0) + goto parselan_error; } - if(n>15) + else { - fprintf(stderr, "Error parsing address/mask : %s\n", str); - return -1; + if(n>15) + goto parselan_error; + memcpy(lan_addr->str, str, n); + lan_addr->str[n] = '\0'; } - memcpy(lan_addr->str, str, n); - lan_addr->str[n] = '\0'; if(!inet_aton(lan_addr->str, &lan_addr->addr)) + goto parselan_error; + if(*p == '/') { - fprintf(stderr, "Error parsing address/mask : %s\n", str); - return -1; + const char * q = ++p; + while(*p && isdigit(*p)) + p++; + if(*p=='.') + { + while(*p && (*p=='.' || isdigit(*p))) + p++; + n = p - q; + if(n>15) + goto parselan_error; + memcpy(tmp, q, n); + tmp[n] = '\0'; + if(!inet_aton(tmp, &lan_addr->mask)) + goto parselan_error; + } + else + { + int nbits = atoi(q); + if(nbits > 32 || nbits < 0) + goto parselan_error; + lan_addr->mask.s_addr = htonl(nbits ? (0xffffffffu << (32 - nbits)) : 0); + } } - lan_addr->mask.s_addr = htonl(nbits ? (0xffffffff << (32 - nbits)) : 0); + else + { + /* by default, networks are /24 */ + lan_addr->mask.s_addr = htonl(0xffffff00u); + } #ifdef MULTIPLE_EXTERNAL_IP /* skip spaces */ while(*p && isspace(*p)) @@ -562,7 +622,20 @@ parselanaddr(struct lan_addr_s * lan_addr, const char } } #endif +#ifdef ENABLE_IPV6 + if(lan_addr->ifname[0] != '\0') + { + lan_addr->index = if_nametoindex(lan_addr->ifname); + if(lan_addr->index == 0) + fprintf(stderr, "Cannot get index for network interface %s", + lan_addr->ifname); + } +#endif return 0; +parselan_error: + fprintf(stderr, "Error parsing address/mask (or interface name) : %s\n", + str); + return -1; } /* init phase : @@ -580,12 +653,14 @@ init(int argc, char * * argv, struct runtime_vars * v) int i; int pid; int debug_flag = 0; - int options_flag = 0; int openlog_option; struct sigaction sa; /*const char * logfilename = 0;*/ const char * presurl = 0; +#ifndef DISABLE_CONFIG_FILE + int options_flag = 0; const char * optionsfile = DEFAULT_CONFIG; +#endif /* DISABLE_CONFIG_FILE */ struct lan_addr_s * lan_addr; struct lan_addr_s * lan_addr2; @@ -595,6 +670,7 @@ init(int argc, char * * argv, struct runtime_vars * v) if(0 == strcmp(argv[i], "-h")) goto print_usage; } +#ifndef DISABLE_CONFIG_FILE /* first check if "-f" option is used */ for(i=2; iport = -1; v->notify_interval = 30; /* seconds between SSDP announces */ v->clean_ruleset_threshold = 20; v->clean_ruleset_interval = 0; /* interval between ruleset check. 0=disabled */ - +#ifndef DISABLE_CONFIG_FILE /* read options file first since * command line arguments have final say */ if(readoptionsfile(optionsfile) < 0) @@ -625,7 +702,7 @@ init(int argc, char * * argv, struct runtime_vars * v) } else { - for(i=0; iclean_ruleset_interval = atoi(ary_options[i].value); break; #ifdef USE_PF + case UPNPANCHOR: + anchor_name = ary_options[i].value; + break; case UPNPQUEUE: queue = ary_options[i].value; break; @@ -745,6 +831,7 @@ init(int argc, char * * argv, struct runtime_vars * v) } } } +#endif /* DISABLE_CONFIG_FILE */ /* command line arguments processing */ for(i=1; iclean_ruleset_interval = atoi(argv[++i]); + else + fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); + break; case 'u': if(i+1 < argc) strncpy(uuidvalue+5, argv[++i], strlen(uuidvalue+5) + 1); else fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); break; + case 'z': + if(i+1 < argc) + strncpy(friendly_name, argv[++i], FRIENDLY_NAME_MAX_LEN); + else + fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); + friendly_name[FRIENDLY_NAME_MAX_LEN-1] = '\0'; + break; case 's': if(i+1 < argc) strncpy(serialnumber, argv[++i], SERIALNUMBER_MAX_LEN); @@ -800,10 +900,12 @@ init(int argc, char * * argv, struct runtime_vars * v) /*case 'l': logfilename = argv[++i]; break;*/ +#if defined(USE_PF) || defined(USE_IPF) case 'L': /*logpackets = 1;*/ SETFLAG(LOGPACKETSMASK); break; +#endif case 'S': SETFLAG(SECUREMODEMASK); break; @@ -880,6 +982,7 @@ init(int argc, char * * argv, struct runtime_vars * v) fprintf(stderr, "Option -%c takes two arguments.\n", argv[i][1]); break; case 'a': +#ifndef MULTIPLE_EXTERNAL_IP if(i+1 < argc) { i++; @@ -906,7 +1009,64 @@ init(int argc, char * * argv, struct runtime_vars * v) } else fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); +#else + if(i+2 < argc) + { + char *val=calloc((strlen(argv[i+1]) + strlen(argv[i+2]) + 1), sizeof(char)); + if (val == NULL) + { + fprintf(stderr, "memory allocation error for listen address storage\n"); + break; + } + sprintf(val, "%s %s", argv[i+1], argv[i+2]); + + lan_addr = (struct lan_addr_s *) malloc(sizeof(struct lan_addr_s)); + if (lan_addr == NULL) + { + fprintf(stderr, "malloc(sizeof(struct lan_addr_s)): %m"); + free(val); + break; + } + if(parselanaddr(lan_addr, val) != 0) + { + fprintf(stderr, "can't parse \"%s\" as valid lan address\n", val); + free(lan_addr); + free(val); + break; + } + /* check if we already have this address */ + for(lan_addr2 = lan_addrs.lh_first; lan_addr2 != NULL; lan_addr2 = lan_addr2->list.le_next) + { + if (0 == strncmp(lan_addr2->str, lan_addr->str, 15)) + break; + } + if (lan_addr2 == NULL) + LIST_INSERT_HEAD(&lan_addrs, lan_addr, list); + + free(val); + i+=2; + } + else + fprintf(stderr, "Option -%c takes two arguments.\n", argv[i][1]); +#endif break; + case 'A': + if(i+1 < argc) { + void * tmp; + tmp = realloc(upnppermlist, sizeof(struct upnpperm) * (num_upnpperm+1)); + if(tmp == NULL) { + fprintf(stderr, "memory allocation error for permission\n"); + } else { + upnppermlist = tmp; + if(read_permission_line(upnppermlist + num_upnpperm, argv[++i]) >= 0) { + num_upnpperm++; + } else { + fprintf(stderr, "Permission rule parsing error :\n%s\n", 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; @@ -954,7 +1114,7 @@ init(int argc, char * * argv, struct runtime_vars * v) { syslog(LOG_ERR, "MiniUPnPd is already running. EXITING"); return 1; - } + } set_startup_time(GETFLAG(SYSUPTIMEMASK)); @@ -975,23 +1135,23 @@ init(int argc, char * * argv, struct runtime_vars * v) memset(&sa, 0, sizeof(struct sigaction)); sa.sa_handler = sigterm; - if (sigaction(SIGTERM, &sa, NULL)) + if(sigaction(SIGTERM, &sa, NULL) < 0) { syslog(LOG_ERR, "Failed to set %s handler. EXITING", "SIGTERM"); return 1; } - if (sigaction(SIGINT, &sa, NULL)) + if(sigaction(SIGINT, &sa, NULL) < 0) { syslog(LOG_ERR, "Failed to set %s handler. EXITING", "SIGINT"); return 1; } - - if(signal(SIGPIPE, SIG_IGN) == SIG_ERR) { + sa.sa_handler = SIG_IGN; + if(sigaction(SIGPIPE, &sa, NULL) < 0) + { syslog(LOG_ERR, "Failed to ignore SIGPIPE signals"); } - sa.sa_handler = sigusr1; - if (sigaction(SIGUSR1, &sa, NULL)) + if(sigaction(SIGUSR1, &sa, NULL) < 0) { syslog(LOG_NOTICE, "Failed to set %s handler", "SIGUSR1"); } @@ -1001,8 +1161,14 @@ init(int argc, char * * argv, struct runtime_vars * v) syslog(LOG_ERR, "Failed to init redirection engine. EXITING"); return 1; } +#ifdef ENABLE_6FC_SERVICE +#ifdef USE_NETFILTER + init_iptpinhole(); +#endif +#endif - writepidfile(pidfilename, pid); + if(writepidfile(pidfilename, pid) < 0) + pidfilename = NULL; #ifdef ENABLE_LEASEFILE /*remove(lease_file);*/ @@ -1013,33 +1179,49 @@ init(int argc, char * * argv, struct runtime_vars * v) return 0; print_usage: 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" + "%s " +#ifndef DISABLE_CONFIG_FILE + "[-f config_file] " +#endif + "[-i ext_ifname] [-o ext_ip]\n" +#ifndef MULTIPLE_EXTERNAL_IP + "\t\t[-a listening_ip]" #else - "\t\t[-a listening_ip] [-p port] [-d] [-L] [-U] [-S] [-N]\n" + "\t\t[-a listening_ip ext_ip]" #endif + " [-p port] [-d]" +#if defined(USE_PF) || defined(USE_IPF) + " [-L]" +#endif + " [-U] [-S]" +#ifdef ENABLE_NATPMP + " [-N]" +#endif + "\n" /*"[-l logfile] " not functionnal */ "\t\t[-u uuid] [-s serial] [-m model_number] \n" - "\t\t[-t notify_interval] [-P pid_filename]\n" - "\t\t[-B down up] [-w url]\n" + "\t\t[-t notify_interval] [-P pid_filename] [-z fiendly_name]\n" + "\t\t[-B down up] [-w url] [-r clean_ruleset_interval]\n" #ifdef USE_PF "\t\t[-q queue] [-T tag]\n" #endif #ifdef ENABLE_NFQUEUE "\t\t[-Q queue] [-n name]\n" #endif + "\t\t[-A \"permission rule\"]\n" "\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" "\tDefault config file is '%s'.\n" "\tWith -d miniupnpd will run as a standard program.\n" +#if defined(USE_PF) || defined(USE_IPF) "\t-L sets packet log in pf and ipf on.\n" +#endif "\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" #ifdef ENABLE_NATPMP - "\t-N enable NAT-PMP functionnality.\n" + "\t-N enable NAT-PMP functionality.\n" #endif "\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" @@ -1048,9 +1230,14 @@ print_usage: "\t-T sets the tag name in pf.\n" #endif #ifdef ENABLE_NFQUEUE - "\t-Q sets the queue number that is used by NFQUEUE.\n" - "\t-n sets the name of the interface(s) that packets will arrive on.\n" + "\t-Q sets the queue number that is used by NFQUEUE.\n" + "\t-n sets the name of the interface(s) that packets will arrive on.\n" #endif + "\t-A use following syntax for permission rules :\n" + "\t (allow|deny) (external port range) ip/mask (internal port range)\n" + "\texamples :\n" + "\t \"allow 1024-65535 192.168.1.0/24 1024-65535\"\n" + "\t \"deny 0-65535 0.0.0.0/0 0-65535\"\n" "\t-h prints this help and quits.\n" "", argv[0], pidfilename, DEFAULT_CONFIG); return 1; @@ -1068,7 +1255,7 @@ main(int argc, char * * argv) int sudpv6 = -1; /* IP v6 socket for receiving SSDP */ #endif #ifdef ENABLE_NATPMP - int * snatpmp; + int * snatpmp = NULL; #endif #ifdef ENABLE_NFQUEUE int nfqh = -1; @@ -1077,15 +1264,13 @@ main(int argc, char * * argv) int sifacewatcher = -1; #endif - int * snotify; + int * snotify = NULL; int addr_count; 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 @@ -1099,7 +1284,9 @@ main(int argc, char * * argv) struct rule_state * rule_list = 0; struct timeval checktime = {0, 0}; struct lan_addr_s * lan_addr; - syslog(LOG_INFO, "SNet version started"); +#ifdef ENABLE_6FC_SERVICE + unsigned int next_pinhole_ts; +#endif if(init(argc, argv, &v) != 0) return 1; @@ -1107,12 +1294,20 @@ main(int argc, char * * argv) addr_count = 0; for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next) addr_count++; - snotify = (int*) malloc(addr_count * sizeof(int)); - memset(snotify, 0, sizeof(snotify)); + if(addr_count > 0) { +#ifndef ENABLE_IPV6 + snotify = calloc(addr_count, sizeof(int)); +#else + /* one for IPv4, one for IPv6 */ + snotify = calloc(addr_count * 2, sizeof(int)); +#endif + } #ifdef ENABLE_NATPMP - snatpmp = (int*) malloc(addr_count * sizeof(int)); - for(i = 0; i < addr_count; i++) - snatpmp[i] = -1; + if(addr_count > 0) { + snatpmp = malloc(addr_count * sizeof(int)); + for(i = 0; i < addr_count; i++) + snatpmp[i] = -1; + } #endif LIST_INIT(&upnphttphead); @@ -1129,6 +1324,15 @@ main(int argc, char * * argv) return 0; } + syslog(LOG_INFO, "Starting%s%swith external interface %s", +#ifdef ENABLE_NATPMP + GETFLAG(ENABLENATPMPMASK) ? " NAT-PMP " : " ", +#else + " ", +#endif + GETFLAG(ENABLEUPNPMASK) ? "UPnP-IGD " : "", + ext_if_name); + if(GETFLAG(ENABLEUPNPMASK)) { @@ -1163,7 +1367,7 @@ main(int argc, char * * argv) sudp = OpenAndConfSSDPReceiveSocket(0); if(sudp < 0) { - syslog(LOG_INFO, "Failed to open socket for receiving SSDP. Trying to use MiniSSDPd"); + syslog(LOG_NOTICE, "Failed to open socket for receiving SSDP. Trying to use MiniSSDPd"); if(SubmitServicesToMiniSSDPD(lan_addrs.lh_first->str, v.port) < 0) { syslog(LOG_ERR, "Failed to connect to MiniSSDPd. EXITING"); return 1; @@ -1173,7 +1377,7 @@ main(int argc, char * * argv) sudpv6 = OpenAndConfSSDPReceiveSocket(1); if(sudpv6 < 0) { - syslog(LOG_INFO, "Failed to open socket for receiving SSDP (IP v6)."); + syslog(LOG_WARNING, "Failed to open socket for receiving SSDP (IP v6)."); } #endif @@ -1231,6 +1435,7 @@ main(int argc, char * * argv) } } #endif + /* main loop */ while(!quitting) { @@ -1238,7 +1443,7 @@ main(int argc, char * * argv) if((startup_time<60*60*24) && (time(NULL)>60*60*24)) { set_startup_time(GETFLAG(SYSUPTIMEMASK)); - } + } /* send public address change notifications if needed */ if(should_send_public_address_change_notif) { @@ -1310,13 +1515,13 @@ main(int argc, char * * argv) /* Remove expired port mappings, based on UPnP IGD LeaseDuration * or NAT-PMP lifetime) */ if(nextruletoclean_timestamp - && (timeofday.tv_sec >= nextruletoclean_timestamp)) + && ((unsigned int)timeofday.tv_sec >= nextruletoclean_timestamp)) { syslog(LOG_DEBUG, "cleaning expired Port Mappings"); get_upnp_rules_state_list(0); } if(nextruletoclean_timestamp - && timeout.tv_sec >= (nextruletoclean_timestamp - timeofday.tv_sec)) + && ((unsigned int)timeout.tv_sec >= (nextruletoclean_timestamp - timeofday.tv_sec))) { timeout.tv_sec = nextruletoclean_timestamp - timeofday.tv_sec; timeout.tv_usec = 0; @@ -1345,11 +1550,22 @@ main(int argc, char * * argv) } #endif #endif +#ifdef ENABLE_6FC_SERVICE + /* Clean up expired IPv6 PinHoles */ + next_pinhole_ts = 0; + upnp_clean_expired_pinholes(&next_pinhole_ts); + if(next_pinhole_ts && + timeout.tv_sec >= (int)(next_pinhole_ts - timeofday.tv_sec)) { + timeout.tv_sec = next_pinhole_ts - timeofday.tv_sec; + timeout.tv_usec = 0; + } +#endif /* select open sockets (SSDP, HTTP listen, and all HTTP soap sockets) */ FD_ZERO(&readset); + FD_ZERO(&writeset); - if (sudp >= 0) + if (sudp >= 0) { FD_SET(sudp, &readset); max_fd = MAX( max_fd, sudp); @@ -1361,7 +1577,7 @@ main(int argc, char * * argv) } #endif } - if (shttpl >= 0) + if (shttpl >= 0) { FD_SET(shttpl, &readset); max_fd = MAX( max_fd, shttpl); @@ -1375,7 +1591,7 @@ main(int argc, char * * argv) #endif #ifdef ENABLE_NFQUEUE - if (nfqh >= 0) + if (nfqh >= 0) { FD_SET(nfqh, &readset); max_fd = MAX( max_fd, nfqh); @@ -1385,10 +1601,15 @@ main(int argc, char * * argv) 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)) + if(e->socket >= 0) { - FD_SET(e->socket, &readset); - max_fd = MAX( max_fd, e->socket); + if(e->state <= EWaitingForHttpContent) + FD_SET(e->socket, &readset); + else if(e->state == ESendingAndClosing) + FD_SET(e->socket, &writeset); + else + continue; + max_fd = MAX(max_fd, e->socket); i++; } } @@ -1412,7 +1633,7 @@ main(int argc, char * * argv) 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) { @@ -1423,15 +1644,10 @@ main(int argc, char * * argv) #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; if(errno == EINTR) continue; /* interrupted by a signal, start again */ @@ -1452,7 +1668,9 @@ main(int argc, char * * argv) { /*write(ectl->socket, buf, l);*/ write_command_line(ectl->socket, argc, argv); +#ifndef DISABLE_CONFIG_FILE write_option_list(ectl->socket); +#endif write_permlist(ectl->socket, upnppermlist, num_upnpperm); write_upnphttp_details(ectl->socket, upnphttphead.lh_first); write_ctlsockets_list(ectl->socket, ctllisthead.lh_first); @@ -1483,13 +1701,21 @@ main(int argc, char * * argv) struct sockaddr_un clientname; struct ctlelem * tmp; socklen_t clientnamelen = sizeof(struct sockaddr_un); - //syslog(LOG_DEBUG, "sctl!"); + /*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); + if (tmp == NULL) + { + syslog(LOG_ERR, "Unable to allocate memory for ctlelem in main()"); + close(s); + } + else + { + tmp->socket = s; + LIST_INSERT_HEAD(&ctllisthead, tmp, entries); + } } #endif #ifdef ENABLE_EVENTS @@ -1528,10 +1754,13 @@ main(int argc, char * * argv) /* 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)) ) + if(e->socket >= 0) { - Process_upnphttp(e); + if(FD_ISSET(e->socket, &readset) || + FD_ISSET(e->socket, &writeset)) + { + Process_upnphttp(e); + } } } /* process incoming HTTP connections */ @@ -1549,7 +1778,9 @@ main(int argc, char * * argv) shttp = accept(shttpl, (struct sockaddr *)&clientname, &clientnamelen); if(shttp<0) { - syslog(LOG_ERR, "accept(http): %m"); + /* ignore EAGAIN, EWOULDBLOCK, EINTR, we just try again later */ + if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) + syslog(LOG_ERR, "accept(http): %m"); } else { @@ -1558,46 +1789,54 @@ main(int argc, char * * argv) sockaddr_to_string((struct sockaddr *)&clientname, addr_str, sizeof(addr_str)); syslog(LOG_INFO, "HTTP connection from %s", addr_str); - /*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) + if(get_lan_for_peer((struct sockaddr *)&clientname) == NULL) { -#ifdef ENABLE_IPV6 - if(clientname.ss_family == AF_INET) + /* The peer is not a LAN ! */ + syslog(LOG_WARNING, + "HTTP peer %s is not from a LAN, closing the connection", + addr_str); + close(shttp); + } + else + { + /* Create a new upnphttp object and add it to + * the active upnphttp object list */ + tmp = New_upnphttp(shttp); + if(tmp) { - tmp->clientaddr = ((struct sockaddr_in *)&clientname)->sin_addr; - } - else if(clientname.ss_family == AF_INET6) - { - struct sockaddr_in6 * addr = (struct sockaddr_in6 *)&clientname; - if(IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) +#ifdef ENABLE_IPV6 + if(clientname.ss_family == AF_INET) { - memcpy(&tmp->clientaddr, - &addr->sin6_addr.s6_addr[12], - 4); + tmp->clientaddr = ((struct sockaddr_in *)&clientname)->sin_addr; } - else + else if(clientname.ss_family == AF_INET6) { - tmp->ipv6 = 1; - memcpy(&tmp->clientaddr_v6, - &addr->sin6_addr, - sizeof(struct in6_addr)); + struct sockaddr_in6 * addr = (struct sockaddr_in6 *)&clientname; + if(IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) + { + memcpy(&tmp->clientaddr, + &addr->sin6_addr.s6_addr[12], + 4); + } + else + { + tmp->ipv6 = 1; + memcpy(&tmp->clientaddr_v6, + &addr->sin6_addr, + sizeof(struct in6_addr)); + } } - } #else - tmp->clientaddr = clientname.sin_addr; + tmp->clientaddr = clientname.sin_addr; #endif - LIST_INSERT_HEAD(&upnphttphead, tmp, entries); + LIST_INSERT_HEAD(&upnphttphead, tmp, entries); + } + else + { + syslog(LOG_ERR, "New_upnphttp() failed"); + close(shttp); + } } - else - { - syslog(LOG_ERR, "New_upnphttp() failed"); - close(shttp); - } } } #ifdef ENABLE_NFQUEUE @@ -1612,7 +1851,7 @@ main(int argc, char * * argv) for(e = upnphttphead.lh_first; e != NULL; ) { next = e->entries.le_next; - if(e->state >= 100) + if(e->state >= EToDelete) { LIST_REMOVE(e, entries); Delete_upnphttp(e); @@ -1635,7 +1874,6 @@ shutdown: if (shttpl >= 0) close(shttpl); #ifdef ENABLE_IPV6 if (sudpv6 >= 0) close(sudpv6); - //if (shttplv6 >= 0) close(shttplv6); #endif #ifdef USE_IFACEWATCHER if(sifacewatcher >= 0) close(sifacewatcher); @@ -1660,19 +1898,26 @@ shutdown: } } #endif - - /*if(SendSSDPGoodbye(snotify, v.n_lan_addr) < 0)*/ + if (GETFLAG(ENABLEUPNPMASK)) { +#ifndef ENABLE_IPV6 if(SendSSDPGoodbye(snotify, addr_count) < 0) +#else + if(SendSSDPGoodbye(snotify, addr_count * 2) < 0) +#endif { syslog(LOG_ERR, "Failed to broadcast good-bye notifications"); } - for(i=0; i