| version 1.1, 2012/02/21 23:16:02 | version 1.1.1.3, 2013/07/22 00:32:35 | 
| Line 1 | Line 1 | 
 | /* $Id$ */ | /* $Id$ */ | 
 | /* MiniUPnP project | /* MiniUPnP project | 
 | * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ | * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ | 
| * (c) 2006-2010 Thomas Bernard | * (c) 2006-2013 Thomas Bernard | 
 | * This software is subject to the conditions detailed | * This software is subject to the conditions detailed | 
 | * in the LICENCE file provided within the distribution */ | * in the LICENCE file provided within the distribution */ | 
 |  |  | 
| Line 12 | Line 12 | 
 | /* apt-get install libnetfilter-queue-dev */ | /* apt-get install libnetfilter-queue-dev */ | 
 | #include <netinet/ip.h> | #include <netinet/ip.h> | 
 | #include <netinet/udp.h> | #include <netinet/udp.h> | 
| //#include <linux/netfilter_ipv4.h>  /* Defines verdicts (NF_ACCEPT, etc) */ | #if 0 | 
|  | #include <linux/netfilter_ipv4.h>  /* Defines verdicts (NF_ACCEPT, etc) */ | 
|  | #endif | 
 | #include <linux/netfilter.h> | #include <linux/netfilter.h> | 
 | #include <libnetfilter_queue/libnetfilter_queue.h> | #include <libnetfilter_queue/libnetfilter_queue.h> | 
 | #include <linux/netfilter/nfnetlink_queue.h> | #include <linux/netfilter/nfnetlink_queue.h> | 
| Line 47 | Line 49 | 
 | #include <sys/un.h> | #include <sys/un.h> | 
 | #endif | #endif | 
 |  |  | 
 |  | #include "macros.h" | 
 | #include "upnpglobalvars.h" | #include "upnpglobalvars.h" | 
 | #include "upnphttp.h" | #include "upnphttp.h" | 
 | #include "upnpdescgen.h" | #include "upnpdescgen.h" | 
| Line 56 | Line 59 | 
 | #include "options.h" | #include "options.h" | 
 | #include "minissdp.h" | #include "minissdp.h" | 
 | #include "upnpredirect.h" | #include "upnpredirect.h" | 
 |  | #include "upnppinhole.h" | 
 | #include "miniupnpdtypes.h" | #include "miniupnpdtypes.h" | 
 | #include "daemonize.h" | #include "daemonize.h" | 
 | #include "upnpevents.h" | #include "upnpevents.h" | 
| Line 63 | Line 67 | 
 | #include "natpmp.h" | #include "natpmp.h" | 
 | #endif | #endif | 
 | #include "commonrdr.h" | #include "commonrdr.h" | 
 |  | #include "upnputils.h" | 
 |  | #ifdef USE_IFACEWATCHER | 
 |  | #include "ifacewatcher.h" | 
 |  | #endif | 
 |  | #ifdef ENABLE_6FC_SERVICE | 
 |  | #ifdef USE_NETFILTER | 
 |  | void init_iptpinhole(void); | 
 |  | #endif | 
 |  | #endif | 
 |  |  | 
 | #ifndef DEFAULT_CONFIG | #ifndef DEFAULT_CONFIG | 
 | #define DEFAULT_CONFIG "/etc/miniupnpd.conf" | #define DEFAULT_CONFIG "/etc/miniupnpd.conf" | 
| Line 81  static struct nfq_handle *nfqHandle; | Line 94  static struct nfq_handle *nfqHandle; | 
 | static struct sockaddr_in ssdp; | static struct sockaddr_in ssdp; | 
 |  |  | 
 | /* prototypes */ | /* prototypes */ | 
 | void ProcessSSDPData(int s, char *bufr, struct sockaddr_in sendername, int n, unsigned short port); |  | 
 | static int nfqueue_cb( struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data) ; | static int nfqueue_cb( struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data) ; | 
 | int identify_ip_protocol (char *payload); | int identify_ip_protocol (char *payload); | 
 | int get_udp_dst_port (char *payload); | int get_udp_dst_port (char *payload); | 
 | #endif | #endif | 
 |  |  | 
 |  | /* variables used by signals */ | 
 |  | static volatile sig_atomic_t quitting = 0; | 
 |  | volatile sig_atomic_t should_send_public_address_change_notif = 0; | 
 |  |  | 
 | static int sudp = -1; |  | 
 |  |  | 
 | /* MAX_LAN_ADDR : maximum number of interfaces |  | 
 | * to listen to SSDP traffic */ |  | 
 | /*#define MAX_LAN_ADDR (4)*/ |  | 
 |  |  | 
 | static volatile int quitting = 0; |  | 
 | static volatile int should_send_public_address_change_notif = 0; |  | 
 |  |  | 
 | /* OpenAndConfHTTPSocket() : | /* OpenAndConfHTTPSocket() : | 
 | * setup the socket used to handle incoming HTTP connections. */ | * setup the socket used to handle incoming HTTP connections. */ | 
 | static int | static int | 
| Line 104  OpenAndConfHTTPSocket(unsigned short port) | Line 110  OpenAndConfHTTPSocket(unsigned short port) | 
 | { | { | 
 | int s; | int s; | 
 | int i = 1; | int i = 1; | 
 |  | #ifdef ENABLE_IPV6 | 
 |  | struct sockaddr_in6 listenname; | 
 |  | #else | 
 | struct sockaddr_in listenname; | struct sockaddr_in listenname; | 
 |  | #endif | 
 |  | socklen_t listenname_len; | 
 |  |  | 
| if( (s = socket(PF_INET, SOCK_STREAM, 0)) < 0) | if( (s = socket( | 
|  | #ifdef ENABLE_IPV6 | 
|  | PF_INET6, | 
|  | #else | 
|  | PF_INET, | 
|  | #endif | 
|  | SOCK_STREAM, 0)) < 0) | 
 | { | { | 
 | syslog(LOG_ERR, "socket(http): %m"); | syslog(LOG_ERR, "socket(http): %m"); | 
 | return -1; | return -1; | 
| Line 116  OpenAndConfHTTPSocket(unsigned short port) | Line 133  OpenAndConfHTTPSocket(unsigned short port) | 
 | { | { | 
 | syslog(LOG_WARNING, "setsockopt(http, SO_REUSEADDR): %m"); | syslog(LOG_WARNING, "setsockopt(http, SO_REUSEADDR): %m"); | 
 | } | } | 
 |  | #if 0 | 
 |  | /* enable this to force IPV6 only for IPV6 socket. | 
 |  | * see http://www.ietf.org/rfc/rfc3493.txt section 5.3 */ | 
 |  | if(setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &i, sizeof(i)) < 0) | 
 |  | { | 
 |  | syslog(LOG_WARNING, "setsockopt(http, IPV6_V6ONLY): %m"); | 
 |  | } | 
 |  | #endif | 
 |  |  | 
| memset(&listenname, 0, sizeof(struct sockaddr_in)); | 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; | 
|  | listenname.sin6_port = htons(port); | 
|  | listenname.sin6_addr = in6addr_any; | 
|  | listenname_len =  sizeof(struct sockaddr_in6); | 
|  | #else | 
 | listenname.sin_family = AF_INET; | listenname.sin_family = AF_INET; | 
 | listenname.sin_port = htons(port); | listenname.sin_port = htons(port); | 
 | listenname.sin_addr.s_addr = htonl(INADDR_ANY); | listenname.sin_addr.s_addr = htonl(INADDR_ANY); | 
 |  | listenname_len =  sizeof(struct sockaddr_in); | 
 |  | #endif | 
 |  |  | 
| if(bind(s, (struct sockaddr *)&listenname, sizeof(struct sockaddr_in)) < 0) | if(bind(s, (struct sockaddr *)&listenname, listenname_len) < 0) | 
 | { | { | 
 | syslog(LOG_ERR, "bind(http): %m"); | syslog(LOG_ERR, "bind(http): %m"); | 
 | close(s); | close(s); | 
 | return -1; | return -1; | 
 | } | } | 
 |  |  | 
| if(listen(s, 6) < 0) | if(listen(s, 5) < 0) | 
 | { | { | 
 | syslog(LOG_ERR, "listen(http): %m"); | syslog(LOG_ERR, "listen(http): %m"); | 
 | close(s); | close(s); | 
| Line 169  OpenAndConfNFqueue(){ | Line 207  OpenAndConfNFqueue(){ | 
 |  |  | 
 | inet_pton(AF_INET, "239.255.255.250", &(ssdp.sin_addr)); | 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())) { | if (!(nfqHandle = nfq_open())) { | 
 | syslog(LOG_ERR, "Error in nfq_open(): %m"); | syslog(LOG_ERR, "Error in nfq_open(): %m"); | 
 | return -1; | return -1; | 
 | } | } | 
 |  |  | 
| //Unbind the handler from processing any IP packets | /* Unbind the handler from processing any IP packets | 
| //      Not totally sure why this is done, or if it's necessary... | Not totally sure why this is done, or if it's necessary... */ | 
 | if ((e = nfq_unbind_pf(nfqHandle, AF_INET)) < 0) { | if ((e = nfq_unbind_pf(nfqHandle, AF_INET)) < 0) { | 
 | syslog(LOG_ERR, "Error in nfq_unbind_pf(): %m"); | syslog(LOG_ERR, "Error in nfq_unbind_pf(): %m"); | 
 | return -1; | return -1; | 
 | } | } | 
 |  |  | 
| //Bind this handler to process IP packets... | /* Bind this handler to process IP packets... */ | 
 | if (nfq_bind_pf(nfqHandle, AF_INET) < 0) { | if (nfq_bind_pf(nfqHandle, AF_INET) < 0) { | 
 | syslog(LOG_ERR, "Error in nfq_bind_pf(): %m"); | syslog(LOG_ERR, "Error in nfq_bind_pf(): %m"); | 
 | return -1; | return -1; | 
 | } | } | 
 |  |  | 
| //      Install a callback on queue -Q | /*      Install a callback on queue -Q */ | 
 | if (!(myQueue = nfq_create_queue(nfqHandle,  nfqueue, &nfqueue_cb, NULL))) { | if (!(myQueue = nfq_create_queue(nfqHandle,  nfqueue, &nfqueue_cb, NULL))) { | 
 | syslog(LOG_ERR, "Error in nfq_create_queue(): %m"); | syslog(LOG_ERR, "Error in nfq_create_queue(): %m"); | 
 | return -1; | return -1; | 
 | } | } | 
 |  |  | 
| //      Turn on packet copy mode | /*      Turn on packet copy mode */ | 
 | if (nfq_set_mode(myQueue, NFQNL_COPY_PACKET, 0xffff) < 0) { | if (nfq_set_mode(myQueue, NFQNL_COPY_PACKET, 0xffff) < 0) { | 
 | syslog(LOG_ERR, "Error setting packet copy mode (): %m"); | syslog(LOG_ERR, "Error setting packet copy mode (): %m"); | 
 | return -1; | return -1; | 
| Line 232  static int nfqueue_cb( | Line 270  static int nfqueue_cb( | 
 | int dport = get_udp_dst_port(pkt); | int dport = get_udp_dst_port(pkt); | 
 |  |  | 
 | int x = sizeof (struct ip) + sizeof (struct udphdr); | 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 | * 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) ) { | && (ssdp.sin_addr.s_addr == iph->ip_dst.s_addr) ) { | 
|  |  | 
 | /* get the index that the packet came in on */ | /* get the index that the packet came in on */ | 
 | u_int32_t idx = nfq_get_indev(nfa); | u_int32_t idx = nfq_get_indev(nfa); | 
 | int i = 0; | int i = 0; | 
| Line 248  static int nfqueue_cb( | Line 286  static int nfqueue_cb( | 
 | struct udphdr *udp = (struct udphdr *) (pkt + sizeof(struct ip)); | struct udphdr *udp = (struct udphdr *) (pkt + sizeof(struct ip)); | 
 |  |  | 
 | char *dd = pkt + x; | char *dd = pkt + x; | 
|  |  | 
 | struct sockaddr_in sendername; | struct sockaddr_in sendername; | 
 | sendername.sin_family = AF_INET; | sendername.sin_family = AF_INET; | 
 | sendername.sin_port = udp->source; | sendername.sin_port = udp->source; | 
 | sendername.sin_addr.s_addr = iph->ip_src.s_addr; | sendername.sin_addr.s_addr = iph->ip_src.s_addr; | 
 |  |  | 
 | /* printf("pkt found %s\n",dd);*/ | /* printf("pkt found %s\n",dd);*/ | 
| ProcessSSDPData (sudp, dd, sendername, size - x, (unsigned short) 5555); | ProcessSSDPData (sudp, dd, size - x, | 
|  | &sendername, (unsigned short) 5555); | 
 | } | } | 
 | } | } | 
 | } | } | 
|  |  | 
 | nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL); | nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL); | 
 |  |  | 
 | } else { | } else { | 
 | syslog(LOG_ERR,"nfq_get_msg_packet_hdr failed"); | 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; | return 0; | 
| Line 344  write_ctlsockets_list(int fd, struct ctlelem * e) | Line 384  write_ctlsockets_list(int fd, struct ctlelem * e) | 
 | } | } | 
 | } | } | 
 |  |  | 
 |  | #ifndef DISABLE_CONFIG_FILE | 
 | static void | static void | 
 | write_option_list(int fd) | write_option_list(int fd) | 
 | { | { | 
 | char buffer[256]; | char buffer[256]; | 
 | int len; | int len; | 
| int i; | unsigned int i; | 
 | write(fd, "Options :\n", 10); | write(fd, "Options :\n", 10); | 
 | for(i=0; i<num_options; i++) | for(i=0; i<num_options; i++) | 
 | { | { | 
| Line 359  write_option_list(int fd) | Line 400  write_option_list(int fd) | 
 | write(fd, buffer, len); | write(fd, buffer, len); | 
 | } | } | 
 | } | } | 
 |  | #endif | 
 |  |  | 
 | static void | static void | 
 | write_command_line(int fd, int argc, char * * argv) | write_command_line(int fd, int argc, char * * argv) | 
| Line 378  write_command_line(int fd, int argc, char * * argv) | Line 420  write_command_line(int fd, int argc, char * * argv) | 
 |  |  | 
 | #endif | #endif | 
 |  |  | 
| /* Handler for the SIGTERM signal (kill) | /* Handler for the SIGTERM signal (kill) | 
 | * SIGINT is also handled */ | * SIGINT is also handled */ | 
 | static void | static void | 
 | sigterm(int sig) | sigterm(int sig) | 
 | { | { | 
| /*int save_errno = errno;*/ | UNUSED(sig); | 
| signal(sig, SIG_IGN);   /* Ignore this signal while we are quitting */ | /*int save_errno = errno; */ | 
|  | /*signal(sig, SIG_IGN);*/        /* Ignore this signal while we are quitting */ | 
|  | /* Note : isn't it useless ? */ | 
 |  |  | 
 |  | #if 0 | 
 |  | /* calling syslog() is forbidden in signal handler according to | 
 |  | * signal(3) */ | 
 | syslog(LOG_NOTICE, "received signal %d, good-bye", sig); | syslog(LOG_NOTICE, "received signal %d, good-bye", sig); | 
 |  | #endif | 
 |  |  | 
 | quitting = 1; | quitting = 1; | 
 | /*errno = save_errno;*/ | /*errno = save_errno;*/ | 
| Line 396  sigterm(int sig) | Line 444  sigterm(int sig) | 
 | static void | static void | 
 | sigusr1(int sig) | sigusr1(int sig) | 
 | { | { | 
 |  | UNUSED(sig); | 
 |  | #if 0 | 
 |  | /* calling syslog() is forbidden in signal handler according to | 
 |  | * signal(3) */ | 
 | syslog(LOG_INFO, "received signal %d, public ip address change", sig); | syslog(LOG_INFO, "received signal %d, public ip address change", sig); | 
 |  | #endif | 
 |  |  | 
 | should_send_public_address_change_notif = 1; | should_send_public_address_change_notif = 1; | 
 | } | } | 
| Line 472  set_startup_time(int sysuptime) | Line 525  set_startup_time(int sysuptime) | 
 | struct runtime_vars { | struct runtime_vars { | 
 | /* LAN IP addresses for SSDP traffic and HTTP */ | /* LAN IP addresses for SSDP traffic and HTTP */ | 
 | /* moved to global vars */ | /* moved to global vars */ | 
 | /*int n_lan_addr;*/ |  | 
 | /*struct lan_addr_s lan_addr[MAX_LAN_ADDR];*/ |  | 
 | int port;       /* HTTP Port */ | int port;       /* HTTP Port */ | 
 | int notify_interval;    /* seconds between SSDP announces */ | int notify_interval;    /* seconds between SSDP announces */ | 
 | /* unused rules cleaning related variables : */ | /* unused rules cleaning related variables : */ | 
| Line 483  struct runtime_vars { | Line 534  struct runtime_vars { | 
 |  |  | 
 | /* parselanaddr() | /* parselanaddr() | 
 | * parse address with mask | * parse address with mask | 
| * ex: 192.168.1.1/24 | * ex: 192.168.1.1/24 or 192.168.1.1/255.255.255.0 | 
 | * When MULTIPLE_EXTERNAL_IP is enabled, the ip address of the | * When MULTIPLE_EXTERNAL_IP is enabled, the ip address of the | 
 | * external interface associated with the lan subnet follows. | * external interface associated with the lan subnet follows. | 
 | * ex : 192.168.1.1/24 81.21.41.11 | * ex : 192.168.1.1/24 81.21.41.11 | 
 | * | * | 
| * return value : | * Can also use the interface name (ie eth0) | 
|  | * | 
|  | * return value : | 
 | *    0 : ok | *    0 : ok | 
 | *   -1 : error */ | *   -1 : error */ | 
 | static int | static int | 
 | parselanaddr(struct lan_addr_s * lan_addr, const char * str) | parselanaddr(struct lan_addr_s * lan_addr, const char * str) | 
 | { | { | 
 | const char * p; | const char * p; | 
 | int nbits = 24; /* by default, networks are /24 */ |  | 
 | int n; | int n; | 
 |  | char tmp[16]; | 
 |  |  | 
 |  | memset(lan_addr, 0, sizeof(struct lan_addr_s)); | 
 | p = str; | p = str; | 
 | while(*p && *p != '/' && !isspace(*p)) | while(*p && *p != '/' && !isspace(*p)) | 
 | p++; | p++; | 
 | n = p - str; | n = p - str; | 
| if(*p == '/') | if(!isdigit(str[0]) && n < (int)sizeof(lan_addr->ifname)) | 
 | { | { | 
| nbits = atoi(++p); | /* not starting with a digit : suppose it is an interface name */ | 
| while(*p && !isspace(*p)) | memcpy(lan_addr->ifname, str, n); | 
| p++; | 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); | if(n>15) | 
| return -1; | 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)) | if(!inet_aton(lan_addr->str, &lan_addr->addr)) | 
 |  | goto parselan_error; | 
 |  | if(*p == '/') | 
 | { | { | 
| fprintf(stderr, "Error parsing address/mask : %s\n", str); | const char * q = ++p; | 
| return -1; | 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 | #ifdef MULTIPLE_EXTERNAL_IP | 
 | /* skip spaces */ | /* skip spaces */ | 
 | while(*p && isspace(*p)) | while(*p && isspace(*p)) | 
| Line 539  parselanaddr(struct lan_addr_s * lan_addr, const char | Line 622  parselanaddr(struct lan_addr_s * lan_addr, const char | 
 | } | } | 
 | } | } | 
 | #endif | #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; | return 0; | 
 |  | parselan_error: | 
 |  | fprintf(stderr, "Error parsing address/mask (or interface name) : %s\n", | 
 |  | str); | 
 |  | return -1; | 
 | } | } | 
 |  |  | 
 | /* init phase : | /* init phase : | 
| Line 557  init(int argc, char * * argv, struct runtime_vars * v) | Line 653  init(int argc, char * * argv, struct runtime_vars * v) | 
 | int i; | int i; | 
 | int pid; | int pid; | 
 | int debug_flag = 0; | int debug_flag = 0; | 
 | int options_flag = 0; |  | 
 | int openlog_option; | int openlog_option; | 
 | struct sigaction sa; | struct sigaction sa; | 
 | /*const char * logfilename = 0;*/ | /*const char * logfilename = 0;*/ | 
 | const char * presurl = 0; | const char * presurl = 0; | 
 |  | #ifndef DISABLE_CONFIG_FILE | 
 |  | int options_flag = 0; | 
 | const char * optionsfile = DEFAULT_CONFIG; | const char * optionsfile = DEFAULT_CONFIG; | 
 |  | #endif /* DISABLE_CONFIG_FILE */ | 
 |  | struct lan_addr_s * lan_addr; | 
 |  | struct lan_addr_s * lan_addr2; | 
 |  |  | 
 | /* only print usage if -h is used */ | /* only print usage if -h is used */ | 
 | for(i=1; i<argc; i++) | for(i=1; i<argc; i++) | 
| Line 570  init(int argc, char * * argv, struct runtime_vars * v) | Line 670  init(int argc, char * * argv, struct runtime_vars * v) | 
 | if(0 == strcmp(argv[i], "-h")) | if(0 == strcmp(argv[i], "-h")) | 
 | goto print_usage; | goto print_usage; | 
 | } | } | 
 |  | #ifndef DISABLE_CONFIG_FILE | 
 | /* first check if "-f" option is used */ | /* first check if "-f" option is used */ | 
 | for(i=2; i<argc; i++) | for(i=2; i<argc; i++) | 
 | { | { | 
| Line 580  init(int argc, char * * argv, struct runtime_vars * v) | Line 681  init(int argc, char * * argv, struct runtime_vars * v) | 
 | break; | break; | 
 | } | } | 
 | } | } | 
 |  | #endif /* DISABLE_CONFIG_FILE */ | 
 |  |  | 
 | /* set initial values */ | /* set initial values */ | 
| SETFLAG(ENABLEUPNPMASK); | SETFLAG(ENABLEUPNPMASK);        /* UPnP is enabled by default */ | 
 |  |  | 
| /*v->n_lan_addr = 0;*/ | LIST_INIT(&lan_addrs); | 
 | v->port = -1; | v->port = -1; | 
 | v->notify_interval = 30;        /* seconds between SSDP announces */ | v->notify_interval = 30;        /* seconds between SSDP announces */ | 
 | v->clean_ruleset_threshold = 20; | v->clean_ruleset_threshold = 20; | 
 | v->clean_ruleset_interval = 0;  /* interval between ruleset check. 0=disabled */ | v->clean_ruleset_interval = 0;  /* interval between ruleset check. 0=disabled */ | 
|  | #ifndef DISABLE_CONFIG_FILE | 
 | /* read options file first since | /* read options file first since | 
 | * command line arguments have final say */ | * command line arguments have final say */ | 
 | if(readoptionsfile(optionsfile) < 0) | if(readoptionsfile(optionsfile) < 0) | 
| Line 600  init(int argc, char * * argv, struct runtime_vars * v) | Line 702  init(int argc, char * * argv, struct runtime_vars * v) | 
 | } | } | 
 | else | else | 
 | { | { | 
| for(i=0; i<num_options; i++) | for(i=0; i<(int)num_options; i++) | 
 | { | { | 
 | switch(ary_options[i].id) | switch(ary_options[i].id) | 
 | { | { | 
| Line 611  init(int argc, char * * argv, struct runtime_vars * v) | Line 713  init(int argc, char * * argv, struct runtime_vars * v) | 
 | use_ext_ip_addr = ary_options[i].value; | use_ext_ip_addr = ary_options[i].value; | 
 | break; | break; | 
 | case UPNPLISTENING_IP: | case UPNPLISTENING_IP: | 
| if(n_lan_addr < MAX_LAN_ADDR)/* if(v->n_lan_addr < MAX_LAN_ADDR)*/ | lan_addr = (struct lan_addr_s *) malloc(sizeof(struct lan_addr_s)); | 
|  | if (lan_addr == NULL) | 
 | { | { | 
| /*if(parselanaddr(&v->lan_addr[v->n_lan_addr],*/ | fprintf(stderr, "malloc(sizeof(struct lan_addr_s)): %m"); | 
| if(parselanaddr(&lan_addr[n_lan_addr], | break; | 
| ary_options[i].value) == 0) |  | 
| n_lan_addr++; /*v->n_lan_addr++; */ |  | 
 | } | } | 
| else | if(parselanaddr(lan_addr, ary_options[i].value) != 0) | 
 | { | { | 
| fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n", | fprintf(stderr, "can't parse \"%s\" as valid lan address\n", ary_options[i].value); | 
| MAX_LAN_ADDR, ary_options[i].value); | free(lan_addr); | 
|  | break; | 
 | } | } | 
 |  | LIST_INSERT_HEAD(&lan_addrs, lan_addr, list); | 
 | break; | break; | 
 | case UPNPPORT: | case UPNPPORT: | 
 | v->port = atoi(ary_options[i].value); | v->port = atoi(ary_options[i].value); | 
| Line 636  init(int argc, char * * argv, struct runtime_vars * v) | Line 739  init(int argc, char * * argv, struct runtime_vars * v) | 
 | case UPNPPRESENTATIONURL: | case UPNPPRESENTATIONURL: | 
 | presurl = ary_options[i].value; | presurl = ary_options[i].value; | 
 | break; | break; | 
 |  | case UPNPFRIENDLY_NAME: | 
 |  | strncpy(friendly_name, ary_options[i].value, FRIENDLY_NAME_MAX_LEN); | 
 |  | friendly_name[FRIENDLY_NAME_MAX_LEN-1] = '\0'; | 
 |  | break; | 
 | #ifdef USE_NETFILTER | #ifdef USE_NETFILTER | 
 | case UPNPFORWARDCHAIN: | case UPNPFORWARDCHAIN: | 
 | miniupnpd_forward_chain = ary_options[i].value; | miniupnpd_forward_chain = ary_options[i].value; | 
| Line 651  init(int argc, char * * argv, struct runtime_vars * v) | Line 758  init(int argc, char * * argv, struct runtime_vars * v) | 
 | if(strcmp(ary_options[i].value, "yes") == 0) | if(strcmp(ary_options[i].value, "yes") == 0) | 
 | SETFLAG(SYSUPTIMEMASK); /*sysuptime = 1;*/ | SETFLAG(SYSUPTIMEMASK); /*sysuptime = 1;*/ | 
 | break; | break; | 
 |  | #if defined(USE_PF) || defined(USE_IPF) | 
 | case UPNPPACKET_LOG: | case UPNPPACKET_LOG: | 
 | if(strcmp(ary_options[i].value, "yes") == 0) | if(strcmp(ary_options[i].value, "yes") == 0) | 
 | SETFLAG(LOGPACKETSMASK);        /*logpackets = 1;*/ | SETFLAG(LOGPACKETSMASK);        /*logpackets = 1;*/ | 
 | break; | break; | 
 |  | #endif | 
 | case UPNPUUID: | case UPNPUUID: | 
 | strncpy(uuidvalue+5, ary_options[i].value, | strncpy(uuidvalue+5, ary_options[i].value, | 
 | strlen(uuidvalue+5) + 1); | strlen(uuidvalue+5) + 1); | 
| Line 662  init(int argc, char * * argv, struct runtime_vars * v) | Line 771  init(int argc, char * * argv, struct runtime_vars * v) | 
 | case UPNPSERIAL: | case UPNPSERIAL: | 
 | strncpy(serialnumber, ary_options[i].value, SERIALNUMBER_MAX_LEN); | strncpy(serialnumber, ary_options[i].value, SERIALNUMBER_MAX_LEN); | 
 | serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0'; | serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0'; | 
| break; | break; | 
 | case UPNPMODEL_NUMBER: | case UPNPMODEL_NUMBER: | 
 | strncpy(modelnumber, ary_options[i].value, MODELNUMBER_MAX_LEN); | strncpy(modelnumber, ary_options[i].value, MODELNUMBER_MAX_LEN); | 
 | modelnumber[MODELNUMBER_MAX_LEN-1] = '\0'; | modelnumber[MODELNUMBER_MAX_LEN-1] = '\0'; | 
| Line 674  init(int argc, char * * argv, struct runtime_vars * v) | Line 783  init(int argc, char * * argv, struct runtime_vars * v) | 
 | v->clean_ruleset_interval = atoi(ary_options[i].value); | v->clean_ruleset_interval = atoi(ary_options[i].value); | 
 | break; | break; | 
 | #ifdef USE_PF | #ifdef USE_PF | 
 |  | case UPNPANCHOR: | 
 |  | anchor_name = ary_options[i].value; | 
 |  | break; | 
 | case UPNPQUEUE: | case UPNPQUEUE: | 
 | queue = ary_options[i].value; | queue = ary_options[i].value; | 
 | break; | break; | 
| Line 719  init(int argc, char * * argv, struct runtime_vars * v) | Line 831  init(int argc, char * * argv, struct runtime_vars * v) | 
 | } | } | 
 | } | } | 
 | } | } | 
 |  | #endif /* DISABLE_CONFIG_FILE */ | 
 |  |  | 
 | /* command line arguments processing */ | /* command line arguments processing */ | 
 | for(i=1; i<argc; i++) | for(i=1; i<argc; i++) | 
| Line 741  init(int argc, char * * argv, struct runtime_vars * v) | Line 854  init(int argc, char * * argv, struct runtime_vars * v) | 
 | else | else | 
 | fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); | fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); | 
 | break; | break; | 
 |  | case 'r': | 
 |  | if(i+1 < argc) | 
 |  | v->clean_ruleset_interval = atoi(argv[++i]); | 
 |  | else | 
 |  | fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); | 
 |  | break; | 
 | case 'u': | case 'u': | 
 | if(i+1 < argc) | if(i+1 < argc) | 
 | strncpy(uuidvalue+5, argv[++i], strlen(uuidvalue+5) + 1); | strncpy(uuidvalue+5, argv[++i], strlen(uuidvalue+5) + 1); | 
 | else | else | 
 | fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); | fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); | 
 | break; | 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': | case 's': | 
 | if(i+1 < argc) | if(i+1 < argc) | 
 | strncpy(serialnumber, argv[++i], SERIALNUMBER_MAX_LEN); | strncpy(serialnumber, argv[++i], SERIALNUMBER_MAX_LEN); | 
| Line 774  init(int argc, char * * argv, struct runtime_vars * v) | Line 900  init(int argc, char * * argv, struct runtime_vars * v) | 
 | /*case 'l': | /*case 'l': | 
 | logfilename = argv[++i]; | logfilename = argv[++i]; | 
 | break;*/ | break;*/ | 
 |  | #if defined(USE_PF) || defined(USE_IPF) | 
 | case 'L': | case 'L': | 
 | /*logpackets = 1;*/ | /*logpackets = 1;*/ | 
 | SETFLAG(LOGPACKETSMASK); | SETFLAG(LOGPACKETSMASK); | 
 | break; | break; | 
 |  | #endif | 
 | case 'S': | case 'S': | 
 | SETFLAG(SECUREMODEMASK); | SETFLAG(SECUREMODEMASK); | 
 | break; | break; | 
| Line 854  init(int argc, char * * argv, struct runtime_vars * v) | Line 982  init(int argc, char * * argv, struct runtime_vars * v) | 
 | fprintf(stderr, "Option -%c takes two arguments.\n", argv[i][1]); | fprintf(stderr, "Option -%c takes two arguments.\n", argv[i][1]); | 
 | break; | break; | 
 | case 'a': | case 'a': | 
 |  | #ifndef MULTIPLE_EXTERNAL_IP | 
 | if(i+1 < argc) | if(i+1 < argc) | 
 | { | { | 
 | int address_already_there = 0; |  | 
 | int j; |  | 
 | i++; | i++; | 
| for(j=0; j<n_lan_addr; j++) | lan_addr = (struct lan_addr_s *) malloc(sizeof(struct lan_addr_s)); | 
|  | if (lan_addr == NULL) | 
 | { | { | 
| struct lan_addr_s tmpaddr; | fprintf(stderr, "malloc(sizeof(struct lan_addr_s)): %m"); | 
| parselanaddr(&tmpaddr, argv[i]); | break; | 
| if(0 == strcmp(lan_addr[j].str, tmpaddr.str)) |  | 
| address_already_there = 1; |  | 
 | } | } | 
| if(address_already_there) | if(parselanaddr(lan_addr, argv[i]) != 0) | 
|  | { | 
|  | fprintf(stderr, "can't parse \"%s\" as valid lan address\n", argv[i]); | 
|  | free(lan_addr); | 
 | break; | break; | 
| if(n_lan_addr < MAX_LAN_ADDR) | } | 
|  | /* 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(parselanaddr(&lan_addr[n_lan_addr], argv[i]) == 0) | if (0 == strncmp(lan_addr2->str, lan_addr->str, 15)) | 
| n_lan_addr++; | break; | 
 | } | } | 
| else | if (lan_addr2 == NULL) | 
|  | LIST_INSERT_HEAD(&lan_addrs, lan_addr, list); | 
|  | } | 
|  | 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, "Too many listening ips (max: %d), ignoring %s\n", | fprintf(stderr, "memory allocation error for listen address storage\n"); | 
| MAX_LAN_ADDR, argv[i]); | 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 | 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]); | fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); | 
 | break; | break; | 
 | case 'f': | case 'f': | 
| Line 889  init(int argc, char * * argv, struct runtime_vars * v) | Line 1074  init(int argc, char * * argv, struct runtime_vars * v) | 
 | fprintf(stderr, "Unknown option: %s\n", argv[i]); | fprintf(stderr, "Unknown option: %s\n", argv[i]); | 
 | } | } | 
 | } | } | 
| if(!ext_if_name || (n_lan_addr==0)) | if(!ext_if_name || !lan_addrs.lh_first) | 
 | { | { | 
 | /* bad configuration */ | /* bad configuration */ | 
 | goto print_usage; | goto print_usage; | 
| Line 929  init(int argc, char * * argv, struct runtime_vars * v) | Line 1114  init(int argc, char * * argv, struct runtime_vars * v) | 
 | { | { | 
 | syslog(LOG_ERR, "MiniUPnPd is already running. EXITING"); | syslog(LOG_ERR, "MiniUPnPd is already running. EXITING"); | 
 | return 1; | return 1; | 
| } | } | 
 |  |  | 
 | set_startup_time(GETFLAG(SYSUPTIMEMASK)); | set_startup_time(GETFLAG(SYSUPTIMEMASK)); | 
 |  |  | 
| Line 942  init(int argc, char * * argv, struct runtime_vars * v) | Line 1127  init(int argc, char * * argv, struct runtime_vars * v) | 
 | else | else | 
 | { | { | 
 | snprintf(presentationurl, PRESENTATIONURL_MAX_LEN, | snprintf(presentationurl, PRESENTATIONURL_MAX_LEN, | 
| "http://%s/", lan_addr[0].str); | "http://%s/", lan_addrs.lh_first->str); | 
| /*"http://%s:%d/", lan_addr[0].str, 80);*/ | /*"http://%s:%d/", lan_addrs.lh_first->str, 80);*/ | 
 | } | } | 
 |  |  | 
 | /* set signal handler */ | /* set signal handler */ | 
 | memset(&sa, 0, sizeof(struct sigaction)); | memset(&sa, 0, sizeof(struct sigaction)); | 
 | sa.sa_handler = sigterm; | 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"); | syslog(LOG_ERR, "Failed to set %s handler. EXITING", "SIGTERM"); | 
 | return 1; | return 1; | 
 | } | } | 
| if (sigaction(SIGINT, &sa, NULL)) | if(sigaction(SIGINT, &sa, NULL) < 0) | 
 | { | { | 
 | syslog(LOG_ERR, "Failed to set %s handler. EXITING", "SIGINT"); | syslog(LOG_ERR, "Failed to set %s handler. EXITING", "SIGINT"); | 
 | return 1; | return 1; | 
 | } | } | 
|  | sa.sa_handler = SIG_IGN; | 
| if(signal(SIGPIPE, SIG_IGN) == SIG_ERR) { | if(sigaction(SIGPIPE, &sa, NULL) < 0) | 
|  | { | 
 | syslog(LOG_ERR, "Failed to ignore SIGPIPE signals"); | syslog(LOG_ERR, "Failed to ignore SIGPIPE signals"); | 
 | } | } | 
 |  |  | 
 | sa.sa_handler = sigusr1; | sa.sa_handler = sigusr1; | 
| if (sigaction(SIGUSR1, &sa, NULL)) | if(sigaction(SIGUSR1, &sa, NULL) < 0) | 
 | { | { | 
 | syslog(LOG_NOTICE, "Failed to set %s handler", "SIGUSR1"); | syslog(LOG_NOTICE, "Failed to set %s handler", "SIGUSR1"); | 
 | } | } | 
| Line 976  init(int argc, char * * argv, struct runtime_vars * v) | Line 1161  init(int argc, char * * argv, struct runtime_vars * v) | 
 | syslog(LOG_ERR, "Failed to init redirection engine. EXITING"); | syslog(LOG_ERR, "Failed to init redirection engine. EXITING"); | 
 | return 1; | 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 | #ifdef ENABLE_LEASEFILE | 
 | /*remove(lease_file);*/ | /*remove(lease_file);*/ | 
| Line 988  init(int argc, char * * argv, struct runtime_vars * v) | Line 1179  init(int argc, char * * argv, struct runtime_vars * v) | 
 | return 0; | return 0; | 
 | print_usage: | print_usage: | 
 | fprintf(stderr, "Usage:\n\t" | fprintf(stderr, "Usage:\n\t" | 
| "%s [-f config_file] [-i ext_ifname] [-o ext_ip]\n" | "%s " | 
| #ifndef ENABLE_NATPMP | #ifndef DISABLE_CONFIG_FILE | 
| "\t\t[-a listening_ip] [-p port] [-d] [-L] [-U] [-S]\n" | "[-f config_file] " | 
|  | #endif | 
|  | "[-i ext_ifname] [-o ext_ip]\n" | 
|  | #ifndef MULTIPLE_EXTERNAL_IP | 
|  | "\t\t[-a listening_ip]" | 
 | #else | #else | 
| "\t\t[-a listening_ip] [-p port] [-d] [-L] [-U] [-S] [-N]\n" | "\t\t[-a listening_ip ext_ip]" | 
 | #endif | #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 */ | /*"[-l logfile] " not functionnal */ | 
 | "\t\t[-u uuid] [-s serial] [-m model_number] \n" | "\t\t[-u uuid] [-s serial] [-m model_number] \n" | 
| "\t\t[-t notify_interval] [-P pid_filename]\n" | "\t\t[-t notify_interval] [-P pid_filename] [-z fiendly_name]\n" | 
| "\t\t[-B down up] [-w url]\n" | "\t\t[-B down up] [-w url] [-r clean_ruleset_interval]\n" | 
 | #ifdef USE_PF | #ifdef USE_PF | 
 | "\t\t[-q queue] [-T tag]\n" | "\t\t[-q queue] [-T tag]\n" | 
 | #endif | #endif | 
 | #ifdef ENABLE_NFQUEUE | #ifdef ENABLE_NFQUEUE | 
 | "\t\t[-Q queue] [-n name]\n" | "\t\t[-Q queue] [-n name]\n" | 
 | #endif | #endif | 
 |  | "\t\t[-A \"permission rule\"]\n" | 
 | "\nNotes:\n\tThere can be one or several listening_ips.\n" | "\nNotes:\n\tThere can be one or several listening_ips.\n" | 
 | "\tNotify interval is in seconds. Default is 30 seconds.\n" | "\tNotify interval is in seconds. Default is 30 seconds.\n" | 
 | "\tDefault pid file is '%s'.\n" | "\tDefault pid file is '%s'.\n" | 
 | "\tDefault config file is '%s'.\n" | "\tDefault config file is '%s'.\n" | 
 | "\tWith -d miniupnpd will run as a standard program.\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" | "\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-S sets \"secure\" mode : clients can only add mappings to their own ip\n" | 
 | "\t-U causes miniupnpd to report system uptime instead " | "\t-U causes miniupnpd to report system uptime instead " | 
 | "of daemon uptime.\n" | "of daemon uptime.\n" | 
 | #ifdef ENABLE_NATPMP | #ifdef ENABLE_NATPMP | 
| "\t-N enable NAT-PMP functionnality.\n" | "\t-N enable NAT-PMP functionality.\n" | 
 | #endif | #endif | 
 | "\t-B sets bitrates reported by daemon in bits per second.\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" | "\t-w sets the presentation url. Default is http address on port 80\n" | 
| Line 1023  print_usage: | Line 1230  print_usage: | 
 | "\t-T sets the tag name in pf.\n" | "\t-T sets the tag name in pf.\n" | 
 | #endif | #endif | 
 | #ifdef ENABLE_NFQUEUE | #ifdef ENABLE_NFQUEUE | 
| "\t-Q sets the queue number that is used by NFQUEUE.\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" | "\t-n sets the name of the interface(s) that packets will arrive on.\n" | 
 | #endif | #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" | "\t-h prints this help and quits.\n" | 
 | "", argv[0], pidfilename, DEFAULT_CONFIG); | "", argv[0], pidfilename, DEFAULT_CONFIG); | 
 | return 1; | return 1; | 
| Line 1037  int | Line 1249  int | 
 | main(int argc, char * * argv) | main(int argc, char * * argv) | 
 | { | { | 
 | int i; | int i; | 
| int shttpl = -1; | int shttpl = -1;        /* socket for HTTP */ | 
|  | int sudp = -1;          /* IP v4 socket for receiving SSDP */ | 
|  | #ifdef ENABLE_IPV6 | 
|  | int sudpv6 = -1;        /* IP v6 socket for receiving SSDP */ | 
|  | #endif | 
 | #ifdef ENABLE_NATPMP | #ifdef ENABLE_NATPMP | 
| int snatpmp[MAX_LAN_ADDR]; | int * snatpmp = NULL; | 
|  | #endif | 
 | #ifdef ENABLE_NFQUEUE | #ifdef ENABLE_NFQUEUE | 
 | int nfqh = -1; | int nfqh = -1; | 
 | #endif | #endif | 
 |  | #ifdef USE_IFACEWATCHER | 
 |  | int sifacewatcher = -1; | 
 | #endif | #endif | 
| int snotify[MAX_LAN_ADDR]; |  | 
|  | int * snotify = NULL; | 
|  | int addr_count; | 
 | LIST_HEAD(httplisthead, upnphttp) upnphttphead; | LIST_HEAD(httplisthead, upnphttp) upnphttphead; | 
 | struct upnphttp * e = 0; | struct upnphttp * e = 0; | 
 | struct upnphttp * next; | struct upnphttp * next; | 
 | fd_set readset; /* for select() */ | fd_set readset; /* for select() */ | 
 | #ifdef ENABLE_EVENTS |  | 
 | fd_set writeset; | fd_set writeset; | 
 | #endif |  | 
 | struct timeval timeout, timeofday, lasttimeofday = {0, 0}; | struct timeval timeout, timeofday, lasttimeofday = {0, 0}; | 
 | int max_fd = -1; | int max_fd = -1; | 
 | #ifdef USE_MINIUPNPDCTL | #ifdef USE_MINIUPNPDCTL | 
| Line 1064  main(int argc, char * * argv) | Line 1283  main(int argc, char * * argv) | 
 | /* variables used for the unused-rule cleanup process */ | /* variables used for the unused-rule cleanup process */ | 
 | struct rule_state * rule_list = 0; | struct rule_state * rule_list = 0; | 
 | struct timeval checktime = {0, 0}; | struct timeval checktime = {0, 0}; | 
| syslog(LOG_INFO, "SNet version started"); | struct lan_addr_s * lan_addr; | 
|  | #ifdef ENABLE_6FC_SERVICE | 
|  | unsigned int next_pinhole_ts; | 
| memset(snotify, 0, sizeof(snotify)); |  | 
| #ifdef ENABLE_NATPMP |  | 
| for(i = 0; i < MAX_LAN_ADDR; i++) |  | 
| snatpmp[i] = -1; |  | 
 | #endif | #endif | 
 |  |  | 
 | if(init(argc, argv, &v) != 0) | if(init(argc, argv, &v) != 0) | 
 | return 1; | return 1; | 
 |  | /* count lan addrs */ | 
 |  | addr_count = 0; | 
 |  | for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next) | 
 |  | addr_count++; | 
 |  | 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 | 
 |  | if(addr_count > 0) { | 
 |  | snatpmp = malloc(addr_count * sizeof(int)); | 
 |  | for(i = 0; i < addr_count; i++) | 
 |  | snatpmp[i] = -1; | 
 |  | } | 
 |  | #endif | 
 |  |  | 
 | LIST_INIT(&upnphttphead); | LIST_INIT(&upnphttphead); | 
 | #ifdef USE_MINIUPNPDCTL | #ifdef USE_MINIUPNPDCTL | 
| Line 1089  main(int argc, char * * argv) | Line 1324  main(int argc, char * * argv) | 
 | return 0; | 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)) | if(GETFLAG(ENABLEUPNPMASK)) | 
 | { | { | 
 |  |  | 
| Line 1109  main(int argc, char * * argv) | Line 1353  main(int argc, char * * argv) | 
 | v.port = ntohs(sockinfo.sin_port); | v.port = ntohs(sockinfo.sin_port); | 
 | } | } | 
 | syslog(LOG_NOTICE, "HTTP listening on port %d", v.port); | syslog(LOG_NOTICE, "HTTP listening on port %d", v.port); | 
 |  | #ifdef ENABLE_IPV6 | 
 |  | if(find_ipv6_addr(NULL, ipv6_addr_for_http_with_brackets, sizeof(ipv6_addr_for_http_with_brackets)) > 0) { | 
 |  | syslog(LOG_NOTICE, "HTTP IPv6 address given to control points : %s", | 
 |  | ipv6_addr_for_http_with_brackets); | 
 |  | } else { | 
 |  | memcpy(ipv6_addr_for_http_with_brackets, "[::1]", 6); | 
 |  | syslog(LOG_WARNING, "no HTTP IPv6 address"); | 
 |  | } | 
 |  | #endif | 
 |  |  | 
 | /* open socket for SSDP connections */ | /* open socket for SSDP connections */ | 
| sudp = OpenAndConfSSDPReceiveSocket(n_lan_addr, lan_addr); | sudp = OpenAndConfSSDPReceiveSocket(0); | 
 | if(sudp < 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_addr[0].str, v.port) < 0) { | if(SubmitServicesToMiniSSDPD(lan_addrs.lh_first->str, v.port) < 0) { | 
 | syslog(LOG_ERR, "Failed to connect to MiniSSDPd. EXITING"); | syslog(LOG_ERR, "Failed to connect to MiniSSDPd. EXITING"); | 
 | return 1; | return 1; | 
 | } | } | 
 | } | } | 
 |  | #ifdef ENABLE_IPV6 | 
 |  | sudpv6 = OpenAndConfSSDPReceiveSocket(1); | 
 |  | if(sudpv6 < 0) | 
 |  | { | 
 |  | syslog(LOG_WARNING, "Failed to open socket for receiving SSDP (IP v6)."); | 
 |  | } | 
 |  | #endif | 
 |  |  | 
 | /* open socket for sending notifications */ | /* open socket for sending notifications */ | 
 | if(OpenAndConfSSDPNotifySockets(snotify) < 0) | if(OpenAndConfSSDPNotifySockets(snotify) < 0) | 
| Line 1128  main(int argc, char * * argv) | Line 1388  main(int argc, char * * argv) | 
 | "messages. EXITING"); | "messages. EXITING"); | 
 | return 1; | return 1; | 
 | } | } | 
 |  |  | 
 |  | #ifdef USE_IFACEWATCHER | 
 |  | /* open socket for kernel notifications about new network interfaces */ | 
 |  | if (sudp >= 0) | 
 |  | { | 
 |  | sifacewatcher = OpenAndConfInterfaceWatchSocket(); | 
 |  | if (sifacewatcher < 0) | 
 |  | { | 
 |  | syslog(LOG_ERR, "Failed to open socket for receiving network interface notifications"); | 
 |  | } | 
 |  | } | 
 |  | #endif | 
 | } | } | 
 |  |  | 
 | #ifdef ENABLE_NATPMP | #ifdef ENABLE_NATPMP | 
| Line 1141  main(int argc, char * * argv) | Line 1413  main(int argc, char * * argv) | 
 | syslog(LOG_NOTICE, "Listening for NAT-PMP traffic on port %u", | syslog(LOG_NOTICE, "Listening for NAT-PMP traffic on port %u", | 
 | NATPMP_PORT); | NATPMP_PORT); | 
 | } | } | 
 |  | #if 0 | 
 | ScanNATPMPforExpiration(); | ScanNATPMPforExpiration(); | 
 |  | #endif | 
 | } | } | 
 | #endif | #endif | 
 |  |  | 
| Line 1161  main(int argc, char * * argv) | Line 1435  main(int argc, char * * argv) | 
 | } | } | 
 | } | } | 
 | #endif | #endif | 
 |  |  | 
 | /* main loop */ | /* main loop */ | 
 | while(!quitting) | while(!quitting) | 
 | { | { | 
| Line 1168  main(int argc, char * * argv) | Line 1443  main(int argc, char * * argv) | 
 | if((startup_time<60*60*24) && (time(NULL)>60*60*24)) | if((startup_time<60*60*24) && (time(NULL)>60*60*24)) | 
 | { | { | 
 | set_startup_time(GETFLAG(SYSUPTIMEMASK)); | set_startup_time(GETFLAG(SYSUPTIMEMASK)); | 
| } | } | 
|  | /* send public address change notifications if needed */ | 
|  | if(should_send_public_address_change_notif) | 
|  | { | 
|  | syslog(LOG_DEBUG, "should send external iface address change notification(s)"); | 
|  | #ifdef ENABLE_NATPMP | 
|  | if(GETFLAG(ENABLENATPMPMASK)) | 
|  | SendNATPMPPublicAddressChangeNotification(snatpmp, addr_count); | 
|  | #endif | 
|  | #ifdef ENABLE_EVENTS | 
|  | if(GETFLAG(ENABLEUPNPMASK)) | 
|  | { | 
|  | upnp_event_var_change_notify(EWanIPC); | 
|  | } | 
|  | #endif | 
|  | should_send_public_address_change_notif = 0; | 
|  | } | 
 | /* Check if we need to send SSDP NOTIFY messages and do it if | /* Check if we need to send SSDP NOTIFY messages and do it if | 
 | * needed */ | * needed */ | 
 | if(gettimeofday(&timeofday, 0) < 0) | if(gettimeofday(&timeofday, 0) < 0) | 
| Line 1221  main(int argc, char * * argv) | Line 1512  main(int argc, char * * argv) | 
 | } | } | 
 | memcpy(&checktime, &timeofday, sizeof(struct timeval)); | memcpy(&checktime, &timeofday, sizeof(struct timeval)); | 
 | } | } | 
 |  | /* Remove expired port mappings, based on UPnP IGD LeaseDuration | 
 |  | * or NAT-PMP lifetime) */ | 
 |  | if(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 | 
 |  | && ((unsigned int)timeout.tv_sec >= (nextruletoclean_timestamp - timeofday.tv_sec))) | 
 |  | { | 
 |  | timeout.tv_sec = nextruletoclean_timestamp - timeofday.tv_sec; | 
 |  | timeout.tv_usec = 0; | 
 |  | syslog(LOG_DEBUG, "setting timeout to %u sec", | 
 |  | (unsigned)timeout.tv_sec); | 
 |  | } | 
 | #ifdef ENABLE_NATPMP | #ifdef ENABLE_NATPMP | 
 |  | #if 0 | 
 | /* Remove expired NAT-PMP mappings */ | /* Remove expired NAT-PMP mappings */ | 
| while( nextnatpmptoclean_timestamp && (timeofday.tv_sec >= nextnatpmptoclean_timestamp + startup_time)) | while(nextnatpmptoclean_timestamp | 
|  | && (timeofday.tv_sec >= nextnatpmptoclean_timestamp + startup_time)) | 
 | { | { | 
 | /*syslog(LOG_DEBUG, "cleaning expired NAT-PMP mappings");*/ | /*syslog(LOG_DEBUG, "cleaning expired NAT-PMP mappings");*/ | 
 | if(CleanExpiredNATPMP() < 0) { | if(CleanExpiredNATPMP() < 0) { | 
| Line 1231  main(int argc, char * * argv) | Line 1540  main(int argc, char * * argv) | 
 | break; | break; | 
 | } | } | 
 | } | } | 
| if(nextnatpmptoclean_timestamp && timeout.tv_sec >= (nextnatpmptoclean_timestamp + startup_time - timeofday.tv_sec)) | 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);*/ | /*syslog(LOG_DEBUG, "setting timeout to %d sec", | 
| #ifdef ENABLE_NFQUEUE | nextnatpmptoclean_timestamp + startup_time - timeofday.tv_sec);*/ | 
| if (nfqh >= 0) | timeout.tv_sec = nextnatpmptoclean_timestamp + startup_time - timeofday.tv_sec; | 
| { | timeout.tv_usec = 0; | 
| FD_SET(nfqh, &readset); |  | 
| max_fd = MAX( max_fd, nfqh); |  | 
 | } | } | 
 | #endif | #endif | 
|  | #endif | 
| timeout.tv_sec = nextnatpmptoclean_timestamp + startup_time - timeofday.tv_sec; | #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; | timeout.tv_usec = 0; | 
 | } | } | 
 | #endif | #endif | 
 |  |  | 
 | /* select open sockets (SSDP, HTTP listen, and all HTTP soap sockets) */ | /* select open sockets (SSDP, HTTP listen, and all HTTP soap sockets) */ | 
 | FD_ZERO(&readset); | FD_ZERO(&readset); | 
 |  | FD_ZERO(&writeset); | 
 |  |  | 
| if (sudp >= 0) | if (sudp >= 0) | 
 | { | { | 
 | FD_SET(sudp, &readset); | FD_SET(sudp, &readset); | 
 | max_fd = MAX( max_fd, sudp); | max_fd = MAX( max_fd, sudp); | 
 |  | #ifdef USE_IFACEWATCHER | 
 |  | if (sifacewatcher >= 0) | 
 |  | { | 
 |  | FD_SET(sifacewatcher, &readset); | 
 |  | max_fd = MAX(max_fd, sifacewatcher); | 
 |  | } | 
 |  | #endif | 
 | } | } | 
|  | if (shttpl >= 0) | 
| if (shttpl >= 0) |  | 
 | { | { | 
 | FD_SET(shttpl, &readset); | FD_SET(shttpl, &readset); | 
 | max_fd = MAX( max_fd, shttpl); | max_fd = MAX( max_fd, shttpl); | 
 | } | } | 
 |  | #ifdef ENABLE_IPV6 | 
 |  | if (sudpv6 >= 0) | 
 |  | { | 
 |  | FD_SET(sudpv6, &readset); | 
 |  | max_fd = MAX( max_fd, sudpv6); | 
 |  | } | 
 |  | #endif | 
 |  |  | 
 |  | #ifdef ENABLE_NFQUEUE | 
 |  | if (nfqh >= 0) | 
 |  | { | 
 |  | FD_SET(nfqh, &readset); | 
 |  | max_fd = MAX( max_fd, nfqh); | 
 |  | } | 
 |  | #endif | 
 |  |  | 
 | i = 0;  /* active HTTP connections count */ | i = 0;  /* active HTTP connections count */ | 
 | for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next) | 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); | if(e->state <= EWaitingForHttpContent) | 
| max_fd = MAX( max_fd, e->socket); | 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++; | i++; | 
 | } | } | 
 | } | } | 
| Line 1280  main(int argc, char * * argv) | Line 1621  main(int argc, char * * argv) | 
 | } | } | 
 | #endif | #endif | 
 | #ifdef ENABLE_NATPMP | #ifdef ENABLE_NATPMP | 
| for(i=0; i<n_lan_addr; i++) { | for(i=0; i<addr_count; i++) { | 
 | if(snatpmp[i] >= 0) { | if(snatpmp[i] >= 0) { | 
 | FD_SET(snatpmp[i], &readset); | FD_SET(snatpmp[i], &readset); | 
 | max_fd = MAX( max_fd, snatpmp[i]); | max_fd = MAX( max_fd, snatpmp[i]); | 
| Line 1292  main(int argc, char * * argv) | Line 1633  main(int argc, char * * argv) | 
 | FD_SET(sctl, &readset); | FD_SET(sctl, &readset); | 
 | max_fd = MAX( max_fd, sctl); | max_fd = MAX( max_fd, sctl); | 
 | } | } | 
|  |  | 
 | for(ectl = ctllisthead.lh_first; ectl; ectl = ectl->entries.le_next) | for(ectl = ctllisthead.lh_first; ectl; ectl = ectl->entries.le_next) | 
 | { | { | 
 | if(ectl->socket >= 0) { | if(ectl->socket >= 0) { | 
| Line 1303  main(int argc, char * * argv) | Line 1644  main(int argc, char * * argv) | 
 | #endif | #endif | 
 |  |  | 
 | #ifdef ENABLE_EVENTS | #ifdef ENABLE_EVENTS | 
 | FD_ZERO(&writeset); |  | 
 | upnpevents_selectfds(&readset, &writeset, &max_fd); | upnpevents_selectfds(&readset, &writeset, &max_fd); | 
 | #endif | #endif | 
 |  |  | 
 | #ifdef ENABLE_EVENTS |  | 
 | if(select(max_fd+1, &readset, &writeset, 0, &timeout) < 0) | 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(quitting) goto shutdown; | 
 | if(errno == EINTR) continue; /* interrupted by a signal, start again */ | if(errno == EINTR) continue; /* interrupted by a signal, start again */ | 
| Line 1332  main(int argc, char * * argv) | Line 1668  main(int argc, char * * argv) | 
 | { | { | 
 | /*write(ectl->socket, buf, l);*/ | /*write(ectl->socket, buf, l);*/ | 
 | write_command_line(ectl->socket, argc, argv); | write_command_line(ectl->socket, argc, argv); | 
 |  | #ifndef DISABLE_CONFIG_FILE | 
 | write_option_list(ectl->socket); | write_option_list(ectl->socket); | 
 |  | #endif | 
 | write_permlist(ectl->socket, upnppermlist, num_upnpperm); | write_permlist(ectl->socket, upnppermlist, num_upnpperm); | 
 | write_upnphttp_details(ectl->socket, upnphttphead.lh_first); | write_upnphttp_details(ectl->socket, upnphttphead.lh_first); | 
 | write_ctlsockets_list(ectl->socket, ctllisthead.lh_first); | write_ctlsockets_list(ectl->socket, ctllisthead.lh_first); | 
| Line 1363  main(int argc, char * * argv) | Line 1701  main(int argc, char * * argv) | 
 | struct sockaddr_un clientname; | struct sockaddr_un clientname; | 
 | struct ctlelem * tmp; | struct ctlelem * tmp; | 
 | socklen_t clientnamelen = sizeof(struct sockaddr_un); | socklen_t clientnamelen = sizeof(struct sockaddr_un); | 
| //syslog(LOG_DEBUG, "sctl!"); | /*syslog(LOG_DEBUG, "sctl!");*/ | 
 | s = accept(sctl, (struct sockaddr *)&clientname, | s = accept(sctl, (struct sockaddr *)&clientname, | 
 | &clientnamelen); | &clientnamelen); | 
 | syslog(LOG_DEBUG, "sctl! : '%s'", clientname.sun_path); | syslog(LOG_DEBUG, "sctl! : '%s'", clientname.sun_path); | 
 | tmp = malloc(sizeof(struct ctlelem)); | tmp = malloc(sizeof(struct ctlelem)); | 
| tmp->socket = s; | if (tmp == NULL) | 
| LIST_INSERT_HEAD(&ctllisthead, tmp, entries); | { | 
|  | syslog(LOG_ERR, "Unable to allocate memory for ctlelem in main()"); | 
|  | close(s); | 
|  | } | 
|  | else | 
|  | { | 
|  | tmp->socket = s; | 
|  | LIST_INSERT_HEAD(&ctllisthead, tmp, entries); | 
|  | } | 
 | } | } | 
 | #endif | #endif | 
 | #ifdef ENABLE_EVENTS | #ifdef ENABLE_EVENTS | 
| Line 1377  main(int argc, char * * argv) | Line 1723  main(int argc, char * * argv) | 
 | #endif | #endif | 
 | #ifdef ENABLE_NATPMP | #ifdef ENABLE_NATPMP | 
 | /* process NAT-PMP packets */ | /* process NAT-PMP packets */ | 
| for(i=0; i<n_lan_addr; i++) | for(i=0; i<addr_count; i++) | 
 | { | { | 
 | if((snatpmp[i] >= 0) && FD_ISSET(snatpmp[i], &readset)) | if((snatpmp[i] >= 0) && FD_ISSET(snatpmp[i], &readset)) | 
 | { | { | 
| Line 1391  main(int argc, char * * argv) | Line 1737  main(int argc, char * * argv) | 
 | /*syslog(LOG_INFO, "Received UDP Packet");*/ | /*syslog(LOG_INFO, "Received UDP Packet");*/ | 
 | ProcessSSDPRequest(sudp, (unsigned short)v.port); | ProcessSSDPRequest(sudp, (unsigned short)v.port); | 
 | } | } | 
 |  | #ifdef ENABLE_IPV6 | 
 |  | if(sudpv6 >= 0 && FD_ISSET(sudpv6, &readset)) | 
 |  | { | 
 |  | syslog(LOG_INFO, "Received UDP Packet (IPv6)"); | 
 |  | ProcessSSDPRequest(sudpv6, (unsigned short)v.port); | 
 |  | } | 
 |  | #endif | 
 |  | #ifdef USE_IFACEWATCHER | 
 |  | /* process kernel notifications */ | 
 |  | if (sifacewatcher >= 0 && FD_ISSET(sifacewatcher, &readset)) | 
 |  | ProcessInterfaceWatchNotify(sifacewatcher); | 
 |  | #endif | 
 |  |  | 
 | /* process active HTTP connections */ | /* process active HTTP connections */ | 
 | /* LIST_FOREACH macro is not available under linux */ | /* LIST_FOREACH macro is not available under linux */ | 
 | for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next) | for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next) | 
 | { | { | 
| if(  (e->socket >= 0) && (e->state <= 2) | if(e->socket >= 0) | 
| &&(FD_ISSET(e->socket, &readset)) ) |  | 
 | { | { | 
| Process_upnphttp(e); | if(FD_ISSET(e->socket, &readset) || | 
|  | FD_ISSET(e->socket, &writeset)) | 
|  | { | 
|  | Process_upnphttp(e); | 
|  | } | 
 | } | } | 
 | } | } | 
 | /* process incoming HTTP connections */ | /* process incoming HTTP connections */ | 
| Line 1406  main(int argc, char * * argv) | Line 1768  main(int argc, char * * argv) | 
 | { | { | 
 | int shttp; | int shttp; | 
 | socklen_t clientnamelen; | socklen_t clientnamelen; | 
 |  | #ifdef ENABLE_IPV6 | 
 |  | struct sockaddr_storage clientname; | 
 |  | clientnamelen = sizeof(struct sockaddr_storage); | 
 |  | #else | 
 | struct sockaddr_in clientname; | struct sockaddr_in clientname; | 
 | clientnamelen = sizeof(struct sockaddr_in); | clientnamelen = sizeof(struct sockaddr_in); | 
 |  | #endif | 
 | shttp = accept(shttpl, (struct sockaddr *)&clientname, &clientnamelen); | shttp = accept(shttpl, (struct sockaddr *)&clientname, &clientnamelen); | 
 | if(shttp<0) | 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 | else | 
 | { | { | 
 | struct upnphttp * tmp = 0; | struct upnphttp * tmp = 0; | 
| syslog(LOG_INFO, "HTTP connection from %s:%d", | char addr_str[64]; | 
| inet_ntoa(clientname.sin_addr), |  | 
| ntohs(clientname.sin_port) ); | sockaddr_to_string((struct sockaddr *)&clientname, addr_str, sizeof(addr_str)); | 
| /*if (fcntl(shttp, F_SETFL, O_NONBLOCK) < 0) { | syslog(LOG_INFO, "HTTP connection from %s", addr_str); | 
| syslog(LOG_ERR, "fcntl F_SETFL, O_NONBLOCK"); | if(get_lan_for_peer((struct sockaddr *)&clientname) == NULL) | 
| }*/ | { | 
|  | /* 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) | 
|  | { | 
|  | #ifdef ENABLE_IPV6 | 
|  | if(clientname.ss_family == AF_INET) | 
|  | { | 
|  | 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)) | 
|  | { | 
|  | 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; | 
|  | #endif | 
|  | LIST_INSERT_HEAD(&upnphttphead, tmp, entries); | 
|  | } | 
|  | else | 
|  | { | 
|  | syslog(LOG_ERR, "New_upnphttp() failed"); | 
|  | close(shttp); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
 | #ifdef ENABLE_NFQUEUE | #ifdef ENABLE_NFQUEUE | 
 | /* process NFQ packets */ | /* process NFQ packets */ | 
 | if(nfqh >= 0 && FD_ISSET(nfqh, &readset)) | if(nfqh >= 0 && FD_ISSET(nfqh, &readset)) | 
| Line 1430  main(int argc, char * * argv) | Line 1847  main(int argc, char * * argv) | 
 | ProcessNFQUEUE(nfqh); | ProcessNFQUEUE(nfqh); | 
 | } | } | 
 | #endif | #endif | 
 | /* 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 */ | /* delete finished HTTP connections */ | 
 | for(e = upnphttphead.lh_first; e != NULL; ) | for(e = upnphttphead.lh_first; e != NULL; ) | 
 | { | { | 
 | next = e->entries.le_next; | next = e->entries.le_next; | 
| if(e->state >= 100) | if(e->state >= EToDelete) | 
 | { | { | 
 | LIST_REMOVE(e, entries); | LIST_REMOVE(e, entries); | 
 | Delete_upnphttp(e); | Delete_upnphttp(e); | 
| Line 1457  main(int argc, char * * argv) | Line 1859  main(int argc, char * * argv) | 
 | e = next; | e = next; | 
 | } | } | 
 |  |  | 
 | /* send public address change notifications */ |  | 
 | if(should_send_public_address_change_notif) |  | 
 | { |  | 
 | #ifdef ENABLE_NATPMP |  | 
 | if(GETFLAG(ENABLENATPMPMASK)) |  | 
 | SendNATPMPPublicAddressChangeNotification(snatpmp/*snotify*/, n_lan_addr); |  | 
 | #endif |  | 
 | #ifdef ENABLE_EVENTS |  | 
 | if(GETFLAG(ENABLEUPNPMASK)) |  | 
 | { |  | 
 | upnp_event_var_change_notify(EWanIPC); |  | 
 | } |  | 
 | #endif |  | 
 | should_send_public_address_change_notif = 0; |  | 
 | } |  | 
 | }       /* end of main loop */ | }       /* end of main loop */ | 
 |  |  | 
 | shutdown: | shutdown: | 
| Line 1485  shutdown: | Line 1872  shutdown: | 
 |  |  | 
 | if (sudp >= 0) close(sudp); | if (sudp >= 0) close(sudp); | 
 | if (shttpl >= 0) close(shttpl); | if (shttpl >= 0) close(shttpl); | 
 |  | #ifdef ENABLE_IPV6 | 
 |  | if (sudpv6 >= 0) close(sudpv6); | 
 |  | #endif | 
 |  | #ifdef USE_IFACEWATCHER | 
 |  | if(sifacewatcher >= 0) close(sifacewatcher); | 
 |  | #endif | 
 | #ifdef ENABLE_NATPMP | #ifdef ENABLE_NATPMP | 
| for(i=0; i<n_lan_addr; i++) { | for(i=0; i<addr_count; i++) { | 
 | if(snatpmp[i]>=0) | if(snatpmp[i]>=0) | 
 | { | { | 
 | close(snatpmp[i]); | close(snatpmp[i]); | 
| Line 1505  shutdown: | Line 1898  shutdown: | 
 | } | } | 
 | } | } | 
 | #endif | #endif | 
|  |  | 
| /*if(SendSSDPGoodbye(snotify, v.n_lan_addr) < 0)*/ |  | 
 | if (GETFLAG(ENABLEUPNPMASK)) | if (GETFLAG(ENABLEUPNPMASK)) | 
 | { | { | 
| if(SendSSDPGoodbye(snotify, n_lan_addr) < 0) | #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"); | 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++)*/ | #ifndef ENABLE_IPV6 | 
|  | for(i = 0; i < addr_count; i++) | 
|  | #else | 
|  | for(i = 0; i < addr_count * 2; i++) | 
|  | #endif | 
 | close(snotify[i]); | close(snotify[i]); | 
 | } | } | 
 |  |  | 
| if(unlink(pidfilename) < 0) | if(pidfilename && (unlink(pidfilename) < 0)) | 
 | { | { | 
 | syslog(LOG_ERR, "Failed to remove pidfile %s: %m", pidfilename); | syslog(LOG_ERR, "Failed to remove pidfile %s: %m", pidfilename); | 
 | } | } | 
 |  |  | 
| closelog(); | /* delete lists */ | 
|  | while(lan_addrs.lh_first != NULL) | 
|  | { | 
|  | lan_addr = lan_addrs.lh_first; | 
|  | LIST_REMOVE(lan_addrs.lh_first, list); | 
|  | free(lan_addr); | 
|  | } | 
|  |  | 
|  | #ifdef ENABLE_NATPMP | 
|  | free(snatpmp); | 
|  | #endif | 
|  | free(snotify); | 
|  | closelog(); | 
|  | #ifndef DISABLE_CONFIG_FILE | 
 | freeoptions(); | freeoptions(); | 
|  | #endif | 
|  |  | 
 | return 0; | return 0; | 
 | } | } | 
 |  |  |