From 013b0df38870d4735919bf16dc5c2def6122ca6c Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 10 Jul 2012 23:25:29 +0200 Subject: [PATCH 001/127] miniupnpd: detect port in use / already forwarded Patch submitted by David Kerr --- README | 1 + miniupnpd/Changelog.txt | 3 ++ miniupnpd/Makefile.linux | 10 ++-- miniupnpd/natpmp.c | 8 +++ miniupnpd/netfilter/iptcrdr.c | 20 ++++++-- miniupnpd/netfilter/iptcrdr.h | 8 +++ miniupnpd/portinuse.c | 95 +++++++++++++++++++++++++++++++++++ miniupnpd/portinuse.h | 19 +++++++ miniupnpd/upnpredirect.c | 5 ++ 9 files changed, 161 insertions(+), 8 deletions(-) create mode 100644 miniupnpd/portinuse.c create mode 100644 miniupnpd/portinuse.h diff --git a/README b/README index fe4186c..ab73a0e 100644 --- a/README +++ b/README @@ -40,4 +40,5 @@ Thanks to : * Alexey Osipov * Alexey Kuznetsov * Chiaki Ishikawa + * David Kerr diff --git a/miniupnpd/Changelog.txt b/miniupnpd/Changelog.txt index a27b118..bcf8b2d 100644 --- a/miniupnpd/Changelog.txt +++ b/miniupnpd/Changelog.txt @@ -1,5 +1,8 @@ $Id: Changelog.txt,v 1.292 2012/06/29 19:26:07 nanard Exp $ +2012/07/10: + Detect port in use - patch by David Kerr + 2012/06/29: added DISABLE_CONFIG_FILE in options.h to disable miniupnpd.conf parsing Add command line parsing for clean_ruleset_interval option diff --git a/miniupnpd/Makefile.linux b/miniupnpd/Makefile.linux index d93eeb1..0421c72 100644 --- a/miniupnpd/Makefile.linux +++ b/miniupnpd/Makefile.linux @@ -41,7 +41,7 @@ SBININSTALLDIR = $(INSTALLPREFIX)/sbin ETCINSTALLDIR = $(PREFIX)/etc/miniupnpd BASEOBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \ - upnpreplyparse.o minixml.o \ + upnpreplyparse.o minixml.o portinuse.o \ upnpredirect.o getifaddr.o daemonize.o upnpglobalvars.o \ options.o upnppermissions.o minissdp.o natpmp.o \ upnpevents.o upnputils.o getconnstatus.o \ @@ -196,14 +196,16 @@ upnpsoap.o: upnpredirect.h upnppinhole.h getifaddr.h getifstats.h upnpsoap.o: getconnstatus.h upnpurns.h upnpreplyparse.o: upnpreplyparse.h minixml.h minixml.o: minixml.h +portinuse.o: macros.h config.h upnpglobalvars.h upnppermissions.h +portinuse.o: miniupnpdtypes.h getifaddr.h portinuse.h upnpredirect.o: macros.h config.h upnpredirect.h upnpglobalvars.h -upnpredirect.o: upnppermissions.h miniupnpdtypes.h upnpevents.h +upnpredirect.o: upnppermissions.h miniupnpdtypes.h upnpevents.h portinuse.h upnpredirect.o: netfilter/iptcrdr.h commonrdr.h getifaddr.o: config.h getifaddr.h daemonize.o: daemonize.h config.h upnpglobalvars.o: config.h upnpglobalvars.h upnppermissions.h upnpglobalvars.o: miniupnpdtypes.h -options.o: options.h config.h upnppermissions.h upnpglobalvars.h +options.o: config.h options.h upnppermissions.h upnpglobalvars.h options.o: miniupnpdtypes.h upnppermissions.o: config.h upnppermissions.h minissdp.o: config.h upnpdescstrings.h miniupnpdpath.h upnphttp.h @@ -211,6 +213,7 @@ minissdp.o: upnpglobalvars.h upnppermissions.h miniupnpdtypes.h minissdp.h minissdp.o: upnputils.h getroute.h codelength.h natpmp.o: macros.h config.h natpmp.h upnpglobalvars.h upnppermissions.h natpmp.o: miniupnpdtypes.h getifaddr.h upnpredirect.h commonrdr.h upnputils.h +natpmp.o: portinuse.h upnpevents.o: config.h upnpevents.h miniupnpdpath.h upnpglobalvars.h upnpevents.o: upnppermissions.h miniupnpdtypes.h upnpdescgen.h upnputils.h upnputils.o: config.h upnputils.h @@ -228,7 +231,6 @@ netfilter/iptcrdr.o: config.h upnpglobalvars.h upnppermissions.h netfilter/iptcrdr.o: miniupnpdtypes.h netfilter/iptpinhole.o: config.h netfilter/iptpinhole.h upnpglobalvars.h netfilter/iptpinhole.o: upnppermissions.h config.h miniupnpdtypes.h -netfilter/iptpinhole.o: netfilter/tiny_nf_nat.h testupnpdescgen.o: macros.h config.h upnpdescgen.h upnpdescgen.o: config.h getifaddr.h upnpredirect.h upnpdescgen.h upnpdescgen.o: miniupnpdpath.h upnpglobalvars.h upnppermissions.h diff --git a/miniupnpd/natpmp.c b/miniupnpd/natpmp.c index c596781..fb4a997 100644 --- a/miniupnpd/natpmp.c +++ b/miniupnpd/natpmp.c @@ -23,9 +23,11 @@ #include "upnpredirect.h" #include "commonrdr.h" #include "upnputils.h" +#include "portinuse.h" #ifdef ENABLE_NATPMP + int OpenAndConfNATPMPSocket(in_addr_t addr) { int snatpmp; @@ -267,6 +269,12 @@ void ProcessIncomingNATPMPPacket(int s) continue; } } + if (port_in_use(ext_if_name, eport, proto, senderaddrstr, iport)) { + syslog(LOG_INFO, "port %hu protocol %s already in use", eport, (proto==IPPROTO_TCP)?"tcp":"udp"); + eport++; + r = 0; + continue; + } { /* do the redirection */ char desc[64]; #if 0 diff --git a/miniupnpd/netfilter/iptcrdr.c b/miniupnpd/netfilter/iptcrdr.c index a18a2c9..acd174e 100644 --- a/miniupnpd/netfilter/iptcrdr.c +++ b/miniupnpd/netfilter/iptcrdr.c @@ -237,6 +237,18 @@ get_redirect_rule(const char * ifname, unsigned short eport, int proto, char * rhost, int rhostlen, unsigned int * timestamp, u_int64_t * packets, u_int64_t * bytes) +{ + return get_nat_redirect_rule(miniupnpd_nat_chain, ifname, eport, proto, iaddr, iaddrlen, iport, + desc, desclen, rhost, rhostlen,timestamp, packets, bytes); +} + +int +get_nat_redirect_rule(const char * nat_chain_name, const char * ifname, unsigned short eport, int proto, + char * iaddr, int iaddrlen, unsigned short * iport, + char * desc, int desclen, + char * rhost, int rhostlen, + unsigned int * timestamp, + u_int64_t * packets, u_int64_t * bytes) { int r = -1; IPTC_HANDLE h; @@ -254,18 +266,18 @@ get_redirect_rule(const char * ifname, unsigned short eport, int proto, iptc_strerror(errno)); return -1; } - if(!iptc_is_chain(miniupnpd_nat_chain, h)) + if(!iptc_is_chain(nat_chain_name, h)) { - syslog(LOG_ERR, "chain %s not found", miniupnpd_nat_chain); + syslog(LOG_ERR, "chain %s not found", nat_chain_name); } else { #ifdef IPTABLES_143 - for(e = iptc_first_rule(miniupnpd_nat_chain, h); + for(e = iptc_first_rule(nat_chain_name, h); e; e = iptc_next_rule(e, h)) #else - for(e = iptc_first_rule(miniupnpd_nat_chain, &h); + for(e = iptc_first_rule(nat_chain_name, &h); e; e = iptc_next_rule(e, &h)) #endif diff --git a/miniupnpd/netfilter/iptcrdr.h b/miniupnpd/netfilter/iptcrdr.h index f26bbc5..b26704f 100644 --- a/miniupnpd/netfilter/iptcrdr.h +++ b/miniupnpd/netfilter/iptcrdr.h @@ -25,6 +25,14 @@ add_filter_rule2(const char * ifname, int delete_redirect_and_filter_rules(unsigned short eport, int proto); +int +get_nat_redirect_rule(const char * nat_chain_name, const char * ifname, unsigned short eport, int proto, + char * iaddr, int iaddrlen, unsigned short * iport, + char * desc, int desclen, + char * rhost, int rhostlen, + unsigned int * timestamp, + u_int64_t * packets, u_int64_t * bytes); + /* for debug */ int list_redirect_rule(const char * ifname); diff --git a/miniupnpd/portinuse.c b/miniupnpd/portinuse.c new file mode 100644 index 0000000..a7dc003 --- /dev/null +++ b/miniupnpd/portinuse.c @@ -0,0 +1,95 @@ +/* */ +/* MiniUPnP project + * (c) 2007-2012 Thomas Bernard + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "macros.h" +#include "config.h" +#include "upnpglobalvars.h" +#include "getifaddr.h" +#include "portinuse.h" + +/* Hardcoded for now. Ideally would come from .conf file */ +char *chains_to_check[] = { "PREROUTING" , 0 }; + +int port_in_use(const char *if_name, unsigned eport, int proto, const char *iaddr, unsigned iport) +{ + char line[256]; + FILE *f; + int found = 0; + char ip_addr_str[INET_ADDRSTRLEN]; + struct in_addr ip_addr = { .s_addr = 0 }; + const char tcpfile[] = "/proc/net/tcp"; + const char udpfile[] = "/proc/net/udp"; + + f = fopen((proto==IPPROTO_TCP)?tcpfile:udpfile, "r"); + if (!f) return 0; + + if(getifaddr(if_name, ip_addr_str, INET_ADDRSTRLEN) == 0) + ip_addr.s_addr = inet_addr(ip_addr_str); + + syslog(LOG_DEBUG, "Check protocol %s for port %d on ext_if %s %s, %8X", + (proto==IPPROTO_TCP)?"tcp":"udp", eport, if_name, ip_addr_str, (unsigned)ip_addr.s_addr); + + while (fgets(line, 255, f)) { + char eaddr[68]; + unsigned tmp_port; + if (sscanf(line, "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x %*x:%*x " + "%*x:%*x %*x %*d %*d %*llu", + eaddr, &tmp_port) == 2 + ) { + /* TODO add IPV6 support if enabled + * Presently assumes IPV4 */ + // syslog(LOG_DEBUG, "port_in_use check port %d and address %s", tmp_port, eaddr); + if (tmp_port == eport) { + char tmp_addr[4]; + struct in_addr *tmp_ip_addr = (struct in_addr *)tmp_addr; + if (sscanf(eaddr,"%2hhx%2hhx%2hhx%2hhx", + &tmp_addr[3],&tmp_addr[2],&tmp_addr[1],&tmp_addr[0]) == 4) + { + if (tmp_ip_addr->s_addr == 0 || tmp_ip_addr->s_addr == ip_addr.s_addr) + { + found++; + break; /* don't care how many, just that we found at least one */ + } + } + } + } + } + fclose(f); + + if (!found) { + char iaddr_old[16]; + unsigned short iport_old; + int i = 0; + while (chains_to_check[i]) { + if (get_nat_redirect_rule(chains_to_check[i], if_name, eport, proto, + iaddr_old, sizeof(iaddr_old),&iport_old, + 0, 0, 0, 0, 0, 0, 0) == 0) + { + syslog(LOG_DEBUG, "port_in_use check port %d on nat chain %s redirected to %s port %d", eport, + chains_to_check[i], iaddr_old, iport_old); + if (!(strcmp(iaddr, iaddr_old)==0 && iport==iport_old)) { + /* only "in use" if redirected to somewhere else */ + found++; + break; /* don't care how many, just that we found at least one */ + } + } + i++; + } + } + return found; +} + diff --git a/miniupnpd/portinuse.h b/miniupnpd/portinuse.h new file mode 100644 index 0000000..8029008 --- /dev/null +++ b/miniupnpd/portinuse.h @@ -0,0 +1,19 @@ +/* */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2006-2011 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ + +#ifndef __PORTINUSE_H__ +#define __PORTINUSE_H__ + +/* portinuse() + * determine wither a port is already in use + * on a given interface. + * returns: 0 not in use, 1 in use */ +int +port_in_use(const char *if_name, unsigned port, int proto, const char *iaddr, unsigned iport); + +#endif + diff --git a/miniupnpd/upnpredirect.c b/miniupnpd/upnpredirect.c index 5c9beae..9242ed5 100644 --- a/miniupnpd/upnpredirect.c +++ b/miniupnpd/upnpredirect.c @@ -23,6 +23,7 @@ #include "upnpredirect.h" #include "upnpglobalvars.h" #include "upnpevents.h" +#include "portinuse.h" #if defined(USE_NETFILTER) #include "netfilter/iptcrdr.h" #endif @@ -294,6 +295,10 @@ upnp_redirect(const char * rhost, unsigned short eport, eport, protocol, iaddr_old, iport_old); return -2; } + } + else if (port_in_use(ext_if_name, eport, proto, iaddr, iport)) { + syslog(LOG_INFO, "port %hu protocol %s already in use", eport, protocol); + return -2; } else { timestamp = (leaseduration > 0) ? time(NULL) + leaseduration : 0; syslog(LOG_INFO, "redirecting port %hu to %s:%hu protocol %s for: %s", From 02f137700f7b72741aa5125ea34ca6da8282163f Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 31 Jan 2014 14:58:40 +0100 Subject: [PATCH 002/127] APIVERSION = 10 --- miniupnpc/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miniupnpc/Makefile b/miniupnpc/Makefile index 1bb996b..554b988 100644 --- a/miniupnpc/Makefile +++ b/miniupnpc/Makefile @@ -55,7 +55,7 @@ ifeq (SunOS, $(OS)) endif # APIVERSION is used to build SONAME -APIVERSION = 9 +APIVERSION = 10 SRCS = igd_desc_parse.c miniupnpc.c minixml.c minisoap.c miniwget.c \ upnpc.c upnpcommands.c upnpreplyparse.c testminixml.c \ From b36900b3e99503cf3dcf274d332136f4662f95c4 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 31 Jan 2014 15:19:38 +0100 Subject: [PATCH 003/127] miniupnpc/Makefile: fix clean target --- miniupnpc/Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/miniupnpc/Makefile b/miniupnpc/Makefile index 554b988..76327d0 100644 --- a/miniupnpc/Makefile +++ b/miniupnpc/Makefile @@ -3,7 +3,7 @@ # http://miniupnp.free.fr/ # http://miniupnp.tuxfamily.org/ # https://github.com/miniupnp/miniupnp -# (c) 2005-2013 Thomas Bernard +# (c) 2005-2014 Thomas Bernard # to install use : # $ make DESTDIR=/tmp/dummylocation install # or @@ -175,7 +175,8 @@ validateupnpreplyparse: testupnpreplyparse testupnpreplyparse.sh clean: $(RM) $(LIBRARY) $(SHAREDLIBRARY) $(EXECUTABLES) $(OBJS) miniupnpcstrings.h # clean python stuff - $(RM) pythonmodule pythonmodule3 validateminixml validateminiwget + $(RM) pythonmodule pythonmodule3 + $(RM) validateminixml validateminiwget validateupnpreplyparse $(RM) -r build/ dist/ #python setup.py clean # clean jnaerator stuff From ab7865ae991708212f21a9893d35763941edd1a3 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 31 Jan 2014 15:20:15 +0100 Subject: [PATCH 004/127] miniupnpc.c: translate comment from French to English :) --- miniupnpc/miniupnpc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/miniupnpc/miniupnpc.c b/miniupnpc/miniupnpc.c index 63460bf..4c1412b 100644 --- a/miniupnpc/miniupnpc.c +++ b/miniupnpc/miniupnpc.c @@ -1,8 +1,8 @@ -/* $Id: miniupnpc.c,v 1.113 2013/10/07 10:04:56 nanard Exp $ */ +/* $Id: miniupnpc.c,v 1.116 2014/01/31 14:09:03 nanard Exp $ */ /* Project : miniupnp * Web : http://miniupnp.free.fr/ * Author : Thomas BERNARD - * copyright (c) 2005-2013 Thomas Bernard + * copyright (c) 2005-2014 Thomas Bernard * This software is subjet to the conditions detailed in the * provided LICENSE file. */ #define __EXTENSIONS__ 1 @@ -545,7 +545,8 @@ upnpDiscover(int delay, const char * multicastif, } } - /* Avant d'envoyer le paquet on bind pour recevoir la reponse */ + /* Before sending the packed, we first "bind" in order to be able + * to receive the response */ if (bind(sudp, (const struct sockaddr *)&sockudp_r, ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0) { From 49780a99ea68f6a9399975fe7b78c87643631de9 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 3 Feb 2014 10:42:38 +0100 Subject: [PATCH 005/127] miniupnpd/minissdp.c: check return value of AddMulticastMembershipIPv6() --- miniupnpd/minissdp.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/miniupnpd/minissdp.c b/miniupnpd/minissdp.c index a67c94b..d593fe8 100644 --- a/miniupnpd/minissdp.c +++ b/miniupnpd/minissdp.c @@ -1,4 +1,4 @@ -/* $Id: minissdp.c,v 1.54 2013/06/15 12:50:10 nanard Exp $ */ +/* $Id: minissdp.c,v 1.56 2014/02/01 16:35:37 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2013 Thomas Bernard @@ -146,7 +146,11 @@ OpenAndConfSSDPReceiveSocket(int ipv6) #ifdef ENABLE_IPV6 if(ipv6) { - AddMulticastMembershipIPv6(s); + if(AddMulticastMembershipIPv6(s) < 0) + { + syslog(LOG_WARNING, + "Failed to add IPv6 multicast membership"); + } } else #endif From 18db1145eae079670350732f388313a8666ac347 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 3 Feb 2014 10:44:24 +0100 Subject: [PATCH 006/127] miniupnpd.c: comments in parselanaddr() --- miniupnpd/miniupnpd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/miniupnpd/miniupnpd.c b/miniupnpd/miniupnpd.c index 42313b4..3ca4dcc 100644 --- a/miniupnpd/miniupnpd.c +++ b/miniupnpd/miniupnpd.c @@ -586,6 +586,7 @@ parselanaddr(struct lan_addr_s * lan_addr, const char * str) p++; if(*p=='.') { + /* parse mask in /255.255.255.0 format */ while(*p && (*p=='.' || isdigit(*p))) p++; n = p - q; @@ -598,6 +599,7 @@ parselanaddr(struct lan_addr_s * lan_addr, const char * str) } else { + /* it is a /24 format */ int nbits = atoi(q); if(nbits > 32 || nbits < 0) goto parselan_error; From 3712118bc41926793ee86e3ae484c846fdbb225e Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 3 Feb 2014 10:45:59 +0100 Subject: [PATCH 007/127] miniupnpd: removed unused code ScanNATPMPforExpiration() CleanExpiredNATPMP() are not used anymore --- miniupnpd/miniupnpd.c | 29 ++------------------ miniupnpd/natpmp.c | 63 +------------------------------------------ miniupnpd/natpmp.h | 8 +----- 3 files changed, 4 insertions(+), 96 deletions(-) diff --git a/miniupnpd/miniupnpd.c b/miniupnpd/miniupnpd.c index 3ca4dcc..31bd643 100644 --- a/miniupnpd/miniupnpd.c +++ b/miniupnpd/miniupnpd.c @@ -1,7 +1,7 @@ -/* $Id: miniupnpd.c,v 1.178 2013/12/13 14:10:02 nanard Exp $ */ +/* $Id: miniupnpd.c,v 1.182 2014/02/03 08:37:32 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2013 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -1515,9 +1515,6 @@ main(int argc, char * * argv) syslog(LOG_NOTICE, "Listening for NAT-PMP traffic on port %u", NATPMP_PORT); } -#endif -#if 0 - ScanNATPMPforExpiration(); #endif } #endif @@ -1631,28 +1628,6 @@ main(int argc, char * * argv) syslog(LOG_DEBUG, "setting timeout to %u sec", (unsigned)timeout.tv_sec); } -#ifdef ENABLE_NATPMP -#if 0 - /* 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 -#endif #ifdef ENABLE_6FC_SERVICE /* Clean up expired IPv6 PinHoles */ next_pinhole_ts = 0; diff --git a/miniupnpd/natpmp.c b/miniupnpd/natpmp.c index d1efd27..8a127a0 100644 --- a/miniupnpd/natpmp.c +++ b/miniupnpd/natpmp.c @@ -1,4 +1,4 @@ -/* $Id: natpmp.c,v 1.35 2013/12/13 14:07:08 nanard Exp $ */ +/* $Id: natpmp.c,v 1.36 2014/02/01 17:17:35 nanard Exp $ */ /* MiniUPnP project * (c) 2007-2013 Thomas Bernard * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ @@ -334,67 +334,6 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, } } -#if 0 -/* iterate through the redirection list to find those who came - * from NAT-PMP and select the first to expire */ -int ScanNATPMPforExpiration() -{ - char desc[64]; - unsigned short iport, eport; - int proto; - int r, i; - unsigned timestamp; - nextnatpmptoclean_eport = 0; - nextnatpmptoclean_timestamp = 0; - for(i = 0; ; i++) { - r = get_redirect_rule_by_index(i, 0, &eport, 0, 0, - &iport, &proto, desc, sizeof(desc), - ×tamp, 0, 0); - if(r<0) - break; - if(sscanf(desc, "NAT-PMP %u", ×tamp) == 1) { - if( !nextnatpmptoclean_eport - || timestamp < nextnatpmptoclean_timestamp) { - nextnatpmptoclean_eport = eport; - nextnatpmptoclean_proto = proto; - nextnatpmptoclean_timestamp = timestamp; - syslog(LOG_DEBUG, "set nextnatpmptoclean_timestamp to %u", timestamp); - } - } - } - return 0; -} - -/* remove the next redirection that is expired - */ -int CleanExpiredNATPMP() -{ - char desc[64]; - unsigned timestamp; - unsigned short iport; - if(get_redirect_rule(ext_if_name, nextnatpmptoclean_eport, - nextnatpmptoclean_proto, - 0, 0, - &iport, desc, sizeof(desc), ×tamp, 0, 0) < 0) - return ScanNATPMPforExpiration(); - /* check desc - this is important since we keep expiration time as part - * of the desc. - * If the rule is renewed, timestamp and nextnatpmptoclean_timestamp - * can be different. In that case, the rule must not be removed ! */ - if(sscanf(desc, "NAT-PMP %u", ×tamp) == 1) { - if(timestamp > nextnatpmptoclean_timestamp) - return ScanNATPMPforExpiration(); - } - /* remove redirection then search for next one:) */ - if(_upnp_delete_redir(nextnatpmptoclean_eport, nextnatpmptoclean_proto)<0) - return -1; - syslog(LOG_INFO, "Expired NAT-PMP mapping port %hu %s removed", - nextnatpmptoclean_eport, - nextnatpmptoclean_proto==IPPROTO_TCP?"TCP":"UDP"); - return ScanNATPMPforExpiration(); -} -#endif - /* SendNATPMPPublicAddressChangeNotification() * should be called when the public IP address changed */ void SendNATPMPPublicAddressChangeNotification(int * sockets, int n_sockets) diff --git a/miniupnpd/natpmp.h b/miniupnpd/natpmp.h index b8a73bf..5f63517 100644 --- a/miniupnpd/natpmp.h +++ b/miniupnpd/natpmp.h @@ -1,4 +1,4 @@ -/* $Id: natpmp.h,v 1.8 2011/05/27 21:36:22 nanard Exp $ */ +/* $Id: natpmp.h,v 1.11 2014/02/01 17:17:35 nanard Exp $ */ /* MiniUPnP project * author : Thomas Bernard * website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ @@ -26,12 +26,6 @@ int ReceiveNATPMPOrPCPPacket(int s, struct sockaddr_in* senderaddr, void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, struct sockaddr_in *senderaddr); -#if 0 -int ScanNATPMPforExpiration(void); - -int CleanExpiredNATPMP(void); -#endif - void SendNATPMPPublicAddressChangeNotification(int * sockets, int n_sockets); #endif From f6b5408e87bc541f1682f5d661254cfdd02eebca Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 3 Feb 2014 10:47:47 +0100 Subject: [PATCH 008/127] miniupnpd: define min/max_lifetime only when needed --- miniupnpd/miniupnpd.c | 4 +++- miniupnpd/upnpglobalvars.c | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/miniupnpd/miniupnpd.c b/miniupnpd/miniupnpd.c index 31bd643..675f3c2 100644 --- a/miniupnpd/miniupnpd.c +++ b/miniupnpd/miniupnpd.c @@ -908,12 +908,14 @@ init(int argc, char * * argv, struct runtime_vars * v) optionsfile); } } - /* if lifetimes ae inverse*/ +#ifdef ENABLE_PCP + /* if lifetimes are inverse */ if (min_lifetime >= max_lifetime) { fprintf(stderr, "Minimum lifetime (%lu) is greater than or equal to maximum lifetime (%lu).\n", min_lifetime, max_lifetime); fprintf(stderr, "Check your configuration file.\n"); return 1; } +#endif } #endif /* DISABLE_CONFIG_FILE */ diff --git a/miniupnpd/upnpglobalvars.c b/miniupnpd/upnpglobalvars.c index 152a689..4ed29d8 100644 --- a/miniupnpd/upnpglobalvars.c +++ b/miniupnpd/upnpglobalvars.c @@ -1,7 +1,7 @@ -/* $Id: upnpglobalvars.c,v 1.32 2013/12/13 14:07:09 nanard Exp $ */ +/* $Id: upnpglobalvars.c,v 1.33 2014/02/03 08:37:32 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2012 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -33,8 +33,11 @@ unsigned long upstream_bitrate = 0; /* startup time */ time_t startup_time = 0; +#ifdef ENABLE_PCP +/* for PCP */ unsigned long int min_lifetime = 120; unsigned long int max_lifetime = 86400; +#endif int runtime_flags = 0; From 46905418caeb0e1f00d7eb933c066b19cc72a845 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 3 Feb 2014 10:49:59 +0100 Subject: [PATCH 009/127] miniupnpd: various PCP fixes --- miniupnpd/pcpserver.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/miniupnpd/pcpserver.c b/miniupnpd/pcpserver.c index bfae5e8..d79609b 100644 --- a/miniupnpd/pcpserver.c +++ b/miniupnpd/pcpserver.c @@ -1,4 +1,4 @@ -/* $Id: pcpserver.c,v 1.5 2014/01/27 10:06:08 nanard Exp $ */ +/* $Id: pcpserver.c,v 1.7 2014/02/03 09:38:26 nanard Exp $ */ /* MiniUPnP project * Website : http://miniupnp.free.fr/ * Author : Peter Tatrai @@ -558,7 +558,7 @@ static int CheckExternalAddress(pcp_info_t* pcp_msg_info) } } - if (IN6_IS_ADDR_UNSPECIFIED(pcp_msg_info->ext_ip)) { + if (pcp_msg_info->ext_ip == NULL || IN6_IS_ADDR_UNSPECIFIED(pcp_msg_info->ext_ip)) { pcp_msg_info->ext_ip = &external_addr; @@ -977,11 +977,16 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info) processedSize = 0; /* discard request that exceeds maximal length, - or that is shorter than 3 + or that is shorter than PCP_MIN_LEN (=24) or that is not the multiple of 4 */ - if (req_size < PCP_MIN_LEN) + if (req_size < 3) return 0; /* ignore msg */ + if (req_size < PCP_MIN_LEN) { + pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST; + return 1; /* send response */ + } + if ( (req_size > PCP_MAX_LEN) || ( (req_size & 3) != 0)) { syslog(LOG_ERR, "PCP: Size of PCP packet(%d) is larger than %d bytes or " "the size is not multiple of 4.\n", req_size, PCP_MAX_LEN); @@ -1000,7 +1005,7 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info) processedSize += sizeof(pcp_request_t); if (common_req->ver == 1) { - + /* legacy PCP version 1 support */ switch ( common_req->r_opcode & 0x7F ) { case PCP_OPCODE_MAP: @@ -1078,7 +1083,8 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info) } } else if (common_req->ver == 2) { - + /* RFC 6887 PCP support + * http://tools.ietf.org/html/rfc6887 */ switch ( common_req->r_opcode & 0x7F) { case PCP_OPCODE_MAP: @@ -1305,7 +1311,10 @@ int ProcessIncomingPCPPacket(int s, unsigned char *buff, int len, createPCPResponse(buff, &pcp_msg_info); - len = (len + 3) & ~3; /* round up resp. length to multiple of 4 */ + if(len < PCP_MIN_LEN) + len = PCP_MIN_LEN; + else + len = (len + 3) & ~3; /* round up resp. length to multiple of 4 */ len = sendto(s, buff, len, 0, (struct sockaddr *)senderaddr, sizeof(struct sockaddr_in)); if( len < 0 ) { From 538c002373eaf2fe44325ce4f791f04d8c1df072 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 3 Feb 2014 10:50:29 +0100 Subject: [PATCH 010/127] miniupnpd: PCP Add support for ANNOUNCE requests --- miniupnpd/Changelog.txt | 5 ++++- miniupnpd/pcpserver.c | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/miniupnpd/Changelog.txt b/miniupnpd/Changelog.txt index f2761ea..9683ace 100644 --- a/miniupnpd/Changelog.txt +++ b/miniupnpd/Changelog.txt @@ -1,4 +1,7 @@ -$Id: Changelog.txt,v 1.346 2013/12/13 13:41:52 nanard Exp $ +$Id: Changelog.txt,v 1.348 2014/02/03 09:32:09 nanard Exp $ + +2014/02/03: + PCP : Add support for ANNOUNCE requests 2013/12/16: Attempt to compile with OS X/pf diff --git a/miniupnpd/pcpserver.c b/miniupnpd/pcpserver.c index d79609b..9b11361 100644 --- a/miniupnpd/pcpserver.c +++ b/miniupnpd/pcpserver.c @@ -1086,6 +1086,10 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info) /* RFC 6887 PCP support * http://tools.ietf.org/html/rfc6887 */ switch ( common_req->r_opcode & 0x7F) { + case PCP_OPCODE_ANNOUNCE: + /* should check PCP Client's IP Address in request */ + /* see http://tools.ietf.org/html/rfc6887#section-14.1 */ + break; case PCP_OPCODE_MAP: remainingSize -= sizeof(pcp_map_v2_t); From b7a4f8d6961d37a1c84742ad02124af7cec4ffc1 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 3 Feb 2014 11:28:31 +0100 Subject: [PATCH 011/127] minixml.c: now handle XML comments --- miniupnpc/Changelog.txt | 3 +++ miniupnpc/minixml.c | 19 ++++++++++++++++--- miniupnpd/Changelog.txt | 1 + miniupnpd/minixml.c | 19 ++++++++++++++++--- 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/miniupnpc/Changelog.txt b/miniupnpc/Changelog.txt index 180015a..ccf3b91 100644 --- a/miniupnpc/Changelog.txt +++ b/miniupnpc/Changelog.txt @@ -1,6 +1,9 @@ $Id: Changelog.txt,v 1.191 2014/01/31 13:18:24 nanard Exp $ miniUPnP client Changelog. +2014/02/03: + minixml now handle XML comments + VERSION 1.9 : released 2014/01/31 2014/01/31: diff --git a/miniupnpc/minixml.c b/miniupnpc/minixml.c index d3f7d06..1f22273 100644 --- a/miniupnpc/minixml.c +++ b/miniupnpc/minixml.c @@ -1,10 +1,10 @@ -/* $Id: minixml.c,v 1.9 2011/02/07 13:44:57 nanard Exp $ */ +/* $Id: minixml.c,v 1.10 2012/03/05 19:42:47 nanard Exp $ */ /* minixml.c : the minimum size a xml parser can be ! */ /* Project : miniupnp * webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * Author : Thomas Bernard -Copyright (c) 2005-2011, Thomas BERNARD +Copyright (c) 2005-2014, Thomas BERNARD All rights reserved. Redistribution and use in source and binary forms, with or without @@ -113,7 +113,20 @@ static void parseelt(struct xmlparser * p) const char * elementname; while(p->xml < (p->xmlend - 1)) { - if((p->xml)[0]=='<' && (p->xml)[1]!='?') + if((p->xml + 4) <= p->xmlend && (0 == memcmp(p->xml, "", 3) != 0); + p->xml += 3; + } + else if((p->xml)[0]=='<' && (p->xml)[1]!='?') { i = 0; elementname = ++p->xml; while( !IS_WHITE_SPACE(*p->xml) diff --git a/miniupnpd/Changelog.txt b/miniupnpd/Changelog.txt index 9683ace..517b83e 100644 --- a/miniupnpd/Changelog.txt +++ b/miniupnpd/Changelog.txt @@ -2,6 +2,7 @@ $Id: Changelog.txt,v 1.348 2014/02/03 09:32:09 nanard Exp $ 2014/02/03: PCP : Add support for ANNOUNCE requests + minixml now handle XML comments 2013/12/16: Attempt to compile with OS X/pf diff --git a/miniupnpd/minixml.c b/miniupnpd/minixml.c index d3f7d06..1f22273 100644 --- a/miniupnpd/minixml.c +++ b/miniupnpd/minixml.c @@ -1,10 +1,10 @@ -/* $Id: minixml.c,v 1.9 2011/02/07 13:44:57 nanard Exp $ */ +/* $Id: minixml.c,v 1.10 2012/03/05 19:42:47 nanard Exp $ */ /* minixml.c : the minimum size a xml parser can be ! */ /* Project : miniupnp * webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * Author : Thomas Bernard -Copyright (c) 2005-2011, Thomas BERNARD +Copyright (c) 2005-2014, Thomas BERNARD All rights reserved. Redistribution and use in source and binary forms, with or without @@ -113,7 +113,20 @@ static void parseelt(struct xmlparser * p) const char * elementname; while(p->xml < (p->xmlend - 1)) { - if((p->xml)[0]=='<' && (p->xml)[1]!='?') + if((p->xml + 4) <= p->xmlend && (0 == memcmp(p->xml, "", 3) != 0); + p->xml += 3; + } + else if((p->xml)[0]=='<' && (p->xml)[1]!='?') { i = 0; elementname = ++p->xml; while( !IS_WHITE_SPACE(*p->xml) From 2e4d11ba280e9f89e6a4bb86e0a2a9cfefce33cc Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 3 Feb 2014 16:48:51 +0100 Subject: [PATCH 012/127] minissdpd/listifaces: fix. now compatible with linux and BSD --- minissdpd/Makefile | 4 ++- minissdpd/listifaces.c | 66 +++++++++++++++++++++++++++++++----------- 2 files changed, 52 insertions(+), 18 deletions(-) diff --git a/minissdpd/Makefile b/minissdpd/Makefile index e924acb..99c2691 100644 --- a/minissdpd/Makefile +++ b/minissdpd/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.17 2012/05/02 10:26:50 nanard Exp $ +# $Id: Makefile,v 1.18 2014/02/03 14:32:14 nanard Exp $ # MiniUPnP project # author: Thomas Bernard # website: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ @@ -59,6 +59,8 @@ testminissdpd: $(TESTMINISSDPDOBJS) testcodelength: testcodelength.o +listifaces: listifaces.o upnputils.o + depend: makedepend -f$(MAKEFILE_LIST) -Y \ $(ALLOBJS:.o=.c) 2>/dev/null diff --git a/minissdpd/listifaces.c b/minissdpd/listifaces.c index 14124ef..f893d6e 100644 --- a/minissdpd/listifaces.c +++ b/minissdpd/listifaces.c @@ -1,4 +1,7 @@ -/* $Id: listifaces.c,v 1.4 2007/09/23 16:59:02 nanard Exp $ */ +/* $Id: listifaces.c,v 1.6 2014/02/03 14:32:14 nanard Exp $ */ +/* (c) 2006-2014 Thomas BERNARD + * http://miniupnp.free.fr/ http://miniupnp.tuxfamily.org/ + */ #include #include #include @@ -8,7 +11,9 @@ #include #include #include +#include "upnputils.h" +/* hexdump */ void printhex(const unsigned char * p, int n) { int i; @@ -27,20 +32,28 @@ void printhex(const unsigned char * p, int n) } } -void listifaces() +/* List network interfaces */ +void listifaces(void) { struct ifconf ifc; - char * buf = 0; - int buflen = sizeof(struct ifreq)*20; - /*[sizeof(struct ifreq)*8];*/ + char * buf = NULL; + int buflen; int s, i; int j; char saddr[256/*INET_ADDRSTRLEN*/]; +#ifdef __linux__ + buflen = sizeof(struct ifreq)*10; +#else + buflen = 0; +#endif /*s = socket(PF_INET, SOCK_DGRAM, 0);*/ s = socket(AF_INET, SOCK_DGRAM, 0); do { +#ifdef __linux__ buflen += buflen; - buf = realloc(buf, buflen); +#endif + if(buflen > 0) + buf = realloc(buf, buflen); ifc.ifc_len = buflen; ifc.ifc_buf = (caddr_t)buf; if(ioctl(s, SIOCGIFCONF, &ifc) < 0) @@ -50,22 +63,39 @@ void listifaces() free(buf); return; } - printf("%d - %d - %d\n", buflen, ifc.ifc_len, (int)sizeof(struct ifreq)); - printf(" %d\n", IFNAMSIZ); - printf(" %d %d\n", (int)sizeof(struct sockaddr), (int)sizeof(struct sockaddr_in) ); - } while(buflen == ifc.ifc_len); + printf("buffer length=%d - buffer used=%d - sizeof(struct ifreq)=%d\n", + buflen, ifc.ifc_len, (int)sizeof(struct ifreq)); + printf("IFNAMSIZ=%d ", IFNAMSIZ); + printf("sizeof(struct sockaddr)=%d sizeof(struct sockaddr_in)=%d\n", + (int)sizeof(struct sockaddr), (int)sizeof(struct sockaddr_in) ); +#ifndef __linux__ + if(buflen == 0) + buflen = ifc.ifc_len; + else + break; + } while(1); +#else + } while(buflen <= ifc.ifc_len); +#endif printhex((const unsigned char *)ifc.ifc_buf, ifc.ifc_len); - j = 0; - for(i=0; iifr_name) + 16;//ifrp->ifr_addr.sa_len; /*inet_ntop(AF_INET, &(((struct sockaddr_in *)&(ifrp->ifr_addr))->sin_addr), saddr, sizeof(saddr));*/ saddr[0] = '\0'; - inet_ntop(ifrp->ifr_addr.sa_family, &(ifrp->ifr_addr.sa_data[2]), saddr, sizeof(saddr)); - printf("%2d %d %d %s %s\n", j, ifrp->ifr_addr.sa_family, -1/*ifrp->ifr_addr.sa_len*/, ifrp->ifr_name, saddr); - j++; + /* inet_ntop(ifrp->ifr_addr.sa_family, &(ifrp->ifr_addr.sa_data[2]), saddr, sizeof(saddr)); */ + sockaddr_to_string(&ifrp->ifr_addr, saddr, sizeof(saddr)); + printf("0x%03x %2d %2d %-16s %s\n", i, j, ifrp->ifr_addr.sa_family, ifrp->ifr_name, saddr); + /*ifrp->ifr_addr.sa_len is only available on BSD */ +#ifdef __linux__ + i += sizeof(struct ifreq); +#else + if(ifrp->ifr_addr.sa_len == 0) + break; + i += IFNAMSIZ + ifrp->ifr_addr.sa_len; +#endif } free(buf); close(s); @@ -73,6 +103,8 @@ void listifaces() int main(int argc, char * * argv) { + (void)argc; + (void)argv; listifaces(); return 0; } From 612d0e44fb91b4bb78a988a1505424540a53899b Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 3 Feb 2014 16:50:37 +0100 Subject: [PATCH 013/127] minissdpd.c: improve comments and logging --- minissdpd/minissdpd.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/minissdpd/minissdpd.c b/minissdpd/minissdpd.c index 520a6c5..25bacb3 100644 --- a/minissdpd/minissdpd.c +++ b/minissdpd/minissdpd.c @@ -1,6 +1,6 @@ -/* $Id: minissdpd.c,v 1.35 2012/05/21 17:13:11 nanard Exp $ */ +/* $Id: minissdpd.c,v 1.36 2014/02/03 15:45:07 nanard Exp $ */ /* MiniUPnP project - * (c) 2007-2012 Thomas Bernard + * (c) 2007-2014 Thomas Bernard * website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -282,8 +282,10 @@ processMSEARCH(int s, const char * st, int st_len, } } else { /* find matching services */ + /* remove version at the end of the ST string */ if(st[st_len-2]==':' && isdigit(st[st_len-1])) st_len -= 2; + /* answer for each matching service */ for(serv = servicelisthead.lh_first; serv; serv = serv->entries.le_next) { @@ -338,6 +340,7 @@ ParseSSDPPacket(int s, const char * p, ssize_t n, unsigned int lifetime = 180; /* 3 minutes by default */ const char * st = NULL; int st_len = 0; + memset(headers, 0, sizeof(headers)); for(methodlen = 0; methodlen < n && (isalpha(p[methodlen]) || p[methodlen]=='-'); @@ -566,9 +569,9 @@ void processRequest(struct reqelem * req) syslog(LOG_INFO, "(s=%d) request type=%d str='%.*s'", req->socket, type, l, p); switch(type) { - case 1: - case 2: - case 3: + case 1: /* request by type */ + case 2: /* request by USN (unique id) */ + case 3: /* everything */ while(d && (nrep < 255)) { if(d->t < t) { syslog(LOG_INFO, "outdated device"); @@ -633,12 +636,14 @@ void processRequest(struct reqelem * req) } } rbuf[0] = nrep; + syslog(LOG_DEBUG, "(s=%d) response : %d device%s", + req->socket, nrep, (nrep > 1) ? "s" : ""); if(write(req->socket, rbuf, rp - rbuf) < 0) { syslog(LOG_ERR, "(s=%d) write: %m", req->socket); goto error; } break; - case 4: + case 4: /* submit service */ newserv = malloc(sizeof(struct service)); if(!newserv) { syslog(LOG_ERR, "cannot allocate memory"); From 178f0b8c4d4b0106817fe291aafb513175928288 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 3 Feb 2014 16:51:25 +0100 Subject: [PATCH 014/127] minissdpd.c: silently ignore EAGAIN, EWOULDBLOCK, EINTR of recv calls --- minissdpd/Changelog.txt | 5 ++++- minissdpd/minissdpd.c | 11 +++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/minissdpd/Changelog.txt b/minissdpd/Changelog.txt index fa17abd..54cd416 100644 --- a/minissdpd/Changelog.txt +++ b/minissdpd/Changelog.txt @@ -1,4 +1,7 @@ -$Id: Changelog.txt,v 1.32 2013/08/19 16:40:55 nanard Exp $ +$Id: Changelog.txt,v 1.33 2014/02/03 15:45:07 nanard Exp $ + +2014/02/03: + silently ignore EAGAIN, EWOULDBLOCK, EINTR of recv calls 2013/08/19: Translate README in english diff --git a/minissdpd/minissdpd.c b/minissdpd/minissdpd.c index 25bacb3..9b6d63b 100644 --- a/minissdpd/minissdpd.c +++ b/minissdpd/minissdpd.c @@ -224,6 +224,7 @@ SendSSDPMSEARCHResponse(int s, const struct sockaddr * sockname, n = sendto(s, buf, l, 0, sockname, sockname_len ); if(n < 0) { + /* XXX handle EINTR, EAGAIN, EWOULDBLOCK */ syslog(LOG_ERR, "sendto(udp): %m"); } } @@ -1002,7 +1003,10 @@ int main(int argc, char * * argv) (struct sockaddr *)&sendername6, &sendername6_len); if(n<0) { - syslog(LOG_ERR, "recvfrom: %m"); + /* EAGAIN, EWOULDBLOCK, EINTR : silently ignore (try again next time) + * other errors : log to LOG_ERR */ + if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) + syslog(LOG_ERR, "recvfrom: %m"); } else { @@ -1033,7 +1037,10 @@ int main(int argc, char * * argv) (struct sockaddr *)&sendername, &sendername_len); if(n<0) { - syslog(LOG_ERR, "recvfrom: %m"); + /* EAGAIN, EWOULDBLOCK, EINTR : silently ignore (try again next time) + * other errors : log to LOG_ERR */ + if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) + syslog(LOG_ERR, "recvfrom: %m"); } else { From 04752985cc48a7e9c16b946a9642e33acdc3ace0 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 3 Feb 2014 16:52:38 +0100 Subject: [PATCH 015/127] minissdpd.c: Discover devices on the network at startup --- minissdpd/Changelog.txt | 1 + minissdpd/minissdpd.c | 67 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/minissdpd/Changelog.txt b/minissdpd/Changelog.txt index 54cd416..0cf152a 100644 --- a/minissdpd/Changelog.txt +++ b/minissdpd/Changelog.txt @@ -2,6 +2,7 @@ $Id: Changelog.txt,v 1.33 2014/02/03 15:45:07 nanard Exp $ 2014/02/03: silently ignore EAGAIN, EWOULDBLOCK, EINTR of recv calls + Discover devices on the network at startup 2013/08/19: Translate README in english diff --git a/minissdpd/minissdpd.c b/minissdpd/minissdpd.c index 9b6d63b..e1068ad 100644 --- a/minissdpd/minissdpd.c +++ b/minissdpd/minissdpd.c @@ -350,6 +350,12 @@ ParseSSDPPacket(int s, const char * p, ssize_t n, method = METHOD_MSEARCH; else if(methodlen==6 && 0==memcmp(p, "NOTIFY", 6)) method = METHOD_NOTIFY; + else if(methodlen==4 && 0==memcmp(p, "HTTP", 4)) { + /* answer to a M-SEARCH => process it as a NOTIFY + * with NTS: ssdp:alive */ + method = METHOD_NOTIFY; + nts = NTS_SSDP_ALIVE; + } linestart = p; while(linestart < p + n - 2) { /* start parsing the line : detect line end */ @@ -439,6 +445,8 @@ ParseSSDPPacket(int s, const char * p, ssize_t n, } else if(l==2 && 0==strncasecmp(linestart, "st", 2)) { st = valuestart; st_len = m; + if(method == METHOD_NOTIFY) + i = HEADER_NT; /* it was a M-SEARCH response */ } if(i>=0) { headers[i].p = valuestart; @@ -785,6 +793,60 @@ sigterm(int sig) /*errno = save_errno;*/ } +#define PORT 1900 +#define XSTR(s) STR(s) +#define STR(s) #s +#define UPNP_MCAST_ADDR "239.255.255.250" +/* for IPv6 */ +#define UPNP_MCAST_LL_ADDR "FF02::C" /* link-local */ +#define UPNP_MCAST_SL_ADDR "FF05::C" /* site-local */ + +/* send the M-SEARCH request for all devices */ +void ssdpDiscoverAll(int s, int ipv6) +{ + static const char MSearchMsgFmt[] = + "M-SEARCH * HTTP/1.1\r\n" + "HOST: %s:" XSTR(PORT) "\r\n" + "ST: ssdp:all\r\n" + "MAN: \"ssdp:discover\"\r\n" + "MX: %u\r\n" + "\r\n"; + char bufr[512]; + int n; + int mx = 3; + int linklocal = 1; + struct sockaddr_storage sockudp_w; + + { + n = snprintf(bufr, sizeof(bufr), + MSearchMsgFmt, + ipv6 ? + (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]") + : UPNP_MCAST_ADDR, mx); + memset(&sockudp_w, 0, sizeof(struct sockaddr_storage)); + if(ipv6) { + struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w; + p->sin6_family = AF_INET6; + p->sin6_port = htons(PORT); + inet_pton(AF_INET6, + linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR, + &(p->sin6_addr)); + } else { + struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w; + p->sin_family = AF_INET; + p->sin_port = htons(PORT); + p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR); + } + + n = sendto(s, bufr, n, 0, (const struct sockaddr *)&sockudp_w, + ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); + if (n < 0) { + /* XXX : EINTR EWOULDBLOCK EAGAIN */ + syslog(LOG_ERR, "sendto: %m"); + } + } +} + /* main(): program entry point */ int main(int argc, char * * argv) { @@ -963,6 +1025,11 @@ int main(int argc, char * * argv) writepidfile(pidfilename, pid); + /* send M-SEARCH ssdp:all Requests */ + ssdpDiscoverAll(s_ssdp, 0); + if(s_ssdp6 >= 0) + ssdpDiscoverAll(s_ssdp6, 1); + /* Main loop */ while(!quitting) { From f354f73238c40a356d85670f03d15b75b1d11fe9 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Wed, 5 Feb 2014 18:31:28 +0100 Subject: [PATCH 016/127] miniupnpc/connecthostport.c: handle EINPROGRESS after connect() --- miniupnpc/Changelog.txt | 5 ++++- miniupnpc/connecthostport.c | 14 ++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/miniupnpc/Changelog.txt b/miniupnpc/Changelog.txt index ccf3b91..53e9a11 100644 --- a/miniupnpc/Changelog.txt +++ b/miniupnpc/Changelog.txt @@ -1,6 +1,9 @@ -$Id: Changelog.txt,v 1.191 2014/01/31 13:18:24 nanard Exp $ +$Id: Changelog.txt,v 1.193 2014/02/05 17:26:45 nanard Exp $ miniUPnP client Changelog. +2014/02/05: + handle EINPROGRESS after connect() + 2014/02/03: minixml now handle XML comments diff --git a/miniupnpc/connecthostport.c b/miniupnpc/connecthostport.c index aabc7a6..98f7253 100644 --- a/miniupnpc/connecthostport.c +++ b/miniupnpc/connecthostport.c @@ -1,7 +1,7 @@ -/* $Id: connecthostport.c,v 1.11 2013/08/01 21:21:25 nanard Exp $ */ +/* $Id: connecthostport.c,v 1.12 2014/02/05 17:26:46 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard - * Copyright (c) 2010-2013 Thomas Bernard + * Copyright (c) 2010-2014 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. */ @@ -109,7 +109,10 @@ int connecthostport(const char * host, unsigned short port, dest.sin_port = htons(port); n = connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr_in)); #ifdef MINIUPNPC_IGNORE_EINTR - while(n < 0 && errno == EINTR) + /* EINTR The system call was interrupted by a signal that was caught + * EINPROGRESS The socket is nonblocking and the connection cannot + * be completed immediately. */ + while(n < 0 && (errno == EINTR || errno = EINPROGRESS)) { socklen_t len; fd_set wset; @@ -203,7 +206,10 @@ int connecthostport(const char * host, unsigned short port, #endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ n = connect(s, p->ai_addr, p->ai_addrlen); #ifdef MINIUPNPC_IGNORE_EINTR - while(n < 0 && errno == EINTR) + /* EINTR The system call was interrupted by a signal that was caught + * EINPROGRESS The socket is nonblocking and the connection cannot + * be completed immediately. */ + while(n < 0 && (errno == EINTR || errno == EINPROGRESS)) { socklen_t len; fd_set wset; From cd5cb6e48e0ea2e89da9c1dbf6e7b3c91cb48c19 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Wed, 5 Feb 2014 18:32:29 +0100 Subject: [PATCH 017/127] removed unused stuff --- miniupnpc/miniwget.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/miniupnpc/miniwget.c b/miniupnpc/miniwget.c index a75f55b..813db93 100644 --- a/miniupnpc/miniwget.c +++ b/miniupnpc/miniwget.c @@ -1,8 +1,8 @@ -/* $Id: miniwget.c,v 1.60 2013/10/07 10:03:16 nanard Exp $ */ +/* $Id: miniwget.c,v 1.61 2014/02/05 17:27:48 nanard Exp $ */ /* Project : miniupnp * Website : http://miniupnp.free.fr/ * Author : Thomas Bernard - * Copyright (c) 2005-2013 Thomas Bernard + * Copyright (c) 2005-2014 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. */ @@ -39,9 +39,6 @@ #include #include #define closesocket close -/* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions - * during the connect() call */ -#define MINIUPNPC_IGNORE_EINTR #endif /* #else _WIN32 */ #if defined(__sun) || defined(sun) #define MIN(x,y) (((x)<(y))?(x):(y)) From 8ffaa91b2df8db34b202af3a610c1940d42066d6 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Wed, 5 Feb 2014 18:32:47 +0100 Subject: [PATCH 018/127] upnpc.c: 2013 -> 2014 --- miniupnpc/upnpc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/miniupnpc/upnpc.c b/miniupnpc/upnpc.c index 9c9979a..70c9a54 100644 --- a/miniupnpc/upnpc.c +++ b/miniupnpc/upnpc.c @@ -1,7 +1,7 @@ -/* $Id: upnpc.c,v 1.101 2014/01/31 13:18:25 nanard Exp $ */ +/* $Id: upnpc.c,v 1.102 2014/02/05 17:27:14 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard - * Copyright (c) 2005-2013 Thomas Bernard + * Copyright (c) 2005-2014 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. */ @@ -500,7 +500,7 @@ int main(int argc, char ** argv) return -1; } #endif - printf("upnpc : miniupnpc library test client. (c) 2005-2013 Thomas Bernard\n"); + printf("upnpc : miniupnpc library test client. (c) 2005-2014 Thomas Bernard\n"); printf("Go to http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/\n" "for more information.\n"); /* command line processing */ From dce25a2e2797ebd5a8516f6ce4304e3a059e428e Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 6 Feb 2014 10:53:52 +0100 Subject: [PATCH 019/127] minissdpd/.gitignore: add listifaces --- minissdpd/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/minissdpd/.gitignore b/minissdpd/.gitignore index 9c8b266..6e1b69d 100644 --- a/minissdpd/.gitignore +++ b/minissdpd/.gitignore @@ -2,4 +2,5 @@ minissdpd testcodelength testminissdpd +listifaces Makefile.bak From 18f02dccb34dec088f5f249ed6ae85c0afcef21a Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 6 Feb 2014 10:55:28 +0100 Subject: [PATCH 020/127] miniupnpd: possibility to disable ipv6 at runtime fixes #049 --- miniupnpd/Changelog.txt | 5 +++- miniupnpd/minissdp.c | 24 +++++++++++++------ miniupnpd/miniupnpd.c | 48 +++++++++++++++++++++++++++----------- miniupnpd/upnpglobalvars.c | 3 ++- miniupnpd/upnpglobalvars.h | 5 ++-- miniupnpd/upnputils.c | 4 ++-- 6 files changed, 63 insertions(+), 26 deletions(-) diff --git a/miniupnpd/Changelog.txt b/miniupnpd/Changelog.txt index 517b83e..6d463e4 100644 --- a/miniupnpd/Changelog.txt +++ b/miniupnpd/Changelog.txt @@ -1,4 +1,7 @@ -$Id: Changelog.txt,v 1.348 2014/02/03 09:32:09 nanard Exp $ +$Id: Changelog.txt,v 1.350 2014/02/06 09:52:03 nanard Exp $ + +2014/02/06: + possibility to disable ipv6 at runtime 2014/02/03: PCP : Add support for ANNOUNCE requests diff --git a/miniupnpd/minissdp.c b/miniupnpd/minissdp.c index d593fe8..fb5a9b8 100644 --- a/miniupnpd/minissdp.c +++ b/miniupnpd/minissdp.c @@ -1,7 +1,7 @@ -/* $Id: minissdp.c,v 1.56 2014/02/01 16:35:37 nanard Exp $ */ +/* $Id: minissdp.c,v 1.57 2014/02/06 09:52:03 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2013 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -280,9 +280,16 @@ OpenAndConfSSDPNotifySockets(int * sockets) goto error; i++; #ifdef ENABLE_IPV6 - sockets[i] = OpenAndConfSSDPNotifySocketIPv6(lan_addr->index); - if(sockets[i] < 0) - goto error; + if(ipv6_enabled) + { + sockets[i] = OpenAndConfSSDPNotifySocketIPv6(lan_addr->index); + if(sockets[i] < 0) + goto error; + } + else + { + sockets[i] = -1; + } i++; #endif } @@ -568,8 +575,11 @@ SendSSDPNotifies2(int * sockets, lifetime, 0); i++; #ifdef ENABLE_IPV6 - SendSSDPNotifies(sockets[i], ipv6_addr_for_http_with_brackets, port, - lifetime, 1); + if(sockets[i] >= 0) + { + SendSSDPNotifies(sockets[i], ipv6_addr_for_http_with_brackets, port, + lifetime, 1); + } i++; #endif } diff --git a/miniupnpd/miniupnpd.c b/miniupnpd/miniupnpd.c index 675f3c2..805d788 100644 --- a/miniupnpd/miniupnpd.c +++ b/miniupnpd/miniupnpd.c @@ -1,4 +1,4 @@ -/* $Id: miniupnpd.c,v 1.182 2014/02/03 08:37:32 nanard Exp $ */ +/* $Id: miniupnpd.c,v 1.183 2014/02/06 09:52:01 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2014 Thomas Bernard @@ -116,7 +116,8 @@ OpenAndConfHTTPSocket(unsigned short port) int s; int i = 1; #ifdef ENABLE_IPV6 - struct sockaddr_in6 listenname; + struct sockaddr_in6 listenname6; + struct sockaddr_in listenname4; #else struct sockaddr_in listenname; #endif @@ -124,7 +125,7 @@ OpenAndConfHTTPSocket(unsigned short port) if( (s = socket( #ifdef ENABLE_IPV6 - PF_INET6, + ipv6_enabled ? PF_INET6 : PF_INET, #else PF_INET, #endif @@ -153,19 +154,35 @@ OpenAndConfHTTPSocket(unsigned short port) } #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); + if(ipv6_enabled) + { + memset(&listenname6, 0, sizeof(struct sockaddr_in6)); + listenname6.sin6_family = AF_INET6; + listenname6.sin6_port = htons(port); + listenname6.sin6_addr = in6addr_any; + listenname_len = sizeof(struct sockaddr_in6); + } else { + memset(&listenname4, 0, sizeof(struct sockaddr_in)); + listenname4.sin_family = AF_INET; + listenname4.sin_port = htons(port); + listenname4.sin_addr.s_addr = htonl(INADDR_ANY); + listenname_len = sizeof(struct sockaddr_in); + } #else + memset(&listenname, 0, sizeof(struct sockaddr_in)); listenname.sin_family = AF_INET; listenname.sin_port = htons(port); listenname.sin_addr.s_addr = htonl(INADDR_ANY); listenname_len = sizeof(struct sockaddr_in); #endif +#ifdef ENABLE_IPV6 + if(bind(s, + ipv6_enabled ? (struct sockaddr *)&listenname6 : (struct sockaddr *)&listenname4, + listenname_len) < 0) +#else if(bind(s, (struct sockaddr *)&listenname, listenname_len) < 0) +#endif { syslog(LOG_ERR, "bind(http): %m"); close(s); @@ -181,6 +198,7 @@ OpenAndConfHTTPSocket(unsigned short port) return s; } + #ifdef ENABLE_NFQUEUE int identify_ip_protocol(char *payload) { @@ -1347,7 +1365,7 @@ main(int argc, char * * argv) int sudpv6 = -1; /* IP v6 socket for receiving SSDP */ #endif #ifdef ENABLE_NATPMP - int * snatpmp = NULL; + int * snatpmp = NULL; /* also used for PCP */ #endif #ifdef ENABLE_NFQUEUE int nfqh = -1; @@ -1455,7 +1473,8 @@ main(int argc, char * * argv) ipv6_addr_for_http_with_brackets); } else { memcpy(ipv6_addr_for_http_with_brackets, "[::1]", 6); - syslog(LOG_WARNING, "no HTTP IPv6 address"); + syslog(LOG_WARNING, "no HTTP IPv6 address, disabling IPv6"); + ipv6_enabled = 0; } #endif @@ -1470,10 +1489,13 @@ main(int argc, char * * argv) } } #ifdef ENABLE_IPV6 - sudpv6 = OpenAndConfSSDPReceiveSocket(1); - if(sudpv6 < 0) + if(ipv6_enabled) { - syslog(LOG_WARNING, "Failed to open socket for receiving SSDP (IP v6)."); + sudpv6 = OpenAndConfSSDPReceiveSocket(1); + if(sudpv6 < 0) + { + syslog(LOG_WARNING, "Failed to open socket for receiving SSDP (IP v6)."); + } } #endif diff --git a/miniupnpd/upnpglobalvars.c b/miniupnpd/upnpglobalvars.c index 4ed29d8..ae4203c 100644 --- a/miniupnpd/upnpglobalvars.c +++ b/miniupnpd/upnpglobalvars.c @@ -1,4 +1,4 @@ -/* $Id: upnpglobalvars.c,v 1.33 2014/02/03 08:37:32 nanard Exp $ */ +/* $Id: upnpglobalvars.c,v 1.34 2014/02/06 09:52:03 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2014 Thomas Bernard @@ -121,6 +121,7 @@ struct lan_addr_list lan_addrs; #ifdef ENABLE_IPV6 /* ipv6 address used for HTTP */ char ipv6_addr_for_http_with_brackets[64]; +int ipv6_enabled = 1; #endif /* Path of the Unix socket used to communicate with MiniSSDPd */ diff --git a/miniupnpd/upnpglobalvars.h b/miniupnpd/upnpglobalvars.h index 80ea147..fb67428 100644 --- a/miniupnpd/upnpglobalvars.h +++ b/miniupnpd/upnpglobalvars.h @@ -1,7 +1,7 @@ -/* $Id: upnpglobalvars.h,v 1.35 2013/06/13 13:21:30 nanard Exp $ */ +/* $Id: upnpglobalvars.h,v 1.37 2014/02/06 09:52:03 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2012 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -139,6 +139,7 @@ extern struct lan_addr_list lan_addrs; #ifdef ENABLE_IPV6 /* ipv6 address used for HTTP */ extern char ipv6_addr_for_http_with_brackets[64]; +extern int ipv6_enabled; #endif extern const char * minissdpdsocketpath; diff --git a/miniupnpd/upnputils.c b/miniupnpd/upnputils.c index 23ad242..197df58 100644 --- a/miniupnpd/upnputils.c +++ b/miniupnpd/upnputils.c @@ -1,7 +1,7 @@ -/* $Id: upnputils.c,v 1.7 2013/04/20 09:03:18 nanard Exp $ */ +/* $Id: upnputils.c,v 1.8 2014/02/05 17:00:26 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2013 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ From bc67a7133b8cdeb6d7bc2d6da4f3756e0a8a33b0 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 6 Feb 2014 10:55:57 +0100 Subject: [PATCH 021/127] miniupnpd/upnputils.c: improve log in get_lan_for_peer() --- miniupnpd/upnputils.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/miniupnpd/upnputils.c b/miniupnpd/upnputils.c index 197df58..33ebc66 100644 --- a/miniupnpd/upnputils.c +++ b/miniupnpd/upnputils.c @@ -93,6 +93,7 @@ struct lan_addr_s * get_lan_for_peer(const struct sockaddr * peer) { struct lan_addr_s * lan_addr = NULL; + char dbg_str[64]; #ifdef ENABLE_IPV6 if(peer->sa_family == AF_INET6) @@ -153,11 +154,15 @@ get_lan_for_peer(const struct sockaddr * peer) } #endif - if(lan_addr) - syslog(LOG_DEBUG, "%s: found in LAN %s %s", - "get_lan_for_peer()", lan_addr->ifname, lan_addr->str); - else - syslog(LOG_DEBUG, "%s: not found !", "get_lan_for_peer()"); + sockaddr_to_string(peer, dbg_str, sizeof(dbg_str)); + if(lan_addr) { + syslog(LOG_DEBUG, "%s: %s found in LAN %s %s", + "get_lan_for_peer()", dbg_str, + lan_addr->ifname, lan_addr->str); + } else { + syslog(LOG_DEBUG, "%s: %s not found !", "get_lan_for_peer()", + dbg_str); + } return lan_addr; } From 32b6e8c0fa21f626017abe7b0cd0672a5df858df Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 11 Feb 2014 10:38:50 +0100 Subject: [PATCH 022/127] miniupnpd/commonrdr.h: improve comments --- miniupnpd/commonrdr.h | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/miniupnpd/commonrdr.h b/miniupnpd/commonrdr.h index dd5cf62..7c0bd7c 100644 --- a/miniupnpd/commonrdr.h +++ b/miniupnpd/commonrdr.h @@ -1,6 +1,6 @@ -/* $Id: commonrdr.h,v 1.7 2011/06/22 20:34:39 nanard Exp $ */ +/* $Id: commonrdr.h,v 1.9 2014/02/11 09:36:15 nanard Exp $ */ /* MiniUPnP project - * (c) 2006-2011 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -10,6 +10,9 @@ #include "config.h" /* init and shutdown functions */ +/* init_redirect() return values : + * 0 : OK + * -1 : error */ int init_redirect(void); @@ -17,7 +20,10 @@ void shutdown_redirect(void); /* get_redirect_rule() gets internal IP and port from - * interface, external port and protocl + * interface, external port and protocol + * return value : + * 0 success (rule found) + * -1 error or rule not found */ int get_redirect_rule(const char * ifname, unsigned short eport, int proto, @@ -27,6 +33,10 @@ get_redirect_rule(const char * ifname, unsigned short eport, int proto, unsigned int * timestamp, u_int64_t * packets, u_int64_t * bytes); +/* get_redirect_rule_by_index() + * return values : + * 0 success (rule found) + * -1 error or rule not found */ int get_redirect_rule_by_index(int index, char * ifname, unsigned short * eport, From 50f8f6c76fde708540812740ba727e9f0e8bdf12 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 11 Feb 2014 10:40:46 +0100 Subject: [PATCH 023/127] miniupnpd/pcpserver.c: add info message for Mapping renewal --- miniupnpd/pcpserver.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/miniupnpd/pcpserver.c b/miniupnpd/pcpserver.c index 9b11361..c12eb96 100644 --- a/miniupnpd/pcpserver.c +++ b/miniupnpd/pcpserver.c @@ -827,6 +827,10 @@ static void CreatePCPMap(pcp_info_t *pcp_msg_info) return; } } else { + syslog(LOG_INFO, "port %hu %s already redirected to %s:%hu, replacing", + pcp_msg_info->ext_port, (pcp_msg_info->protocol==IPPROTO_TCP)?"tcp":"udp", + iaddr_old, iport_old); + /* remove and then add again */ if (_upnp_delete_redir(pcp_msg_info->ext_port, pcp_msg_info->protocol)==0) { break; From 16ea0db41162f80bdbee37bcc92bc8ce1f45e695 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 11 Feb 2014 10:41:26 +0100 Subject: [PATCH 024/127] miniupnpd: Fix PCP Map renewal --- miniupnpd/Changelog.txt | 5 ++++- miniupnpd/pcpserver.c | 6 ++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/miniupnpd/Changelog.txt b/miniupnpd/Changelog.txt index 6d463e4..2835f5b 100644 --- a/miniupnpd/Changelog.txt +++ b/miniupnpd/Changelog.txt @@ -1,4 +1,7 @@ -$Id: Changelog.txt,v 1.350 2014/02/06 09:52:03 nanard Exp $ +$Id: Changelog.txt,v 1.351 2014/02/11 09:35:52 nanard Exp $ + +2014/02/11: + Fix PCP Map renewal 2014/02/06: possibility to disable ipv6 at runtime diff --git a/miniupnpd/pcpserver.c b/miniupnpd/pcpserver.c index c12eb96..7354fb3 100644 --- a/miniupnpd/pcpserver.c +++ b/miniupnpd/pcpserver.c @@ -1,4 +1,4 @@ -/* $Id: pcpserver.c,v 1.7 2014/02/03 09:38:26 nanard Exp $ */ +/* $Id: pcpserver.c,v 1.9 2014/02/11 09:35:53 nanard Exp $ */ /* MiniUPnP project * Website : http://miniupnp.free.fr/ * Author : Peter Tatrai @@ -803,7 +803,7 @@ static void CreatePCPMap(pcp_info_t *pcp_msg_info) char desc[64]; char iaddr_old[INET_ADDRSTRLEN]; uint16_t iport_old; - unsigned int timestamp = time(NULL) + pcp_msg_info->lifetime; + unsigned int timestamp; int r=0; if (pcp_msg_info->ext_port == 0) { @@ -840,6 +840,8 @@ static void CreatePCPMap(pcp_info_t *pcp_msg_info) } } while (r==0); + timestamp = time(NULL) + pcp_msg_info->lifetime; + if ((pcp_msg_info->ext_port == 0) || (IN6_IS_ADDR_V4MAPPED(pcp_msg_info->int_ip) && (!check_upnp_rule_against_permissions(upnppermlist, From 86d3e7c0530ff28ef11b6cfb4cc98211df4aac45 Mon Sep 17 00:00:00 2001 From: Christopher Meng Date: Fri, 14 Feb 2014 16:56:10 +0800 Subject: [PATCH 025/127] Corrent the binary permission from 555 to 755 --- miniupnpd/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miniupnpd/Makefile b/miniupnpd/Makefile index 4f085fd..09f776b 100644 --- a/miniupnpd/Makefile +++ b/miniupnpd/Makefile @@ -148,7 +148,7 @@ clean: install: miniupnpd genuuid $(STRIP) miniupnpd $(INSTALL) -d $(DESTDIR)$(INSTALLBINDIR) - $(INSTALL) -m 555 miniupnpd $(DESTDIR)$(INSTALLBINDIR) + $(INSTALL) -m 755 miniupnpd $(DESTDIR)$(INSTALLBINDIR) $(INSTALL) -d $(DESTDIR)$(INSTALLETCDIR) $(INSTALL) -b miniupnpd.conf $(DESTDIR)$(INSTALLETCDIR) # TODO : install man page correctly From 7fb5fe5dcb8b64bdbd2bf285f2fd03e53cfc0a6e Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 17 Feb 2014 16:52:53 +0100 Subject: [PATCH 026/127] miniupnpc/upnpcommands.h: explain UPNP error codes --- miniupnpc/upnpcommands.h | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/miniupnpc/upnpcommands.h b/miniupnpc/upnpcommands.h index dc3f23f..93d9f3d 100644 --- a/miniupnpc/upnpcommands.h +++ b/miniupnpc/upnpcommands.h @@ -1,7 +1,7 @@ -/* $Id: upnpcommands.h,v 1.26 2014/01/31 13:18:26 nanard Exp $ */ +/* $Id: upnpcommands.h,v 1.27 2014/02/17 15:38:26 nanard Exp $ */ /* Miniupnp project : http://miniupnp.free.fr/ * Author : Thomas Bernard - * Copyright (c) 2005-2011 Thomas Bernard + * Copyright (c) 2005-2014 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided within this distribution */ #ifndef UPNPCOMMANDS_H_INCLUDED @@ -100,6 +100,8 @@ UPNP_GetLinkLayerMaxBitRates(const char* controlURL, * errorCode errorDescription (short) - Description (long) * 402 Invalid Args - See UPnP Device Architecture section on Control. * 501 Action Failed - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization and + * the sender was not authorized. * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be * wild-carded * 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded @@ -112,7 +114,13 @@ UPNP_GetLinkLayerMaxBitRates(const char* controlURL, * 726 RemoteHostOnlySupportsWildcard - RemoteHost must be a wildcard * and cannot be a specific IP address or DNS name * 727 ExternalPortOnlySupportsWildcard - ExternalPort must be a wildcard and - * cannot be a specific port value */ + * cannot be a specific port value + * 728 NoPortMapsAvailable - There are not enough free ports available to + * complete port mapping. + * 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed + * due to conflict with other mechanisms. + * 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded + */ LIBSPEC int UPNP_AddPortMapping(const char * controlURL, const char * servicetype, const char * extPort, @@ -132,6 +140,8 @@ UPNP_AddPortMapping(const char * controlURL, const char * servicetype, * * List of possible UPnP errors for DeletePortMapping : * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization + * and the sender was not authorized. * 714 NoSuchEntryInArray - The specified value does not exist in the array */ LIBSPEC int UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, @@ -159,7 +169,15 @@ UPNP_GetPortMappingNumberOfEntries(const char* controlURL, * * return value : * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR - * or a UPnP Error Code. */ + * or a UPnP Error Code. + * + * List of possible UPnP errors for _GetSpecificPortMappingEntry : + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 501 Action Failed - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization + * and the sender was not authorized. + * 714 NoSuchEntryInArray - The specified value does not exist in the array. + */ LIBSPEC int UPNP_GetSpecificPortMappingEntry(const char * controlURL, const char * servicetype, @@ -190,6 +208,8 @@ UPNP_GetSpecificPortMappingEntry(const char * controlURL, * * Possible UPNP Error codes : * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization + * and the sender was not authorized. * 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds */ LIBSPEC int From b2143eff9436d4a76f4716022474a0058f013a9b Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 18 Feb 2014 09:34:42 +0100 Subject: [PATCH 027/127] implementation of queuing of messages to send. --- miniupnpd/.gitignore | 1 + miniupnpd/Makefile | 8 +- miniupnpd/Makefile.linux | 8 +- miniupnpd/asyncsendto.c | 153 ++++++++++++++++++++++++++++++++++++ miniupnpd/asyncsendto.h | 26 ++++++ miniupnpd/testasyncsendto.c | 117 +++++++++++++++++++++++++++ 6 files changed, 308 insertions(+), 5 deletions(-) create mode 100644 miniupnpd/asyncsendto.c create mode 100644 miniupnpd/asyncsendto.h create mode 100644 miniupnpd/testasyncsendto.c diff --git a/miniupnpd/.gitignore b/miniupnpd/.gitignore index f97b1ce..d6c6eb9 100644 --- a/miniupnpd/.gitignore +++ b/miniupnpd/.gitignore @@ -9,6 +9,7 @@ testgetifstats testupnpdescgen testupnppermissions testgetroute +testasyncsendto netfilter/testiptcrdr netfilter/testiptcrdr_dscp netfilter/testiptcrdr_peer diff --git a/miniupnpd/Makefile b/miniupnpd/Makefile index 09f776b..8fa4e4d 100644 --- a/miniupnpd/Makefile +++ b/miniupnpd/Makefile @@ -116,10 +116,11 @@ TESTUPNPDESCGENOBJS = testupnpdescgen.o upnpdescgen.o TESTUPNPPERMISSIONSOBJS = testupnppermissions.o upnppermissions.o TESTGETIFADDROBJS = testgetifaddr.o getifaddr.o MINIUPNPDCTLOBJS = miniupnpdctl.o +TESTASYNCSENDTOOBJS = testasyncsendto.o asyncsendto.o upnputils.o EXECUTABLES = miniupnpd testupnpdescgen testgetifstats \ testupnppermissions miniupnpdctl \ - testgetifaddr testgetroute + testgetifaddr testgetroute testasyncsendto .if $(OSNAME) == "Darwin" LIBS = .else @@ -142,7 +143,7 @@ clean: $(RM) $(STDOBJS) $(BSDOBJS) $(SUNOSOBJS) $(MACOBJS) $(EXECUTABLES) \ testupnpdescgen.o \ $(MISCOBJS) config.h testgetifstats.o testupnppermissions.o \ - miniupnpdctl.o testgetifaddr.o testgetroute.o \ + miniupnpdctl.o testgetifaddr.o testgetroute.o testasyncsendto.o \ $(PFOBJS) $(IPFOBJS) $(IPFWOBJS) install: miniupnpd genuuid @@ -199,6 +200,9 @@ testupnppermissions: config.h $(TESTUPNPPERMISSIONSOBJS) testgetroute: config.h $(TESTGETROUTEOBJS) $(CC) $(CFLAGS) -o $@ $(TESTGETROUTEOBJS) +testasyncsendto: config.h $(TESTASYNCSENDTOOBJS) + $(CC) $(CFLAGS) -o $@ $(TESTASYNCSENDTOOBJS) + # gmake : # $(CC) $(CFLAGS) -o $@ $^ # BSDmake : diff --git a/miniupnpd/Makefile.linux b/miniupnpd/Makefile.linux index a9bab57..6c3b9ad 100644 --- a/miniupnpd/Makefile.linux +++ b/miniupnpd/Makefile.linux @@ -150,7 +150,7 @@ TESTUPNPDESCGENOBJS = testupnpdescgen.o upnpdescgen.o EXECUTABLES = miniupnpd testupnpdescgen testgetifstats \ testupnppermissions miniupnpdctl testgetifaddr \ - testgetroute + testgetroute testasyncsendto .PHONY: all clean install depend genuuid @@ -161,7 +161,7 @@ clean: $(RM) $(EXECUTABLES) $(RM) testupnpdescgen.o testgetifstats.o $(RM) testupnppermissions.o testgetifaddr.o - $(RM) testgetroute.o + $(RM) testgetroute.o testasyncsendto.o $(RM) miniupnpdctl.o install: miniupnpd miniupnpd.8 miniupnpd.conf genuuid \ @@ -205,6 +205,8 @@ testgetifaddr: testgetifaddr.o getifaddr.o testgetroute: testgetroute.o linux/getroute.o upnputils.o -lnfnetlink +testasyncsendto: testasyncsendto.o asyncsendto.o upnputils.o + miniupnpdctl: miniupnpdctl.o config.h: genconfig.sh VERSION @@ -214,7 +216,7 @@ depend: config.h makedepend -f$(MAKEFILE_LIST) -Y \ $(ALLOBJS:.o=.c) $(TESTUPNPDESCGENOBJS:.o=.c) \ testgetifstats.c testupnppermissions.c testgetifaddr.c \ - testgetroute.c miniupnpdctl.c 2>/dev/null + testgetroute.c testasyncsendto.c miniupnpdctl.c 2>/dev/null # DO NOT DELETE diff --git a/miniupnpd/asyncsendto.c b/miniupnpd/asyncsendto.c new file mode 100644 index 0000000..1107f6d --- /dev/null +++ b/miniupnpd/asyncsendto.c @@ -0,0 +1,153 @@ +/* $Id: $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2006-2014 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "asyncsendto.h" + +struct scheduled_send { + LIST_ENTRY(scheduled_send) entries; + struct timeval ts; + int sockfd; + const void * buf; + size_t len; + int flags; + const struct sockaddr *dest_addr; + socklen_t addrlen; + char data[]; +}; + +static LIST_HEAD(listhead, scheduled_send) send_list = { NULL }; + +/* + * ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, + * const struct sockaddr *dest_addr, socklen_t addrlen); + */ + +/* delay = milli seconds */ +ssize_t +sendto_schedule(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen, + unsigned int delay) +{ + ssize_t n; + struct timeval tv; + struct scheduled_send * elt; + + if(delay == 0) { + /* first try to send at once */ + n = sendto(sockfd, buf, len, flags, dest_addr, addrlen); + if((n >= 0) || (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK)) + return n; + } + /* schedule */ + if(gettimeofday(&tv, 0) < 0) { + return -1; + } + /* allocate enough space for structure + buffers */ + elt = malloc(sizeof(struct scheduled_send) + len + addrlen); + if(elt == NULL) { + syslog(LOG_ERR, "malloc failed to allocate %u bytes", + (unsigned)(sizeof(struct scheduled_send) + len + addrlen)); + return -1; + } + /* time the packet should be sent */ + elt->ts.tv_sec = tv.tv_sec + (delay / 1000); + elt->ts.tv_usec = tv.tv_usec + (delay % 1000) * 1000; + if(elt->ts.tv_usec > 1000000) { + elt->ts.tv_sec++; + elt->ts.tv_usec -= 1000000; + } + elt->sockfd = sockfd; + elt->flags = flags; + memcpy(elt->data, dest_addr, addrlen); + elt->dest_addr = (struct sockaddr *)elt->data; + elt->addrlen = addrlen; + memcpy(elt->data + addrlen, buf, len); + elt->buf = (void *)(elt->data + addrlen); + elt->len = len; + /* insert */ + LIST_INSERT_HEAD( &send_list, elt, entries); + return 0; +} + + +ssize_t +sendto_or_schedule(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen) +{ + return sendto_schedule(sockfd, buf, len, flags, dest_addr, addrlen, 0); +} + +/* get_next_scheduled_send() return number of scheduled send in list */ +int get_next_scheduled_send(struct timeval * next_send) +{ + int n = 0; + struct scheduled_send * elt; + if(next_send == NULL) + return -1; + for(elt = send_list.lh_first; elt != NULL; elt = elt->entries.le_next) { + if(n == 0 || (elt->ts.tv_sec < next_send->tv_sec) || + (elt->ts.tv_sec == next_send->tv_sec && elt->ts.tv_usec < next_send->tv_usec)) { + next_send->tv_sec = elt->ts.tv_sec; + next_send->tv_usec = elt->ts.tv_usec; + } + n++; + } + return n; +} + +int get_sendto_fds(fd_set * writefds, int * max_fd, const struct timeval * now) +{ + int n = 0; + struct scheduled_send * elt; + for(elt = send_list.lh_first; elt != NULL; elt = elt->entries.le_next) { + if((elt->ts.tv_sec < now->tv_sec) || + (elt->ts.tv_sec == now->tv_sec && elt->ts.tv_usec <= now->tv_usec)) { + FD_SET(elt->sockfd, writefds); + if(elt->sockfd > *max_fd) + *max_fd = elt->sockfd; + n++; + } + } +syslog(LOG_DEBUG, "%x", (int)writefds->fds_bits[0]); + return n; +} + +int try_sendto(fd_set * writefds) +{ + ssize_t n; + struct scheduled_send * elt; + struct scheduled_send * next; + for(elt = send_list.lh_first; elt != NULL; elt = next) { + next = elt->entries.le_next; +syslog(LOG_DEBUG, "s=%d fds=%x", elt->sockfd, (int)writefds->fds_bits[0]); + if(FD_ISSET(elt->sockfd, writefds)) { + syslog(LOG_DEBUG, "sending %d bytes", (int)elt->len); + n = sendto(elt->sockfd, elt->buf, elt->len, elt->flags, + elt->dest_addr, elt->addrlen); + if(n < 0) { + syslog(LOG_DEBUG, "sendto: %m"); + if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) + continue; + return n; + } else { + LIST_REMOVE(elt, entries); + free(elt); + } + } + } + return 0; +} + diff --git a/miniupnpd/asyncsendto.h b/miniupnpd/asyncsendto.h new file mode 100644 index 0000000..d46de69 --- /dev/null +++ b/miniupnpd/asyncsendto.h @@ -0,0 +1,26 @@ +/* $Id: $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2006-2014 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ + +#ifndef ASYNCSENDTO_H_INCLUDED +#define ASYNCSENDTO_H_INCLUDED + +ssize_t +sendto_schedule(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen, + unsigned int delay); + +ssize_t +sendto_or_schedule(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen); + +int get_next_scheduled_send(struct timeval * next_send); + +int try_sendto(fd_set * writefds); + +int get_sendto_fds(fd_set * writefds, int * max_fd, const struct timeval * now); + +#endif diff --git a/miniupnpd/testasyncsendto.c b/miniupnpd/testasyncsendto.c new file mode 100644 index 0000000..e2bc5d4 --- /dev/null +++ b/miniupnpd/testasyncsendto.c @@ -0,0 +1,117 @@ +/* $Id: $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2006-2014 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "miniupnpdtypes.h" +#include "upnputils.h" +#include "asyncsendto.h" + +struct lan_addr_list lan_addrs; + +#define DEST_IP "239.255.255.250" +#define DEST_PORT 1900 +/* +ssize_t +sendto_schedule(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen, + unsigned int delay) +*/ + +int test(void) +{ + int s; + ssize_t n; + int i; + struct sockaddr_in addr; + struct sockaddr_in dest_addr; + struct timeval next_send; + if( (s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, "socket(): %m"); + return 1; + } + set_non_blocking(s); + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + if(bind(s, &addr, sizeof(addr)) < 0) { + syslog(LOG_ERR, "bind(): %m"); + close(s); + return 1; + } + memset(&dest_addr, 0, sizeof(struct sockaddr_in)); + dest_addr.sin_family = AF_INET; + dest_addr.sin_addr.s_addr = inet_addr(DEST_IP); + dest_addr.sin_port = htons(DEST_PORT); + n = sendto_or_schedule(s, "1234", 4, 0, + (struct sockaddr *)&dest_addr, sizeof(dest_addr)); + syslog(LOG_DEBUG, "sendto_or_schedule : %d", (int)n); + n = sendto_schedule(s, "1234", 4, 0, + (struct sockaddr *)&dest_addr, sizeof(dest_addr), + 3000); + syslog(LOG_DEBUG, "sendto_schedule : %d", (int)n); + while ((i = get_next_scheduled_send(&next_send)) > 0) { + fd_set writefds; + int max_fd; + struct timeval timeout; + struct timeval now; + syslog(LOG_DEBUG, "get_next_scheduled_send : %d next_send=%ld.%06ld", + i, next_send.tv_sec, next_send.tv_usec); + FD_ZERO(&writefds); + max_fd = 0; + gettimeofday(&now, NULL); + if(now.tv_sec > next_send.tv_sec || + (now.tv_sec == next_send.tv_sec && now.tv_usec >= next_send.tv_usec)) { + /* wait 10sec :) */ + timeout.tv_sec = 10; + timeout.tv_usec = 0; + } else { + /* ... */ + timeout.tv_sec = (next_send.tv_sec - now.tv_sec); + timeout.tv_usec = (next_send.tv_usec - now.tv_usec); + if(timeout.tv_usec < 0) { + timeout.tv_usec += 1000000; + timeout.tv_sec--; + } + } + i = get_sendto_fds(&writefds, &max_fd, &now); + syslog(LOG_DEBUG, "get_sendto_fds() returned %d", i); + syslog(LOG_DEBUG, "select(%d, NULL, xx, NULL, %ld.%06ld)", + max_fd, timeout.tv_sec, timeout.tv_usec); + i = select(max_fd, NULL, &writefds, NULL, &timeout); + if(i < 0) { + syslog(LOG_ERR, "select: %m"); + if(errno != EINTR) + break; + } else if(try_sendto(&writefds) < 0) { + syslog(LOG_ERR, "try_sendto: %m"); + break; + } + } + close(s); + return 0; +} + +int main(int argc, char * * argv) +{ + int r; + (void)argc; + (void)argv; + openlog("testasyncsendto", LOG_CONS|LOG_PERROR, LOG_USER); + r = test(); + closelog(); + return r; +} + From 06d9d36e990dfab57a46db68112f0cb347b8f24a Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 20 Feb 2014 16:08:20 +0100 Subject: [PATCH 028/127] miniupnpd/asyncsendto: make sendto_schedule work --- miniupnpd/asyncsendto.c | 59 +++++++++++++++++++++++++++++++------ miniupnpd/testasyncsendto.c | 15 ++++++++-- 2 files changed, 62 insertions(+), 12 deletions(-) diff --git a/miniupnpd/asyncsendto.c b/miniupnpd/asyncsendto.c index 1107f6d..4a79bc0 100644 --- a/miniupnpd/asyncsendto.c +++ b/miniupnpd/asyncsendto.c @@ -16,9 +16,19 @@ #include "asyncsendto.h" +/* state diagram for a packet : + * + * | + * V + * -> ESCHEDULED -> ESENDNOW -> sent + * ^ | + * | V + * EWAITREADY -> sent + */ struct scheduled_send { LIST_ENTRY(scheduled_send) entries; struct timeval ts; + enum {ESCHEDULED=1, EWAITREADY=2, ESENDNOW=3} state; int sockfd; const void * buf; size_t len; @@ -41,6 +51,7 @@ sendto_schedule(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen, unsigned int delay) { + enum {ESCHEDULED, EWAITREADY, ESENDNOW} state; ssize_t n; struct timeval tv; struct scheduled_send * elt; @@ -48,9 +59,21 @@ sendto_schedule(int sockfd, const void *buf, size_t len, int flags, if(delay == 0) { /* first try to send at once */ n = sendto(sockfd, buf, len, flags, dest_addr, addrlen); - if((n >= 0) || (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK)) + if(n >= 0) return n; + else if(errno == EAGAIN || errno == EWOULDBLOCK) { + /* use select() on this socket */ + state = EWAITREADY; + } else if(errno == EINTR) { + state = ESENDNOW; + } else { + /* uncatched error */ + return n; + } + } else { + state = ESCHEDULED; } + /* schedule */ if(gettimeofday(&tv, 0) < 0) { return -1; @@ -62,6 +85,7 @@ sendto_schedule(int sockfd, const void *buf, size_t len, int flags, (unsigned)(sizeof(struct scheduled_send) + len + addrlen)); return -1; } + elt->state = state; /* time the packet should be sent */ elt->ts.tv_sec = tv.tv_sec + (delay / 1000); elt->ts.tv_usec = tv.tv_usec + (delay % 1000) * 1000; @@ -83,6 +107,7 @@ sendto_schedule(int sockfd, const void *buf, size_t len, int flags, } +/* try to send at once, and queue the packet if needed */ ssize_t sendto_or_schedule(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) @@ -108,23 +133,30 @@ int get_next_scheduled_send(struct timeval * next_send) return n; } +/* update writefds for select() call + * return the number of packets to try to send at once */ int get_sendto_fds(fd_set * writefds, int * max_fd, const struct timeval * now) { int n = 0; struct scheduled_send * elt; for(elt = send_list.lh_first; elt != NULL; elt = elt->entries.le_next) { - if((elt->ts.tv_sec < now->tv_sec) || - (elt->ts.tv_sec == now->tv_sec && elt->ts.tv_usec <= now->tv_usec)) { + if(elt->state == EWAITREADY) { + /* last sendto() call returned EAGAIN/EWOULDBLOCK */ FD_SET(elt->sockfd, writefds); if(elt->sockfd > *max_fd) *max_fd = elt->sockfd; n++; + } else if((elt->ts.tv_sec < now->tv_sec) || + (elt->ts.tv_sec == now->tv_sec && elt->ts.tv_usec <= now->tv_usec)) { + /* we waited long enough, now send ! */ + elt->state = ESENDNOW; + n++; } } -syslog(LOG_DEBUG, "%x", (int)writefds->fds_bits[0]); return n; } +/* executed sendto() when needed */ int try_sendto(fd_set * writefds) { ssize_t n; @@ -132,17 +164,26 @@ int try_sendto(fd_set * writefds) struct scheduled_send * next; for(elt = send_list.lh_first; elt != NULL; elt = next) { next = elt->entries.le_next; -syslog(LOG_DEBUG, "s=%d fds=%x", elt->sockfd, (int)writefds->fds_bits[0]); - if(FD_ISSET(elt->sockfd, writefds)) { - syslog(LOG_DEBUG, "sending %d bytes", (int)elt->len); + if((elt->state == ESENDNOW) || + (elt->state == EWAITREADY && FD_ISSET(elt->sockfd, writefds))) { + syslog(LOG_DEBUG, "try_sendto(): %d bytes on socket %d", + (int)elt->len, elt->sockfd); n = sendto(elt->sockfd, elt->buf, elt->len, elt->flags, elt->dest_addr, elt->addrlen); if(n < 0) { - syslog(LOG_DEBUG, "sendto: %m"); - if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) + if(errno == EINTR) { + /* retry at once */ + elt->state = ESENDNOW; continue; + } else if(errno == EAGAIN || errno == EWOULDBLOCK) { + /* retry once the socket is ready for writing */ + elt->state = EWAITREADY; + continue; + } + /* uncatched error */ return n; } else { + /* remove from the list */ LIST_REMOVE(elt, entries); free(elt); } diff --git a/miniupnpd/testasyncsendto.c b/miniupnpd/testasyncsendto.c index e2bc5d4..7a4eb6e 100644 --- a/miniupnpd/testasyncsendto.c +++ b/miniupnpd/testasyncsendto.c @@ -58,6 +58,10 @@ int test(void) n = sendto_or_schedule(s, "1234", 4, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr)); syslog(LOG_DEBUG, "sendto_or_schedule : %d", (int)n); + n = sendto_schedule(s, "1234", 4, 0, + (struct sockaddr *)&dest_addr, sizeof(dest_addr), + 4400); + syslog(LOG_DEBUG, "sendto_schedule : %d", (int)n); n = sendto_schedule(s, "1234", 4, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr), 3000); @@ -72,10 +76,16 @@ int test(void) FD_ZERO(&writefds); max_fd = 0; gettimeofday(&now, NULL); + i = get_sendto_fds(&writefds, &max_fd, &now); if(now.tv_sec > next_send.tv_sec || (now.tv_sec == next_send.tv_sec && now.tv_usec >= next_send.tv_usec)) { - /* wait 10sec :) */ - timeout.tv_sec = 10; + if(i > 0) { + /* dont wait */ + timeout.tv_sec = 0; + } else { + /* wait 10sec :) */ + timeout.tv_sec = 10; + } timeout.tv_usec = 0; } else { /* ... */ @@ -86,7 +96,6 @@ int test(void) timeout.tv_sec--; } } - i = get_sendto_fds(&writefds, &max_fd, &now); syslog(LOG_DEBUG, "get_sendto_fds() returned %d", i); syslog(LOG_DEBUG, "select(%d, NULL, xx, NULL, %ld.%06ld)", max_fd, timeout.tv_sec, timeout.tv_usec); From 8691c9c0e0246773397e22608d9c11ec76aca4d2 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 25 Feb 2014 10:23:59 +0100 Subject: [PATCH 029/127] miniupnpd.c: improve comment for init() --- miniupnpd/miniupnpd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/miniupnpd/miniupnpd.c b/miniupnpd/miniupnpd.c index 805d788..3840833 100644 --- a/miniupnpd/miniupnpd.c +++ b/miniupnpd/miniupnpd.c @@ -705,7 +705,9 @@ void complete_uuidvalues(void) * 5) check and write pid file * 6) set startup time stamp * 7) compute presentation URL - * 8) set signal handlers */ + * 8) set signal handlers + * 10) init redirection engine + * 11) reload mapping from leasefile */ static int init(int argc, char * * argv, struct runtime_vars * v) { @@ -1263,6 +1265,7 @@ init(int argc, char * * argv, struct runtime_vars * v) syslog(LOG_NOTICE, "Failed to set %s handler", "SIGUSR1"); } + /* initialize redirection engine (and pinholes) */ if(init_redirect() < 0) { syslog(LOG_ERR, "Failed to init redirection engine. EXITING"); From e00c1bc6e9e08b7d4deae27272b2409c3f03c707 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 25 Feb 2014 10:24:22 +0100 Subject: [PATCH 030/127] miniupnpd.c: init random number generator in init() --- miniupnpd/miniupnpd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/miniupnpd/miniupnpd.c b/miniupnpd/miniupnpd.c index 3840833..8bd4a0f 100644 --- a/miniupnpd/miniupnpd.c +++ b/miniupnpd/miniupnpd.c @@ -706,6 +706,7 @@ void complete_uuidvalues(void) * 6) set startup time stamp * 7) compute presentation URL * 8) set signal handlers + * 9) init random generator (srandom()) * 10) init redirection engine * 11) reload mapping from leasefile */ static int @@ -1265,6 +1266,9 @@ init(int argc, char * * argv, struct runtime_vars * v) syslog(LOG_NOTICE, "Failed to set %s handler", "SIGUSR1"); } + /* initialize random number generator */ + srandom((unsigned int)time(NULL)); + /* initialize redirection engine (and pinholes) */ if(init_redirect() < 0) { From d20d959920ed660b3fa1aa86b1cc06a39ee2cbe2 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 25 Feb 2014 11:07:47 +0100 Subject: [PATCH 031/127] miniupnpd/asyncsendto.h: improve comments/doc --- miniupnpd/asyncsendto.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/miniupnpd/asyncsendto.h b/miniupnpd/asyncsendto.h index d46de69..6afb322 100644 --- a/miniupnpd/asyncsendto.h +++ b/miniupnpd/asyncsendto.h @@ -8,19 +8,28 @@ #ifndef ASYNCSENDTO_H_INCLUDED #define ASYNCSENDTO_H_INCLUDED +/* sendto_schedule() : see sendto(2) + * schedule sendto() call after delay (milliseconds) */ ssize_t sendto_schedule(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen, unsigned int delay); +/* sendto_schedule() : see sendto(2) + * try sendto() at once and schedule if EINTR/EAGAIN/EWOULDBLOCK */ ssize_t sendto_or_schedule(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); +/* get_next_scheduled_send() + * return number of scheduled sendto + * set next_send to timestamp to send next packet */ int get_next_scheduled_send(struct timeval * next_send); +/* execute sendto() for needed packets */ int try_sendto(fd_set * writefds); +/* set writefds before select() */ int get_sendto_fds(fd_set * writefds, int * max_fd, const struct timeval * now); #endif From 1985cbf3ef4e0d0790eafa277e9f06617a761445 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 25 Feb 2014 11:08:27 +0100 Subject: [PATCH 032/127] asyncsendto: remove failed sendto() from queue --- miniupnpd/asyncsendto.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/miniupnpd/asyncsendto.c b/miniupnpd/asyncsendto.c index 4a79bc0..faae87e 100644 --- a/miniupnpd/asyncsendto.c +++ b/miniupnpd/asyncsendto.c @@ -181,6 +181,9 @@ int try_sendto(fd_set * writefds) continue; } /* uncatched error */ + /* remove from the list */ + LIST_REMOVE(elt, entries); + free(elt); return n; } else { /* remove from the list */ From cbc1a3c96a5b49a35481e30be7e46a2c7b2ad705 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 25 Feb 2014 11:10:05 +0100 Subject: [PATCH 033/127] miniupnpd: add sendto() queuing --- miniupnpd/Makefile | 2 +- miniupnpd/Makefile.linux | 2 +- miniupnpd/Makefile.macosx | 3 ++- miniupnpd/miniupnpd.c | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/miniupnpd/Makefile b/miniupnpd/Makefile index 8fa4e4d..e404609 100644 --- a/miniupnpd/Makefile +++ b/miniupnpd/Makefile @@ -80,7 +80,7 @@ STDOBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \ upnpredirect.o getifaddr.o daemonize.o upnpglobalvars.o \ options.o upnppermissions.o minissdp.o natpmp.o pcpserver.o \ upnpevents.o upnputils.o getconnstatus.o \ - upnppinhole.o + upnppinhole.o asyncsendto.o BSDOBJS = bsd/getifstats.o bsd/ifacewatcher.o bsd/getroute.o SUNOSOBJS = solaris/getifstats.o bsd/ifacewatcher.o bsd/getroute.o MACOBJS = mac/getifstats.o bsd/ifacewatcher.o bsd/getroute.o diff --git a/miniupnpd/Makefile.linux b/miniupnpd/Makefile.linux index 6c3b9ad..270c72d 100644 --- a/miniupnpd/Makefile.linux +++ b/miniupnpd/Makefile.linux @@ -47,7 +47,7 @@ BASEOBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \ upnpredirect.o getifaddr.o daemonize.o upnpglobalvars.o \ options.o upnppermissions.o minissdp.o natpmp.o pcpserver.o \ upnpevents.o upnputils.o getconnstatus.o \ - upnppinhole.o pcplearndscp.o + upnppinhole.o pcplearndscp.o asyncsendto.o LNXOBJS = linux/getifstats.o linux/ifacewatcher.o linux/getroute.o NETFILTEROBJS = netfilter/iptcrdr.o netfilter/iptpinhole.o netfilter/nfct_get.o diff --git a/miniupnpd/Makefile.macosx b/miniupnpd/Makefile.macosx index 7520124..27280c6 100644 --- a/miniupnpd/Makefile.macosx +++ b/miniupnpd/Makefile.macosx @@ -32,7 +32,8 @@ FWNAME = $(shell [ `uname -r | cut -d. -f1` -ge 11 ] && echo "pf" || echo "ipfw STD_OBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \ upnpredirect.o getifaddr.o daemonize.o upnpglobalvars.o \ options.o upnppermissions.o minissdp.o natpmp.o \ - upnpevents.o getconnstatus.o upnputils.o + upnpevents.o getconnstatus.o upnputils.o \ + asyncsendto.o MAC_OBJS = mac/getifstats.o bsd/ifacewatcher.o IPFW_OBJS = ipfw/ipfwrdr.o ipfw/ipfwaux.o PF_OBJS = pf/obsdrdr.o pf/pfpinhole.o diff --git a/miniupnpd/miniupnpd.c b/miniupnpd/miniupnpd.c index 8bd4a0f..9219e47 100644 --- a/miniupnpd/miniupnpd.c +++ b/miniupnpd/miniupnpd.c @@ -63,6 +63,7 @@ #include "miniupnpdtypes.h" #include "daemonize.h" #include "upnpevents.h" +#include "asyncsendto.h" #ifdef ENABLE_NATPMP #include "natpmp.h" #ifdef ENABLE_PCP @@ -1756,6 +1757,38 @@ main(int argc, char * * argv) upnpevents_selectfds(&readset, &writeset, &max_fd); #endif + /* queued "sendto" */ + { + struct timeval next_send; + i = get_next_scheduled_send(&next_send); + if(i > 0) { +#ifdef DEBUG + syslog(LOG_DEBUG, "%d queued sendto", i); +#endif + i = get_sendto_fds(&writeset, &max_fd, &timeofday); + if(timeofday.tv_sec > next_send.tv_sec || + (timeofday.tv_sec == next_send.tv_sec && timeofday.tv_usec >= next_send.tv_usec)) { + if(i > 0) { + timeout.tv_sec = 0; + timeout.tv_usec = 0; + } + } else { + struct timeval tmp_timeout; + tmp_timeout.tv_sec = (next_send.tv_sec - timeofday.tv_sec); + tmp_timeout.tv_usec = (next_send.tv_usec - timeofday.tv_usec); + if(tmp_timeout.tv_usec < 0) { + tmp_timeout.tv_usec += 1000000; + tmp_timeout.tv_sec--; + } + if(timeout.tv_sec > tmp_timeout.tv_sec + || (timeout.tv_sec == tmp_timeout.tv_sec && timeout.tv_usec > tmp_timeout.tv_usec)) { + timeout.tv_sec = tmp_timeout.tv_sec; + timeout.tv_usec = tmp_timeout.tv_usec; + } + } + } + } + if(select(max_fd+1, &readset, &writeset, 0, &timeout) < 0) { if(quitting) goto shutdown; @@ -1764,6 +1797,9 @@ main(int argc, char * * argv) syslog(LOG_ERR, "Failed to select open sockets. EXITING"); return 1; /* very serious cause of error */ } + if(try_sendto(&writeset) < 0) { + syslog(LOG_ERR, "try_sendto: %m"); + } #ifdef USE_MINIUPNPDCTL for(ectl = ctllisthead.lh_first; ectl;) { From c1e624ecd4e9d035240ec2a927beb29f60035df3 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 25 Feb 2014 11:15:30 +0100 Subject: [PATCH 034/127] miniupnpd: use asyncsendto --- miniupnpd/minissdp.c | 46 +++++++++++++++++++++++++++++-------------- miniupnpd/natpmp.c | 9 +++++---- miniupnpd/pcpserver.c | 3 ++- 3 files changed, 38 insertions(+), 20 deletions(-) diff --git a/miniupnpd/minissdp.c b/miniupnpd/minissdp.c index fb5a9b8..c6b70f2 100644 --- a/miniupnpd/minissdp.c +++ b/miniupnpd/minissdp.c @@ -24,6 +24,7 @@ #include "minissdp.h" #include "upnputils.h" #include "getroute.h" +#include "asyncsendto.h" #include "codelength.h" /* SSDP ip/port */ @@ -330,11 +331,13 @@ EXT: * st, st_len : ST: header * suffix : suffix for USN: header * host, port : our HTTP host, port + * delay : in milli-seconds */ static void SendSSDPResponse(int s, const struct sockaddr * addr, const char * st, int st_len, const char * suffix, - const char * host, unsigned short port, const char * uuidvalue) + const char * host, unsigned short port, const char * uuidvalue, + unsigned int delay) { int l, n; char buf[512]; @@ -399,15 +402,14 @@ SendSSDPResponse(int s, const struct sockaddr * addr, } addrlen = (addr->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); - n = sendto(s, buf, l, 0, - addr, addrlen); + n = sendto_schedule(s, buf, l, 0, + addr, addrlen, delay); sockaddr_to_string(addr, addr_str, sizeof(addr_str)); syslog(LOG_INFO, "SSDP Announce %d bytes to %s ST: %.*s",n, addr_str, l, buf); if(n < 0) { - /* XXX handle EINTR, EAGAIN, EWOULDBLOCK */ syslog(LOG_ERR, "sendto(udp): %m"); } } @@ -488,7 +490,7 @@ SendSSDPNotify(int s, const struct sockaddr * dest, syslog(LOG_WARNING, "SendSSDPNotify(): truncated output"); l = sizeof(bufr) - 1; } - n = sendto(s, bufr, l, 0, dest, + n = sendto_or_schedule(s, bufr, l, 0, dest, #ifdef ENABLE_IPV6 ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in) #else @@ -497,7 +499,6 @@ SendSSDPNotify(int s, const struct sockaddr * dest, ); if(n < 0) { - /* XXX handle EINTR, EAGAIN, EWOULDBLOCK */ syslog(LOG_ERR, "sendto(udp_notify=%d, %s): %m", s, host ? host : "NULL"); } @@ -636,6 +637,16 @@ ProcessSSDPData(int s, const char *bufr, int n, #endif int mx_value = -1; #endif + unsigned int delay = 0; + /* UPnP Device Architecture v1.1. 1.3.3 Search response : + * Devices responding to a multicast M-SEARCH SHOULD wait a random period + * of time between 0 seconds and the number of seconds specified in the + * MX field value of the search request before responding, in order to + * avoid flooding the requesting control point with search responses + * from multiple devices. If the search request results in the need for + * a multiple part response from the device, those multiple part + * responses SHOULD be spread at random intervals through the time period + * from 0 to the number of seconds specified in the MX header field. */ /* get the string representation of the sender address */ sockaddr_to_string(sender, sender_str, sizeof(sender_str)); @@ -771,7 +782,8 @@ ProcessSSDPData(int s, const char *bufr, int n, SendSSDPResponse(s, sender, st, st_len, "", announced_host, port, - known_service_types[i].uuid); + known_service_types[i].uuid, + delay); break; } } @@ -790,15 +802,16 @@ ProcessSSDPData(int s, const char *bufr, int n, SendSSDPResponse(s, sender, known_service_types[i].s, l, ver_str, announced_host, port, - known_service_types[i].uuid); + known_service_types[i].uuid, + delay); } /* also answer for uuid */ SendSSDPResponse(s, sender, uuidvalue_igd, strlen(uuidvalue_igd), "", - announced_host, port, uuidvalue_igd); + announced_host, port, uuidvalue_igd, delay); SendSSDPResponse(s, sender, uuidvalue_wan, strlen(uuidvalue_wan), "", - announced_host, port, uuidvalue_wan); + announced_host, port, uuidvalue_wan, delay); SendSSDPResponse(s, sender, uuidvalue_wcd, strlen(uuidvalue_wcd), "", - announced_host, port, uuidvalue_wcd); + announced_host, port, uuidvalue_wcd, delay); } /* responds to request by UUID value */ l = (int)strlen(uuidvalue_igd); @@ -808,19 +821,22 @@ ProcessSSDPData(int s, const char *bufr, int n, { syslog(LOG_INFO, "ssdp:uuid (IGD) found"); SendSSDPResponse(s, sender, st, st_len, "", - announced_host, port, uuidvalue_igd); + announced_host, port, uuidvalue_igd, + delay); } else if(0 == memcmp(st, uuidvalue_wan, l)) { syslog(LOG_INFO, "ssdp:uuid (WAN) found"); SendSSDPResponse(s, sender, st, st_len, "", - announced_host, port, uuidvalue_wan); + announced_host, port, uuidvalue_wan, + delay); } else if(0 == memcmp(st, uuidvalue_wcd, l)) { syslog(LOG_INFO, "ssdp:uuid (WCD) found"); SendSSDPResponse(s, sender, st, st_len, "", - announced_host, port, uuidvalue_wcd); + announced_host, port, uuidvalue_wcd, + delay); } } } @@ -870,7 +886,7 @@ SendSSDPbyebye(int s, const struct sockaddr * dest, syslog(LOG_WARNING, "SendSSDPbyebye(): truncated output"); l = sizeof(bufr) - 1; } - n = sendto(s, bufr, l, 0, dest, + n = sendto_or_schedule(s, bufr, l, 0, dest, #ifdef ENABLE_IPV6 ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in) #else diff --git a/miniupnpd/natpmp.c b/miniupnpd/natpmp.c index 8a127a0..860c41b 100644 --- a/miniupnpd/natpmp.c +++ b/miniupnpd/natpmp.c @@ -1,6 +1,6 @@ /* $Id: natpmp.c,v 1.36 2014/02/01 17:17:35 nanard Exp $ */ /* MiniUPnP project - * (c) 2007-2013 Thomas Bernard + * (c) 2007-2014 Thomas Bernard * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -23,6 +23,7 @@ #include "upnpredirect.h" #include "commonrdr.h" #include "upnputils.h" +#include "asyncsendto.h" #ifdef ENABLE_NATPMP @@ -324,7 +325,7 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, default: resp[3] = 5; /* Unsupported OPCODE */ } - n = sendto(s, resp, resplen, 0, + n = sendto_or_schedule(s, resp, resplen, 0, (struct sockaddr *)senderaddr, sizeof(*senderaddr)); if(n<0) { syslog(LOG_ERR, "sendto(natpmp): %m"); @@ -378,7 +379,7 @@ void SendNATPMPPublicAddressChangeNotification(int * sockets, int n_sockets) #endif /* Port to use in 2006 version of the NAT-PMP specification */ sockname.sin_port = htons(NATPMP_PORT); - n = sendto(sockets[j], notif, 12, 0, + n = sendto_or_schedule(sockets[j], notif, 12, 0, (struct sockaddr *)&sockname, sizeof(struct sockaddr_in)); if(n < 0) { @@ -388,7 +389,7 @@ void SendNATPMPPublicAddressChangeNotification(int * sockets, int n_sockets) } /* Port to use in 2008 version of the NAT-PMP specification */ sockname.sin_port = htons(NATPMP_NOTIF_PORT); - n = sendto(sockets[j], notif, 12, 0, + n = sendto_or_schedule(sockets[j], notif, 12, 0, (struct sockaddr *)&sockname, sizeof(struct sockaddr_in)); if(n < 0) { diff --git a/miniupnpd/pcpserver.c b/miniupnpd/pcpserver.c index 7354fb3..61a6208 100644 --- a/miniupnpd/pcpserver.c +++ b/miniupnpd/pcpserver.c @@ -58,6 +58,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "upnpredirect.h" #include "commonrdr.h" #include "getifaddr.h" +#include "asyncsendto.h" #include "pcp_msg_struct.h" #ifdef PCP_PEER @@ -1325,7 +1326,7 @@ int ProcessIncomingPCPPacket(int s, unsigned char *buff, int len, len = PCP_MIN_LEN; else len = (len + 3) & ~3; /* round up resp. length to multiple of 4 */ - len = sendto(s, buff, len, 0, + len = sendto_or_schedule(s, buff, len, 0, (struct sockaddr *)senderaddr, sizeof(struct sockaddr_in)); if( len < 0 ) { syslog(LOG_ERR, "sendto(pcpserver): %m"); From 02165b70dc64b2acbae7b85283c296fdfc5d0865 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 25 Feb 2014 11:16:34 +0100 Subject: [PATCH 035/127] minissdp.c: wait for a delay before answering M-SEARCH --- miniupnpd/genconfig.sh | 12 +++++++++-- miniupnpd/minissdp.c | 46 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/miniupnpd/genconfig.sh b/miniupnpd/genconfig.sh index 2bf59db..fdb81c5 100755 --- a/miniupnpd/genconfig.sh +++ b/miniupnpd/genconfig.sh @@ -2,7 +2,7 @@ # $Id: genconfig.sh,v 1.65 2013/12/13 14:07:08 nanard Exp $ # miniupnp daemon # http://miniupnp.free.fr or http://miniupnp.tuxfamily.org/ -# (c) 2006-2013 Thomas Bernard +# (c) 2006-2014 Thomas Bernard # This software is subject to the conditions detailed in the # LICENCE file provided within the distribution @@ -83,7 +83,7 @@ ${RM} ${CONFIGFILE} echo "/* MiniUPnP Project" >> ${CONFIGFILE} echo " * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/" >> ${CONFIGFILE} -echo " * (c) 2006-2013 Thomas Bernard" >> ${CONFIGFILE} +echo " * (c) 2006-2014 Thomas Bernard" >> ${CONFIGFILE} echo " * generated by $0 on `date`" >> ${CONFIGFILE} echo " * using command line options $* */" >> ${CONFIGFILE} echo "#ifndef $CONFIGMACRO" >> ${CONFIGFILE} @@ -465,6 +465,14 @@ else fi echo "" >> ${CONFIGFILE} +echo "/* Wait a little before answering M-SEARCH request */" >> ${CONFIGFILE} +if [ -n "$STRICT" ] ; then + echo "#define DELAY_MSEARCH_RESPONSE" >> ${CONFIGFILE} +else + echo "/*#define DELAY_MSEARCH_RESPONSE*/" >> ${CONFIGFILE} +fi +echo "" >> ${CONFIGFILE} + echo "/* disable reading and parsing of config file (miniupnpd.conf) */" >> ${CONFIGFILE} echo "/*#define DISABLE_CONFIG_FILE*/" >> ${CONFIGFILE} echo "" >> ${CONFIGFILE} diff --git a/miniupnpd/minissdp.c b/miniupnpd/minissdp.c index c6b70f2..dc050e0 100644 --- a/miniupnpd/minissdp.c +++ b/miniupnpd/minissdp.c @@ -635,6 +635,8 @@ ProcessSSDPData(int s, const char *bufr, int n, #ifdef ENABLE_IPV6 char announced_host_buf[64]; #endif +#endif +#if defined(UPNP_STRICT) || defined(DELAY_MSEARCH_RESPONSE) int mx_value = -1; #endif unsigned int delay = 0; @@ -689,7 +691,7 @@ ProcessSSDPData(int s, const char *bufr, int n, /*while(bufr[i+j]!='\r') j++;*/ /*syslog(LOG_INFO, "%.*s", j, bufr+i);*/ } -#ifdef UPNP_STRICT +#if defined(UPNP_STRICT) || defined(DELAY_MSEARCH_RESPONSE) else if((i < n - 3) && (strncasecmp(bufr+i, "mx:", 3) == 0)) { const char * mx; @@ -707,16 +709,32 @@ ProcessSSDPData(int s, const char *bufr, int n, #endif } #ifdef UPNP_STRICT + /* For multicast M-SEARCH requests, if the search request does + * not contain an MX header field, the device MUST silently + * discard and ignore the search request. */ if(mx_value < 0) { syslog(LOG_INFO, "ignoring SSDP packet missing MX: header"); return; + } else if(mx_value > 5) { + /* If the MX header field specifies a field value greater + * than 5, the device SHOULD assume that it contained the + * value 5 or less. */ + mx_value = 5; + } +#elif defined(DELAY_MSEARCH_RESPONSE) + if(mx_value < 0) { + mx_value = 1; + } else if(mx_value > 5) { + /* If the MX header field specifies a field value greater + * than 5, the device SHOULD assume that it contained the + * value 5 or less. */ + mx_value = 5; } #endif /*syslog(LOG_INFO, "SSDP M-SEARCH packet received from %s", sender_str );*/ if(st && (st_len > 0)) { - /* TODO : doesnt answer at once but wait for a random time */ syslog(LOG_INFO, "SSDP M-SEARCH from %s ST: %.*s", sender_str, st_len, st); /* find in which sub network the client is */ @@ -779,6 +797,12 @@ ProcessSSDPData(int s, const char *bufr, int n, ) { syslog(LOG_INFO, "Single search found"); +#ifdef DELAY_MSEARCH_RESPONSE + delay = random() / (1 + RAND_MAX / (1000 * mx_value)); +#ifdef DEBUG + syslog(LOG_DEBUG, "mx=%dsec delay=%ums", mx_value, delay); +#endif +#endif SendSSDPResponse(s, sender, st, st_len, "", announced_host, port, @@ -791,9 +815,15 @@ ProcessSSDPData(int s, const char *bufr, int n, /* strlen("ssdp:all") == 8 */ if(st_len==8 && (0 == memcmp(st, "ssdp:all", 8))) { +#ifdef DELAY_MSEARCH_RESPONSE + unsigned int delay_increment = (mx_value * 1000) / 15; +#endif syslog(LOG_INFO, "ssdp:all found"); for(i=0; known_service_types[i].s; i++) { +#ifdef DELAY_MSEARCH_RESPONSE + delay += delay_increment; +#endif if(i==0) ver_str[0] = '\0'; else @@ -806,10 +836,19 @@ ProcessSSDPData(int s, const char *bufr, int n, delay); } /* also answer for uuid */ +#ifdef DELAY_MSEARCH_RESPONSE + delay += delay_increment; +#endif SendSSDPResponse(s, sender, uuidvalue_igd, strlen(uuidvalue_igd), "", announced_host, port, uuidvalue_igd, delay); +#ifdef DELAY_MSEARCH_RESPONSE + delay += delay_increment; +#endif SendSSDPResponse(s, sender, uuidvalue_wan, strlen(uuidvalue_wan), "", announced_host, port, uuidvalue_wan, delay); +#ifdef DELAY_MSEARCH_RESPONSE + delay += delay_increment; +#endif SendSSDPResponse(s, sender, uuidvalue_wcd, strlen(uuidvalue_wcd), "", announced_host, port, uuidvalue_wcd, delay); } @@ -817,6 +856,9 @@ ProcessSSDPData(int s, const char *bufr, int n, l = (int)strlen(uuidvalue_igd); if(l==st_len) { +#ifdef DELAY_MSEARCH_RESPONSE + delay = random() / (1 + RAND_MAX / (1000 * mx_value)); +#endif if(0 == memcmp(st, uuidvalue_igd, l)) { syslog(LOG_INFO, "ssdp:uuid (IGD) found"); From a06c695fe3dd822d3e1af17326b6c15d6af9c6aa Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 25 Feb 2014 11:36:58 +0100 Subject: [PATCH 036/127] miniupnpd/asyncsendto: finalize_sendto() --- miniupnpd/asyncsendto.c | 22 ++++++++++++++++++++++ miniupnpd/asyncsendto.h | 3 +++ miniupnpd/miniupnpd.c | 24 ++++++++++++++++-------- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/miniupnpd/asyncsendto.c b/miniupnpd/asyncsendto.c index faae87e..5cd2a3d 100644 --- a/miniupnpd/asyncsendto.c +++ b/miniupnpd/asyncsendto.c @@ -195,3 +195,25 @@ int try_sendto(fd_set * writefds) return 0; } +/* empty the list */ +void finalize_sendto(void) +{ + ssize_t n; + struct scheduled_send * elt; + struct scheduled_send * next; + /* TODO : improve with a select() and a short timeout */ + for(elt = send_list.lh_first; elt != NULL; elt = next) { + next = elt->entries.le_next; + syslog(LOG_DEBUG, "finalize_sendto(): %d bytes on socket %d", + (int)elt->len, elt->sockfd); + n = sendto(elt->sockfd, elt->buf, elt->len, elt->flags, + elt->dest_addr, elt->addrlen); + if(n < 0) { + syslog(LOG_WARNING, "sendto(): %m"); + } + /* remove from the list */ + LIST_REMOVE(elt, entries); + free(elt); + } +} + diff --git a/miniupnpd/asyncsendto.h b/miniupnpd/asyncsendto.h index 6afb322..60c04de 100644 --- a/miniupnpd/asyncsendto.h +++ b/miniupnpd/asyncsendto.h @@ -32,4 +32,7 @@ int try_sendto(fd_set * writefds); /* set writefds before select() */ int get_sendto_fds(fd_set * writefds, int * max_fd, const struct timeval * now); +/* empty the list */ +void finalize_sendto(void); + #endif diff --git a/miniupnpd/miniupnpd.c b/miniupnpd/miniupnpd.c index 9219e47..10667a7 100644 --- a/miniupnpd/miniupnpd.c +++ b/miniupnpd/miniupnpd.c @@ -2026,6 +2026,21 @@ main(int argc, char * * argv) } /* end of main loop */ shutdown: + /* send good-bye */ + 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"); + } + } + /* try to send pending packets */ + finalize_sendto(); + /* close out open sockets */ while(upnphttphead.lh_first != NULL) { @@ -2065,14 +2080,6 @@ shutdown: 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"); - } #ifndef ENABLE_IPV6 for(i = 0; i < addr_count; i++) #else @@ -2081,6 +2088,7 @@ shutdown: close(snotify[i]); } + /* remove pidfile */ if(pidfilename && (unlink(pidfilename) < 0)) { syslog(LOG_ERR, "Failed to remove pidfile %s: %m", pidfilename); From 9832adc45613d0b079ac8a09e49755ec01991736 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 25 Feb 2014 11:37:36 +0100 Subject: [PATCH 037/127] miniupnpd/minissdp.c: send ssdp:alive packets more than once fixes #35 --- miniupnpd/minissdp.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/miniupnpd/minissdp.c b/miniupnpd/minissdp.c index dc050e0..967c092 100644 --- a/miniupnpd/minissdp.c +++ b/miniupnpd/minissdp.c @@ -506,6 +506,22 @@ SendSSDPNotify(int s, const struct sockaddr * dest, { syslog(LOG_NOTICE, "sendto() sent %d out of %d bytes", n, l); } + /* Due to the unreliable nature of UDP, devices SHOULD send the entire + * set of discovery messages more than once with some delay between + * sets e.g. a few hundred milliseconds. To avoid network congestion + * discovery messages SHOULD NOT be sent more than three times. */ + n = sendto_schedule(s, bufr, l, 0, dest, +#ifdef ENABLE_IPV6 + ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in), +#else + sizeof(struct sockaddr_in), +#endif + 250); + if(n < 0) + { + syslog(LOG_ERR, "sendto(udp_notify=%d, %s): %m", s, + host ? host : "NULL"); + } } static void From ec1686f29f1a8facb00f06f60feb8e7b9a458162 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 25 Feb 2014 11:45:51 +0100 Subject: [PATCH 038/127] miniupnpd/minissdp: Introduce SSDP_RESPOND_SAME_VERSION changes something when compiled as IGDv2. --- miniupnpd/Changelog.txt | 5 ++++- miniupnpd/genconfig.sh | 8 +++++++- miniupnpd/minissdp.c | 27 ++++++++++++++++++++++++++- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/miniupnpd/Changelog.txt b/miniupnpd/Changelog.txt index 2835f5b..36594c2 100644 --- a/miniupnpd/Changelog.txt +++ b/miniupnpd/Changelog.txt @@ -1,4 +1,7 @@ -$Id: Changelog.txt,v 1.351 2014/02/11 09:35:52 nanard Exp $ +$Id: Changelog.txt,v 1.352 2014/02/24 18:41:23 nanard Exp $ + +2014/02/24: + Defaulting to SSDP_RESPOND_SAME_VERSION 2014/02/11: Fix PCP Map renewal diff --git a/miniupnpd/genconfig.sh b/miniupnpd/genconfig.sh index 2bf59db..1a4e785 100755 --- a/miniupnpd/genconfig.sh +++ b/miniupnpd/genconfig.sh @@ -1,5 +1,5 @@ #! /bin/sh -# $Id: genconfig.sh,v 1.65 2013/12/13 14:07:08 nanard Exp $ +# $Id: genconfig.sh,v 1.69 2014/02/24 18:41:25 nanard Exp $ # miniupnp daemon # http://miniupnp.free.fr or http://miniupnp.tuxfamily.org/ # (c) 2006-2013 Thomas Bernard @@ -457,6 +457,12 @@ else fi echo "" >> ${CONFIGFILE} +echo "/* If SSDP_RESPOND_SAME_VERSION is defined, the M-SEARCH response" >> ${CONFIGFILE} +echo " * include the same device version as was contained in the search" >> ${CONFIGFILE} +echo " * request. It conforms to UPnP DA v1.1 */" >> ${CONFIGFILE} +echo "#define SSDP_RESPOND_SAME_VERSION" >> ${CONFIGFILE} +echo "" >> ${CONFIGFILE} + echo "/* Add the optional Date: header in all HTTP responses */" >> ${CONFIGFILE} if [ -n "$STRICT" ] ; then echo "#define ENABLE_HTTP_DATE" >> ${CONFIGFILE} diff --git a/miniupnpd/minissdp.c b/miniupnpd/minissdp.c index fb5a9b8..31110dc 100644 --- a/miniupnpd/minissdp.c +++ b/miniupnpd/minissdp.c @@ -1,4 +1,4 @@ -/* $Id: minissdp.c,v 1.57 2014/02/06 09:52:03 nanard Exp $ */ +/* $Id: minissdp.c,v 1.58 2014/02/24 18:41:24 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2014 Thomas Bernard @@ -767,9 +767,34 @@ ProcessSSDPData(int s, const char *bufr, int n, #endif ) { + /* SSDP_RESPOND_SAME_VERSION : + * response is urn:schemas-upnp-org:service:WANIPConnection:1 when + * M-SEARCH included urn:schemas-upnp-org:service:WANIPConnection:1 + * else the implemented versions is included in the response + * + * From UPnP Device Architecture v1.1 : + * 1.3.2 [...] Updated versions of device and service types + * are REQUIRED to be fully backward compatible with + * previous versions. Devices MUST respond to M-SEARCH + * requests for any supported version. For example, if a + * device implements “urn:schemas-upnporg:service:xyz:2”, + * it MUST respond to search requests for both that type + * and “urn:schemas-upnp-org:service:xyz:1”. The response + * MUST specify the same version as was contained in the + * search request. [...] */ +#ifndef SSDP_RESPOND_SAME_VERSION + if(i==0) + ver_str[0] = '\0'; + else + snprintf(ver_str, sizeof(ver_str), "%d", known_service_types[i].version); +#endif syslog(LOG_INFO, "Single search found"); SendSSDPResponse(s, sender, +#ifdef SSDP_RESPOND_SAME_VERSION st, st_len, "", +#else + known_service_types[i].s, l, ver_str, +#endif announced_host, port, known_service_types[i].uuid); break; From c492b6f56f846b511276a80d62f08c8192fdf56e Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Wed, 26 Feb 2014 02:02:34 +0100 Subject: [PATCH 039/127] minissdp.c: try again write after EINTR in SubmitServicesToMiniSSDPD() --- miniupnpd/minissdp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/miniupnpd/minissdp.c b/miniupnpd/minissdp.c index dcee00c..9f5fc72 100644 --- a/miniupnpd/minissdp.c +++ b/miniupnpd/minissdp.c @@ -1126,6 +1126,8 @@ SubmitServicesToMiniSSDPD(const char * host, unsigned short port) { while(n > 0) { l = write(s, p, n); if (l < 0) { + if(errno == EINTR) + continue; syslog(LOG_ERR, "write(): %m"); close(s); return -1; From 1efb4cc03c167abc40a3a1bd77e06561ab61f555 Mon Sep 17 00:00:00 2001 From: hashiz Date: Fri, 28 Feb 2014 11:28:07 +0900 Subject: [PATCH 040/127] * fix incorrect filter port in pf redirect. --- miniupnpd/pf/obsdrdr.c | 10 +++++----- miniupnpd/upnpredirect.c | 16 +++++++++++++++- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/miniupnpd/pf/obsdrdr.c b/miniupnpd/pf/obsdrdr.c index 04c2ddb..663cea3 100644 --- a/miniupnpd/pf/obsdrdr.c +++ b/miniupnpd/pf/obsdrdr.c @@ -374,7 +374,7 @@ add_filter_rule2(const char * ifname, #endif pcr.rule.dst.port_op = PF_OP_EQ; - pcr.rule.dst.port[0] = htons(eport); + pcr.rule.dst.port[0] = htons(iport); pcr.rule.direction = PF_IN; pcr.rule.action = PF_PASS; pcr.rule.af = AF_INET; @@ -408,7 +408,7 @@ add_filter_rule2(const char * ifname, pcr.rule.src.addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE); } #ifndef PF_NEWSTYLE - pcr.rule.rpool.proxy_port[0] = eport; + pcr.rule.rpool.proxy_port[0] = iport; a = calloc(1, sizeof(struct pf_pooladdr)); inet_pton(AF_INET, iaddr, &a->addr.v.a.addr.v4.s_addr); a->addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE); @@ -636,10 +636,10 @@ error: } int -delete_filter_rule(const char * ifname, unsigned short eport, int proto) +delete_filter_rule(const char * ifname, unsigned short iport, int proto) { #ifndef PF_ENABLE_FILTER_RULES - UNUSED(ifname); UNUSED(eport); UNUSED(proto); + UNUSED(ifname); UNUSED(iport); UNUSED(proto); return 0; #else int i, n; @@ -665,7 +665,7 @@ delete_filter_rule(const char * ifname, unsigned short eport, int proto) syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m"); goto error; } - if( (eport == ntohs(pr.rule.dst.port[0])) + if( (iport == ntohs(pr.rule.dst.port[0])) && (pr.rule.proto == proto) ) { pr.action = PF_CHANGE_GET_TICKET; diff --git a/miniupnpd/upnpredirect.c b/miniupnpd/upnpredirect.c index 7b398ec..1e03b93 100644 --- a/miniupnpd/upnpredirect.c +++ b/miniupnpd/upnpredirect.c @@ -420,8 +420,22 @@ _upnp_delete_redir(unsigned short eport, int proto) #if defined(__linux__) r = delete_redirect_and_filter_rules(eport, proto); #else + char iaddr[INET6_ADDRSTRLEN]; + unsigned short iport; + char desc[64]; + char rhost[64]; + unsigned int timestamp; + u_int64_t packets; + u_int64_t bytes; + int r2 = get_redirect_rule(ext_if_name, eport, proto, + &iaddr, sizeof(iaddr), &iport, + &desc, sizeof(desc), + &rhost, sizeof(rhost), + ×tamp, + &packets, &bytes); r = delete_redirect_rule(ext_if_name, eport, proto); - delete_filter_rule(ext_if_name, eport, proto); + if (r2==0) + delete_filter_rule(ext_if_name, iport, proto); #endif #ifdef ENABLE_LEASEFILE lease_file_remove( eport, proto); From c6a8879c8717aec43774913cc355054f383b4c97 Mon Sep 17 00:00:00 2001 From: Daniel Becker Date: Fri, 28 Feb 2014 00:00:26 -0800 Subject: [PATCH 041/127] miniupnpd/natpmp.c: avoid hang when all external ports in use The NAT-PMP code attempts to find a different eport if the requested one is already in use. If all eports are in use, that would previously cause the code to iterate through the range of eports forever. To avoid this case, we keep track of the first eport we attempted to use and abort the loop once we've cycled through all possible values exactly once (which takes us back to the initial eport). --- miniupnpd/natpmp.c | 94 +++++++++++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 42 deletions(-) diff --git a/miniupnpd/natpmp.c b/miniupnpd/natpmp.c index 860c41b..6764732 100644 --- a/miniupnpd/natpmp.c +++ b/miniupnpd/natpmp.c @@ -205,6 +205,7 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, int proto; char iaddr_old[16]; unsigned short iport_old; + unsigned short eport_first; unsigned int timestamp; iport = ntohs(*((uint16_t *)(req+4))); @@ -266,56 +267,65 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, } else if(iport==0 || !check_upnp_rule_against_permissions(upnppermlist, num_upnpperm, eport, senderaddr->sin_addr, iport)) { resp[3] = 2; /* Not Authorized/Refused */ - } else do { - r = get_redirect_rule(ext_if_name, eport, proto, - iaddr_old, sizeof(iaddr_old), - &iport_old, 0, 0, 0, 0, - ×tamp, 0, 0); - if(r==0) { - if(strcmp(senderaddrstr, iaddr_old)==0 - && iport==iport_old) { - /* redirection allready existing */ - syslog(LOG_INFO, "port %hu %s already redirected to %s:%hu, replacing", - eport, (proto==IPPROTO_TCP)?"tcp":"udp", iaddr_old, iport_old); - /* remove and then add again */ - if(_upnp_delete_redir(eport, proto) < 0) { - syslog(LOG_ERR, "failed to remove port mapping"); - break; + } else { + eport_first = eport; + do { + r = get_redirect_rule(ext_if_name, eport, proto, + iaddr_old, sizeof(iaddr_old), + &iport_old, 0, 0, 0, 0, + ×tamp, 0, 0); + if(r==0) { + if(strcmp(senderaddrstr, iaddr_old)==0 + && iport==iport_old) { + /* redirection allready existing */ + syslog(LOG_INFO, "port %hu %s already redirected to %s:%hu, replacing", + eport, (proto==IPPROTO_TCP)?"tcp":"udp", iaddr_old, iport_old); + /* remove and then add again */ + if(_upnp_delete_redir(eport, proto) < 0) { + syslog(LOG_ERR, "failed to remove port mapping"); + break; + } + } else { + eport++; + if(eport == eport_first) { /* no external port available */ + syslog(LOG_ERR, "Failed to find available eport for NAT-PMP %hu %s->%s:%hu", + eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport); + resp[3] = 3; /* Failure */ + break; + } + continue; } - } else { - eport++; - continue; } - } - { /* do the redirection */ - char desc[64]; + { /* do the redirection */ + char desc[64]; #if 0 - timestamp = (unsigned)(time(NULL) - startup_time) - + lifetime; - snprintf(desc, sizeof(desc), "NAT-PMP %u", timestamp); + timestamp = (unsigned)(time(NULL) - startup_time) + + lifetime; + snprintf(desc, sizeof(desc), "NAT-PMP %u", timestamp); #else - timestamp = time(NULL) + lifetime; - snprintf(desc, sizeof(desc), "NAT-PMP %hu %s", - eport, (proto==IPPROTO_TCP)?"tcp":"udp"); + timestamp = time(NULL) + lifetime; + snprintf(desc, sizeof(desc), "NAT-PMP %hu %s", + eport, (proto==IPPROTO_TCP)?"tcp":"udp"); #endif - /* TODO : check return code */ - if(upnp_redirect_internal(NULL, eport, senderaddrstr, - iport, proto, desc, - timestamp) < 0) { - syslog(LOG_ERR, "Failed to add NAT-PMP %hu %s->%s:%hu '%s'", - eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport, desc); - resp[3] = 3; /* Failure */ + /* TODO : check return code */ + if(upnp_redirect_internal(NULL, eport, senderaddrstr, + iport, proto, desc, + timestamp) < 0) { + syslog(LOG_ERR, "Failed to add NAT-PMP %hu %s->%s:%hu '%s'", + eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport, desc); + resp[3] = 3; /* Failure */ #if 0 - } else if( !nextnatpmptoclean_eport - || timestamp < nextnatpmptoclean_timestamp) { - nextnatpmptoclean_timestamp = timestamp; - nextnatpmptoclean_eport = eport; - nextnatpmptoclean_proto = proto; + } else if( !nextnatpmptoclean_eport + || timestamp < nextnatpmptoclean_timestamp) { + nextnatpmptoclean_timestamp = timestamp; + nextnatpmptoclean_eport = eport; + nextnatpmptoclean_proto = proto; #endif + } + break; } - break; - } - } while(r==0); + } while(r==0); + } *((uint16_t *)(resp+8)) = htons(iport); /* private port */ *((uint16_t *)(resp+10)) = htons(eport); /* public port */ *((uint32_t *)(resp+12)) = htonl(lifetime); /* Port Mapping lifetime */ From 6dff4263bd9f1ca023da29fd4d3320c55b30fc70 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 28 Feb 2014 13:16:06 +0100 Subject: [PATCH 042/127] miniupnpd/Changelog.txt catch up... --- miniupnpd/Changelog.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/miniupnpd/Changelog.txt b/miniupnpd/Changelog.txt index 36594c2..7aeb0a9 100644 --- a/miniupnpd/Changelog.txt +++ b/miniupnpd/Changelog.txt @@ -1,4 +1,8 @@ -$Id: Changelog.txt,v 1.352 2014/02/24 18:41:23 nanard Exp $ +$Id: Changelog.txt,v 1.354 2014/02/28 12:14:29 nanard Exp $ + +2014/02/25: + add implementation of scheduled sendto (asyncsendto) in order + to retry failed sendto() calls or schedule sending of packets 2014/02/24: Defaulting to SSDP_RESPOND_SAME_VERSION From 8fc7f0b5e13aa71e5a213dc0785b9a975e5859aa Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 28 Feb 2014 13:16:22 +0100 Subject: [PATCH 043/127] miniupnpd: log message when shutting down --- miniupnpd/Changelog.txt | 3 +++ miniupnpd/miniupnpd.c | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/miniupnpd/Changelog.txt b/miniupnpd/Changelog.txt index 7aeb0a9..e47f2fb 100644 --- a/miniupnpd/Changelog.txt +++ b/miniupnpd/Changelog.txt @@ -1,5 +1,8 @@ $Id: Changelog.txt,v 1.354 2014/02/28 12:14:29 nanard Exp $ +2014/02/28: + log message when shutting down + 2014/02/25: add implementation of scheduled sendto (asyncsendto) in order to retry failed sendto() calls or schedule sending of packets diff --git a/miniupnpd/miniupnpd.c b/miniupnpd/miniupnpd.c index 10667a7..b215b6c 100644 --- a/miniupnpd/miniupnpd.c +++ b/miniupnpd/miniupnpd.c @@ -1,4 +1,4 @@ -/* $Id: miniupnpd.c,v 1.183 2014/02/06 09:52:01 nanard Exp $ */ +/* $Id: miniupnpd.c,v 1.185 2014/02/28 12:14:26 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2014 Thomas Bernard @@ -2026,6 +2026,7 @@ main(int argc, char * * argv) } /* end of main loop */ shutdown: + syslog(LOG_NOTICE, "shutting down MiniUPnPd"); /* send good-bye */ if (GETFLAG(ENABLEUPNPMASK)) { From 3c90f6a30d83e1803f34497136003bc3c0b3787e Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 28 Feb 2014 13:34:46 +0100 Subject: [PATCH 044/127] miniupnpd/natpmp.c: avoid hang when all external ports in use reorganize a bit --- miniupnpd/Changelog.txt | 3 +++ miniupnpd/natpmp.c | 55 ++++++++++++++++++++--------------------- 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/miniupnpd/Changelog.txt b/miniupnpd/Changelog.txt index 36594c2..c6b04ea 100644 --- a/miniupnpd/Changelog.txt +++ b/miniupnpd/Changelog.txt @@ -1,5 +1,8 @@ $Id: Changelog.txt,v 1.352 2014/02/24 18:41:23 nanard Exp $ +2014/02/28: + natpmp : avoid hang when all external ports in use + 2014/02/24: Defaulting to SSDP_RESPOND_SAME_VERSION diff --git a/miniupnpd/natpmp.c b/miniupnpd/natpmp.c index 6764732..c3d26ce 100644 --- a/miniupnpd/natpmp.c +++ b/miniupnpd/natpmp.c @@ -205,7 +205,6 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, int proto; char iaddr_old[16]; unsigned short iport_old; - unsigned short eport_first; unsigned int timestamp; iport = ntohs(*((uint16_t *)(req+4))); @@ -268,12 +267,14 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, || !check_upnp_rule_against_permissions(upnppermlist, num_upnpperm, eport, senderaddr->sin_addr, iport)) { resp[3] = 2; /* Not Authorized/Refused */ } else { + unsigned short eport_first; + char desc[64]; eport_first = eport; do { r = get_redirect_rule(ext_if_name, eport, proto, - iaddr_old, sizeof(iaddr_old), - &iport_old, 0, 0, 0, 0, - ×tamp, 0, 0); + iaddr_old, sizeof(iaddr_old), + &iport_old, 0, 0, 0, 0, + ×tamp, 0, 0); if(r==0) { if(strcmp(senderaddrstr, iaddr_old)==0 && iport==iport_old) { @@ -288,42 +289,40 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, } else { eport++; if(eport == eport_first) { /* no external port available */ - syslog(LOG_ERR, "Failed to find available eport for NAT-PMP %hu %s->%s:%hu", - eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport); + syslog(LOG_ERR, "Failed to find available eport for NAT-PMP %hu %s->%s:%hu", + eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport); resp[3] = 3; /* Failure */ break; } continue; } } - { /* do the redirection */ - char desc[64]; + /* do the redirection */ #if 0 - timestamp = (unsigned)(time(NULL) - startup_time) - + lifetime; - snprintf(desc, sizeof(desc), "NAT-PMP %u", timestamp); + timestamp = (unsigned)(time(NULL) - startup_time) + + lifetime; + snprintf(desc, sizeof(desc), "NAT-PMP %u", timestamp); #else - timestamp = time(NULL) + lifetime; - snprintf(desc, sizeof(desc), "NAT-PMP %hu %s", - eport, (proto==IPPROTO_TCP)?"tcp":"udp"); + timestamp = time(NULL) + lifetime; + snprintf(desc, sizeof(desc), "NAT-PMP %hu %s", + eport, (proto==IPPROTO_TCP)?"tcp":"udp"); #endif - /* TODO : check return code */ - if(upnp_redirect_internal(NULL, eport, senderaddrstr, - iport, proto, desc, - timestamp) < 0) { - syslog(LOG_ERR, "Failed to add NAT-PMP %hu %s->%s:%hu '%s'", - eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport, desc); - resp[3] = 3; /* Failure */ + /* TODO : check return code */ + if(upnp_redirect_internal(NULL, eport, senderaddrstr, + iport, proto, desc, + timestamp) < 0) { + syslog(LOG_ERR, "Failed to add NAT-PMP %hu %s->%s:%hu '%s'", + eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport, desc); + resp[3] = 3; /* Failure */ #if 0 - } else if( !nextnatpmptoclean_eport - || timestamp < nextnatpmptoclean_timestamp) { - nextnatpmptoclean_timestamp = timestamp; - nextnatpmptoclean_eport = eport; - nextnatpmptoclean_proto = proto; + } else if( !nextnatpmptoclean_eport + || timestamp < nextnatpmptoclean_timestamp) { + nextnatpmptoclean_timestamp = timestamp; + nextnatpmptoclean_eport = eport; + nextnatpmptoclean_proto = proto; #endif - } - break; } + break; } while(r==0); } *((uint16_t *)(resp+8)) = htons(iport); /* private port */ From dbdad6a79b1cb3105fd3dc3f3735e39e3fee9f49 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 28 Feb 2014 16:39:59 +0100 Subject: [PATCH 045/127] miniupnpd: improve finalize_sendto() --- miniupnpd/asyncsendto.c | 78 ++++++++++++++++++++++++++++++++++------- 1 file changed, 66 insertions(+), 12 deletions(-) diff --git a/miniupnpd/asyncsendto.c b/miniupnpd/asyncsendto.c index 5cd2a3d..8c83e25 100644 --- a/miniupnpd/asyncsendto.c +++ b/miniupnpd/asyncsendto.c @@ -195,25 +195,79 @@ int try_sendto(fd_set * writefds) return 0; } +/* maximum execution time for finalize_sendto() in milliseconds */ +#define FINALIZE_SENDTO_DELAY (500) + /* empty the list */ void finalize_sendto(void) { ssize_t n; struct scheduled_send * elt; struct scheduled_send * next; - /* TODO : improve with a select() and a short timeout */ - for(elt = send_list.lh_first; elt != NULL; elt = next) { - next = elt->entries.le_next; - syslog(LOG_DEBUG, "finalize_sendto(): %d bytes on socket %d", - (int)elt->len, elt->sockfd); - n = sendto(elt->sockfd, elt->buf, elt->len, elt->flags, - elt->dest_addr, elt->addrlen); - if(n < 0) { - syslog(LOG_WARNING, "sendto(): %m"); + fd_set writefds; + struct timeval deadline; + struct timeval now; + struct timeval timeout; + int max_fd; + + if(gettimeofday(&deadline, NULL) < 0) { + syslog(LOG_ERR, "gettimeofday: %m"); + return; + } + deadline.tv_usec += FINALIZE_SENDTO_DELAY*1000; + if(deadline.tv_usec > 1000000) { + deadline.tv_sec++; + deadline.tv_usec -= 1000000; + } + while(send_list.lh_first) { + FD_ZERO(&writefds); + max_fd = -1; + for(elt = send_list.lh_first; elt != NULL; elt = next) { + next = elt->entries.le_next; + syslog(LOG_DEBUG, "finalize_sendto(): %d bytes on socket %d", + (int)elt->len, elt->sockfd); + n = sendto(elt->sockfd, elt->buf, elt->len, elt->flags, + elt->dest_addr, elt->addrlen); + if(n < 0) { + if(errno==EAGAIN || errno==EWOULDBLOCK) { + FD_SET(elt->sockfd, &writefds); + if(elt->sockfd > max_fd) + max_fd = elt->sockfd; + continue; + } + syslog(LOG_WARNING, "finalize_sendto(): socket=%d sendto: %m", elt->sockfd); + } + /* remove from the list */ + LIST_REMOVE(elt, entries); + free(elt); + } + /* check deadline */ + if(gettimeofday(&now, NULL) < 0) { + syslog(LOG_ERR, "gettimeofday: %m"); + return; + } + if(now.tv_sec > deadline.tv_sec || + (now.tv_sec == deadline.tv_sec && now.tv_usec > deadline.tv_usec)) { + /* deadline ! */ + while((elt = send_list.lh_first) != NULL) { + LIST_REMOVE(elt, entries); + free(elt); + } + return; + } + /* compute timeout value */ + timeout.tv_sec = deadline.tv_sec - now.tv_sec; + timeout.tv_usec = deadline.tv_usec - now.tv_usec; + if(timeout.tv_usec < 0) { + timeout.tv_sec--; + timeout.tv_usec += 1000000; + } + if(max_fd >= 0) { + if(select(max_fd + 1, NULL, &writefds, NULL, &timeout) < 0) { + syslog(LOG_ERR, "select: %m"); + return; + } } - /* remove from the list */ - LIST_REMOVE(elt, entries); - free(elt); } } From 802ad22f4d45512c1db6d024d674ed5aa1bad75c Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 28 Feb 2014 16:40:20 +0100 Subject: [PATCH 046/127] miniupnpd: minor stuff (remove warning, add debug log) --- miniupnpd/testasyncsendto.c | 4 ++-- miniupnpd/upnpsoap.c | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/miniupnpd/testasyncsendto.c b/miniupnpd/testasyncsendto.c index 7a4eb6e..e413bd7 100644 --- a/miniupnpd/testasyncsendto.c +++ b/miniupnpd/testasyncsendto.c @@ -1,4 +1,4 @@ -/* $Id: $ */ +/* $Id: testasyncsendto.c,v 1.2 2014/02/25 11:00:14 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2014 Thomas Bernard @@ -46,7 +46,7 @@ int test(void) memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; - if(bind(s, &addr, sizeof(addr)) < 0) { + if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { syslog(LOG_ERR, "bind(): %m"); close(s); return 1; diff --git a/miniupnpd/upnpsoap.c b/miniupnpd/upnpsoap.c index a8023c0..fc08ecb 100644 --- a/miniupnpd/upnpsoap.c +++ b/miniupnpd/upnpsoap.c @@ -1,4 +1,4 @@ -/* $Id: upnpsoap.c,v 1.119 2013/08/19 16:16:00 nanard Exp $ */ +/* $Id: upnpsoap.c,v 1.121 2014/02/28 15:01:31 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2013 Thomas Bernard @@ -1910,6 +1910,10 @@ ExecuteSoapAction(struct upnphttp * h, const char * action, int n) len = strlen(soapMethods[i].methodName); if(strncmp(p, soapMethods[i].methodName, len) == 0) { +#ifdef DEBUG + syslog(LOG_DEBUG, "Remote Call of SoapMethod '%s'\n", + soapMethods[i].methodName); +#endif soapMethods[i].methodImpl(h, soapMethods[i].methodName); return; } From 56aca98164690743b475bfe0ff1e3dce3b74ffde Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 28 Feb 2014 20:20:51 +0100 Subject: [PATCH 047/127] miniupnpd/pf: catch up test programs --- miniupnpd/pf/testobsdrdr.c | 13 +++++++------ miniupnpd/pf/testpfpinhole.c | 16 +++++++++------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/miniupnpd/pf/testobsdrdr.c b/miniupnpd/pf/testobsdrdr.c index 7d288c6..3ce3c85 100644 --- a/miniupnpd/pf/testobsdrdr.c +++ b/miniupnpd/pf/testobsdrdr.c @@ -1,7 +1,7 @@ -/* $Id: testobsdrdr.c,v 1.24 2012/04/18 19:42:03 nanard Exp $ */ +/* $Id: testobsdrdr.c,v 1.26 2014/02/28 18:03:31 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2012 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -17,6 +17,7 @@ int runtime_flags = 0; const char * tag = 0; const char * anchor_name = "miniupnpd"; +const char * queue = NULL; void list_rules(void); @@ -90,10 +91,10 @@ main(int arc, char * * argv) #endif add_redirect_rule2("ep0", "8.8.8.8", 12123, "192.168.1.125", 1234, IPPROTO_UDP, "test description", 0); -#if 0 - add_redirect_rule2("em0", 12123, "127.1.2.3", 1234, - IPPROTO_TCP, "test description tcp"); -#endif + add_redirect_rule2("em0", NULL, 12123, "127.1.2.3", 1234, + IPPROTO_TCP, "test description tcp", 0); + add_filter_rule2("em0", NULL, "127.1.2.3", 12123, 1234, IPPROTO_TCP, + "test description tcp"); list_rules(); list_eports_tcp(); diff --git a/miniupnpd/pf/testpfpinhole.c b/miniupnpd/pf/testpfpinhole.c index e09199c..ec754e2 100644 --- a/miniupnpd/pf/testpfpinhole.c +++ b/miniupnpd/pf/testpfpinhole.c @@ -1,7 +1,7 @@ -/* $Id: testpfpinhole.c,v 1.10 2012/04/22 23:12:51 nanard Exp $ */ +/* $Id: testpfpinhole.c,v 1.11 2014/02/28 16:49:15 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2012 Thomas Bernard + * (c) 2012-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -21,6 +21,7 @@ const char * tag = NULL; const char * anchor_name = "miniupnpd"; const char * queue = NULL; +#ifdef ENABLE_IPV6 static int print_pinhole(int uid) { int r; @@ -32,11 +33,11 @@ static int print_pinhole(int uid) unsigned int timestamp; u_int64_t packets, bytes; - r = get_pinhole((unsigned short)uid, - rem_host, sizeof(rem_host), &rem_port, - int_client, sizeof(int_client), &int_port, - &proto, ×tamp, - &packets, &bytes); + r = get_pinhole_info((unsigned short)uid, + rem_host, sizeof(rem_host), &rem_port, + int_client, sizeof(int_client), &int_port, + &proto, ×tamp, + &packets, &bytes); if(r < 0) { fprintf(stderr, "get_pinhole(%d) returned %d\n", uid, r); } else { @@ -47,6 +48,7 @@ static int print_pinhole(int uid) } return r; } +#endif int main(int argc, char * *argv) { From bd83aa90c53f9a91cf4dfb5a425b6f16accdd081 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 28 Feb 2014 20:23:51 +0100 Subject: [PATCH 048/127] minissdpd: accept request of type 3 with 0 lenght argument --- minissdpd/minissdpd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/minissdpd/minissdpd.c b/minissdpd/minissdpd.c index e1068ad..2421a42 100644 --- a/minissdpd/minissdpd.c +++ b/minissdpd/minissdpd.c @@ -1,4 +1,4 @@ -/* $Id: minissdpd.c,v 1.36 2014/02/03 15:45:07 nanard Exp $ */ +/* $Id: minissdpd.c,v 1.37 2014/02/28 18:39:11 nanard Exp $ */ /* MiniUPnP project * (c) 2007-2014 Thomas Bernard * website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ @@ -571,7 +571,7 @@ void processRequest(struct reqelem * req) syslog(LOG_WARNING, "bad request (length encoding)"); goto error; } - if(l == 0) { + if(l == 0 && type != 3) { syslog(LOG_WARNING, "bad request (length=0)"); goto error; } From 7f3fbccbebdda4588189eb4a9a0ef17feae6e256 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 28 Feb 2014 20:24:19 +0100 Subject: [PATCH 049/127] testminissdpd: various improvements more tests. --- minissdpd/testminissdpd.c | 67 ++++++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 12 deletions(-) diff --git a/minissdpd/testminissdpd.c b/minissdpd/testminissdpd.c index c06cf50..30ee92d 100644 --- a/minissdpd/testminissdpd.c +++ b/minissdpd/testminissdpd.c @@ -1,12 +1,13 @@ -/* $Id: testminissdpd.c,v 1.7 2012/05/02 10:28:25 nanard Exp $ */ +/* $Id: testminissdpd.c,v 1.8 2014/02/28 18:38:21 nanard Exp $ */ /* Project : miniupnp * website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * Author : Thomas BERNARD - * copyright (c) 2005-2007 Thomas Bernard + * copyright (c) 2005-2014 Thomas Bernard * This software is subjet to the conditions detailed in the * provided LICENCE file. */ #include #include +#include #include #include #include @@ -21,6 +22,8 @@ void printresponse(const unsigned char * resp, int n) int i, l; unsigned int nresp; const unsigned char * p; + if(n == 0) + return; for(i=0; i Date: Fri, 28 Feb 2014 20:26:02 +0100 Subject: [PATCH 050/127] miniupnpd/pcpserver.c: fix defines with OpenBSD, must be included before --- miniupnpd/pcpserver.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/miniupnpd/pcpserver.c b/miniupnpd/pcpserver.c index 61a6208..8a88c6a 100644 --- a/miniupnpd/pcpserver.c +++ b/miniupnpd/pcpserver.c @@ -1,4 +1,4 @@ -/* $Id: pcpserver.c,v 1.9 2014/02/11 09:35:53 nanard Exp $ */ +/* $Id: pcpserver.c,v 1.12 2014/02/28 17:50:22 nanard Exp $ */ /* MiniUPnP project * Website : http://miniupnp.free.fr/ * Author : Peter Tatrai @@ -43,6 +43,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include #include #include From 37208eecae0a9b9c8a4ad3e7a5f748a827651023 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 28 Feb 2014 21:22:52 +0100 Subject: [PATCH 051/127] miniupnpd/pf/obsdrdr.c: improve documentation --- miniupnpd/pf/obsdrdr.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/miniupnpd/pf/obsdrdr.c b/miniupnpd/pf/obsdrdr.c index 663cea3..ac3616d 100644 --- a/miniupnpd/pf/obsdrdr.c +++ b/miniupnpd/pf/obsdrdr.c @@ -1,7 +1,7 @@ -/* $Id: obsdrdr.c,v 1.74 2012/05/01 09:20:43 nanard Exp $ */ +/* $Id: obsdrdr.c,v 1.78 2014/02/28 20:18:41 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2012 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -9,15 +9,19 @@ * pf rules created (with ext_if = xl1) * - OpenBSD up to version 4.6 : * rdr pass on xl1 inet proto udp from any to any port = 54321 \ - * label "test label" -> 192.168.0.141 port 12345 - * or a rdr rule + a pass rule + * keep state label "test label" -> 192.168.0.42 port 12345 + * or a rdr rule + a pass rule : + * rdr quick on xl1 inet proto udp from any to any port = 54321 \ + * keep state label "test label" -> 192.168.0.42 port 12345 + * pass in quick on xl1 inet proto udp from any to any port = 12345 \ + * flags S/SA keep state label "test label" * * - OpenBSD starting from version 4.7 * match in on xl1 inet proto udp from any to any port 54321 \ - * label "test label" rdr-to 192.168.0.141 port 12345 + * label "test label" rdr-to 192.168.0.42 port 12345 * or * pass in quick on xl1 inet proto udp from any to any port 54321 \ - * label "test label" rdr-to 192.168.0.141 port 12345 + * label "test label" rdr-to 192.168.0.42 port 12345 * * * From 9d23b88cefd3736b5a72826c876c3b7e593e550e Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 28 Feb 2014 21:26:52 +0100 Subject: [PATCH 052/127] miniupnpd/pf: replace delete_filter_rule() now use delete_redirect_and_filter_rules() --- miniupnpd/pf/obsdrdr.c | 35 ++++++++++++++++++++++++++++++++--- miniupnpd/pf/obsdrdr.h | 9 +++++---- miniupnpd/upnpredirect.c | 22 +++++----------------- 3 files changed, 42 insertions(+), 24 deletions(-) diff --git a/miniupnpd/pf/obsdrdr.c b/miniupnpd/pf/obsdrdr.c index ac3616d..e4887bf 100644 --- a/miniupnpd/pf/obsdrdr.c +++ b/miniupnpd/pf/obsdrdr.c @@ -579,8 +579,9 @@ error: return -1; } -int -delete_redirect_rule(const char * ifname, unsigned short eport, int proto) +static int +priv_delete_redirect_rule(const char * ifname, unsigned short eport, + int proto, unsigned short * iport) { int i, n; struct pfioc_rule pr; @@ -618,6 +619,12 @@ delete_redirect_rule(const char * ifname, unsigned short eport, int proto) #endif && (pr.rule.proto == proto) ) { + /* retrieve iport in order to remove filter rule */ +#ifndef PF_NEWSTYLE + if(iport) *iport = pr.rule.rpool.proxy_port[0]; +#else + if(iport) *iport = pr.rule.rdr.proxy_port[0]; +#endif pr.action = PF_CHANGE_GET_TICKET; if(ioctl(dev, DIOCCHANGERULE, &pr) < 0) { @@ -640,7 +647,15 @@ error: } int -delete_filter_rule(const char * ifname, unsigned short iport, int proto) +delete_redirect_rule(const char * ifname, unsigned short eport, + int proto) +{ + return priv_delete_redirect_rule(ifname, eport, proto, NULL); +} + +static int +priv_delete_filter_rule(const char * ifname, unsigned short iport, + int proto) { #ifndef PF_ENABLE_FILTER_RULES UNUSED(ifname); UNUSED(iport); UNUSED(proto); @@ -693,6 +708,20 @@ error: #endif } +int +delete_redirect_and_filter_rules(const char * ifname, unsigned short eport, + int proto) +{ + int r; + unsigned short iport; + r = priv_delete_redirect_rule(ifname, eport, proto, &iport); + if(r == 0) + { + priv_delete_filter_rule(ifname, iport, proto); + } + return r; +} + int get_redirect_rule_by_index(int index, char * ifname, unsigned short * eport, diff --git a/miniupnpd/pf/obsdrdr.h b/miniupnpd/pf/obsdrdr.h index 59225fd..7bd7e0c 100644 --- a/miniupnpd/pf/obsdrdr.h +++ b/miniupnpd/pf/obsdrdr.h @@ -1,7 +1,7 @@ -/* $Id: obsdrdr.h,v 1.20 2012/03/05 20:36:20 nanard Exp $ */ +/* $Id: obsdrdr.h,v 1.22 2014/02/28 20:18:41 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -52,10 +52,11 @@ get_redirect_rule_by_index(int index, int delete_redirect_rule(const char * ifname, unsigned short eport, int proto); -/* delete_filter_rule() +/* delete_redirect_and_filter_rules() */ int -delete_filter_rule(const char * ifname, unsigned short eport, int proto); +delete_redirect_and_filter_rules(const char * ifname, unsigned short eport, + int proto); int clear_redirect_rules(void); diff --git a/miniupnpd/upnpredirect.c b/miniupnpd/upnpredirect.c index 1e03b93..0b7e8a3 100644 --- a/miniupnpd/upnpredirect.c +++ b/miniupnpd/upnpredirect.c @@ -1,7 +1,7 @@ -/* $Id: upnpredirect.c,v 1.80 2012/05/01 20:08:22 nanard Exp $ */ +/* $Id: upnpredirect.c,v 1.82 2014/02/28 20:18:35 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2012 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -419,23 +419,11 @@ _upnp_delete_redir(unsigned short eport, int proto) int r; #if defined(__linux__) r = delete_redirect_and_filter_rules(eport, proto); +#elif defined(USE_PF) + r = delete_redirect_and_filter_rules(ext_if_name, eport, proto); #else - char iaddr[INET6_ADDRSTRLEN]; - unsigned short iport; - char desc[64]; - char rhost[64]; - unsigned int timestamp; - u_int64_t packets; - u_int64_t bytes; - int r2 = get_redirect_rule(ext_if_name, eport, proto, - &iaddr, sizeof(iaddr), &iport, - &desc, sizeof(desc), - &rhost, sizeof(rhost), - ×tamp, - &packets, &bytes); r = delete_redirect_rule(ext_if_name, eport, proto); - if (r2==0) - delete_filter_rule(ext_if_name, iport, proto); + delete_filter_rule(ext_if_name, eport, proto); #endif #ifdef ENABLE_LEASEFILE lease_file_remove( eport, proto); From 5512d022acb84cd23d73cd91a7e7d35d02f6b887 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 28 Feb 2014 21:28:12 +0100 Subject: [PATCH 053/127] miniupnpd/pf/obsdrdr.c: add UNUSED() when necessary --- miniupnpd/pf/obsdrdr.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/miniupnpd/pf/obsdrdr.c b/miniupnpd/pf/obsdrdr.c index e4887bf..5c87fec 100644 --- a/miniupnpd/pf/obsdrdr.c +++ b/miniupnpd/pf/obsdrdr.c @@ -353,6 +353,10 @@ add_filter_rule2(const char * ifname, struct pfioc_pooladdr pp; struct pf_pooladdr *a; #endif +#ifndef USE_IFNAME_IN_RULES + UNUSED(ifname); +#endif + UNUSED(eport); if(dev<0) { syslog(LOG_ERR, "pf device is not open"); return -1; @@ -663,6 +667,7 @@ priv_delete_filter_rule(const char * ifname, unsigned short iport, #else int i, n; struct pfioc_rule pr; + UNUSED(ifname); if(dev<0) { syslog(LOG_ERR, "pf device is not open"); return -1; From edd501f59c957547c5098ad480c48dfdfa5adf7e Mon Sep 17 00:00:00 2001 From: Daniel Becker Date: Fri, 28 Feb 2014 14:47:53 -0800 Subject: [PATCH 054/127] miniupnpd/natpmp.c: return correct error code when all external ports in use Instead of returning code 3 ("Network Failure"), we should the more appropriate code 4 ("Out of resources") when no external port is available for a mapping. --- miniupnpd/natpmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miniupnpd/natpmp.c b/miniupnpd/natpmp.c index c3d26ce..8238a11 100644 --- a/miniupnpd/natpmp.c +++ b/miniupnpd/natpmp.c @@ -291,7 +291,7 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, if(eport == eport_first) { /* no external port available */ syslog(LOG_ERR, "Failed to find available eport for NAT-PMP %hu %s->%s:%hu", eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport); - resp[3] = 3; /* Failure */ + resp[3] = 4; /* Out of resources */ break; } continue; From e5146cdf24c777d01b99c45e989b5659e0bb7080 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 3 Mar 2014 12:35:12 +0100 Subject: [PATCH 055/127] miniupnpd/Makefile.linux: fixes for testasyncsendto also update dependencies --- miniupnpd/Makefile.linux | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/miniupnpd/Makefile.linux b/miniupnpd/Makefile.linux index 270c72d..636ba94 100644 --- a/miniupnpd/Makefile.linux +++ b/miniupnpd/Makefile.linux @@ -205,7 +205,8 @@ testgetifaddr: testgetifaddr.o getifaddr.o testgetroute: testgetroute.o linux/getroute.o upnputils.o -lnfnetlink -testasyncsendto: testasyncsendto.o asyncsendto.o upnputils.o +testasyncsendto: testasyncsendto.o asyncsendto.o upnputils.o \ + linux/getroute.o -lnfnetlink miniupnpdctl: miniupnpdctl.o @@ -223,8 +224,8 @@ depend: config.h miniupnpd.o: config.h macros.h upnpglobalvars.h upnppermissions.h miniupnpd.o: miniupnpdtypes.h upnphttp.h upnpdescgen.h miniupnpdpath.h miniupnpd.o: getifaddr.h upnpsoap.h options.h minissdp.h upnpredirect.h -miniupnpd.o: upnppinhole.h daemonize.h upnpevents.h natpmp.h pcpserver.h -miniupnpd.o: commonrdr.h upnputils.h ifacewatcher.h +miniupnpd.o: upnppinhole.h daemonize.h upnpevents.h asyncsendto.h natpmp.h +miniupnpd.o: pcpserver.h commonrdr.h upnputils.h ifacewatcher.h upnphttp.o: config.h upnphttp.h upnpdescgen.h miniupnpdpath.h upnpsoap.h upnphttp.o: upnpevents.h upnputils.h upnpdescgen.o: config.h getifaddr.h upnpredirect.h upnpdescgen.h @@ -248,12 +249,13 @@ options.o: miniupnpdtypes.h upnppermissions.o: config.h upnppermissions.h minissdp.o: config.h upnpdescstrings.h miniupnpdpath.h upnphttp.h minissdp.o: upnpglobalvars.h upnppermissions.h miniupnpdtypes.h minissdp.h -minissdp.o: upnputils.h getroute.h codelength.h +minissdp.o: upnputils.h getroute.h asyncsendto.h codelength.h natpmp.o: macros.h config.h natpmp.h upnpglobalvars.h upnppermissions.h natpmp.o: miniupnpdtypes.h getifaddr.h upnpredirect.h commonrdr.h upnputils.h +natpmp.o: asyncsendto.h pcpserver.o: config.h pcpserver.h macros.h upnpglobalvars.h upnppermissions.h pcpserver.o: miniupnpdtypes.h pcplearndscp.h upnpredirect.h commonrdr.h -pcpserver.o: getifaddr.h pcp_msg_struct.h +pcpserver.o: getifaddr.h asyncsendto.h pcp_msg_struct.h upnpevents.o: config.h upnpevents.h miniupnpdpath.h upnpglobalvars.h upnpevents.o: upnppermissions.h miniupnpdtypes.h upnpdescgen.h upnputils.h upnputils.o: config.h upnputils.h upnpglobalvars.h upnppermissions.h @@ -264,6 +266,7 @@ upnppinhole.o: upnppermissions.h miniupnpdtypes.h upnpevents.h upnppinhole.o: netfilter/iptpinhole.h pcplearndscp.o: config.h upnpglobalvars.h upnppermissions.h miniupnpdtypes.h pcplearndscp.o: pcplearndscp.h +asyncsendto.o: asyncsendto.h linux/getifstats.o: config.h getifstats.h linux/ifacewatcher.o: config.h ifacewatcher.h config.h minissdp.h linux/ifacewatcher.o: miniupnpdtypes.h getifaddr.h upnpglobalvars.h @@ -284,4 +287,5 @@ testupnppermissions.o: upnppermissions.h config.h testgetifaddr.o: getifaddr.h testgetroute.o: getroute.h upnputils.h upnpglobalvars.h upnppermissions.h testgetroute.o: config.h miniupnpdtypes.h +testasyncsendto.o: miniupnpdtypes.h config.h upnputils.h asyncsendto.h miniupnpdctl.o: macros.h From f49a70aab02e9359d93e4bd19924ee5a1d1e85b3 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 3 Mar 2014 12:37:01 +0100 Subject: [PATCH 056/127] miniupnpd/testgetifaddr.c: also test find_ipv6_addr() --- miniupnpd/Makefile.linux | 2 +- miniupnpd/testgetifaddr.c | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/miniupnpd/Makefile.linux b/miniupnpd/Makefile.linux index 636ba94..86d7d7c 100644 --- a/miniupnpd/Makefile.linux +++ b/miniupnpd/Makefile.linux @@ -284,7 +284,7 @@ upnpdescgen.o: miniupnpdpath.h upnpglobalvars.h upnppermissions.h upnpdescgen.o: miniupnpdtypes.h upnpdescstrings.h upnpurns.h getconnstatus.h testgetifstats.o: getifstats.h testupnppermissions.o: upnppermissions.h config.h -testgetifaddr.o: getifaddr.h +testgetifaddr.o: config.h getifaddr.h testgetroute.o: getroute.h upnputils.h upnpglobalvars.h upnppermissions.h testgetroute.o: config.h miniupnpdtypes.h testasyncsendto.o: miniupnpdtypes.h config.h upnputils.h asyncsendto.h diff --git a/miniupnpd/testgetifaddr.c b/miniupnpd/testgetifaddr.c index 4c31907..8045b89 100644 --- a/miniupnpd/testgetifaddr.c +++ b/miniupnpd/testgetifaddr.c @@ -1,7 +1,7 @@ /* $Id: testgetifaddr.c,v 1.7 2013/04/27 15:38:57 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2013 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ #include @@ -10,6 +10,7 @@ #include #include #include +#include "config.h" #include "getifaddr.h" #if defined(__sun) @@ -21,6 +22,10 @@ int main(int argc, char * * argv) { char str_addr[64]; struct in_addr addr; struct in_addr mask; +#ifdef ENABLE_IPV6 + int r; + char str_addr6[64]; +#endif if(argc < 2) { fprintf(stderr, "Usage:\t%s interface_name\n", argv[0]); return 1; @@ -34,5 +39,16 @@ int main(int argc, char * * argv) { printf("Interface %s has IP address %s.\n", argv[1], str_addr); printf("addr=%s ", inet_ntoa(addr)); printf("mask=%s\n", inet_ntoa(mask)); +#ifdef ENABLE_IPV6 + r = find_ipv6_addr(argv[1], str_addr6, sizeof(str_addr6)); + if(r < 0) { + fprintf(stderr, "find_ipv6_addr() failed\n"); + return 1; + } else if(r == 0) { + printf("Interface %s has no IPv6 address.\n", argv[1]); + } else { + printf("Interface %s has IPv6 address %s.\n", argv[1], str_addr6); + } +#endif return 0; } From 65b776f1edf1fa12f542a14d191db6f4dfa06e82 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 6 Mar 2014 14:21:39 +0100 Subject: [PATCH 057/127] miniupnpd/pf: add clear_filter_rules() for testing also add a --clear / -c argument to testobsdrdr programm --- miniupnpd/pf/obsdrdr.c | 39 ++++++++++++++++++++++++++++++++++++++ miniupnpd/pf/obsdrdr.h | 6 +++++- miniupnpd/pf/testobsdrdr.c | 23 +++++++++++++++------- 3 files changed, 60 insertions(+), 8 deletions(-) diff --git a/miniupnpd/pf/obsdrdr.c b/miniupnpd/pf/obsdrdr.c index 5c87fec..d09a1be 100644 --- a/miniupnpd/pf/obsdrdr.c +++ b/miniupnpd/pf/obsdrdr.c @@ -180,6 +180,45 @@ clear_redirect_rules(void) error: return -1; } + +int +clear_filter_rules(void) +{ +#ifndef PF_ENABLE_FILTER_RULES + return 0; +#else + struct pfioc_trans io; + struct pfioc_trans_e ioe; + if(dev<0) { + syslog(LOG_ERR, "pf device is not open"); + return -1; + } + memset(&ioe, 0, sizeof(ioe)); + io.size = 1; + io.esize = sizeof(ioe); + io.array = &ioe; +#ifndef PF_NEWSTYLE + ioe.rs_num = PF_RULESET_FILTER; +#else + /* ? */ + ioe.type = PF_TRANS_RULESET; +#endif + strlcpy(ioe.anchor, anchor_name, MAXPATHLEN); + if(ioctl(dev, DIOCXBEGIN, &io) < 0) + { + syslog(LOG_ERR, "ioctl(dev, DIOCXBEGIN, ...): %m"); + goto error; + } + if(ioctl(dev, DIOCXCOMMIT, &io) < 0) + { + syslog(LOG_ERR, "ioctl(dev, DIOCXCOMMIT, ...): %m"); + goto error; + } + return 0; +error: + return -1; +#endif +} #endif /* add_redirect_rule2() : diff --git a/miniupnpd/pf/obsdrdr.h b/miniupnpd/pf/obsdrdr.h index 7bd7e0c..3defa8e 100644 --- a/miniupnpd/pf/obsdrdr.h +++ b/miniupnpd/pf/obsdrdr.h @@ -1,4 +1,4 @@ -/* $Id: obsdrdr.h,v 1.22 2014/02/28 20:18:41 nanard Exp $ */ +/* $Id: obsdrdr.h,v 1.23 2014/03/06 12:24:33 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2014 Thomas Bernard @@ -58,8 +58,12 @@ int delete_redirect_and_filter_rules(const char * ifname, unsigned short eport, int proto); +#ifdef TEST int clear_redirect_rules(void); +int +clear_filter_rules(void); +#endif #endif diff --git a/miniupnpd/pf/testobsdrdr.c b/miniupnpd/pf/testobsdrdr.c index 7d288c6..5cf8307 100644 --- a/miniupnpd/pf/testobsdrdr.c +++ b/miniupnpd/pf/testobsdrdr.c @@ -1,10 +1,11 @@ -/* $Id: testobsdrdr.c,v 1.24 2012/04/18 19:42:03 nanard Exp $ */ +/* $Id: testobsdrdr.c,v 1.28 2014/03/06 13:02:47 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2012 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ +#include #include #include #include @@ -17,6 +18,7 @@ int runtime_flags = 0; const char * tag = 0; const char * anchor_name = "miniupnpd"; +const char * queue = NULL; void list_rules(void); @@ -67,7 +69,7 @@ test_index(void) } int -main(int arc, char * * argv) +main(int argc, char * * argv) { char buf[32]; char desc[64]; @@ -77,6 +79,12 @@ main(int arc, char * * argv) unsigned int timestamp; u_int64_t packets = 0; u_int64_t bytes = 0; + int clear = 0; + + if(argc > 1) { + if(0 == strcmp(argv[1], "--clear") || 0 == strcmp(argv[1], "-c")) + clear = 1; + } openlog("testobsdrdr", LOG_PERROR, LOG_USER); if(init_redirect() < 0) @@ -121,12 +129,13 @@ main(int arc, char * * argv) else printf("delete_redirect_rule() succeded\n"); -#if 0 test_index(); - clear_redirect_rules(); - list_rules(); -#endif + if(clear) { + clear_redirect_rules(); + clear_filter_rules(); + } + /*list_rules();*/ return 0; } From acc149ee995d5d0e6679dc3406a83accf9f7d173 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 6 Mar 2014 14:23:13 +0100 Subject: [PATCH 058/127] miniupnpd/pf: fix add_filter_rule2() by adding internal address --- miniupnpd/pf/obsdrdr.c | 36 +++++++----------------------------- 1 file changed, 7 insertions(+), 29 deletions(-) diff --git a/miniupnpd/pf/obsdrdr.c b/miniupnpd/pf/obsdrdr.c index d09a1be..63bd0aa 100644 --- a/miniupnpd/pf/obsdrdr.c +++ b/miniupnpd/pf/obsdrdr.c @@ -1,4 +1,4 @@ -/* $Id: obsdrdr.c,v 1.78 2014/02/28 20:18:41 nanard Exp $ */ +/* $Id: obsdrdr.c,v 1.80 2014/03/06 13:02:46 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2014 Thomas Bernard @@ -13,7 +13,7 @@ * or a rdr rule + a pass rule : * rdr quick on xl1 inet proto udp from any to any port = 54321 \ * keep state label "test label" -> 192.168.0.42 port 12345 - * pass in quick on xl1 inet proto udp from any to any port = 12345 \ + * pass in quick on xl1 inet proto udp from any to 192.168.0.42 port = 12345 \ * flags S/SA keep state label "test label" * * - OpenBSD starting from version 4.7 @@ -390,7 +390,6 @@ add_filter_rule2(const char * ifname, struct pfioc_rule pcr; #ifndef PF_NEWSTYLE struct pfioc_pooladdr pp; - struct pf_pooladdr *a; #endif #ifndef USE_IFNAME_IN_RULES UNUSED(ifname); @@ -419,7 +418,6 @@ add_filter_rule2(const char * ifname, if(1) { #endif - pcr.rule.dst.port_op = PF_OP_EQ; pcr.rule.dst.port[0] = htons(iport); pcr.rule.direction = PF_IN; @@ -454,33 +452,16 @@ add_filter_rule2(const char * ifname, inet_pton(AF_INET, rhost, &pcr.rule.src.addr.v.a.addr.v4.s_addr); pcr.rule.src.addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE); } + /* we want any - iaddr port = # keep state label */ + inet_pton(AF_INET, iaddr, &pcr.rule.dst.addr.v.a.addr.v4.s_addr); + pcr.rule.dst.addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE); #ifndef PF_NEWSTYLE pcr.rule.rpool.proxy_port[0] = iport; - a = calloc(1, sizeof(struct pf_pooladdr)); - inet_pton(AF_INET, iaddr, &a->addr.v.a.addr.v4.s_addr); - a->addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE); - memcpy(&pp.addr, a, sizeof(struct pf_pooladdr)); + pcr.rule.rpool.proxy_port[1] = iport; TAILQ_INIT(&pcr.rule.rpool.list); - inet_pton(AF_INET, iaddr, &a->addr.v.a.addr.v4.s_addr); - TAILQ_INSERT_TAIL(&pcr.rule.rpool.list, a, entries); - - /* we have any - any port = # keep state label */ - /* we want any - iaddr port = # keep state label */ - /* memcpy(&pcr.rule.dst, a, sizeof(struct pf_pooladdr)); */ - - memcpy(&pp.addr, a, sizeof(struct pf_pooladdr)); - strlcpy(pcr.rule.label, desc, PF_RULE_LABEL_SIZE); - if(ioctl(dev, DIOCADDADDR, &pp) < 0) - { - syslog(LOG_ERR, "ioctl(dev, DIOCADDADDR, ...): %m"); - r = -1; - } - else - { -#else +#endif if(1) { -#endif pcr.action = PF_CHANGE_GET_TICKET; if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0) { @@ -497,9 +478,6 @@ add_filter_rule2(const char * ifname, } } } -#ifndef PF_NEWSTYLE - free(a); -#endif } return r; #endif From 60e129d131494ec16bc9f14b2aaf85ca016f30d5 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 6 Mar 2014 14:24:10 +0100 Subject: [PATCH 059/127] miniupnpd/pf: delete_redirect_and_filter_rules() now take internal address into account --- miniupnpd/pf/obsdrdr.c | 54 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/miniupnpd/pf/obsdrdr.c b/miniupnpd/pf/obsdrdr.c index 63bd0aa..349f68e 100644 --- a/miniupnpd/pf/obsdrdr.c +++ b/miniupnpd/pf/obsdrdr.c @@ -602,7 +602,8 @@ error: static int priv_delete_redirect_rule(const char * ifname, unsigned short eport, - int proto, unsigned short * iport) + int proto, unsigned short * iport, + in_addr_t * iaddr) { int i, n; struct pfioc_rule pr; @@ -643,8 +644,40 @@ priv_delete_redirect_rule(const char * ifname, unsigned short eport, /* retrieve iport in order to remove filter rule */ #ifndef PF_NEWSTYLE if(iport) *iport = pr.rule.rpool.proxy_port[0]; + if(iaddr) + { + /* retrieve internal address */ + struct pfioc_pooladdr pp; + memset(&pp, 0, sizeof(pp)); + strlcpy(pp.anchor, anchor_name, MAXPATHLEN); + pp.r_action = PF_RDR; + pp.r_num = i; + pp.ticket = pr.ticket; + if(ioctl(dev, DIOCGETADDRS, &pp) < 0) + { + syslog(LOG_ERR, "ioctl(dev, DIOCGETADDRS, ...): %m"); + goto error; + } + if(pp.nr != 1) + { + syslog(LOG_NOTICE, "No address associated with pf rule"); + goto error; + } + pp.nr = 0; /* first */ + if(ioctl(dev, DIOCGETADDR, &pp) < 0) + { + syslog(LOG_ERR, "ioctl(dev, DIOCGETADDR, ...): %m"); + goto error; + } + *iaddr = pp.addr.addr.v.a.addr.v4.s_addr; + } #else if(iport) *iport = pr.rule.rdr.proxy_port[0]; + if(iaddr) + { + /* retrieve internal address */ + *iaddr = pr.rule.rdr.addr.v.a.addr.v4.s_addr; + } #endif pr.action = PF_CHANGE_GET_TICKET; if(ioctl(dev, DIOCCHANGERULE, &pr) < 0) @@ -671,12 +704,12 @@ int delete_redirect_rule(const char * ifname, unsigned short eport, int proto) { - return priv_delete_redirect_rule(ifname, eport, proto, NULL); + return priv_delete_redirect_rule(ifname, eport, proto, NULL, NULL); } static int priv_delete_filter_rule(const char * ifname, unsigned short iport, - int proto) + int proto, in_addr_t iaddr) { #ifndef PF_ENABLE_FILTER_RULES UNUSED(ifname); UNUSED(iport); UNUSED(proto); @@ -706,8 +739,16 @@ priv_delete_filter_rule(const char * ifname, unsigned short iport, syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m"); goto error; } +#ifdef TEST +syslog(LOG_DEBUG, "%2d port=%hu proto=%d addr=%8x", + i, ntohs(pr.rule.dst.port[0]), pr.rule.proto, + pr.rule.dst.addr.v.a.addr.v4.s_addr); +/*pr.rule.dst.addr.v.a.mask.v4.s_addr*/ +#endif if( (iport == ntohs(pr.rule.dst.port[0])) - && (pr.rule.proto == proto) ) + && (pr.rule.proto == proto) && + (iaddr == pr.rule.dst.addr.v.a.addr.v4.s_addr) + ) { pr.action = PF_CHANGE_GET_TICKET; if(ioctl(dev, DIOCCHANGERULE, &pr) < 0) @@ -736,10 +777,11 @@ delete_redirect_and_filter_rules(const char * ifname, unsigned short eport, { int r; unsigned short iport; - r = priv_delete_redirect_rule(ifname, eport, proto, &iport); + in_addr_t iaddr; + r = priv_delete_redirect_rule(ifname, eport, proto, &iport, &iaddr); if(r == 0) { - priv_delete_filter_rule(ifname, iport, proto); + r = priv_delete_filter_rule(ifname, iport, proto, iaddr); } return r; } From b7ee4699809705238643b1ef4aaf847d6a8dee3b Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 6 Mar 2014 14:24:58 +0100 Subject: [PATCH 060/127] miniupnpd/pf: update testobsdrdr.c --- miniupnpd/pf/testobsdrdr.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/miniupnpd/pf/testobsdrdr.c b/miniupnpd/pf/testobsdrdr.c index 5cf8307..13d9ee5 100644 --- a/miniupnpd/pf/testobsdrdr.c +++ b/miniupnpd/pf/testobsdrdr.c @@ -96,12 +96,15 @@ main(int argc, char * * argv) add_redirect_rule("ep0", 12123, "192.168.1.23", 1234); add_redirect_rule2("ep0", 12155, "192.168.1.155", 1255, IPPROTO_TCP); #endif - add_redirect_rule2("ep0", "8.8.8.8", 12123, "192.168.1.125", 1234, - IPPROTO_UDP, "test description", 0); -#if 0 - add_redirect_rule2("em0", 12123, "127.1.2.3", 1234, - IPPROTO_TCP, "test description tcp"); -#endif + if(add_redirect_rule2("ep0", "8.8.8.8", 12123, "192.168.1.125", 1234, + IPPROTO_UDP, "test description", 0) < 0) + printf("add_redirect_rule2() #3 failed\n"); + if(add_redirect_rule2("em0", NULL, 12123, "127.1.2.3", 1234, + IPPROTO_TCP, "test description tcp", 0) < 0) + printf("add_redirect_rule2() #4 failed\n"); + if(add_filter_rule2("em0", NULL, "127.1.2.3", 12123, 1234, IPPROTO_TCP, + "test description tcp") < 0) + printf("add_filter_rule2() #1 failed\n"); list_rules(); list_eports_tcp(); @@ -121,13 +124,12 @@ main(int argc, char * * argv) if(delete_redirect_rule("ep0", 12123, IPPROTO_UDP) < 0) printf("delete_redirect_rule() failed\n"); - else - printf("delete_redirect_rule() succeded\n"); if(delete_redirect_rule("ep0", 12123, IPPROTO_UDP) < 0) printf("delete_redirect_rule() failed\n"); - else - printf("delete_redirect_rule() succeded\n"); + + if(delete_redirect_and_filter_rules("em0", 12123, IPPROTO_TCP) < 0) + printf("delete_redirect_and_filter_rules() failed\n"); test_index(); From e385db03b9262ff8e459e175f0ad1d444a06ade3 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 7 Mar 2014 11:48:17 +0100 Subject: [PATCH 061/127] miniupnpd: improved permission checking for NAT-PMP NAT-PMP now searches an allowed eport if the one from request is not, instead of returning an error --- miniupnpd/Changelog.txt | 6 +++++- miniupnpd/natpmp.c | 37 ++++++++++++++++++++++++------------- miniupnpd/upnppermissions.c | 37 +++++++++++++++++++++++++++++++++++-- miniupnpd/upnppermissions.h | 13 +++++++++++-- 4 files changed, 75 insertions(+), 18 deletions(-) diff --git a/miniupnpd/Changelog.txt b/miniupnpd/Changelog.txt index 830fcc4..e2856ad 100644 --- a/miniupnpd/Changelog.txt +++ b/miniupnpd/Changelog.txt @@ -1,4 +1,8 @@ -$Id: Changelog.txt,v 1.354 2014/02/28 12:14:29 nanard Exp $ +$Id: Changelog.txt,v 1.357 2014/03/07 10:43:29 nanard Exp $ + +2014/04/07: + NAT-PMP search an allowed eport instead of returning an error + if the original eport is not allowed. 2014/02/28: log message when shutting down diff --git a/miniupnpd/natpmp.c b/miniupnpd/natpmp.c index 8238a11..533fdfe 100644 --- a/miniupnpd/natpmp.c +++ b/miniupnpd/natpmp.c @@ -1,4 +1,4 @@ -/* $Id: natpmp.c,v 1.36 2014/02/01 17:17:35 nanard Exp $ */ +/* $Id: natpmp.c,v 1.39 2014/03/07 10:43:30 nanard Exp $ */ /* MiniUPnP project * (c) 2007-2014 Thomas Bernard * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ @@ -263,14 +263,32 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, } } eport = 0; /* to indicate correct removing of port mapping */ - } else if(iport==0 - || !check_upnp_rule_against_permissions(upnppermlist, num_upnpperm, eport, senderaddr->sin_addr, iport)) { + } else if(iport==0) { resp[3] = 2; /* Not Authorized/Refused */ - } else { + } else { /* iport > 0 && lifetime > 0 */ unsigned short eport_first; char desc[64]; + if(!check_upnp_rule_against_permissions(upnppermlist, num_upnpperm, eport, senderaddr->sin_addr, iport)) { + /* if the mapping is forbidden because of eport only + * (ie iaddr/iport are ok with another eport) + * change eport value ! */ + if(!find_allowed_eport(upnppermlist, num_upnpperm, senderaddr->sin_addr, iport, &eport)) { + /* no rule allow a mapping with this iaddr/iport */ + resp[3] = 2; /* Not Authorized/Refused */ + } + } eport_first = eport; - do { + while(resp[3] == 0) { + if(!check_upnp_rule_against_permissions(upnppermlist, num_upnpperm, eport, senderaddr->sin_addr, iport)) { + eport++; + if(eport == eport_first) { /* no external port available */ + syslog(LOG_ERR, "Failed to find available eport for NAT-PMP %hu %s->%s:%hu", + eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport); + resp[3] = 4; /* Out of resources */ + break; + } + continue; + } r = get_redirect_rule(ext_if_name, eport, proto, iaddr_old, sizeof(iaddr_old), &iport_old, 0, 0, 0, 0, @@ -314,16 +332,9 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, syslog(LOG_ERR, "Failed to add NAT-PMP %hu %s->%s:%hu '%s'", eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport, desc); resp[3] = 3; /* Failure */ -#if 0 - } else if( !nextnatpmptoclean_eport - || timestamp < nextnatpmptoclean_timestamp) { - nextnatpmptoclean_timestamp = timestamp; - nextnatpmptoclean_eport = eport; - nextnatpmptoclean_proto = proto; -#endif } break; - } while(r==0); + } } *((uint16_t *)(resp+8)) = htons(iport); /* private port */ *((uint16_t *)(resp+10)) = htons(eport); /* public port */ diff --git a/miniupnpd/upnppermissions.c b/miniupnpd/upnppermissions.c index 0fd43f7..c016451 100644 --- a/miniupnpd/upnppermissions.c +++ b/miniupnpd/upnppermissions.c @@ -1,7 +1,7 @@ -/* $Id: upnppermissions.c,v 1.17 2012/02/15 22:43:34 nanard Exp $ */ +/* $Id: upnppermissions.c,v 1.18 2014/03/07 10:43:29 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2012 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -223,6 +223,21 @@ match_permission(const struct upnpperm * perm, return 1; } +/* match_permission_internal() + * returns: 1 if address, iport matches the permission rule + * 0 if no match */ +static int +match_permission_internal(const struct upnpperm * perm, + struct in_addr address, u_short iport) +{ + if( (iport < perm->iport_min) || (perm->iport_max < iport)) + return 0; + if( (address.s_addr & perm->mask.s_addr) + != (perm->address.s_addr & perm->mask.s_addr) ) + return 0; + return 1; +} + int check_upnp_rule_against_permissions(const struct upnpperm * permary, int n_perms, @@ -245,3 +260,21 @@ check_upnp_rule_against_permissions(const struct upnpperm * permary, return 1; /* Default : accept */ } +int +find_allowed_eport(const struct upnpperm * permary, + int n_perms, + struct in_addr address, u_short iport, + u_short *allowed_eport) +{ + int i; + for(i=0; i Date: Fri, 7 Mar 2014 07:42:40 -0800 Subject: [PATCH 062/127] miniupnpd/natpmp.c: remove redundant break statements These two break statements are redundant: The subsequent continue statement will cause the loop condition to be re-evaluated, at which point the loop will terminate if resp[3] != 0. --- miniupnpd/natpmp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/miniupnpd/natpmp.c b/miniupnpd/natpmp.c index 533fdfe..5de5f73 100644 --- a/miniupnpd/natpmp.c +++ b/miniupnpd/natpmp.c @@ -285,7 +285,6 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, syslog(LOG_ERR, "Failed to find available eport for NAT-PMP %hu %s->%s:%hu", eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport); resp[3] = 4; /* Out of resources */ - break; } continue; } @@ -310,7 +309,6 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, syslog(LOG_ERR, "Failed to find available eport for NAT-PMP %hu %s->%s:%hu", eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport); resp[3] = 4; /* Out of resources */ - break; } continue; } From 1db670d6ff2b143cb6e1c3f07132bf88a1b90429 Mon Sep 17 00:00:00 2001 From: Daniel Becker Date: Fri, 7 Mar 2014 11:02:04 -0800 Subject: [PATCH 063/127] miniupnpd/natpmp.c: skip port zero when finding free eport When skipping ports that are in use or not allowed, the existing NAT-PMP code will consider port zero as a candidate eport after wraparound occurs. Since this is not a legal port, we skip over it. port zero as an eport value. --- miniupnpd/natpmp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/miniupnpd/natpmp.c b/miniupnpd/natpmp.c index 533fdfe..7e456de 100644 --- a/miniupnpd/natpmp.c +++ b/miniupnpd/natpmp.c @@ -281,6 +281,7 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, while(resp[3] == 0) { if(!check_upnp_rule_against_permissions(upnppermlist, num_upnpperm, eport, senderaddr->sin_addr, iport)) { eport++; + if(eport == 0) eport++; /* skip port zero */ if(eport == eport_first) { /* no external port available */ syslog(LOG_ERR, "Failed to find available eport for NAT-PMP %hu %s->%s:%hu", eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport); @@ -306,6 +307,7 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, } } else { eport++; + if(eport == 0) eport++; /* skip port zero */ if(eport == eport_first) { /* no external port available */ syslog(LOG_ERR, "Failed to find available eport for NAT-PMP %hu %s->%s:%hu", eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport); From ecf414e1608af330f503b397bd6c01c32097c679 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 10 Mar 2014 00:12:20 +0100 Subject: [PATCH 064/127] miniupnpd/Changelog.txt: Catch up changes... --- miniupnpd/Changelog.txt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/miniupnpd/Changelog.txt b/miniupnpd/Changelog.txt index e2856ad..3078657 100644 --- a/miniupnpd/Changelog.txt +++ b/miniupnpd/Changelog.txt @@ -1,9 +1,15 @@ -$Id: Changelog.txt,v 1.357 2014/03/07 10:43:29 nanard Exp $ +$Id: Changelog.txt,v 1.358 2014/03/09 23:11:43 nanard Exp $ -2014/04/07: +2014/03/09: + IPv6 support in testgetifaddr + +2014/03/07: NAT-PMP search an allowed eport instead of returning an error if the original eport is not allowed. +2014/03/06: + Fix add_filter_rule2() for pf. + 2014/02/28: log message when shutting down natpmp : avoid hang when all external ports in use From f4f4573f5387fa909ad833d40ed47ac691717fdd Mon Sep 17 00:00:00 2001 From: Daniel Becker Date: Mon, 10 Mar 2014 00:32:23 -0700 Subject: [PATCH 065/127] miniupnpd: fix eport selection and error handling The find_available_eport function that was intended to check if at least one eport is allowed for a given iaddr/iport does not work as intended; for example, it does not properly handle rule precedence (i.e., it considers allow rules even if they are effectively masked by earlier deny rules), and it also does not handle the case where no rules are specified at all (which should default to accept in order to be consistent with check_upnp_rule_against_permissions). The present change removes this function and instead integrates the check into the existing while loop that iterates over all eports. --- miniupnpd/natpmp.c | 39 +++++++++++++++++-------------------- miniupnpd/upnppermissions.c | 18 ----------------- miniupnpd/upnppermissions.h | 9 --------- 3 files changed, 18 insertions(+), 48 deletions(-) diff --git a/miniupnpd/natpmp.c b/miniupnpd/natpmp.c index 5f434fe..74a035e 100644 --- a/miniupnpd/natpmp.c +++ b/miniupnpd/natpmp.c @@ -266,29 +266,31 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, } else if(iport==0) { resp[3] = 2; /* Not Authorized/Refused */ } else { /* iport > 0 && lifetime > 0 */ - unsigned short eport_first; + unsigned short eport_first = 0; + int any_eport_allowed = 0; char desc[64]; - if(!check_upnp_rule_against_permissions(upnppermlist, num_upnpperm, eport, senderaddr->sin_addr, iport)) { - /* if the mapping is forbidden because of eport only - * (ie iaddr/iport are ok with another eport) - * change eport value ! */ - if(!find_allowed_eport(upnppermlist, num_upnpperm, senderaddr->sin_addr, iport, &eport)) { - /* no rule allow a mapping with this iaddr/iport */ - resp[3] = 2; /* Not Authorized/Refused */ - } - } eport_first = eport; while(resp[3] == 0) { - if(!check_upnp_rule_against_permissions(upnppermlist, num_upnpperm, eport, senderaddr->sin_addr, iport)) { - eport++; - if(eport == 0) eport++; /* skip port zero */ - if(eport == eport_first) { /* no external port available */ + if(eport_first == 0) { /* first time in loop */ + eport_first = eport; + } else if(eport == eport_first) { /* no eport available */ + if(any_eport_allowed == 0) { /* all eports rejected by permissions */ + syslog(LOG_ERR, "No allowed eport for NAT-PMP %hu %s->%s:%hu", + eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport); + resp[3] = 2; /* Not Authorized/Refused */ + } else { /* at least one eport allowed (but none available) */ syslog(LOG_ERR, "Failed to find available eport for NAT-PMP %hu %s->%s:%hu", eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport); - resp[3] = 4; /* Out of resources */ + resp[3] = 4; /* Out of resources */ } + break; + } + if(!check_upnp_rule_against_permissions(upnppermlist, num_upnpperm, eport, senderaddr->sin_addr, iport)) { + eport++; + if(eport == 0) eport++; /* skip port zero */ continue; } + any_eport_allowed = 1; r = get_redirect_rule(ext_if_name, eport, proto, iaddr_old, sizeof(iaddr_old), &iport_old, 0, 0, 0, 0, @@ -306,12 +308,7 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, } } else { eport++; - if(eport == 0) eport++; /* skip port zero */ - if(eport == eport_first) { /* no external port available */ - syslog(LOG_ERR, "Failed to find available eport for NAT-PMP %hu %s->%s:%hu", - eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport); - resp[3] = 4; /* Out of resources */ - } + if(eport == 0) eport++; /* skip port zero */ continue; } } diff --git a/miniupnpd/upnppermissions.c b/miniupnpd/upnppermissions.c index c016451..edc9ad9 100644 --- a/miniupnpd/upnppermissions.c +++ b/miniupnpd/upnppermissions.c @@ -260,21 +260,3 @@ check_upnp_rule_against_permissions(const struct upnpperm * permary, return 1; /* Default : accept */ } -int -find_allowed_eport(const struct upnpperm * permary, - int n_perms, - struct in_addr address, u_short iport, - u_short *allowed_eport) -{ - int i; - for(i=0; i Date: Mon, 10 Mar 2014 11:14:49 -0700 Subject: [PATCH 066/127] miniupnpd/natpmp.c: remove obsolete assignment The eport_first variable now gets initialized in the first iteration of the while loop; the assignment right before the loop should have been removed in the previous commit. --- miniupnpd/natpmp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/miniupnpd/natpmp.c b/miniupnpd/natpmp.c index 74a035e..802aba2 100644 --- a/miniupnpd/natpmp.c +++ b/miniupnpd/natpmp.c @@ -269,7 +269,6 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, unsigned short eport_first = 0; int any_eport_allowed = 0; char desc[64]; - eport_first = eport; while(resp[3] == 0) { if(eport_first == 0) { /* first time in loop */ eport_first = eport; From 210876f2a7a96e01e4d8496184c278ff66f363cf Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 11 Mar 2014 09:47:09 +0100 Subject: [PATCH 067/127] miniupnpd/natpmp.c: make indentation consistant and add a comment --- miniupnpd/natpmp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/miniupnpd/natpmp.c b/miniupnpd/natpmp.c index 802aba2..3c55ee5 100644 --- a/miniupnpd/natpmp.c +++ b/miniupnpd/natpmp.c @@ -267,7 +267,7 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, resp[3] = 2; /* Not Authorized/Refused */ } else { /* iport > 0 && lifetime > 0 */ unsigned short eport_first = 0; - int any_eport_allowed = 0; + int any_eport_allowed = 0; char desc[64]; while(resp[3] == 0) { if(eport_first == 0) { /* first time in loop */ @@ -280,7 +280,7 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, } else { /* at least one eport allowed (but none available) */ syslog(LOG_ERR, "Failed to find available eport for NAT-PMP %hu %s->%s:%hu", eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport); - resp[3] = 4; /* Out of resources */ + resp[3] = 4; /* Out of resources */ } break; } @@ -289,7 +289,7 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, if(eport == 0) eport++; /* skip port zero */ continue; } - any_eport_allowed = 1; + any_eport_allowed = 1; /* at lease one eport is allowed */ r = get_redirect_rule(ext_if_name, eport, proto, iaddr_old, sizeof(iaddr_old), &iport_old, 0, 0, 0, 0, From efbb95aa10765326a2358b11e5d6b9657caf255f Mon Sep 17 00:00:00 2001 From: Daniel Becker Date: Tue, 11 Mar 2014 01:54:10 -0700 Subject: [PATCH 068/127] miniupnpd/pcpserver.c: port NAT-PMP updates to PCP This change ports the recent updates to the permissions checking and eport selection code for NAT-PMP to the PCP MAP handler. --- miniupnpd/pcpserver.c | 44 +++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/miniupnpd/pcpserver.c b/miniupnpd/pcpserver.c index 8a88c6a..5ba4a25 100644 --- a/miniupnpd/pcpserver.c +++ b/miniupnpd/pcpserver.c @@ -805,6 +805,8 @@ static void CreatePCPMap(pcp_info_t *pcp_msg_info) char desc[64]; char iaddr_old[INET_ADDRSTRLEN]; uint16_t iport_old; + uint16_t eport_first = 0; + int any_eport_allowed = 0; unsigned int timestamp; int r=0; @@ -812,6 +814,32 @@ static void CreatePCPMap(pcp_info_t *pcp_msg_info) pcp_msg_info->ext_port = pcp_msg_info->int_port; } do { + if (eport_first == 0) { /* first time in loop */ + eport_first = pcp_msg_info->ext_port; + } else if (pcp_msg_info->ext_port == eport_first) { /* no eport available */ + if (any_eport_allowed == 0) { /* all eports rejected by permissions */ + pcp_msg_info->result_code = PCP_ERR_NOT_AUTHORIZED; + } else { /* at least one eport allowed (but none available) */ + pcp_msg_info->result_code = PCP_ERR_NO_RESOURCES; + } + return; + } + if ((IN6_IS_ADDR_V4MAPPED(pcp_msg_info->int_ip) && + (!check_upnp_rule_against_permissions(upnppermlist, + num_upnpperm, pcp_msg_info->ext_port, + ((struct in_addr*)pcp_msg_info->int_ip->s6_addr)[3], + pcp_msg_info->int_port)))) { + if (pcp_msg_info->pfailure_present) { + pcp_msg_info->result_code = PCP_ERR_CANNOT_PROVIDE_EXTERNAL; + return; + } + pcp_msg_info->ext_port++; + if (pcp_msg_info->ext_port == 0) { /* skip port zero */ + pcp_msg_info->ext_port++; + } + continue; + } + any_eport_allowed = 1; r = get_redirect_rule(ext_if_name, pcp_msg_info->ext_port, pcp_msg_info->protocol, @@ -836,24 +864,20 @@ static void CreatePCPMap(pcp_info_t *pcp_msg_info) if (_upnp_delete_redir(pcp_msg_info->ext_port, pcp_msg_info->protocol)==0) { break; + } else if (pcp_msg_info->pfailure_present) { + pcp_msg_info->result_code = PCP_ERR_CANNOT_PROVIDE_EXTERNAL; + return; } } pcp_msg_info->ext_port++; + if (pcp_msg_info->ext_port == 0) { /* skip port zero */ + pcp_msg_info->ext_port++; + } } } while (r==0); timestamp = time(NULL) + pcp_msg_info->lifetime; - if ((pcp_msg_info->ext_port == 0) || - (IN6_IS_ADDR_V4MAPPED(pcp_msg_info->int_ip) && - (!check_upnp_rule_against_permissions(upnppermlist, - num_upnpperm, pcp_msg_info->ext_port, - ((struct in_addr*)pcp_msg_info->int_ip->s6_addr)[3], - pcp_msg_info->int_port)))) { - pcp_msg_info->result_code = PCP_ERR_CANNOT_PROVIDE_EXTERNAL; - return; - } - snprintf(desc, sizeof(desc), "PCP %hu %s", pcp_msg_info->ext_port, (pcp_msg_info->protocol==IPPROTO_TCP)?"tcp":"udp"); From 408a0b55f60d475157d1c9234b217cda9232c6dc Mon Sep 17 00:00:00 2001 From: Daniel Becker Date: Tue, 11 Mar 2014 02:06:38 -0700 Subject: [PATCH 069/127] miniupnpd/pcpserver.c: return error code if PCP mapping fails This change causes CreatePCPMap to return a PCP_ERR_NO_RESOURCES response when upnp_redirect_internal does not succeed; previously, no error code was returned in this case. --- miniupnpd/pcpserver.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/miniupnpd/pcpserver.c b/miniupnpd/pcpserver.c index 5ba4a25..98a6feb 100644 --- a/miniupnpd/pcpserver.c +++ b/miniupnpd/pcpserver.c @@ -897,6 +897,8 @@ static void CreatePCPMap(pcp_info_t *pcp_msg_info) pcp_msg_info->int_port, desc); + pcp_msg_info->result_code = PCP_ERR_NO_RESOURCES; + } else { syslog(LOG_INFO, "PCP MAP: added mapping %s %hu->%s:%hu '%s'", (pcp_msg_info->protocol==IPPROTO_TCP)?"TCP":"UDP", From b01152666c7b497cd031037b5fb5ca7bc1149824 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Wed, 12 Mar 2014 09:04:47 +0100 Subject: [PATCH 070/127] Adding Daniel Becker to thanks list --- README | 1 + 1 file changed, 1 insertion(+) diff --git a/README b/README index 96b37df..95cac83 100644 --- a/README +++ b/README @@ -44,3 +44,4 @@ Thanks to : * Leah X. Schmidt * Peter Tatrai * Leo Moll + * Daniel Becker From 081c46338c74918bf25709f9ad167010d974f23f Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 13 Mar 2014 09:53:44 +0100 Subject: [PATCH 071/127] miniupnpd/upnppermissions.c: disable match_permission_internal() --- miniupnpd/upnppermissions.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/miniupnpd/upnppermissions.c b/miniupnpd/upnppermissions.c index edc9ad9..ad02d8c 100644 --- a/miniupnpd/upnppermissions.c +++ b/miniupnpd/upnppermissions.c @@ -223,6 +223,7 @@ match_permission(const struct upnpperm * perm, return 1; } +#if 0 /* match_permission_internal() * returns: 1 if address, iport matches the permission rule * 0 if no match */ @@ -237,6 +238,7 @@ match_permission_internal(const struct upnpperm * perm, return 0; return 1; } +#endif int check_upnp_rule_against_permissions(const struct upnpperm * permary, From d397d736282affae9862fd114f243518e7680f14 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 13 Mar 2014 09:56:34 +0100 Subject: [PATCH 072/127] miniupnpd/getifaddr.c: fix getifaddr_in6() -1 is returned if no address is found --- miniupnpd/getifaddr.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/miniupnpd/getifaddr.c b/miniupnpd/getifaddr.c index 1430336..2b71909 100644 --- a/miniupnpd/getifaddr.c +++ b/miniupnpd/getifaddr.c @@ -122,6 +122,7 @@ getifaddr(const char * ifname, char * buf, int len, int getifaddr_in6(const char * ifname, struct in6_addr * addr){ struct ifaddrs * ifap; struct ifaddrs * ife; + int found = 0; if(!ifname || ifname[0]=='\0') return -1; @@ -130,9 +131,8 @@ int getifaddr_in6(const char * ifname, struct in6_addr * addr){ syslog(LOG_ERR, "getifaddrs: %m"); return -1; } - for(ife = ifap; ife; ife = ife->ifa_next) + for(ife = ifap; ife && !found; ife = ife->ifa_next) { - int found = 0; /* skip other interfaces if one was specified */ if(ifname && (0 != strcmp(ifname, ife->ifa_name))) continue; @@ -165,12 +165,9 @@ int getifaddr_in6(const char * ifname, struct in6_addr * addr){ } break; } - if (found) { - break; - } } freeifaddrs(ifap); - return 0; + return (found ? 0 : -1); } #endif From 81fa1bcd57e6f00b3b1d0aa6d240abb3e35a30a7 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 13 Mar 2014 10:00:42 +0100 Subject: [PATCH 073/127] miniupnpd/getifaddr.c: getifaddr_in6() only return IPv4 address when IPV6 disabled see if it can help for issue #62 pcp/CheckAddress() is likely to need more changes. --- miniupnpd/getifaddr.c | 6 +++++- miniupnpd/pcpserver.c | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/miniupnpd/getifaddr.c b/miniupnpd/getifaddr.c index 2b71909..3bdc281 100644 --- a/miniupnpd/getifaddr.c +++ b/miniupnpd/getifaddr.c @@ -119,6 +119,8 @@ getifaddr(const char * ifname, char * buf, int len, } #ifdef ENABLE_PCP +/* XXX I don't know if this function should return + * IPv4 or IPv6 if both are enabled... */ int getifaddr_in6(const char * ifname, struct in6_addr * addr){ struct ifaddrs * ifap; struct ifaddrs * ife; @@ -157,6 +159,7 @@ int getifaddr_in6(const char * ifname, struct in6_addr * addr){ found = 1; break; +#ifdef ENABLE_IPV6 case AF_INET6: if(!IN6_IS_ADDR_LOOPBACK(addr) && !IN6_IS_ADDR_LINKLOCAL(addr)) { @@ -164,12 +167,13 @@ int getifaddr_in6(const char * ifname, struct in6_addr * addr){ found = 1; } break; +#endif /* ENABLE_IPV6 */ } } freeifaddrs(ifap); return (found ? 0 : -1); } -#endif +#endif /* ENABLE_PCP */ #ifdef ENABLE_IPV6 int diff --git a/miniupnpd/pcpserver.c b/miniupnpd/pcpserver.c index 98a6feb..ed6416e 100644 --- a/miniupnpd/pcpserver.c +++ b/miniupnpd/pcpserver.c @@ -536,6 +536,7 @@ static int parsePCPOptions(void* pcp_buf, int* remainingSize, static int CheckExternalAddress(pcp_info_t* pcp_msg_info) { + /* can contain a IPv4-mapped IPv6 address */ static struct in6_addr external_addr; if(use_ext_ip_addr) { @@ -554,6 +555,7 @@ static int CheckExternalAddress(pcp_info_t* pcp_msg_info) pcp_msg_info->result_code = PCP_ERR_NETWORK_FAILURE; return -1; } + /* how do we know which address we need ? IPv6 or IPv4 ? */ if(getifaddr_in6(ext_if_name, &external_addr) < 0) { pcp_msg_info->result_code = PCP_ERR_NETWORK_FAILURE; return -1; From 3ed34783981881856b14dcd3e98246495dc6e419 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 13 Mar 2014 10:42:07 +0100 Subject: [PATCH 074/127] miniupnpd/getifaddr.c: clean up and fix getifaddr_in6() --- miniupnpd/getifaddr.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/miniupnpd/getifaddr.c b/miniupnpd/getifaddr.c index 3bdc281..f3459a5 100644 --- a/miniupnpd/getifaddr.c +++ b/miniupnpd/getifaddr.c @@ -121,9 +121,13 @@ getifaddr(const char * ifname, char * buf, int len, #ifdef ENABLE_PCP /* XXX I don't know if this function should return * IPv4 or IPv6 if both are enabled... */ -int getifaddr_in6(const char * ifname, struct in6_addr * addr){ +int getifaddr_in6(const char * ifname, struct in6_addr * addr) +{ struct ifaddrs * ifap; struct ifaddrs * ife; +#ifdef ENABLE_IPV6 + const struct sockaddr_in6 * tmpaddr; +#endif /* ENABLE_IPV6 */ int found = 0; if(!ifname || ifname[0]=='\0') @@ -143,27 +147,25 @@ int getifaddr_in6(const char * ifname, struct in6_addr * addr){ switch(ife->ifa_addr->sa_family) { case AF_INET: -#if 0 - addr->s6_addr32[0]=0; - addr->s6_addr32[1]=0; - addr->s6_addr32[2]=htonl(0xffff); - addr->s6_addr32[3]=((struct sockaddr_in *)ife->ifa_addr)->sin_addr.s_addr; -#endif + /* IPv4-mapped IPv6 address ::ffff:1.2.3.4 */ memset(addr->s6_addr, 0, 10); addr->s6_addr[10] = 0xff; addr->s6_addr[11] = 0xff; - memcpy(addr->s6_addr + 12, &(((struct sockaddr_in *)ife->ifa_addr)->sin_addr.s_addr), 4); - /*inet_ntop(ife->ifa_addr->sa_family, - &((struct sockaddr_in *)ife->ifa_addr)->sin_addr, - buf, len);*/ + memcpy(addr->s6_addr + 12, + &(((struct sockaddr_in *)ife->ifa_addr)->sin_addr.s_addr), + 4); found = 1; break; #ifdef ENABLE_IPV6 case AF_INET6: - if(!IN6_IS_ADDR_LOOPBACK(addr) - && !IN6_IS_ADDR_LINKLOCAL(addr)) { - memcpy(addr->s6_addr, &((struct sockaddr_in6 *)ife->ifa_addr)->sin6_addr, 16); + tmpaddr = (const struct sockaddr_in6 *)ife->ifa_addr; + if(!IN6_IS_ADDR_LOOPBACK(&tmpaddr->sin6_addr) + && !IN6_IS_ADDR_LINKLOCAL(&tmpaddr->sin6_addr)) + { + memcpy(addr->s6_addr, + &tmpaddr->sin6_addr, + 16); found = 1; } break; From 2a48074f4504a5330745d582bccc1384860b7345 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 13 Mar 2014 11:24:04 +0100 Subject: [PATCH 075/127] miniupnpd: Enable PCP by default. --- miniupnpd/Changelog.txt | 5 ++++- miniupnpd/genconfig.sh | 15 ++------------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/miniupnpd/Changelog.txt b/miniupnpd/Changelog.txt index 3078657..73065ad 100644 --- a/miniupnpd/Changelog.txt +++ b/miniupnpd/Changelog.txt @@ -1,4 +1,7 @@ -$Id: Changelog.txt,v 1.358 2014/03/09 23:11:43 nanard Exp $ +$Id: Changelog.txt,v 1.362 2014/03/13 10:20:57 nanard Exp $ + +2014/03/10: + Enable PCP by default. 2014/03/09: IPv6 support in testgetifaddr diff --git a/miniupnpd/genconfig.sh b/miniupnpd/genconfig.sh index 8b13389..755a5be 100755 --- a/miniupnpd/genconfig.sh +++ b/miniupnpd/genconfig.sh @@ -1,5 +1,5 @@ #! /bin/sh -# $Id: genconfig.sh,v 1.69 2014/02/24 18:41:25 nanard Exp $ +# $Id: genconfig.sh,v 1.72 2014/03/10 10:17:17 nanard Exp $ # miniupnp daemon # http://miniupnp.free.fr or http://miniupnp.tuxfamily.org/ # (c) 2006-2014 Thomas Bernard @@ -13,11 +13,7 @@ case "$argv" in --strict) STRICT=1 ;; --leasefile) LEASEFILE=1 ;; --vendorcfg) VENDORCFG=1 ;; - --pcp) PCP=1 ;; - --pcp-peer) - PCP=1 - PCP_PEER=1 - ;; + --pcp-peer) PCP_PEER=1 ;; --help|-h) echo "Usage : $0 [options]" echo " --ipv6 enable IPv6" @@ -25,7 +21,6 @@ case "$argv" in echo " --strict be more strict regarding compliance with UPnP specifications" echo " --leasefile enable lease file" echo " --vendorcfg enable configuration of manufacturer info" - echo " --pcp enable PCP" echo " --pcp-peer enable PCP PEER operation" exit 1 ;; @@ -341,15 +336,9 @@ echo "/* Comment the following line to disable NAT-PMP operations */" >> ${CONFI echo "#define ENABLE_NATPMP" >> ${CONFIGFILE} echo "" >> ${CONFIGFILE} -if [ -n "$PCP" ]; then echo "/* Comment the following line to disable PCP operations */" >> ${CONFIGFILE} echo "#define ENABLE_PCP" >> ${CONFIGFILE} echo "" >> ${CONFIGFILE} -else -echo "/* Uncomment the following line to enable PCP operations */" >> ${CONFIGFILE} -echo "/*#define ENABLE_PCP*/" >> ${CONFIGFILE} -echo "" >> ${CONFIGFILE} -fi echo "#ifdef ENABLE_PCP" >> ${CONFIGFILE} if [ -n "$PCP_PEER" ]; then From 15682180a5f658b10797b99107e2dbe3e6263c50 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 13 Mar 2014 11:30:24 +0100 Subject: [PATCH 076/127] miniupnpd: Work in IPv6 on system where PF_INET6 are restricted to IPv6 only --- miniupnpd/Changelog.txt | 1 + miniupnpd/genconfig.sh | 17 ++++ miniupnpd/miniupnpd.c | 198 +++++++++++++++++++++++++--------------- 3 files changed, 143 insertions(+), 73 deletions(-) diff --git a/miniupnpd/Changelog.txt b/miniupnpd/Changelog.txt index 73065ad..513aa01 100644 --- a/miniupnpd/Changelog.txt +++ b/miniupnpd/Changelog.txt @@ -2,6 +2,7 @@ $Id: Changelog.txt,v 1.362 2014/03/13 10:20:57 nanard Exp $ 2014/03/10: Enable PCP by default. + Work in IPv6 on system where PF_INET6 are restricted to IPv6 only 2014/03/09: IPv6 support in testgetifaddr diff --git a/miniupnpd/genconfig.sh b/miniupnpd/genconfig.sh index 755a5be..13a54e6 100755 --- a/miniupnpd/genconfig.sh +++ b/miniupnpd/genconfig.sh @@ -115,6 +115,7 @@ case $OS_NAME in FW=pf echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} OS_URL=http://www.openbsd.org/ + V6SOCKETS_ARE_V6ONLY=`sysctl -n net.inet6.ip6.v6only` ;; FreeBSD) VER=`grep '#define __FreeBSD_version' /usr/include/sys/param.h | awk '{print $3}'` @@ -145,12 +146,14 @@ case $OS_NAME in fi echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} OS_URL=http://www.freebsd.org/ + V6SOCKETS_ARE_V6ONLY=`sysctl -n net.inet6.ip6.v6only` ;; pfSense) # we need to detect if PFRULE_INOUT_COUNTS macro is needed FW=pf echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} OS_URL=http://www.pfsense.com/ + V6SOCKETS_ARE_V6ONLY=`sysctl -n net.inet6.ip6.v6only` ;; NetBSD) if [ -f /etc/rc.subr ] && [ -f /etc/rc.conf ] ; then @@ -308,6 +311,11 @@ case $FW in ;; esac +# set V6SOCKETS_ARE_V6ONLY to 0 if it was not set above +if [ -z "$V6SOCKETS_ARE_V6ONLY" ] ; then + V6SOCKETS_ARE_V6ONLY=0 +fi + echo "Configuring compilation for [$OS_NAME] [$OS_VERSION] with [$FW] firewall software." echo "Please edit config.h for more compilation options." @@ -403,6 +411,15 @@ else fi echo "" >> ${CONFIGFILE} +echo "/* Define V6SOCKETS_ARE_V6ONLY if AF_INET6 sockets are restricted" >> ${CONFIGFILE} +echo " * to IPv6 communications only. */" >> ${CONFIGFILE} +if [ $V6SOCKETS_ARE_V6ONLY -eq 1 ] ; then + echo "#define V6SOCKETS_ARE_V6ONLY" >> ${CONFIGFILE} +else + echo "/*#define V6SOCKETS_ARE_V6ONLY*/" >> ${CONFIGFILE} +fi +echo "" >> ${CONFIGFILE} + echo "/* Enable the support of IGD v2 specification." >> ${CONFIGFILE} echo " * This is not fully tested yet and can cause incompatibilities with some" >> ${CONFIGFILE} echo " * control points, so enable with care. */" >> ${CONFIGFILE} diff --git a/miniupnpd/miniupnpd.c b/miniupnpd/miniupnpd.c index b215b6c..6616c63 100644 --- a/miniupnpd/miniupnpd.c +++ b/miniupnpd/miniupnpd.c @@ -112,7 +112,11 @@ volatile sig_atomic_t should_send_public_address_change_notif = 0; /* OpenAndConfHTTPSocket() : * setup the socket used to handle incoming HTTP connections. */ static int +#ifdef ENABLE_IPV6 +OpenAndConfHTTPSocket(unsigned short port, int ipv6) +#else OpenAndConfHTTPSocket(unsigned short port) +#endif { int s; int i = 1; @@ -126,7 +130,7 @@ OpenAndConfHTTPSocket(unsigned short port) if( (s = socket( #ifdef ENABLE_IPV6 - ipv6_enabled ? PF_INET6 : PF_INET, + ipv6 ? PF_INET6 : PF_INET, #else PF_INET, #endif @@ -155,7 +159,7 @@ OpenAndConfHTTPSocket(unsigned short port) } #ifdef ENABLE_IPV6 - if(ipv6_enabled) + if(ipv6) { memset(&listenname6, 0, sizeof(struct sockaddr_in6)); listenname6.sin6_family = AF_INET6; @@ -179,7 +183,7 @@ OpenAndConfHTTPSocket(unsigned short port) #ifdef ENABLE_IPV6 if(bind(s, - ipv6_enabled ? (struct sockaddr *)&listenname6 : (struct sockaddr *)&listenname4, + ipv6 ? (struct sockaddr *)&listenname6 : (struct sockaddr *)&listenname4, listenname_len) < 0) #else if(bind(s, (struct sockaddr *)&listenname, listenname_len) < 0) @@ -200,6 +204,84 @@ OpenAndConfHTTPSocket(unsigned short port) return s; } +static struct upnphttp * +ProcessIncomingHTTP(int shttpl) +{ + int shttp; + socklen_t clientnamelen; +#ifdef ENABLE_IPV6 + struct sockaddr_storage clientname; + clientnamelen = sizeof(struct sockaddr_storage); +#else + struct sockaddr_in clientname; + clientnamelen = sizeof(struct sockaddr_in); +#endif + shttp = accept(shttpl, (struct sockaddr *)&clientname, &clientnamelen); + if(shttp<0) + { + /* ignore EAGAIN, EWOULDBLOCK, EINTR, we just try again later */ + if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) + syslog(LOG_ERR, "accept(http): %m"); + } + else + { + struct upnphttp * tmp = 0; + char addr_str[64]; + + sockaddr_to_string((struct sockaddr *)&clientname, addr_str, sizeof(addr_str)); + syslog(LOG_INFO, "HTTP connection from %s", addr_str); + 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 + return tmp; + } + else + { + syslog(LOG_ERR, "New_upnphttp() failed"); + close(shttp); + } + } + } + return NULL; +} + #ifdef ENABLE_NFQUEUE int identify_ip_protocol(char *payload) { @@ -1368,6 +1450,9 @@ main(int argc, char * * argv) { int i; int shttpl = -1; /* socket for HTTP */ +#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6) + int shttpl_v4 = -1; /* socket for HTTP (ipv4 only) */ +#endif int sudp = -1; /* IP v4 socket for receiving SSDP */ #ifdef ENABLE_IPV6 int sudpv6 = -1; /* IP v6 socket for receiving SSDP */ @@ -1459,7 +1544,11 @@ main(int argc, char * * argv) { /* open socket for HTTP connections. Listen on the 1st LAN address */ +#ifdef ENABLE_IPV6 + shttpl = OpenAndConfHTTPSocket((v.port > 0) ? v.port : 0, 1); +#else /* ENABLE_IPV6 */ shttpl = OpenAndConfHTTPSocket((v.port > 0) ? v.port : 0); +#endif /* ENABLE_IPV6 */ if(shttpl < 0) { syslog(LOG_ERR, "Failed to open socket for HTTP. EXITING"); @@ -1475,6 +1564,14 @@ main(int argc, char * * argv) v.port = ntohs(sockinfo.sin_port); } syslog(LOG_NOTICE, "HTTP listening on port %d", v.port); +#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6) + shttpl_v4 = OpenAndConfHTTPSocket(v.port, 0); + if(shttpl_v4 < 0) + { + syslog(LOG_ERR, "Failed to open socket for HTTP on port %hu (IPv4). EXITING", v.port); + return 1; + } +#endif /* V6SOCKETS_ARE_V6ONLY */ #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", @@ -1692,6 +1789,13 @@ main(int argc, char * * argv) FD_SET(shttpl, &readset); max_fd = MAX( max_fd, shttpl); } +#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6) + if (shttpl_v4 >= 0) + { + FD_SET(shttpl_v4, &readset); + max_fd = MAX( max_fd, shttpl_v4); + } +#endif #ifdef ENABLE_IPV6 if (sudpv6 >= 0) { @@ -1930,79 +2034,24 @@ main(int argc, char * * argv) /* process incoming HTTP connections */ if(shttpl >= 0 && FD_ISSET(shttpl, &readset)) { - int shttp; - socklen_t clientnamelen; -#ifdef ENABLE_IPV6 - struct sockaddr_storage clientname; - clientnamelen = sizeof(struct sockaddr_storage); -#else - struct sockaddr_in clientname; - clientnamelen = sizeof(struct sockaddr_in); -#endif - shttp = accept(shttpl, (struct sockaddr *)&clientname, &clientnamelen); - if(shttp<0) + struct upnphttp * tmp; + tmp = ProcessIncomingHTTP(shttpl); + if(tmp) { - /* ignore EAGAIN, EWOULDBLOCK, EINTR, we just try again later */ - if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) - syslog(LOG_ERR, "accept(http): %m"); - } - else - { - struct upnphttp * tmp = 0; - char addr_str[64]; - - sockaddr_to_string((struct sockaddr *)&clientname, addr_str, sizeof(addr_str)); - syslog(LOG_INFO, "HTTP connection from %s", addr_str); - 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); - } - } + LIST_INSERT_HEAD(&upnphttphead, tmp, entries); } } +#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6) + if(shttpl_v4 >= 0 && FD_ISSET(shttpl_v4, &readset)) + { + struct upnphttp * tmp; + tmp = ProcessIncomingHTTP(shttpl_v4); + if(tmp) + { + LIST_INSERT_HEAD(&upnphttphead, tmp, entries); + } + } +#endif #ifdef ENABLE_NFQUEUE /* process NFQ packets */ if(nfqh >= 0 && FD_ISSET(nfqh, &readset)) @@ -2052,6 +2101,9 @@ shutdown: if (sudp >= 0) close(sudp); if (shttpl >= 0) close(shttpl); +#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6) + if (shttpl_v4 >= 0) close(shttpl_v4); +#endif #ifdef ENABLE_IPV6 if (sudpv6 >= 0) close(sudpv6); #endif From 7b13adafbd4dce38a2b58c571d16856ab27ee2f8 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 13 Mar 2014 11:26:53 +0100 Subject: [PATCH 077/127] miniupnpd: reduce number of global variables by using more runtime_flags change ipv6_enabled/ipv6fc_inbound_pinhole_allowed/ipv6fc_firewall_enabled global vars to flags in runtime_flags --- miniupnpd/Changelog.txt | 2 ++ miniupnpd/minissdp.c | 12 ++++++------ miniupnpd/miniupnpd.c | 6 +++--- miniupnpd/testupnpdescgen.c | 9 +++------ miniupnpd/upnpdescgen.c | 8 ++++---- miniupnpd/upnpglobalvars.c | 19 +------------------ miniupnpd/upnpglobalvars.h | 23 ++++++++--------------- miniupnpd/upnpsoap.c | 14 ++++++++------ 8 files changed, 35 insertions(+), 58 deletions(-) diff --git a/miniupnpd/Changelog.txt b/miniupnpd/Changelog.txt index 513aa01..7856b4e 100644 --- a/miniupnpd/Changelog.txt +++ b/miniupnpd/Changelog.txt @@ -3,6 +3,8 @@ $Id: Changelog.txt,v 1.362 2014/03/13 10:20:57 nanard Exp $ 2014/03/10: Enable PCP by default. Work in IPv6 on system where PF_INET6 are restricted to IPv6 only + change ipv6_enabled/ipv6fc_inbound_pinhole_allowed/ipv6fc_firewall_enabled + global vars to flags in runtime_flags 2014/03/09: IPv6 support in testgetifaddr diff --git a/miniupnpd/minissdp.c b/miniupnpd/minissdp.c index 9f5fc72..cdd6f08 100644 --- a/miniupnpd/minissdp.c +++ b/miniupnpd/minissdp.c @@ -1,4 +1,4 @@ -/* $Id: minissdp.c,v 1.58 2014/02/24 18:41:24 nanard Exp $ */ +/* $Id: minissdp.c,v 1.61 2014/03/10 11:04:51 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2014 Thomas Bernard @@ -281,16 +281,16 @@ OpenAndConfSSDPNotifySockets(int * sockets) goto error; i++; #ifdef ENABLE_IPV6 - if(ipv6_enabled) + if(GETFLAG(IPV6DISABLEDMASK)) + { + sockets[i] = -1; + } + else { sockets[i] = OpenAndConfSSDPNotifySocketIPv6(lan_addr->index); if(sockets[i] < 0) goto error; } - else - { - sockets[i] = -1; - } i++; #endif } diff --git a/miniupnpd/miniupnpd.c b/miniupnpd/miniupnpd.c index 6616c63..ccbbd8f 100644 --- a/miniupnpd/miniupnpd.c +++ b/miniupnpd/miniupnpd.c @@ -1,4 +1,4 @@ -/* $Id: miniupnpd.c,v 1.185 2014/02/28 12:14:26 nanard Exp $ */ +/* $Id: miniupnpd.c,v 1.189 2014/03/10 11:04:52 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2014 Thomas Bernard @@ -1579,7 +1579,7 @@ main(int argc, char * * argv) } else { memcpy(ipv6_addr_for_http_with_brackets, "[::1]", 6); syslog(LOG_WARNING, "no HTTP IPv6 address, disabling IPv6"); - ipv6_enabled = 0; + SETFLAG(IPV6DISABLEDMASK); } #endif @@ -1594,7 +1594,7 @@ main(int argc, char * * argv) } } #ifdef ENABLE_IPV6 - if(ipv6_enabled) + if(!GETFLAG(IPV6DISABLEDMASK)) { sudpv6 = OpenAndConfSSDPReceiveSocket(1); if(sudpv6 < 0) diff --git a/miniupnpd/testupnpdescgen.c b/miniupnpd/testupnpdescgen.c index c2cd028..ee30a8b 100644 --- a/miniupnpd/testupnpdescgen.c +++ b/miniupnpd/testupnpdescgen.c @@ -1,7 +1,7 @@ -/* $Id: testupnpdescgen.c,v 1.30 2013/06/13 13:21:30 nanard Exp $ */ +/* $Id: testupnpdescgen.c,v 1.32 2014/03/10 11:04:52 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2013 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -38,10 +38,7 @@ char model_url[] = ROOTDEV_MODELURL; char * use_ext_ip_addr = NULL; const char * ext_if_name = "eth0"; -#ifdef ENABLE_6FC_SERVICE -int ipv6fc_firewall_enabled = 1; -int ipv6fc_inbound_pinhole_allowed = 1; -#endif +int runtime_flags = 0; int getifaddr(const char * ifname, char * buf, int len, struct in_addr * addr, struct in_addr * mask) { diff --git a/miniupnpd/upnpdescgen.c b/miniupnpd/upnpdescgen.c index f88ea0b..5e5ebfb 100644 --- a/miniupnpd/upnpdescgen.c +++ b/miniupnpd/upnpdescgen.c @@ -1,7 +1,7 @@ -/* $Id: upnpdescgen.c,v 1.74 2013/06/13 13:21:30 nanard Exp $ */ +/* $Id: upnpdescgen.c,v 1.77 2014/03/10 11:04:53 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2013 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -1176,13 +1176,13 @@ genEventVars(int * len, const struct serviceDesc * s) case FIREWALLENABLED_MAGICALVALUE: /* see 2.4.2 of UPnP-gw-WANIPv6FirewallControl-v1-Service.pdf */ snprintf(tmp, sizeof(tmp), "%d", - ipv6fc_firewall_enabled); + GETFLAG(IPV6FCFWDISABLEDMASK) ? 0 : 1); str = strcat_str(str, len, &tmplen, tmp); break; case INBOUNDPINHOLEALLOWED_MAGICALVALUE: /* see 2.4.3 of UPnP-gw-WANIPv6FirewallControl-v1-Service.pdf */ snprintf(tmp, sizeof(tmp), "%d", - ipv6fc_inbound_pinhole_allowed); + GETFLAG(IPV6FCINBOUNDDISALLOWEDMASK) ? 0 : 1); str = strcat_str(str, len, &tmplen, tmp); break; #endif diff --git a/miniupnpd/upnpglobalvars.c b/miniupnpd/upnpglobalvars.c index ae4203c..9750f04 100644 --- a/miniupnpd/upnpglobalvars.c +++ b/miniupnpd/upnpglobalvars.c @@ -1,4 +1,4 @@ -/* $Id: upnpglobalvars.c,v 1.34 2014/02/06 09:52:03 nanard Exp $ */ +/* $Id: upnpglobalvars.c,v 1.35 2014/03/10 11:04:53 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2014 Thomas Bernard @@ -24,9 +24,6 @@ const char* lease_file = 0; * when NULL, getifaddr() is used */ const char * use_ext_ip_addr = 0; -/* LAN address */ -/*const char * listen_addr = 0;*/ - unsigned long downstream_bitrate = 0; unsigned long upstream_bitrate = 0; @@ -78,18 +75,10 @@ char model_url[MODEL_URL_MAX_LEN] = ROOTDEV_MODELURL; struct upnpperm * upnppermlist = 0; unsigned int num_upnpperm = 0; -#ifdef ENABLE_NATPMP -/* NAT-PMP */ -#if 0 -unsigned int nextnatpmptoclean_timestamp = 0; -unsigned short nextnatpmptoclean_eport = 0; -unsigned short nextnatpmptoclean_proto = 0; -#endif #ifdef PCP_SADSCP struct dscp_values* dscp_values_list = 0; unsigned int num_dscp_values = 0; #endif /*PCP_SADSCP*/ -#endif /* For automatic removal of expired rules (with LeaseDuration) */ unsigned int nextruletoclean_timestamp = 0; @@ -121,7 +110,6 @@ struct lan_addr_list lan_addrs; #ifdef ENABLE_IPV6 /* ipv6 address used for HTTP */ char ipv6_addr_for_http_with_brackets[64]; -int ipv6_enabled = 1; #endif /* Path of the Unix socket used to communicate with MiniSSDPd */ @@ -131,8 +119,3 @@ const char * minissdpdsocketpath = "/var/run/minissdpd.sock"; unsigned int upnp_bootid = 1; unsigned int upnp_configid = 1337; -#ifdef ENABLE_6FC_SERVICE -int ipv6fc_firewall_enabled = 1; -int ipv6fc_inbound_pinhole_allowed = 1; -#endif - diff --git a/miniupnpd/upnpglobalvars.h b/miniupnpd/upnpglobalvars.h index fb67428..bbfccef 100644 --- a/miniupnpd/upnpglobalvars.h +++ b/miniupnpd/upnpglobalvars.h @@ -1,4 +1,4 @@ -/* $Id: upnpglobalvars.h,v 1.37 2014/02/06 09:52:03 nanard Exp $ */ +/* $Id: upnpglobalvars.h,v 1.38 2014/03/10 11:04:53 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2014 Thomas Bernard @@ -51,6 +51,13 @@ extern int runtime_flags; #ifdef PF_ENABLE_FILTER_RULES #define PFNOQUICKRULESMASK 0x0040 #endif +#ifdef ENABLE_IPV6 +#define IPV6DISABLEDMASK 0x0080 +#endif +#ifdef ENABLE_6FC_SERVICE +#define IPV6FCFWDISABLEDMASK 0x0100 +#define IPV6FCINBOUNDDISALLOWEDMASK 0x0200 +#endif #define SETFLAG(mask) runtime_flags |= mask #define GETFLAG(mask) (runtime_flags & mask) @@ -95,18 +102,10 @@ extern char model_url[]; extern struct upnpperm * upnppermlist; extern unsigned int num_upnpperm; -#ifdef ENABLE_NATPMP -/* NAT-PMP */ -#if 0 -extern unsigned int nextnatpmptoclean_timestamp; -extern unsigned short nextnatpmptoclean_eport; -extern unsigned short nextnatpmptoclean_proto; -#endif #ifdef PCP_SADSCP extern struct dscp_values* dscp_values_list; extern unsigned int num_dscp_values; #endif -#endif /* For automatic removal of expired rules (with LeaseDuration) */ extern unsigned int nextruletoclean_timestamp; @@ -139,7 +138,6 @@ extern struct lan_addr_list lan_addrs; #ifdef ENABLE_IPV6 /* ipv6 address used for HTTP */ extern char ipv6_addr_for_http_with_brackets[64]; -extern int ipv6_enabled; #endif extern const char * minissdpdsocketpath; @@ -148,10 +146,5 @@ extern const char * minissdpdsocketpath; extern unsigned int upnp_bootid; extern unsigned int upnp_configid; -#ifdef ENABLE_6FC_SERVICE -extern int ipv6fc_firewall_enabled; -extern int ipv6fc_inbound_pinhole_allowed; -#endif - #endif diff --git a/miniupnpd/upnpsoap.c b/miniupnpd/upnpsoap.c index fc08ecb..21fc33b 100644 --- a/miniupnpd/upnpsoap.c +++ b/miniupnpd/upnpsoap.c @@ -1,7 +1,7 @@ -/* $Id: upnpsoap.c,v 1.121 2014/02/28 15:01:31 nanard Exp $ */ +/* $Id: upnpsoap.c,v 1.122 2014/03/10 11:04:53 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2013 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -1220,19 +1220,21 @@ GetFirewallStatus(struct upnphttp * h, const char * action) bodylen = snprintf(body, sizeof(body), resp, action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", - ipv6fc_firewall_enabled, ipv6fc_inbound_pinhole_allowed, action); + GETFLAG(IPV6FCFWDISABLEDMASK) ? 0 : 1, + GETFLAG(IPV6FCINBOUNDDISALLOWEDMASK) ? 0 : 1, + action); BuildSendAndCloseSoapResp(h, body, bodylen); } static int CheckStatus(struct upnphttp * h) { - if (!ipv6fc_firewall_enabled) + if (GETFLAG(IPV6FCFWDISABLEDMASK)) { SoapError(h, 702, "FirewallDisabled"); return 0; } - else if(!ipv6fc_inbound_pinhole_allowed) + else if(GETFLAG(IPV6FCINBOUNDDISALLOWEDMASK)) { SoapError(h, 703, "InboundPinholeNotAllowed"); return 0; @@ -1604,7 +1606,7 @@ GetOutboundPinholeTimeout(struct upnphttp * h, const char * action) int opt=0, proto=0; unsigned short iport, rport; - if (!ipv6fc_firewall_enabled) + if (GETFLAG(IPV6FCFWDISABLEDMASK)) { SoapError(h, 702, "FirewallDisabled"); return; From 62d6c860ce83171c6c22d86d4e26c00f7a5a59a2 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 13 Mar 2014 11:30:53 +0100 Subject: [PATCH 078/127] catch up Changelog.txt see commit 3ed34783981881856b14dcd3e98246495dc6e419 --- miniupnpd/Changelog.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/miniupnpd/Changelog.txt b/miniupnpd/Changelog.txt index 7856b4e..18cac00 100644 --- a/miniupnpd/Changelog.txt +++ b/miniupnpd/Changelog.txt @@ -1,5 +1,9 @@ $Id: Changelog.txt,v 1.362 2014/03/13 10:20:57 nanard Exp $ +2014/03/13: + fix getifaddr_in6() (used for PCP) + implement permissions with PCP Map + 2014/03/10: Enable PCP by default. Work in IPv6 on system where PF_INET6 are restricted to IPv6 only From 9f665b572fe43e2186b9d954ced9ba22979ae39c Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 13 Mar 2014 11:31:34 +0100 Subject: [PATCH 079/127] miniupnpd: fix BSD Makefile --- miniupnpd/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miniupnpd/Makefile b/miniupnpd/Makefile index e404609..0025377 100644 --- a/miniupnpd/Makefile +++ b/miniupnpd/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.74 2013/12/13 15:28:34 nanard Exp $ +# $Id: Makefile,v 1.76 2014/03/10 10:26:15 nanard Exp $ # MiniUPnP project # http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ # Author: Thomas Bernard @@ -116,7 +116,7 @@ TESTUPNPDESCGENOBJS = testupnpdescgen.o upnpdescgen.o TESTUPNPPERMISSIONSOBJS = testupnppermissions.o upnppermissions.o TESTGETIFADDROBJS = testgetifaddr.o getifaddr.o MINIUPNPDCTLOBJS = miniupnpdctl.o -TESTASYNCSENDTOOBJS = testasyncsendto.o asyncsendto.o upnputils.o +TESTASYNCSENDTOOBJS = testasyncsendto.o asyncsendto.o upnputils.o bsd/getroute.o EXECUTABLES = miniupnpd testupnpdescgen testgetifstats \ testupnppermissions miniupnpdctl \ From 8d93ddb07672c73ef880ec76e63d3b380b503c32 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 13 Mar 2014 11:31:51 +0100 Subject: [PATCH 080/127] miniupnpd: change IP change msg from LOG_DEBUG to LOG_INFO --- miniupnpd/miniupnpd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miniupnpd/miniupnpd.c b/miniupnpd/miniupnpd.c index ccbbd8f..3a8be99 100644 --- a/miniupnpd/miniupnpd.c +++ b/miniupnpd/miniupnpd.c @@ -1676,7 +1676,7 @@ main(int argc, char * * argv) /* 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)"); + syslog(LOG_INFO, "should send external iface address change notification(s)"); #ifdef ENABLE_NATPMP if(GETFLAG(ENABLENATPMPMASK)) SendNATPMPPublicAddressChangeNotification(snatpmp, addr_count); From a7d9071c5a03b6009cf3a0e4e62a15a6112e72fd Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 13 Mar 2014 11:56:28 +0100 Subject: [PATCH 081/127] miniupnpd/upnpevents.c: fix upnp_event_notify_connect() when ENABLE_IPV6 is set --- miniupnpd/Changelog.txt | 3 ++- miniupnpd/upnpevents.c | 13 ++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/miniupnpd/Changelog.txt b/miniupnpd/Changelog.txt index 18cac00..6fe9f06 100644 --- a/miniupnpd/Changelog.txt +++ b/miniupnpd/Changelog.txt @@ -1,8 +1,9 @@ -$Id: Changelog.txt,v 1.362 2014/03/13 10:20:57 nanard Exp $ +$Id: Changelog.txt,v 1.363 2014/03/13 10:53:40 nanard Exp $ 2014/03/13: fix getifaddr_in6() (used for PCP) implement permissions with PCP Map + fix upnp_event_notify_connect() when ENABLE_IPV6 is set 2014/03/10: Enable PCP by default. diff --git a/miniupnpd/upnpevents.c b/miniupnpd/upnpevents.c index 660ccc0..617da21 100644 --- a/miniupnpd/upnpevents.c +++ b/miniupnpd/upnpevents.c @@ -1,4 +1,4 @@ -/* $Id: upnpevents.c,v 1.27 2013/06/13 13:21:30 nanard Exp $ */ +/* $Id: upnpevents.c,v 1.28 2014/03/13 10:53:40 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2008-2013 Thomas Bernard @@ -233,8 +233,10 @@ upnp_event_notify_connect(struct upnp_event_notify * obj) unsigned short port; #ifdef ENABLE_IPV6 struct sockaddr_storage addr; + socklen_t addrlen; #else struct sockaddr_in addr; + socklen_t addrlen; #endif if(!obj) return; @@ -283,23 +285,28 @@ upnp_event_notify_connect(struct upnp_event_notify * obj) sa->sin6_family = AF_INET6; inet_pton(AF_INET6, obj->addrstr, &(sa->sin6_addr)); sa->sin6_port = htons(port); + addrlen = sizeof(struct sockaddr_in6); } else { struct sockaddr_in * sa = (struct sockaddr_in *)&addr; sa->sin_family = AF_INET; inet_pton(AF_INET, obj->addrstr, &(sa->sin_addr)); sa->sin_port = htons(port); + addrlen = sizeof(struct sockaddr_in); } #else addr.sin_family = AF_INET; inet_aton(obj->addrstr, &addr.sin_addr); addr.sin_port = htons(port); + addrlen = sizeof(struct sockaddr_in); #endif syslog(LOG_DEBUG, "%s: '%s' %hu '%s'", "upnp_event_notify_connect", obj->addrstr, port, obj->path); obj->state = EConnecting; - if(connect(obj->s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + if(connect(obj->s, (struct sockaddr *)&addr, addrlen) < 0) { if(errno != EINPROGRESS && errno != EWOULDBLOCK) { - syslog(LOG_ERR, "%s: connect(): %m", "upnp_event_notify_connect"); + syslog(LOG_ERR, "%s: connect(%d, %s, %u): %m", + "upnp_event_notify_connect", obj->s, + obj->addrstr, addrlen); obj->state = EError; } } From c4e63048c43912fd016fe95b41e1bc37838c2fa5 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 13 Mar 2014 14:48:52 +0100 Subject: [PATCH 082/127] miniupnpd: add CHECK_PORTINUSE to enable/disable port_in_use() --- miniupnpd/genconfig.sh | 12 +++++++++++- miniupnpd/natpmp.c | 2 ++ miniupnpd/portinuse.c | 16 ++++++++++++---- miniupnpd/portinuse.h | 13 ++++++++----- miniupnpd/upnpredirect.c | 5 +++-- 5 files changed, 36 insertions(+), 12 deletions(-) diff --git a/miniupnpd/genconfig.sh b/miniupnpd/genconfig.sh index 13a54e6..1089876 100755 --- a/miniupnpd/genconfig.sh +++ b/miniupnpd/genconfig.sh @@ -14,6 +14,7 @@ case "$argv" in --leasefile) LEASEFILE=1 ;; --vendorcfg) VENDORCFG=1 ;; --pcp-peer) PCP_PEER=1 ;; + --portinuse) PORTINUSE=1 ;; --help|-h) echo "Usage : $0 [options]" echo " --ipv6 enable IPv6" @@ -22,6 +23,7 @@ case "$argv" in echo " --leasefile enable lease file" echo " --vendorcfg enable configuration of manufacturer info" echo " --pcp-peer enable PCP PEER operation" + echo " --portinuse enable port in use check" exit 1 ;; *) @@ -395,6 +397,14 @@ else fi echo "" >> ${CONFIGFILE} +echo "/* Uncomment the following line to enable port in use check */" >> ${CONFIGFILE} +if [ -n "$PORTINUSE" ]; then + echo "#define CHECK_PORTINUSE" >> ${CONFIGFILE} +else + echo "/*#define CHECK_PORTINUSE*/" >> ${CONFIGFILE} +fi +echo "" >> ${CONFIGFILE} + echo "/* Define one or none of the two following macros in order to make some" >> ${CONFIGFILE} echo " * clients happy. It will change the XML Root Description of the IGD." >> ${CONFIGFILE} echo " * Enabling the Layer3Forwarding Service seems to be the more compatible" >> ${CONFIGFILE} @@ -497,7 +507,7 @@ else fi echo "" >> ${CONFIGFILE} -echo "#endif" >> ${CONFIGFILE} +echo "#endif /* ${CONFIGMACRO} */" >> ${CONFIGFILE} ${MV} ${CONFIGFILE} ${CONFIGFILE_FINAL} diff --git a/miniupnpd/natpmp.c b/miniupnpd/natpmp.c index b98a5c2..2bacb8f 100644 --- a/miniupnpd/natpmp.c +++ b/miniupnpd/natpmp.c @@ -292,12 +292,14 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, continue; } any_eport_allowed = 1; /* at lease one eport is allowed */ +#ifdef CHECK_PORTINUSE if (port_in_use(ext_if_name, eport, proto, senderaddrstr, iport)) { syslog(LOG_INFO, "port %hu protocol %s already in use", eport, (proto==IPPROTO_TCP)?"tcp":"udp"); eport++; if(eport == 0) eport++; /* skip port zero */ continue; } +#endif r = get_redirect_rule(ext_if_name, eport, proto, iaddr_old, sizeof(iaddr_old), &iport_old, 0, 0, 0, 0, diff --git a/miniupnpd/portinuse.c b/miniupnpd/portinuse.c index a4a1fed..d62a9a2 100644 --- a/miniupnpd/portinuse.c +++ b/miniupnpd/portinuse.c @@ -1,6 +1,6 @@ -/* */ +/* $Id $ */ /* MiniUPnP project - * (c) 2007-2013 Thomas Bernard + * (c) 2007-2014 Thomas Bernard * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -21,10 +21,16 @@ #include "getifaddr.h" #include "portinuse.h" +#if defined(USE_NETFILTER) #include "netfilter/iptcrdr.h" +#endif +#ifdef CHECK_PORTINUSE + +#if defined(USE_NETFILTER) /* Hardcoded for now. Ideally would come from .conf file */ char *chains_to_check[] = { "PREROUTING" , 0 }; +#endif int port_in_use(const char *if_name, unsigned eport, int proto, const char *iaddr, unsigned iport) { @@ -72,13 +78,14 @@ int port_in_use(const char *if_name, unsigned eport, int proto, const char *iadd } fclose(f); +#if defined(USE_NETFILTER) if (!found) { char iaddr_old[16]; unsigned short iport_old; int i = 0; while (chains_to_check[i]) { if (get_nat_redirect_rule(chains_to_check[i], if_name, eport, proto, - iaddr_old, sizeof(iaddr_old),&iport_old, + iaddr_old, sizeof(iaddr_old), &iport_old, 0, 0, 0, 0, 0, 0, 0) == 0) { syslog(LOG_DEBUG, "port_in_use check port %d on nat chain %s redirected to %s port %d", eport, @@ -92,6 +99,7 @@ int port_in_use(const char *if_name, unsigned eport, int proto, const char *iadd i++; } } +#endif /* USE_NETFILTER */ return found; } - +#endif /* CHECK_PORTINUSE */ diff --git a/miniupnpd/portinuse.h b/miniupnpd/portinuse.h index 8029008..fddc7c8 100644 --- a/miniupnpd/portinuse.h +++ b/miniupnpd/portinuse.h @@ -1,19 +1,22 @@ -/* */ +/* $Id $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2011 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ #ifndef __PORTINUSE_H__ #define __PORTINUSE_H__ +#ifdef CHECK_PORTINUSE /* portinuse() - * determine wither a port is already in use + * determine wether a port is already in use * on a given interface. * returns: 0 not in use, 1 in use */ int -port_in_use(const char *if_name, unsigned port, int proto, const char *iaddr, unsigned iport); +port_in_use(const char *if_name, + unsigned port, int proto, + const char *iaddr, unsigned iport); +#endif /* CHECK_PORTINUSE */ #endif - diff --git a/miniupnpd/upnpredirect.c b/miniupnpd/upnpredirect.c index 8306ce6..0139a7d 100644 --- a/miniupnpd/upnpredirect.c +++ b/miniupnpd/upnpredirect.c @@ -295,10 +295,11 @@ upnp_redirect(const char * rhost, unsigned short eport, eport, protocol, iaddr_old, iport_old); return -2; } - } - else if (port_in_use(ext_if_name, eport, proto, iaddr, iport)) { +#ifdef CHECK_PORTINUSE + } else if (port_in_use(ext_if_name, eport, proto, iaddr, iport)) { syslog(LOG_INFO, "port %hu protocol %s already in use", eport, protocol); return -2; +#endif /* CHECK_PORTINUSE */ } else { timestamp = (leaseduration > 0) ? time(NULL) + leaseduration : 0; syslog(LOG_INFO, "redirecting port %hu to %s:%hu protocol %s for: %s", From 15a2320c867d512bc4c8d11318ffde2b0e336b7b Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 13 Mar 2014 14:49:05 +0100 Subject: [PATCH 083/127] miniupnpd/portinuse.c/iptcrdr.c: cosmetic changes --- miniupnpd/netfilter/iptcrdr.c | 8 ++++++-- miniupnpd/portinuse.c | 9 ++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/miniupnpd/netfilter/iptcrdr.c b/miniupnpd/netfilter/iptcrdr.c index 1b58be6..e5951e8 100644 --- a/miniupnpd/netfilter/iptcrdr.c +++ b/miniupnpd/netfilter/iptcrdr.c @@ -285,8 +285,12 @@ get_redirect_rule(const char * ifname, unsigned short eport, int proto, unsigned int * timestamp, u_int64_t * packets, u_int64_t * bytes) { - return get_nat_redirect_rule(miniupnpd_nat_chain, ifname, eport, proto, iaddr, iaddrlen, iport, - desc, desclen, rhost, rhostlen,timestamp, packets, bytes); + return get_nat_redirect_rule(miniupnpd_nat_chain, + ifname, eport, proto, + iaddr, iaddrlen, iport, + desc, desclen, + rhost, rhostlen, + timestamp, packets, bytes); } int diff --git a/miniupnpd/portinuse.c b/miniupnpd/portinuse.c index d62a9a2..2c20f48 100644 --- a/miniupnpd/portinuse.c +++ b/miniupnpd/portinuse.c @@ -32,15 +32,18 @@ char *chains_to_check[] = { "PREROUTING" , 0 }; #endif -int port_in_use(const char *if_name, unsigned eport, int proto, const char *iaddr, unsigned iport) +int +port_in_use(const char *if_name, + unsigned eport, int proto, + const char *iaddr, unsigned iport) { char line[256]; FILE *f; int found = 0; char ip_addr_str[INET_ADDRSTRLEN]; struct in_addr ip_addr; - const char tcpfile[] = "/proc/net/tcp"; - const char udpfile[] = "/proc/net/udp"; + const char * tcpfile = "/proc/net/tcp"; + const char * udpfile = "/proc/net/udp"; f = fopen((proto==IPPROTO_TCP)?tcpfile:udpfile, "r"); if (!f) return 0; From 09bbaac63a88505078e5420799fee11146e97712 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 13 Mar 2014 14:58:36 +0100 Subject: [PATCH 084/127] miniupnpd/portinuse.c: add #ifdef __linux__ TODO : BSD Code --- miniupnpd/portinuse.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/miniupnpd/portinuse.c b/miniupnpd/portinuse.c index 2c20f48..e12b5a5 100644 --- a/miniupnpd/portinuse.c +++ b/miniupnpd/portinuse.c @@ -37,11 +37,13 @@ port_in_use(const char *if_name, unsigned eport, int proto, const char *iaddr, unsigned iport) { - char line[256]; - FILE *f; int found = 0; char ip_addr_str[INET_ADDRSTRLEN]; struct in_addr ip_addr; +#ifdef __linux__ + /* linux code */ + char line[256]; + FILE *f; const char * tcpfile = "/proc/net/tcp"; const char * udpfile = "/proc/net/udp"; @@ -80,6 +82,7 @@ port_in_use(const char *if_name, } } fclose(f); +#endif /* __linux__ */ #if defined(USE_NETFILTER) if (!found) { From acbe15c5eadcc163bdd52891fb40637beb296538 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 14 Mar 2014 09:21:11 +0100 Subject: [PATCH 085/127] miniupnpc: fix exported symbols in OS X dynlibs fixes #63 --- miniupnpc/declspec.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/miniupnpc/declspec.h b/miniupnpc/declspec.h index f66b6d7..7729969 100644 --- a/miniupnpc/declspec.h +++ b/miniupnpc/declspec.h @@ -2,13 +2,19 @@ #define DECLSPEC_H_INCLUDED #if defined(_WIN32) && !defined(STATICLIB) + /* for windows dll */ #ifdef MINIUPNP_EXPORTS #define LIBSPEC __declspec(dllexport) #else #define LIBSPEC __declspec(dllimport) #endif #else - #define LIBSPEC + #if defined(__GNUC__) && __GNUC__ >= 4 + /* fix dynlib for OS X 10.9.2 and Apple LLVM version 5.0 */ + #define LIBSPEC __attribute__ ((visibility ("default"))) + #else + #define LIBSPEC + #endif #endif #endif From 7cb493919fd7e5b88b8e9c947d51cd731b1a657b Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 14 Mar 2014 10:04:49 +0100 Subject: [PATCH 086/127] miniupnpd/getifaddr.c: don't use getifaddrs() in IPv4 only should fix #62 : Don't use getifaddrs() in IPv4 only so we avoid problems if getifaddrs() implementation is buggy --- miniupnpd/getifaddr.c | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/miniupnpd/getifaddr.c b/miniupnpd/getifaddr.c index f3459a5..be57050 100644 --- a/miniupnpd/getifaddr.c +++ b/miniupnpd/getifaddr.c @@ -1,7 +1,7 @@ /* $Id: getifaddr.c,v 1.19 2013/12/13 14:28:40 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2013 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -55,11 +55,14 @@ getifaddr(const char * ifname, char * buf, int len, } ifaddr = (struct sockaddr_in *)&ifr.ifr_addr; if(addr) *addr = ifaddr->sin_addr; - if(!inet_ntop(AF_INET, &ifaddr->sin_addr, buf, len)) + if(buf) { - syslog(LOG_ERR, "inet_ntop(): %m"); - close(s); - return -1; + if(!inet_ntop(AF_INET, &ifaddr->sin_addr, buf, len)) + { + syslog(LOG_ERR, "inet_ntop(): %m"); + close(s); + return -1; + } } if(mask) { @@ -99,9 +102,12 @@ getifaddr(const char * ifname, char * buf, int len, switch(ife->ifa_addr->sa_family) { case AF_INET: - inet_ntop(ife->ifa_addr->sa_family, - &((struct sockaddr_in *)ife->ifa_addr)->sin_addr, - buf, len); + if(buf) + { + inet_ntop(ife->ifa_addr->sa_family, + &((struct sockaddr_in *)ife->ifa_addr)->sin_addr, + buf, len); + } if(addr) *addr = ((struct sockaddr_in *)ife->ifa_addr)->sin_addr; if(mask) *mask = ((struct sockaddr_in *)ife->ifa_netmask)->sin_addr; break; @@ -123,6 +129,7 @@ getifaddr(const char * ifname, char * buf, int len, * IPv4 or IPv6 if both are enabled... */ int getifaddr_in6(const char * ifname, struct in6_addr * addr) { +#if defined(ENABLE_IPV6) || defined(USE_GETIFADDRS) struct ifaddrs * ifap; struct ifaddrs * ife; #ifdef ENABLE_IPV6 @@ -174,6 +181,18 @@ int getifaddr_in6(const char * ifname, struct in6_addr * addr) } freeifaddrs(ifap); return (found ? 0 : -1); +#else /* defined(ENABLE_IPV6) || defined(USE_GETIFADDRS) */ + /* IPv4 only */ + struct in_addr addr4; + if(getifaddr(ifname, NULL, 0, &addr4, NULL) < 0) + return -1; + /* IPv4-mapped IPv6 address ::ffff:1.2.3.4 */ + memset(addr->s6_addr, 0, 10); + addr->s6_addr[10] = 0xff; + addr->s6_addr[11] = 0xff; + memcpy(addr->s6_addr + 12, &addr4.s_addr, 4); + return 0; +#endif } #endif /* ENABLE_PCP */ From dcce22647d9f867e56c8f2485b53a4ea3f7d0186 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 14 Mar 2014 12:07:03 +0100 Subject: [PATCH 087/127] miniupnpd: add testportinuse test program --- miniupnpd/Makefile | 13 ++++++--- miniupnpd/Makefile.linux | 11 +++++--- miniupnpd/testportinuse.c | 56 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 6 deletions(-) create mode 100644 miniupnpd/testportinuse.c diff --git a/miniupnpd/Makefile b/miniupnpd/Makefile index 0025377..93e63a8 100644 --- a/miniupnpd/Makefile +++ b/miniupnpd/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.76 2014/03/10 10:26:15 nanard Exp $ +# $Id: Makefile,v 1.76.2.2 2014/03/14 10:49:08 nanard Exp $ # MiniUPnP project # http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ # Author: Thomas Bernard @@ -117,10 +117,13 @@ TESTUPNPPERMISSIONSOBJS = testupnppermissions.o upnppermissions.o TESTGETIFADDROBJS = testgetifaddr.o getifaddr.o MINIUPNPDCTLOBJS = miniupnpdctl.o TESTASYNCSENDTOOBJS = testasyncsendto.o asyncsendto.o upnputils.o bsd/getroute.o +TESTPORTINUSEOBJS = testportinuse.o portinuse.o getifaddr.o EXECUTABLES = miniupnpd testupnpdescgen testgetifstats \ testupnppermissions miniupnpdctl \ - testgetifaddr testgetroute testasyncsendto + testgetifaddr testgetroute testasyncsendto \ + testportinuse + .if $(OSNAME) == "Darwin" LIBS = .else @@ -144,6 +147,7 @@ clean: testupnpdescgen.o \ $(MISCOBJS) config.h testgetifstats.o testupnppermissions.o \ miniupnpdctl.o testgetifaddr.o testgetroute.o testasyncsendto.o \ + testportinuse.o \ $(PFOBJS) $(IPFOBJS) $(IPFWOBJS) install: miniupnpd genuuid @@ -174,7 +178,7 @@ genuuid: depend: config.h mkdep $(ALLOBJS:.o=.c) testupnpdescgen.c testgetifstats.c \ testupnppermissions.c miniupnpdctl.c testgetifaddr.c \ - testgetroute.c + testgetroute.c testportinuse.c testasyncsendto.c miniupnpd: config.h $(ALLOBJS) $(CC) $(CFLAGS) -o $@ $(ALLOBJS) $(LIBS) @@ -203,6 +207,9 @@ testgetroute: config.h $(TESTGETROUTEOBJS) testasyncsendto: config.h $(TESTASYNCSENDTOOBJS) $(CC) $(CFLAGS) -o $@ $(TESTASYNCSENDTOOBJS) +testportinuse: config.h $(TESTPORTINUSEOBJS) + $(CC) $(CFLAGS) -o $@ $(TESTPORTINUSEOBJS) -lkvm + # gmake : # $(CC) $(CFLAGS) -o $@ $^ # BSDmake : diff --git a/miniupnpd/Makefile.linux b/miniupnpd/Makefile.linux index 27639b2..90e8c94 100644 --- a/miniupnpd/Makefile.linux +++ b/miniupnpd/Makefile.linux @@ -1,4 +1,4 @@ -# $Id: Makefile.linux,v 1.81 2014/01/27 10:06:58 nanard Exp $ +# $Id: Makefile.linux,v 1.83.2.3 2014/03/14 11:04:06 nanard Exp $ # MiniUPnP project # (c) 2006-2014 Thomas Bernard # http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ @@ -150,7 +150,7 @@ TESTUPNPDESCGENOBJS = testupnpdescgen.o upnpdescgen.o EXECUTABLES = miniupnpd testupnpdescgen testgetifstats \ testupnppermissions miniupnpdctl testgetifaddr \ - testgetroute testasyncsendto + testgetroute testasyncsendto testportinuse .PHONY: all clean install depend genuuid @@ -208,6 +208,9 @@ testgetroute: testgetroute.o linux/getroute.o upnputils.o -lnfnetlink testasyncsendto: testasyncsendto.o asyncsendto.o upnputils.o \ linux/getroute.o -lnfnetlink +testportinuse: testportinuse.o portinuse.o getifaddr.o \ + netfilter/iptcrdr.o $(LIBS) + miniupnpdctl: miniupnpdctl.o config.h: genconfig.sh VERSION @@ -217,7 +220,8 @@ depend: config.h makedepend -f$(MAKEFILE_LIST) -Y \ $(ALLOBJS:.o=.c) $(TESTUPNPDESCGENOBJS:.o=.c) \ testgetifstats.c testupnppermissions.c testgetifaddr.c \ - testgetroute.c testasyncsendto.c miniupnpdctl.c 2>/dev/null + testgetroute.c testasyncsendto.c testportinuse.c \ + miniupnpdctl.c 2>/dev/null # DO NOT DELETE @@ -292,4 +296,5 @@ testgetifaddr.o: config.h getifaddr.h testgetroute.o: getroute.h upnputils.h upnpglobalvars.h upnppermissions.h testgetroute.o: config.h miniupnpdtypes.h testasyncsendto.o: miniupnpdtypes.h config.h upnputils.h asyncsendto.h +testportinuse.o: macros.h config.h portinuse.h miniupnpdctl.o: macros.h diff --git a/miniupnpd/testportinuse.c b/miniupnpd/testportinuse.c new file mode 100644 index 0000000..0efc42f --- /dev/null +++ b/miniupnpd/testportinuse.c @@ -0,0 +1,56 @@ +/* $Id $ */ +/* MiniUPnP project + * (c) 2014 Thomas Bernard + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ +#include +#include +#include +#include +#include + +#include "macros.h" +#include "config.h" +#include "portinuse.h" + +#ifdef CHECK_PORTINUSE +#ifdef USE_NETFILTER +const char * miniupnpd_nat_chain = "MINIUPNPD"; +const char * miniupnpd_peer_chain = "MINIUPNPD-PCP-PEER"; +const char * miniupnpd_forward_chain = "MINIUPNPD"; +#endif /* USE_NETFILTER */ +#endif /* CHECK_PORTINUSE */ + +int main(int argc, char * * argv) +{ +#ifndef CHECK_PORTINUSE + UNUSED(argc); UNUSED(argv); + printf("CHECK_PORTINUSE is not defined.\n"); +#else /* CHECK_PORTINUSE */ + int r; + const char * if_name; + unsigned eport; + int proto; + const char * iaddr; + unsigned iport; + + if(argc <= 5) { + fprintf(stderr, "usage: %s if_name eport (tcp|udp) iaddr iport\n", + argv[0]); + return 1; + } + openlog("testportinuse", LOG_CONS|LOG_PERROR, LOG_USER); + if_name = argv[1]; + eport = (unsigned)atoi(argv[2]); + proto = (0==strcmp(argv[3], "tcp"))?IPPROTO_TCP:IPPROTO_UDP; + iaddr = argv[4]; + iport = (unsigned)atoi(argv[5]); + + r = port_in_use(if_name, eport, proto, iaddr, iport); + printf("port_in_use(%s, %u, %d, %s, %u) returned %d\n", + if_name, eport, proto, iaddr, iport, r); + closelog(); +#endif /* CHECK_PORTINUSE */ + return 0; +} From 3629b10ff5d6015c4259c934c0410b7aee89c396 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 14 Mar 2014 12:08:13 +0100 Subject: [PATCH 088/127] miniupnpd: add port_in_use() implementation for OpenBSD --- miniupnpd/Makefile | 2 +- miniupnpd/portinuse.c | 99 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 93 insertions(+), 8 deletions(-) diff --git a/miniupnpd/Makefile b/miniupnpd/Makefile index 93e63a8..5db6fbd 100644 --- a/miniupnpd/Makefile +++ b/miniupnpd/Makefile @@ -80,7 +80,7 @@ STDOBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \ upnpredirect.o getifaddr.o daemonize.o upnpglobalvars.o \ options.o upnppermissions.o minissdp.o natpmp.o pcpserver.o \ upnpevents.o upnputils.o getconnstatus.o \ - upnppinhole.o asyncsendto.o + upnppinhole.o asyncsendto.o portinuse.o BSDOBJS = bsd/getifstats.o bsd/ifacewatcher.o bsd/getroute.o SUNOSOBJS = solaris/getifstats.o bsd/ifacewatcher.o bsd/getroute.o MACOBJS = mac/getifstats.o bsd/ifacewatcher.o bsd/getroute.o diff --git a/miniupnpd/portinuse.c b/miniupnpd/portinuse.c index e12b5a5..48fb91f 100644 --- a/miniupnpd/portinuse.c +++ b/miniupnpd/portinuse.c @@ -14,6 +14,25 @@ #include #include #include +#if defined(__OpenBSD__) +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* +#include +#include +#include +#include +#include +#include +*/ +#endif #include "macros.h" #include "config.h" @@ -46,16 +65,21 @@ port_in_use(const char *if_name, FILE *f; const char * tcpfile = "/proc/net/tcp"; const char * udpfile = "/proc/net/udp"; - - f = fopen((proto==IPPROTO_TCP)?tcpfile:udpfile, "r"); - if (!f) return 0; +#endif if(getifaddr(if_name, ip_addr_str, INET_ADDRSTRLEN, &ip_addr, NULL) < 0) ip_addr.s_addr = 0; - syslog(LOG_DEBUG, "Check protocol %s for port %d on ext_if %s %s, %8X", + syslog(LOG_DEBUG, "Check protocol %s for port %d on ext_if %s %s, %08X", (proto==IPPROTO_TCP)?"tcp":"udp", eport, if_name, ip_addr_str, (unsigned)ip_addr.s_addr); +#ifdef __linux__ + f = fopen((proto==IPPROTO_TCP)?tcpfile:udpfile, "r"); + if (!f) { + syslog(LOG_ERR, "cannot open %s", (proto==IPPROTO_TCP)?tcpfile:udpfile); + return 0; + } + while (fgets(line, 255, f)) { char eaddr[68]; unsigned tmp_port; @@ -84,12 +108,72 @@ port_in_use(const char *if_name, fclose(f); #endif /* __linux__ */ +#if defined(__OpenBSD__) +static struct nlist list[] = { +#if 0 + {"_tcpstat", 0, 0, 0, 0}, + {"_udpstat", 0, 0, 0, 0}, + {"_tcbinfo", 0, 0, 0, 0}, + {"_udbinfo", 0, 0, 0, 0}, +#endif + {"_tcbtable", 0, 0, 0, 0}, + {"_udbtable", 0, 0, 0, 0}, + {NULL,0, 0, 0, 0} +}; + char errstr[_POSIX2_LINE_MAX]; + kvm_t *kd; + ssize_t n; + struct inpcbtable table; + struct inpcb *next; + struct inpcb inpcb; + kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errstr); + if(!kd) { + syslog(LOG_ERR, "portinuse(): kvm_openfiles(): %s", errstr); + return -1; + } + if(kvm_nlist(kd, list) < 0) { + syslog(LOG_ERR, "portinuse(): kvm_nlist(): %s", kvm_geterr(kd)); + kvm_close(kd); + return -1; + } + n = kvm_read(kd, list[(proto==IPPROTO_TCP)?0:1].n_value, &table, sizeof(table)); + if(n < 0) { + syslog(LOG_ERR, "kvm_read(): %s", kvm_geterr(kd)); + kvm_close(kd); + return -1; + } + next = CIRCLEQ_FIRST(&table.inpt_queue); /*TAILQ_FIRST(&table.inpt_queue);*/ + while(next != NULL) { + /* syslog(LOG_DEBUG, "next=0x%08lx", (u_long)next); */ + if(((u_long)next & 3) != 0) break; + n = kvm_read(kd, (u_long)next, &inpcb, sizeof(inpcb)); + if(n < 0) { + syslog(LOG_ERR, "kvm_read(): %s", kvm_geterr(kd)); + break; + } + next = CIRCLEQ_NEXT(&inpcb, inp_queue); /*TAILQ_NEXT(&inpcb, inp_queue);*/ + if((inpcb.inp_flags & INP_IPV6) != 0) + continue; + syslog(LOG_DEBUG, "%08lx:%hu %08lx:%hu", + (u_long)inpcb.inp_laddr.s_addr, ntohs(inpcb.inp_lport), + (u_long)inpcb.inp_faddr.s_addr, ntohs(inpcb.inp_fport)); + if(eport == (unsigned)ntohs(inpcb.inp_lport)) { + if(inpcb.inp_laddr.s_addr == INADDR_ANY || inpcb.inp_laddr.s_addr == ip_addr.s_addr) { + found++; + break; /* don't care how many, just that we found at least one */ + } + } + } + kvm_close(kd); +#endif + + #if defined(USE_NETFILTER) if (!found) { char iaddr_old[16]; unsigned short iport_old; - int i = 0; - while (chains_to_check[i]) { + int i; + for (i = 0; chains_to_check[i]; i++) { if (get_nat_redirect_rule(chains_to_check[i], if_name, eport, proto, iaddr_old, sizeof(iaddr_old), &iport_old, 0, 0, 0, 0, 0, 0, 0) == 0) @@ -102,9 +186,10 @@ port_in_use(const char *if_name, break; /* don't care how many, just that we found at least one */ } } - i++; } } +#else /* USE_NETFILTER */ + UNUSED(iport); UNUSED(iaddr); #endif /* USE_NETFILTER */ return found; } From 19261b6fefc31f4a36f72a8de39ed5c92873f53e Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Sat, 15 Mar 2014 10:51:32 +0100 Subject: [PATCH 089/127] reject renewal of subscribtion that already timeouted --- miniupnpd/Changelog.txt | 5 ++++- miniupnpd/upnpevents.c | 11 +++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/miniupnpd/Changelog.txt b/miniupnpd/Changelog.txt index 6fe9f06..497ea1d 100644 --- a/miniupnpd/Changelog.txt +++ b/miniupnpd/Changelog.txt @@ -1,4 +1,7 @@ -$Id: Changelog.txt,v 1.363 2014/03/13 10:53:40 nanard Exp $ +$Id: Changelog.txt,v 1.365 2014/03/14 21:26:34 nanard Exp $ + +2014/03/14: + reject renewal of subscribtion that already timeouted 2014/03/13: fix getifaddr_in6() (used for PCP) diff --git a/miniupnpd/upnpevents.c b/miniupnpd/upnpevents.c index 617da21..673fc46 100644 --- a/miniupnpd/upnpevents.c +++ b/miniupnpd/upnpevents.c @@ -1,7 +1,7 @@ -/* $Id: upnpevents.c,v 1.28 2014/03/13 10:53:40 nanard Exp $ */ +/* $Id: upnpevents.c,v 1.30 2014/03/14 22:26:07 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2008-2013 Thomas Bernard + * (c) 2008-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -149,6 +149,11 @@ renewSubscription(const char * sid, int sidlen, int timeout) struct subscriber * sub; for(sub = subscriberlist.lh_first; sub != NULL; sub = sub->entries.le_next) { if((sidlen == 41) && (memcmp(sid, sub->uuid, 41) == 0)) { +#ifdef UPNP_STRICT + /* check if the subscription already timeouted */ + if(sub->timeout && time(NULL) > sub->timeout) + continue; +#endif sub->timeout = (timeout ? time(NULL) + timeout : 0); return 0; } @@ -542,6 +547,8 @@ void upnpevents_processfds(fd_set *readset, fd_set *writeset) for(sub = subscriberlist.lh_first; sub != NULL; ) { subnext = sub->entries.le_next; if(sub->timeout && curtime > sub->timeout && sub->notify == NULL) { + syslog(LOG_INFO, "subscriber timeouted : %u > %u SID=%s", + (unsigned)curtime, (unsigned)sub->timeout, sub->uuid); LIST_REMOVE(sub, entries); free(sub); } From 76170e5413bb3465bdfbd281fd40ce9c343eaa9c Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Sat, 15 Mar 2014 10:52:39 +0100 Subject: [PATCH 090/127] miniupnpd/upnphttp.c: Support for multiple URL in Callback: header (SUBSCRIBE) --- miniupnpd/Changelog.txt | 1 + miniupnpd/upnphttp.c | 73 +++++++++++++++++++++++++++++------------ 2 files changed, 53 insertions(+), 21 deletions(-) diff --git a/miniupnpd/Changelog.txt b/miniupnpd/Changelog.txt index 497ea1d..104e129 100644 --- a/miniupnpd/Changelog.txt +++ b/miniupnpd/Changelog.txt @@ -2,6 +2,7 @@ $Id: Changelog.txt,v 1.365 2014/03/14 21:26:34 nanard Exp $ 2014/03/14: reject renewal of subscribtion that already timeouted + Support for multiple URL in Callback: header (SUBSCRIBE) 2014/03/13: fix getifaddr_in6() (used for PCP) diff --git a/miniupnpd/upnphttp.c b/miniupnpd/upnphttp.c index 31456e3..97d8d44 100644 --- a/miniupnpd/upnphttp.c +++ b/miniupnpd/upnphttp.c @@ -1,8 +1,8 @@ -/* $Id: upnphttp.c,v 1.86 2013/02/07 10:26:07 nanard Exp $ */ +/* $Id: upnphttp.c,v 1.87 2014/03/14 21:26:01 nanard Exp $ */ /* Project : miniupnp * Website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * Author : Thomas Bernard - * Copyright (c) 2005-2012 Thomas Bernard + * Copyright (c) 2005-2014 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file included in this distribution. * */ @@ -162,14 +162,22 @@ ParseHttpHeaders(struct upnphttp * h) #ifdef ENABLE_EVENTS else if(strncasecmp(line, "Callback", 8)==0) { + /* The Callback can contain several urls : + * If there is more than one URL, when the service sends + * events, it will try these URLs in order until one + * succeeds. One or more URLs each enclosed by angle + * brackets ("<" and ">") */ p = colon; while(*p != '<' && *p != '\r' ) p++; n = 0; - while(p[n] != '>' && p[n] != '\r' ) + while(p[n] != '\r') n++; - h->req_CallbackOff = p + 1 - h->req_buf; - h->req_CallbackLen = MAX(0, n - 1); + while(n > 0 && p[n] != '>') + n--; + /* found last > character */ + h->req_CallbackOff = p - h->req_buf; + h->req_CallbackLen = MAX(0, n + 1); } else if(strncasecmp(line, "SID", 3)==0) { @@ -374,6 +382,9 @@ ProcessHTTPPOST_upnphttp(struct upnphttp * h) #ifdef ENABLE_EVENTS /** + * checkCallbackURL() + * check that url is on originating IP + * extract first correct URL * returns 0 if the callback header value is not valid * 1 if it is valid. */ @@ -385,56 +396,76 @@ checkCallbackURL(struct upnphttp * h) const char * p; unsigned int i; - if(h->req_CallbackOff <= 0 || h->req_CallbackLen < 8) +start_again: + if(h->req_CallbackOff <= 0 || h->req_CallbackLen < 10) return 0; - if(memcmp(h->req_buf + h->req_CallbackOff, "http://", 7) != 0) - return 0; - ipv6 = 0; + if(memcmp(h->req_buf + h->req_CallbackOff, "req_buf + h->req_CallbackOff + 1; + goto invalid; + } + /* extract host from url to addrstr[] */ i = 0; - p = h->req_buf + h->req_CallbackOff + 7; + p = h->req_buf + h->req_CallbackOff + 8; if(*p == '[') { p++; ipv6 = 1; - while(*p != ']' && i < (sizeof(addrstr)-1) + while(*p != ']' && *p != '>' && i < (sizeof(addrstr)-1) && p < (h->req_buf + h->req_CallbackOff + h->req_CallbackLen)) addrstr[i++] = *(p++); } else { - while(*p != '/' && *p != ':' && i < (sizeof(addrstr)-1) + ipv6 = 0; + while(*p != '/' && *p != ':' && *p != '>' && i < (sizeof(addrstr)-1) && p < (h->req_buf + h->req_CallbackOff + h->req_CallbackLen)) addrstr[i++] = *(p++); } addrstr[i] = '\0'; + /* check addrstr */ if(ipv6) { +#ifdef ENABLE_IPV6 struct in6_addr addr; if(inet_pton(AF_INET6, addrstr, &addr) <= 0) - return 0; -#ifdef ENABLE_IPV6 + goto invalid; if(!h->ipv6 || (0!=memcmp(&addr, &(h->clientaddr_v6), sizeof(struct in6_addr)))) - return 0; + goto invalid; #else - return 0; + goto invalid; #endif } else { struct in_addr addr; if(inet_pton(AF_INET, addrstr, &addr) <= 0) - return 0; + goto invalid; #ifdef ENABLE_IPV6 if(h->ipv6) { if(!IN6_IS_ADDR_V4MAPPED(&(h->clientaddr_v6))) - return 0; + goto invalid; if(0!=memcmp(&addr, ((const char *)&(h->clientaddr_v6) + 12), 4)) - return 0; + goto invalid; } else { if(0!=memcmp(&addr, &(h->clientaddr), sizeof(struct in_addr))) - return 0; + goto invalid; } #else if(0!=memcmp(&addr, &(h->clientaddr), sizeof(struct in_addr))) - return 0; + goto invalid; #endif } + /* select only the good callback url */ + while(p < h->req_buf + h->req_CallbackOff + h->req_CallbackLen && *p != '>') + p++; + h->req_CallbackOff++; /* skip initial '<' */ + h->req_CallbackLen = (int)(p - h->req_buf - h->req_CallbackOff); return 1; +invalid: + while(p < h->req_buf + h->req_CallbackOff + h->req_CallbackLen && *p != '>') + p++; + if(*p != '>') return 0; + while(p < h->req_buf + h->req_CallbackOff + h->req_CallbackLen && *p != '<') + p++; + if(*p != '<') return 0; + h->req_CallbackLen -= (int)(p - h->req_buf - h->req_CallbackOff); + h->req_CallbackOff = (int)(p - h->req_buf); + goto start_again; } static void From a959e9e7def25fbd391b930490b9338444d4c0c6 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Sat, 15 Mar 2014 10:54:23 +0100 Subject: [PATCH 091/127] miniupnpd/upnpevents.c: comments/logs/etc. --- miniupnpd/upnpevents.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/miniupnpd/upnpevents.c b/miniupnpd/upnpevents.c index 673fc46..628aff8 100644 --- a/miniupnpd/upnpevents.c +++ b/miniupnpd/upnpevents.c @@ -197,6 +197,7 @@ static void upnp_event_create_notify(struct subscriber * sub) { struct upnp_event_notify * obj; + /*struct timeval sock_timeout;*/ obj = calloc(1, sizeof(struct upnp_event_notify)); if(!obj) { @@ -215,6 +216,22 @@ upnp_event_create_notify(struct subscriber * sub) syslog(LOG_ERR, "%s: socket(): %m", "upnp_event_create_notify"); goto error; } +#if 0 /* does not work for non blocking connect() */ + /* set timeout to 3 seconds */ + sock_timeout.tv_sec = 3; + sock_timeout.tv_usec = 0; + if(setsockopt(obj->s, SOL_SOCKET, SO_RCVTIMEO, &sock_timeout, sizeof(struct timeval)) < 0) { + syslog(LOG_WARNING, "%s: setsockopt(SO_RCVTIMEO): %m", + "upnp_event_create_notify"); + } + sock_timeout.tv_sec = 3; + sock_timeout.tv_usec = 0; + if(setsockopt(obj->s, SOL_SOCKET, SO_SNDTIMEO, &sock_timeout, sizeof(struct timeval)) < 0) { + syslog(LOG_WARNING, "%s: setsockopt(SO_SNDTIMEO): %m", + "upnp_event_create_notify"); + } +#endif + /* set socket non blocking */ if(!set_non_blocking(obj->s)) { syslog(LOG_ERR, "%s: set_non_blocking(): %m", "upnp_event_create_notify"); @@ -243,6 +260,7 @@ upnp_event_notify_connect(struct upnp_event_notify * obj) struct sockaddr_in addr; socklen_t addrlen; #endif + if(!obj) return; memset(&addr, 0, sizeof(addr)); @@ -389,7 +407,7 @@ static void upnp_event_send(struct upnp_event_notify * obj) { int i; - syslog(LOG_DEBUG, "%s: sending event notify message to %s:%s", + syslog(LOG_DEBUG, "%s: sending event notify message to %s%s", "upnp_event_send", obj->addrstr, obj->portstr); syslog(LOG_DEBUG, "%s: msg: %s", "upnp_event_send", obj->buffer + obj->sent); @@ -451,7 +469,9 @@ upnp_event_process_notify(struct upnp_event_notify * obj) } if(err != 0) { errno = err; - syslog(LOG_WARNING, "%s: connect failed: %m", "upnp_event_process_notify"); + syslog(LOG_WARNING, "%s: connect(%s%s): %m", + "upnp_event_process_notify", + obj->addrstr, obj->portstr); obj->state = EError; break; } From ba448fd7dd0847cc1ae929b31e6a7e40e8e066ac Mon Sep 17 00:00:00 2001 From: Thomas BERNARD Date: Mon, 17 Mar 2014 15:35:18 +0100 Subject: [PATCH 092/127] miniupnpd/testasyncsendto.c: remove warning if struct timeval fields are not long int --- miniupnpd/testasyncsendto.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miniupnpd/testasyncsendto.c b/miniupnpd/testasyncsendto.c index e413bd7..7006bf2 100644 --- a/miniupnpd/testasyncsendto.c +++ b/miniupnpd/testasyncsendto.c @@ -72,7 +72,7 @@ int test(void) struct timeval timeout; struct timeval now; syslog(LOG_DEBUG, "get_next_scheduled_send : %d next_send=%ld.%06ld", - i, next_send.tv_sec, next_send.tv_usec); + i, (long)next_send.tv_sec, (long)next_send.tv_usec); FD_ZERO(&writefds); max_fd = 0; gettimeofday(&now, NULL); @@ -98,7 +98,7 @@ int test(void) } syslog(LOG_DEBUG, "get_sendto_fds() returned %d", i); syslog(LOG_DEBUG, "select(%d, NULL, xx, NULL, %ld.%06ld)", - max_fd, timeout.tv_sec, timeout.tv_usec); + max_fd, (long)timeout.tv_sec, (long)timeout.tv_usec); i = select(max_fd, NULL, &writefds, NULL, &timeout); if(i < 0) { syslog(LOG_ERR, "select: %m"); From e65721115700431c4f409c84469fe4e58594267d Mon Sep 17 00:00:00 2001 From: Thomas BERNARD Date: Mon, 17 Mar 2014 15:36:10 +0100 Subject: [PATCH 093/127] miniupnpd/Makefile.macosx: update for testasyncsendto and testportinuse --- miniupnpd/.gitignore | 1 + miniupnpd/Makefile.macosx | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/miniupnpd/.gitignore b/miniupnpd/.gitignore index d6c6eb9..dd37154 100644 --- a/miniupnpd/.gitignore +++ b/miniupnpd/.gitignore @@ -10,6 +10,7 @@ testupnpdescgen testupnppermissions testgetroute testasyncsendto +testportinuse netfilter/testiptcrdr netfilter/testiptcrdr_dscp netfilter/testiptcrdr_peer diff --git a/miniupnpd/Makefile.macosx b/miniupnpd/Makefile.macosx index 27280c6..7d821ff 100644 --- a/miniupnpd/Makefile.macosx +++ b/miniupnpd/Makefile.macosx @@ -33,7 +33,7 @@ STD_OBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \ upnpredirect.o getifaddr.o daemonize.o upnpglobalvars.o \ options.o upnppermissions.o minissdp.o natpmp.o \ upnpevents.o getconnstatus.o upnputils.o \ - asyncsendto.o + asyncsendto.o portinuse.o pcpserver.o MAC_OBJS = mac/getifstats.o bsd/ifacewatcher.o IPFW_OBJS = ipfw/ipfwrdr.o ipfw/ipfwaux.o PF_OBJS = pf/obsdrdr.o pf/pfpinhole.o @@ -51,11 +51,13 @@ TEST_UPNPDESCGEN_OBJS = testupnpdescgen.o upnpdescgen.o TEST_GETIFSTATS_OBJS = testgetifstats.o mac/getifstats.o TEST_UPNPPERMISSIONS_OBJS = testupnppermissions.o upnppermissions.o TEST_GETIFADDR_OBJS = testgetifaddr.o getifaddr.o +TEST_PORTINUSE_OBJS = testportinuse.o portinuse.o getifaddr.o +TEST_ASYNCSENDTO_OBJS = testasyncsendto.o asyncsendto.o upnputils.o MINIUPNPDCTL_OBJS = miniupnpdctl.o EXECUTABLES = miniupnpd testupnpdescgen testgetifstats \ testupnppermissions miniupnpdctl \ - testgetifaddr + testgetifaddr testportinuse testasyncsendto LIBS = @@ -116,6 +118,11 @@ testgetifaddr: config.h $(TEST_GETIFADDR_OBJS) testupnppermissions: config.h $(TEST_UPNPPERMISSIONS_OBJS) $(CC) $(CFLAGS) -o $@ $(TEST_UPNPPERMISSIONS_OBJS) +testasyncsendto: config.h $(TEST_ASYNCSENDTO_OBJS) + $(CC) $(CFLAGS) -o $@ $(TEST_ASYNCSENDTO_OBJS) + +testportinuse: config.h $(TEST_PORTINUSE_OBJS) + $(CC) $(CFLAGS) -o $@ $(TEST_PORTINUSE_OBJS) config.h: genconfig.sh ./genconfig.sh From 708c83d873638424430cf222fdf022a98997ddcd Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 18 Mar 2014 09:33:33 +0100 Subject: [PATCH 094/127] miniupnpd/Makefile: fix for DragonFly BSD --- miniupnpd/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miniupnpd/Makefile b/miniupnpd/Makefile index 0025377..68ebc12 100644 --- a/miniupnpd/Makefile +++ b/miniupnpd/Makefile @@ -42,7 +42,7 @@ FWNAME = ipf .endif # better way to find if we are using ipf or pf -.if defined(/etc/rc.subr) && defined(/etc/rc.conf) +.if exists(/etc/rc.subr) && exists(/etc/rc.conf) .if $(OSNAME) == "FreeBSD" FWNAME != . /etc/rc.subr; . /etc/rc.conf; \ if checkyesno ipfilter_enable; then \ From f7b6b1ec1905d0afa6a4389c0f9705d2605ec9c1 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 18 Mar 2014 09:34:25 +0100 Subject: [PATCH 095/127] miniupnpd/Makefile: Mac OS X switched from ipfw to pf OS X 10.7 Lion switched to pf --- miniupnpd/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/miniupnpd/Makefile b/miniupnpd/Makefile index 68ebc12..7edbf6c 100644 --- a/miniupnpd/Makefile +++ b/miniupnpd/Makefile @@ -63,7 +63,9 @@ FWNAME != . /etc/rc.subr; . /etc/rc.conf; \ .endif .if $(OSNAME) == "Darwin" -FWNAME = ipfw +# Firewall is ipfw up to OS X 10.6 Snow Leopard +# and pf since OS X 10.7 Lion (Darwin 11.0) +FWNAME != [ `uname -r | cut -d. -f1` -ge 11 ] && echo "pf" || echo "ipfw" .endif # Solaris specific CFLAGS From 601bd2618b5de968418f72d54bd2ee2c6d2d06a2 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 18 Mar 2014 10:17:19 +0100 Subject: [PATCH 096/127] miniupnpd/Makefile: fix for DragonFly BSD TYPE : chechyesno => checkyesno --- miniupnpd/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miniupnpd/Makefile b/miniupnpd/Makefile index 7edbf6c..e17b865 100644 --- a/miniupnpd/Makefile +++ b/miniupnpd/Makefile @@ -57,7 +57,7 @@ FWNAME != . /etc/rc.subr; . /etc/rc.conf; \ .if $(OSNAME) == "DragonFly" FWNAME != . /etc/rc.subr; . /etc/rc.conf; \ - if chechyesno ipfilter; then \ + if checkyesno ipfilter; then \ echo "ipf"; else echo "pf"; fi .endif .endif From 75cb38edda8aa695a8a4efc75845dcc9d969b659 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Wed, 19 Mar 2014 12:23:48 +0100 Subject: [PATCH 097/127] miniupnpd/Makefile: allow to override FWNAME --- miniupnpd/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/miniupnpd/Makefile b/miniupnpd/Makefile index e17b865..142cb95 100644 --- a/miniupnpd/Makefile +++ b/miniupnpd/Makefile @@ -39,7 +39,6 @@ FWNAME = pf .else FWNAME = ipf .endif -.endif # better way to find if we are using ipf or pf .if exists(/etc/rc.subr) && exists(/etc/rc.conf) @@ -68,6 +67,8 @@ FWNAME != . /etc/rc.subr; . /etc/rc.conf; \ FWNAME != [ `uname -r | cut -d. -f1` -ge 11 ] && echo "pf" || echo "ipfw" .endif +.endif + # Solaris specific CFLAGS .if $(OSNAME) == "SunOS" CFLAGS += -DSOLARIS2=`uname -r | cut -d. -f2` From 5a3a670e89429f5c3846b1474e507318ef9de478 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Wed, 19 Mar 2014 12:24:28 +0100 Subject: [PATCH 098/127] miniupnpd/bsd/getifstats.c: fix for DragonFly BSD struct ifnet is private to kernel code and is hidden from the userland code unless you define a macro _KERNEL_STRUCTURES. Although other people argue that it should be exposed as it is on other BSDs, that's the way it is on DragonFly BSD. Thanks to YONETANI Tomokazu for DragonFly BSD patches --- README | 1 + miniupnpd/bsd/getifstats.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/README b/README index 95cac83..f3519b7 100644 --- a/README +++ b/README @@ -45,3 +45,4 @@ Thanks to : * Peter Tatrai * Leo Moll * Daniel Becker + * Yonetani Tomokazu diff --git a/miniupnpd/bsd/getifstats.c b/miniupnpd/bsd/getifstats.c index 69b8eeb..7238a46 100644 --- a/miniupnpd/bsd/getifstats.c +++ b/miniupnpd/bsd/getifstats.c @@ -12,6 +12,9 @@ #include #include #if defined(__FreeBSD__) || defined(__DragonFly__) +#ifdef __DragonFly__ +#define _KERNEL_STRUCTURES +#endif #include #endif #if defined(__DragonFly__) From aea062a7baf82c3b8bea9f2824ed966162f43544 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 20 Mar 2014 13:40:53 +0100 Subject: [PATCH 099/127] miniupnpd/portinuse.c: Add DragonFly BSD implementation Thanks to YONETANI Tomokazu. --- miniupnpd/portinuse.c | 94 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/miniupnpd/portinuse.c b/miniupnpd/portinuse.c index 48fb91f..c9b4849 100644 --- a/miniupnpd/portinuse.c +++ b/miniupnpd/portinuse.c @@ -4,6 +4,10 @@ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ +#if defined(__DragonFly__) +#include +#include +#endif #include #include #include @@ -34,6 +38,14 @@ */ #endif +#if defined(__DragonFly__) +#include +#include +/* sys/socketvar.h must be included above the following headers */ +#include +#include +#endif + #include "macros.h" #include "config.h" #include "upnpglobalvars.h" @@ -167,6 +179,88 @@ static struct nlist list[] = { kvm_close(kd); #endif +#if defined(__DragonFly__) + const char *varname; + struct xinpcb *xip; + struct xtcpcb *xtp; + struct inpcb *inp; + void *buf = NULL; + void *so_begin, *so_end; + + size_t len; + + switch (proto) { + case IPPROTO_TCP: + varname = "net.inet.tcp.pcblist"; + break; + case IPPROTO_UDP: + varname = "net.inet.udp.pcblist"; + break; + default: + abort(); + } + + if (sysctlbyname(varname, NULL, &len, NULL, 0)) { + if (errno == ENOENT) + goto out; + err(1, "fetching %s", varname); + } + if ((buf = malloc(len)) == NULL) + err(1, "malloc()"); + if (sysctlbyname(varname, buf, &len, NULL, 0)) { + if (errno == ENOENT) + goto out; + err(1, "fetching %s", varname); + } + + so_begin = buf; + so_end = (uint8_t *)buf + len; + for (so_begin = buf, so_end = (uint8_t *)so_begin + len; + (uint8_t *)so_begin + sizeof(size_t) < (uint8_t *)so_end && + (uint8_t *)so_begin + *(size_t *)so_begin <= (uint8_t *)so_end; + so_begin = (uint8_t *)so_begin + *(size_t *)so_begin) { + switch (proto) { + case IPPROTO_TCP: + xtp = (struct xtcpcb *)so_begin; + if (xtp->xt_len != sizeof *xtp) { + warnx("struct xtcpcb size mismatch; %ld vs %ld", xtp->xt_len, sizeof *xtp); + goto out; + } + inp = &xtp->xt_inp; + break; + case IPPROTO_UDP: + xip = (struct xinpcb *)so_begin; + if (xip->xi_len != sizeof *xip) { + warnx("struct xinpcb size mismatch"); + goto out; + } + inp = &xip->xi_inp; + break; + default: + abort(); + } + /* no support for IPv6 */ + if ((inp->inp_vflag & INP_IPV6) != 0) + continue; + syslog(LOG_DEBUG, "%08lx:%hu %08lx:%hu <=> %hu %08lx:%hu", + (u_long)inp->inp_laddr.s_addr, ntohs(inp->inp_lport), + (u_long)inp->inp_faddr.s_addr, ntohs(inp->inp_fport), + eport, (u_long)ip_addr.s_addr, iport + ); + if (eport == (unsigned)ntohs(inp->inp_lport)) { + if (inp->inp_laddr.s_addr == INADDR_ANY || inp->inp_laddr.s_addr == ip_addr.s_addr) { + found++; + break; /* don't care how many, just that we found at least one */ + } + } + } + errno = 0; +out: + if (errno) { + free(buf); + return -1; + } +#endif #if defined(USE_NETFILTER) if (!found) { From 6419602e1412067315c2906744ce96baa0467590 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 20 Mar 2014 13:49:10 +0100 Subject: [PATCH 100/127] miniupnpd/portinuse: port_in_use() returns -1 in case of error --- miniupnpd/natpmp.c | 5 +++-- miniupnpd/portinuse.c | 7 ++++--- miniupnpd/portinuse.h | 5 +++-- miniupnpd/upnpredirect.c | 5 +++-- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/miniupnpd/natpmp.c b/miniupnpd/natpmp.c index 2bacb8f..be37e29 100644 --- a/miniupnpd/natpmp.c +++ b/miniupnpd/natpmp.c @@ -293,8 +293,9 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, } any_eport_allowed = 1; /* at lease one eport is allowed */ #ifdef CHECK_PORTINUSE - if (port_in_use(ext_if_name, eport, proto, senderaddrstr, iport)) { - syslog(LOG_INFO, "port %hu protocol %s already in use", eport, (proto==IPPROTO_TCP)?"tcp":"udp"); + if (port_in_use(ext_if_name, eport, proto, senderaddrstr, iport) > 0) { + syslog(LOG_INFO, "port %hu protocol %s already in use", + eport, (proto==IPPROTO_TCP)?"tcp":"udp"); eport++; if(eport == 0) eport++; /* skip port zero */ continue; diff --git a/miniupnpd/portinuse.c b/miniupnpd/portinuse.c index c9b4849..278faa7 100644 --- a/miniupnpd/portinuse.c +++ b/miniupnpd/portinuse.c @@ -1,4 +1,4 @@ -/* $Id $ */ +/* $Id: $ */ /* MiniUPnP project * (c) 2007-2014 Thomas Bernard * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ @@ -83,13 +83,14 @@ port_in_use(const char *if_name, ip_addr.s_addr = 0; syslog(LOG_DEBUG, "Check protocol %s for port %d on ext_if %s %s, %08X", - (proto==IPPROTO_TCP)?"tcp":"udp", eport, if_name, ip_addr_str, (unsigned)ip_addr.s_addr); + (proto==IPPROTO_TCP)?"tcp":"udp", eport, if_name, + ip_addr_str, (unsigned)ip_addr.s_addr); #ifdef __linux__ f = fopen((proto==IPPROTO_TCP)?tcpfile:udpfile, "r"); if (!f) { syslog(LOG_ERR, "cannot open %s", (proto==IPPROTO_TCP)?tcpfile:udpfile); - return 0; + return -1; } while (fgets(line, 255, f)) { diff --git a/miniupnpd/portinuse.h b/miniupnpd/portinuse.h index fddc7c8..01842f6 100644 --- a/miniupnpd/portinuse.h +++ b/miniupnpd/portinuse.h @@ -1,4 +1,4 @@ -/* $Id $ */ +/* $Id: $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2014 Thomas Bernard @@ -12,7 +12,8 @@ /* portinuse() * determine wether a port is already in use * on a given interface. - * returns: 0 not in use, 1 in use */ + * returns: 0 not in use, > 0 in use + * -1 in case of error */ int port_in_use(const char *if_name, unsigned port, int proto, diff --git a/miniupnpd/upnpredirect.c b/miniupnpd/upnpredirect.c index 0139a7d..5a50c6d 100644 --- a/miniupnpd/upnpredirect.c +++ b/miniupnpd/upnpredirect.c @@ -296,8 +296,9 @@ upnp_redirect(const char * rhost, unsigned short eport, return -2; } #ifdef CHECK_PORTINUSE - } else if (port_in_use(ext_if_name, eport, proto, iaddr, iport)) { - syslog(LOG_INFO, "port %hu protocol %s already in use", eport, protocol); + } else if (port_in_use(ext_if_name, eport, proto, iaddr, iport) > 0) { + syslog(LOG_INFO, "port %hu protocol %s already in use", + eport, protocol); return -2; #endif /* CHECK_PORTINUSE */ } else { From 6eab849b2eaa72390814c9ffe946799770af33f6 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 20 Mar 2014 14:07:52 +0100 Subject: [PATCH 101/127] miniupnpd/portinuse.c: Improve error handling in DragonFly BSD code --- miniupnpd/portinuse.c | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/miniupnpd/portinuse.c b/miniupnpd/portinuse.c index 278faa7..4e2118c 100644 --- a/miniupnpd/portinuse.c +++ b/miniupnpd/portinuse.c @@ -198,20 +198,23 @@ static struct nlist list[] = { varname = "net.inet.udp.pcblist"; break; default: - abort(); + syslog(LOG_ERR, "port_in_use() unknown proto=%d", proto); + return -1; } - if (sysctlbyname(varname, NULL, &len, NULL, 0)) { - if (errno == ENOENT) - goto out; - err(1, "fetching %s", varname); + if (sysctlbyname(varname, NULL, &len, NULL, 0) < 0) { + syslog(LOG_ERR, "sysctlbyname(%s, NULL, ...): %m", varname); + return -1; } - if ((buf = malloc(len)) == NULL) - err(1, "malloc()"); - if (sysctlbyname(varname, buf, &len, NULL, 0)) { - if (errno == ENOENT) - goto out; - err(1, "fetching %s", varname); + buf = malloc(len); + if (buf == NULL) { + syslog(LOG_ERR, "malloc(%u) failed", (unsigned)len); + return -1; + } + if (sysctlbyname(varname, buf, &len, NULL, 0) < 0) { + syslog(LOG_ERR, "sysctlbyname(%s, buf, ...): %m", varname); + free(buf); + return -1; } so_begin = buf; @@ -224,16 +227,20 @@ static struct nlist list[] = { case IPPROTO_TCP: xtp = (struct xtcpcb *)so_begin; if (xtp->xt_len != sizeof *xtp) { - warnx("struct xtcpcb size mismatch; %ld vs %ld", xtp->xt_len, sizeof *xtp); - goto out; + syslog(LOG_WARNING, "struct xtcpcb size mismatch; %ld vs %ld", + (long)xtp->xt_len, sizeof *xtp); + free(buf); + return -1; } inp = &xtp->xt_inp; break; case IPPROTO_UDP: xip = (struct xinpcb *)so_begin; if (xip->xi_len != sizeof *xip) { - warnx("struct xinpcb size mismatch"); - goto out; + syslog(LOG_WARNING, "struct xinpcb size mismatch : %ld vs %ld", + (long)xip->xi_len, sizeof *xip); + free(buf); + return -1; } inp = &xip->xi_inp; break; @@ -255,11 +262,9 @@ static struct nlist list[] = { } } } - errno = 0; -out: - if (errno) { + if(buf) { free(buf); - return -1; + buf = NULL; } #endif From 4a7f97c7f3275c7918acc282f6c710ae89739a58 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Sat, 22 Mar 2014 13:12:10 +0100 Subject: [PATCH 102/127] miniupnpd/pcp_msg_struct.h: comments --- miniupnpd/pcp_msg_struct.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/miniupnpd/pcp_msg_struct.h b/miniupnpd/pcp_msg_struct.h index bb557bc..0d5f912 100644 --- a/miniupnpd/pcp_msg_struct.h +++ b/miniupnpd/pcp_msg_struct.h @@ -178,12 +178,12 @@ typedef struct pcp_options_hdr { /* same for both request and response */ typedef struct pcp_map_v2 { uint32_t nonce[3]; - uint8_t protocol; + uint8_t protocol; /* 6 = TCP, 17 = UDP, 0 = 'all protocols' */ uint8_t reserved[3]; - uint16_t int_port; - uint16_t ext_port; - struct in6_addr ext_ip; /* ipv4 will be represented - by the ipv4 mapped ipv6 */ + uint16_t int_port; /* 0 indicates 'all ports' */ + uint16_t ext_port; /* suggested external port */ + struct in6_addr ext_ip; /* suggested external IP address + * ipv4 will be represented by the ipv4 mapped ipv6 */ uint8_t next_data[0]; } pcp_map_v2_t; From b1fb9cfdc49a6d80e5de72ff52b0db53cc6974e8 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 24 Mar 2014 10:21:26 +0100 Subject: [PATCH 103/127] miniupnpd/pcpserver.c: take care of "nonce" value --- miniupnpd/pcpserver.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/miniupnpd/pcpserver.c b/miniupnpd/pcpserver.c index ed6416e..0bdc19c 100644 --- a/miniupnpd/pcpserver.c +++ b/miniupnpd/pcpserver.c @@ -1,4 +1,4 @@ -/* $Id: pcpserver.c,v 1.12 2014/02/28 17:50:22 nanard Exp $ */ +/* $Id: pcpserver.c,v 1.20 2014/03/22 12:06:15 nanard Exp $ */ /* MiniUPnP project * Website : http://miniupnp.free.fr/ * Author : Peter Tatrai @@ -84,6 +84,7 @@ typedef struct pcp_info { uint32_t lifetime; /* lifetime of the mapping */ uint32_t epochtime; /* both MAP and PEER opcode specific information */ + uint32_t nonce[3]; /* random value generated by client */ uint8_t protocol; uint16_t int_port; const struct in6_addr *int_ip; /* in network order */ @@ -214,11 +215,13 @@ static void printMAPOpcodeVersion1(pcp_map_v1_t *map_buf) static void printMAPOpcodeVersion2(pcp_map_v2_t *map_buf) { char map_addr[INET6_ADDRSTRLEN]; - syslog(LOG_DEBUG, "PCP MAP: v2 Opcode specific information. \n"); - syslog(LOG_DEBUG, "MAP protocol: \t\t %d\n",map_buf->protocol ); - syslog(LOG_DEBUG, "MAP int port: \t\t %d\n", ntohs(map_buf->int_port) ); - syslog(LOG_DEBUG, "MAP ext port: \t\t %d\n", ntohs(map_buf->ext_port) ); - syslog(LOG_DEBUG, "MAP Ext IP: \t\t %s\n", inet_ntop(AF_INET6, + syslog(LOG_DEBUG, "PCP MAP: v2 Opcode specific information."); + syslog(LOG_DEBUG, "MAP nonce: \t%08x%08x%08x", + map_buf->nonce[0], map_buf->nonce[1], map_buf->nonce[2]); + syslog(LOG_DEBUG, "MAP protocol:\t%d", map_buf->protocol); + syslog(LOG_DEBUG, "MAP int port:\t%d", ntohs(map_buf->int_port)); + syslog(LOG_DEBUG, "MAP ext port:\t%d", ntohs(map_buf->ext_port)); + syslog(LOG_DEBUG, "MAP Ext IP: \t%s", inet_ntop(AF_INET6, &map_buf->ext_ip, map_addr, INET6_ADDRSTRLEN)); } #endif /* DEBUG */ @@ -241,10 +244,11 @@ static int parsePCPMAP_version1(pcp_map_v1_t *map_v1, return 0; } -static int parsePCPMAP_version2(pcp_map_v2_t *map_v2, +static int parsePCPMAP_version2(const pcp_map_v2_t *map_v2, pcp_info_t *pcp_msg_info) { pcp_msg_info->is_map_op = 1; + memcpy(pcp_msg_info->nonce, map_v2->nonce, 12); pcp_msg_info->protocol = map_v2->protocol; pcp_msg_info->int_port = ntohs(map_v2->int_port); pcp_msg_info->ext_port = ntohs(map_v2->ext_port); @@ -282,15 +286,17 @@ static void printPEEROpcodeVersion2(pcp_peer_v2_t *peer_buf) char ext_addr[INET6_ADDRSTRLEN]; char peer_addr[INET6_ADDRSTRLEN]; - syslog(LOG_DEBUG, "PCP PEER: v2 Opcode specific information. \n"); - syslog(LOG_DEBUG, "Protocol: \t\t %d\n",peer_buf->protocol ); - syslog(LOG_DEBUG, "Internal port: \t\t %d\n", ntohs(peer_buf->int_port) ); - syslog(LOG_DEBUG, "External IP: \t\t %s\n", inet_ntop(AF_INET6, &peer_buf->ext_ip, + syslog(LOG_DEBUG, "PCP PEER: v2 Opcode specific information."); + syslog(LOG_DEBUG, "nonce: \t%08x%08x%08x", + map_buf->nonce[0], map_buf->nonce[1], map_buf->nonce[2]); + syslog(LOG_DEBUG, "Protocol: \t%d",peer_buf->protocol ); + syslog(LOG_DEBUG, "Internal port:\t%d", ntohs(peer_buf->int_port) ); + syslog(LOG_DEBUG, "External IP: \t%s", inet_ntop(AF_INET6, &peer_buf->ext_ip, ext_addr,INET6_ADDRSTRLEN)); - syslog(LOG_DEBUG, "External port port: \t\t %d\n", ntohs(peer_buf->ext_port) ); - syslog(LOG_DEBUG, "PEER IP: \t\t %s\n", inet_ntop(AF_INET6, &peer_buf->peer_ip, + syslog(LOG_DEBUG, "External port:\t%d", ntohs(peer_buf->ext_port) ); + syslog(LOG_DEBUG, "PEER IP: \t%s", inet_ntop(AF_INET6, &peer_buf->peer_ip, peer_addr,INET6_ADDRSTRLEN)); - syslog(LOG_DEBUG, "PEER port port: \t\t %d\n", ntohs(peer_buf->peer_port) ); + syslog(LOG_DEBUG, "PEER port: \t%d", ntohs(peer_buf->peer_port) ); } #endif /* DEBUG */ @@ -326,6 +332,7 @@ static int parsePCPPEER_version2(pcp_peer_v2_t *peer_buf, \ pcp_info_t *pcp_msg_info) { pcp_msg_info->is_peer_op = 1; + memcpy(pcp_msg_info->nonce, peer_buf->nonce, 12); pcp_msg_info->protocol = peer_buf->protocol; pcp_msg_info->int_port = ntohs(peer_buf->int_port); pcp_msg_info->ext_port = ntohs(peer_buf->ext_port); From 814a6b253a2f1d98e0e5f5ae129e857d899ccb91 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 24 Mar 2014 10:23:07 +0100 Subject: [PATCH 104/127] miniupnpd/pcpserver.c: use const where useful --- miniupnpd/pcpserver.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/miniupnpd/pcpserver.c b/miniupnpd/pcpserver.c index 0bdc19c..9df0369 100644 --- a/miniupnpd/pcpserver.c +++ b/miniupnpd/pcpserver.c @@ -176,10 +176,10 @@ int get_dscp_value(pcp_info_t *pcp_msg_info) { * result code is assigned to pcp_msg_info->result_code to indicate * what kind of error occurred */ -static int parseCommonRequestHeader(pcp_request_t *common_req, pcp_info_t *pcp_msg_info) +static int parseCommonRequestHeader(const pcp_request_t *common_req, pcp_info_t *pcp_msg_info) { pcp_msg_info->version = common_req->ver ; - pcp_msg_info->opcode = common_req->r_opcode &0x7f ; + pcp_msg_info->opcode = common_req->r_opcode & 0x7f; pcp_msg_info->lifetime = ntohl(common_req->req_lifetime); pcp_msg_info->int_ip = &common_req->ip; @@ -201,7 +201,7 @@ static int parseCommonRequestHeader(pcp_request_t *common_req, pcp_info_t *pcp_m } #ifdef DEBUG -static void printMAPOpcodeVersion1(pcp_map_v1_t *map_buf) +static void printMAPOpcodeVersion1(const pcp_map_v1_t *map_buf) { char map_addr[INET6_ADDRSTRLEN]; syslog(LOG_DEBUG, "PCP MAP: v1 Opcode specific information. \n"); @@ -212,7 +212,7 @@ static void printMAPOpcodeVersion1(pcp_map_v1_t *map_buf) &map_buf->ext_ip, map_addr, INET6_ADDRSTRLEN)); } -static void printMAPOpcodeVersion2(pcp_map_v2_t *map_buf) +static void printMAPOpcodeVersion2(const pcp_map_v2_t *map_buf) { char map_addr[INET6_ADDRSTRLEN]; syslog(LOG_DEBUG, "PCP MAP: v2 Opcode specific information."); @@ -226,7 +226,7 @@ static void printMAPOpcodeVersion2(pcp_map_v2_t *map_buf) } #endif /* DEBUG */ -static int parsePCPMAP_version1(pcp_map_v1_t *map_v1, +static int parsePCPMAP_version1(const pcp_map_v1_t *map_v1, pcp_info_t *pcp_msg_info) { pcp_msg_info->is_map_op = 1; @@ -1002,9 +1002,8 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info) int remainingSize; int processedSize; - pcp_request_t* common_req; - pcp_map_v1_t* map_v1; - pcp_map_v2_t* map_v2; + const pcp_map_v1_t* map_v1; + const pcp_map_v2_t* map_v2; #ifdef PCP_PEER pcp_peer_v1_t* peer_v1; pcp_peer_v2_t* peer_v2; @@ -1037,19 +1036,17 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info) return 1; /* send response */ } - /* first print out info from common request header */ - common_req = (pcp_request_t*)req; - - if (parseCommonRequestHeader(common_req, pcp_msg_info) ) { + /* first parse request header */ + if (parseCommonRequestHeader((pcp_request_t*)req, pcp_msg_info) ) { return 1; } remainingSize -= sizeof(pcp_request_t); processedSize += sizeof(pcp_request_t); - if (common_req->ver == 1) { + if (pcp_msg_info->version == 1) { /* legacy PCP version 1 support */ - switch ( common_req->r_opcode & 0x7F ) { + switch (pcp_msg_info->opcode) { case PCP_OPCODE_MAP: remainingSize -= sizeof(pcp_map_v1_t); @@ -1125,10 +1122,10 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info) break; } - } else if (common_req->ver == 2) { + } else if (pcp_msg_info->version == 2) { /* RFC 6887 PCP support * http://tools.ietf.org/html/rfc6887 */ - switch ( common_req->r_opcode & 0x7F) { + switch (pcp_msg_info->opcode) { case PCP_OPCODE_ANNOUNCE: /* should check PCP Client's IP Address in request */ /* see http://tools.ietf.org/html/rfc6887#section-14.1 */ From 713766510194de96184042379777c22aa38b79a3 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 24 Mar 2014 10:24:19 +0100 Subject: [PATCH 105/127] miniupnpd/pcpserver.c: prepare code to be able to manage more than just TCP and UDP --- miniupnpd/pcpserver.c | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/miniupnpd/pcpserver.c b/miniupnpd/pcpserver.c index 9df0369..2f246ef 100644 --- a/miniupnpd/pcpserver.c +++ b/miniupnpd/pcpserver.c @@ -675,6 +675,7 @@ static int CreatePCPPeer(pcp_info_t *pcp_msg_info) /* Create Peer Mapping */ { char desc[64]; + char proto_str[8]; char peerip_s[INET_ADDRSTRLEN], extip_s[INET_ADDRSTRLEN]; time_t timestamp = time(NULL) + pcp_msg_info->lifetime; @@ -682,8 +683,19 @@ static int CreatePCPPeer(pcp_info_t *pcp_msg_info) eport = pcp_msg_info->int_port; } - snprintf(desc, sizeof(desc), "PCP %hu %s", - eport, (proto==IPPROTO_TCP)?"tcp":"udp"); + switch(proto) { + case IPPROTO_TCP: + snprintf(proto_str, sizeof(proto_str), "TCP"); + break; + case IPPROTO_UDP: + snprintf(proto_str, sizeof(proto_str), "UDP"); + break; + default: + snprintf(proto_str, sizeof(proto_str), "%d", proto); + } + snprintf(desc, sizeof(desc), "PCP %hu %s %08x%08x%08x", + eport, proto_str, + pcp_msg_info->nonce[0], pcp_msg_info->nonce[1], pcp_msg_info->nonce[2]); inet_satop((struct sockaddr*)&peerip, peerip_s, sizeof(peerip_s)); inet_satop((struct sockaddr*)&extip, extip_s, sizeof(extip_s)); @@ -695,7 +707,7 @@ static int CreatePCPPeer(pcp_info_t *pcp_msg_info) pcp_msg_info->senderaddrstr, pcp_msg_info->int_port, proto, desc, timestamp) < 0 ) { syslog(LOG_ERR, "PCP: failed to add flowp upstream mapping %s %s:%hu->%s:%hu '%s'", - (pcp_msg_info->protocol==IPPROTO_TCP)?"TCP":"UDP", + proto_str, pcp_msg_info->senderaddrstr, pcp_msg_info->int_port, peerip_s, @@ -711,7 +723,7 @@ static int CreatePCPPeer(pcp_info_t *pcp_msg_info) peerip_s, pcp_msg_info->peer_port, proto, desc, timestamp) < 0 ) { syslog(LOG_ERR, "PCP: failed to add flowp downstream mapping %s %s:%hu->%s:%hu '%s'", - (pcp_msg_info->protocol==IPPROTO_TCP)?"TCP":"UDP", + proto_str, pcp_msg_info->senderaddrstr, pcp_msg_info->int_port, peerip_s, @@ -812,6 +824,7 @@ static void DeletePCPPeer(pcp_info_t *pcp_msg_info) static void CreatePCPMap(pcp_info_t *pcp_msg_info) { char desc[64]; + char proto_str[8]; char iaddr_old[INET_ADDRSTRLEN]; uint16_t iport_old; uint16_t eport_first = 0; @@ -887,9 +900,20 @@ static void CreatePCPMap(pcp_info_t *pcp_msg_info) timestamp = time(NULL) + pcp_msg_info->lifetime; - snprintf(desc, sizeof(desc), "PCP %hu %s", + switch(pcp_msg_info->protocol) { + case IPPROTO_TCP: + snprintf(proto_str, sizeof(proto_str), "TCP"); + break; + case IPPROTO_UDP: + snprintf(proto_str, sizeof(proto_str), "UDP"); + break; + default: + snprintf(proto_str, sizeof(proto_str), "%d", pcp_msg_info->protocol); + } + snprintf(desc, sizeof(desc), "PCP %hu %s %08x%08x%08x", pcp_msg_info->ext_port, - (pcp_msg_info->protocol==IPPROTO_TCP)?"tcp":"udp"); + proto_str, + pcp_msg_info->nonce[0], pcp_msg_info->nonce[1], pcp_msg_info->nonce[2]); if(upnp_redirect_internal(NULL, pcp_msg_info->ext_port, @@ -900,7 +924,7 @@ static void CreatePCPMap(pcp_info_t *pcp_msg_info) timestamp) < 0) { syslog(LOG_ERR, "PCP MAP: Failed to add mapping %s %hu->%s:%hu '%s'", - (pcp_msg_info->protocol==IPPROTO_TCP)?"TCP":"UDP", + proto_str, pcp_msg_info->ext_port, pcp_msg_info->senderaddrstr, pcp_msg_info->int_port, @@ -910,7 +934,7 @@ static void CreatePCPMap(pcp_info_t *pcp_msg_info) } else { syslog(LOG_INFO, "PCP MAP: added mapping %s %hu->%s:%hu '%s'", - (pcp_msg_info->protocol==IPPROTO_TCP)?"TCP":"UDP", + proto_str, pcp_msg_info->ext_port, pcp_msg_info->senderaddrstr, pcp_msg_info->int_port, From ba1875b52c0e0102920c472942a2ce67b7ee8f30 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 24 Mar 2014 10:24:41 +0100 Subject: [PATCH 106/127] miniupnpd/pcpserver.c: add comments --- miniupnpd/pcpserver.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/miniupnpd/pcpserver.c b/miniupnpd/pcpserver.c index 2f246ef..e6a62bd 100644 --- a/miniupnpd/pcpserver.c +++ b/miniupnpd/pcpserver.c @@ -821,6 +821,34 @@ static void DeletePCPPeer(pcp_info_t *pcp_msg_info) } #endif /* PCP_PEER */ +/* internal external PCP remote peer actual remote peer + * -------- ------- --------------- ------------------ + * IPv4 firewall IPv4 IPv4 IPv4 IPv4 + * IPv6 firewall IPv6 IPv6 IPv6 IPv6 + * NAT44 IPv4 IPv4 IPv4 IPv4 + * NAT46 IPv4 IPv6 IPv4 IPv6 + * NAT64 IPv6 IPv4 IPv6 IPv4 + * NPTv6 IPv6 IPv6 IPv6 IPv6 + * + * Address Families with MAP and PEER + * + * The 'internal' address is implicitly the same as the source IP + * address of the PCP request, except when the THIRD_PARTY option is + * used. + * + * The 'external' address is the Suggested External Address field of the + * MAP or PEER request, and its address family is usually the same as + * the 'internal' address family, except when technologies like NAT64 + * are used. + * + * The 'remote peer' address is the remote peer IP address of the PEER + * request or the FILTER option of the MAP request, and is always the + * same address family as the 'internal' address, even when NAT64 is + * used. In NAT64, the IPv6 PCP client is not necessarily aware of the + * NAT64 or aware of the actual IPv4 address of the remote peer, so it + * expresses the IPv6 address from its perspective. */ + +/* TODO : support more scenarios than just NAT44 */ static void CreatePCPMap(pcp_info_t *pcp_msg_info) { char desc[64]; @@ -993,7 +1021,8 @@ static int ValidatePCPMsg(pcp_info_t *pcp_msg_info) return 0; } - if (pcp_msg_info->protocol == 0 && pcp_msg_info->int_port !=0 ){ + /* protocol zero means 'all protocols' : internal port MUST be zero */ + if (pcp_msg_info->protocol == 0 && pcp_msg_info->int_port != 0) { pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST; return 0; } From f70484f27f5dde2220b1e7bbe828d3407819f878 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 24 Mar 2014 10:33:52 +0100 Subject: [PATCH 107/127] miniupnpd/minissdp.c: reduce syslog() verbosity LOG_INFO => LOG_DEBUG --- miniupnpd/minissdp.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/miniupnpd/minissdp.c b/miniupnpd/minissdp.c index cdd6f08..3e6534c 100644 --- a/miniupnpd/minissdp.c +++ b/miniupnpd/minissdp.c @@ -1,4 +1,4 @@ -/* $Id: minissdp.c,v 1.61 2014/03/10 11:04:51 nanard Exp $ */ +/* $Id: minissdp.c,v 1.62 2014/03/24 09:31:23 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2014 Thomas Bernard @@ -405,12 +405,13 @@ SendSSDPResponse(int s, const struct sockaddr * addr, n = sendto_schedule(s, buf, l, 0, addr, addrlen, delay); sockaddr_to_string(addr, addr_str, sizeof(addr_str)); - syslog(LOG_INFO, "SSDP Announce %d bytes to %s ST: %.*s",n, - addr_str, - l, buf); + syslog(LOG_DEBUG, "%s: %d bytes to %s ST: %.*s", + "SendSSDPResponse()", + n, addr_str, l, buf); if(n < 0) { - syslog(LOG_ERR, "sendto(udp): %m"); + syslog(LOG_ERR, "%s: sendto(udp): %m", + "SendSSDPResponse()"); } } From ad88cc0819321eb2841958f846138ac3a225152f Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 24 Mar 2014 12:07:31 +0100 Subject: [PATCH 108/127] miniupnpd: start work to enable IPv6 PCP operations --- miniupnpd/Changelog.txt | 5 ++- miniupnpd/Makefile.linux | 9 +++--- miniupnpd/miniupnpd.c | 53 +++++++++++++++++++++++++++--- miniupnpd/natpmp.c | 40 ++++++++++++----------- miniupnpd/natpmp.h | 11 ++++--- miniupnpd/pcpserver.c | 70 ++++++++++++++++++++++++++++++++++------ miniupnpd/pcpserver.h | 11 +++++-- 7 files changed, 154 insertions(+), 45 deletions(-) diff --git a/miniupnpd/Changelog.txt b/miniupnpd/Changelog.txt index 104e129..eefa138 100644 --- a/miniupnpd/Changelog.txt +++ b/miniupnpd/Changelog.txt @@ -1,4 +1,7 @@ -$Id: Changelog.txt,v 1.365 2014/03/14 21:26:34 nanard Exp $ +$Id: Changelog.txt,v 1.366 2014/03/24 11:03:50 nanard Exp $ + +2014/03/24: + start work to enable IPv6 PCP operations 2014/03/14: reject renewal of subscribtion that already timeouted diff --git a/miniupnpd/Makefile.linux b/miniupnpd/Makefile.linux index 86d7d7c..a162db3 100644 --- a/miniupnpd/Makefile.linux +++ b/miniupnpd/Makefile.linux @@ -1,4 +1,4 @@ -# $Id: Makefile.linux,v 1.81 2014/01/27 10:06:58 nanard Exp $ +# $Id: Makefile.linux,v 1.84 2014/03/24 10:43:25 nanard Exp $ # MiniUPnP project # (c) 2006-2014 Thomas Bernard # http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ @@ -253,9 +253,10 @@ minissdp.o: upnputils.h getroute.h asyncsendto.h codelength.h natpmp.o: macros.h config.h natpmp.h upnpglobalvars.h upnppermissions.h natpmp.o: miniupnpdtypes.h getifaddr.h upnpredirect.h commonrdr.h upnputils.h natpmp.o: asyncsendto.h -pcpserver.o: config.h pcpserver.h macros.h upnpglobalvars.h upnppermissions.h -pcpserver.o: miniupnpdtypes.h pcplearndscp.h upnpredirect.h commonrdr.h -pcpserver.o: getifaddr.h asyncsendto.h pcp_msg_struct.h +pcpserver.o: config.h pcpserver.h natpmp.h macros.h upnpglobalvars.h +pcpserver.o: upnppermissions.h miniupnpdtypes.h pcplearndscp.h upnpredirect.h +pcpserver.o: commonrdr.h getifaddr.h asyncsendto.h upnputils.h +pcpserver.o: pcp_msg_struct.h netfilter/iptcrdr.h commonrdr.h upnpevents.o: config.h upnpevents.h miniupnpdpath.h upnpglobalvars.h upnpevents.o: upnppermissions.h miniupnpdtypes.h upnpdescgen.h upnputils.h upnputils.o: config.h upnputils.h upnpglobalvars.h upnppermissions.h diff --git a/miniupnpd/miniupnpd.c b/miniupnpd/miniupnpd.c index 3a8be99..42829fb 100644 --- a/miniupnpd/miniupnpd.c +++ b/miniupnpd/miniupnpd.c @@ -1,4 +1,4 @@ -/* $Id: miniupnpd.c,v 1.189 2014/03/10 11:04:52 nanard Exp $ */ +/* $Id: miniupnpd.c,v 1.190 2014/03/24 10:49:44 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2014 Thomas Bernard @@ -1460,6 +1460,9 @@ main(int argc, char * * argv) #ifdef ENABLE_NATPMP int * snatpmp = NULL; /* also used for PCP */ #endif +#if defined(ENABLE_IPV6) && defined(ENABLE_PCP) + int spcp_v6 = -1; +#endif #ifdef ENABLE_NFQUEUE int nfqh = -1; #endif @@ -1648,6 +1651,10 @@ main(int argc, char * * argv) } #endif +#if defined(ENABLE_IPV6) && defined(ENABLE_PCP) + spcp_v6 = OpenAndConfPCPv6Socket(); +#endif + /* for miniupnpdctl */ #ifdef USE_MINIUPNPDCTL sctl = OpenAndConfCtlUnixSocket("/var/run/miniupnpd.ctl"); @@ -1842,6 +1849,12 @@ main(int argc, char * * argv) } } #endif +#if defined(ENABLE_IPV6) && defined(ENABLE_PCP) + if(spcp_v6 >= 0) { + FD_SET(spcp_v6, &readset); + max_fd = MAX(max_fd, spcp_v6); + } +#endif #ifdef USE_MINIUPNPDCTL if(sctl >= 0) { FD_SET(sctl, &readset); @@ -1978,19 +1991,23 @@ main(int argc, char * * argv) { unsigned char msg_buff[PCP_MAX_LEN]; struct sockaddr_in senderaddr; + socklen_t senderaddrlen; int len; memset(msg_buff, 0, PCP_MAX_LEN); - len = ReceiveNATPMPOrPCPPacket(snatpmp[i], &senderaddr, - msg_buff, sizeof(msg_buff)); + senderaddrlen = sizeof(senderaddr); + len = ReceiveNATPMPOrPCPPacket(snatpmp[i], + (struct sockaddr *)&senderaddr, + &senderaddrlen, + msg_buff, sizeof(msg_buff)); if (len < 1) continue; #ifdef ENABLE_PCP if (msg_buff[0]==0) { /* version equals to 0 -> means NAT-PMP */ ProcessIncomingNATPMPPacket(snatpmp[i], msg_buff, len, - &senderaddr); + &senderaddr); } else { /* everything else can be PCP */ ProcessIncomingPCPPacket(snatpmp[i], msg_buff, len, - &senderaddr); + (struct sockaddr *)&senderaddr); } #else @@ -1998,6 +2015,25 @@ main(int argc, char * * argv) #endif } } +#endif +#if defined(ENABLE_IPV6) && defined(ENABLE_PCP) + /* in IPv6, only PCP is supported, not NAT-PMP */ + if(spcp_v6 >= 0 && FD_ISSET(spcp_v6, &readset)) + { + unsigned char msg_buff[PCP_MAX_LEN]; + struct sockaddr_in6 senderaddr; + socklen_t senderaddrlen; + int len; + memset(msg_buff, 0, PCP_MAX_LEN); + senderaddrlen = sizeof(senderaddr); + len = ReceiveNATPMPOrPCPPacket(spcp_v6, + (struct sockaddr *)&senderaddr, + &senderaddrlen, + msg_buff, sizeof(msg_buff)); + if(len >= 1) + ProcessIncomingPCPPacket(spcp_v6, msg_buff, len, + (struct sockaddr *)&senderaddr); + } #endif /* process SSDP packets */ if(sudp >= 0 && FD_ISSET(sudp, &readset)) @@ -2119,6 +2155,13 @@ shutdown: } } #endif +#if defined(ENABLE_IPV6) && defined(ENABLE_PCP) + if(spcp_v6 >= 0) + { + close(spcp_v6); + spcp_v6 = -1; + } +#endif #ifdef USE_MINIUPNPDCTL if(sctl>=0) { diff --git a/miniupnpd/natpmp.c b/miniupnpd/natpmp.c index 3c55ee5..694e26c 100644 --- a/miniupnpd/natpmp.c +++ b/miniupnpd/natpmp.c @@ -1,4 +1,4 @@ -/* $Id: natpmp.c,v 1.39 2014/03/07 10:43:30 nanard Exp $ */ +/* $Id: natpmp.c,v 1.43 2014/03/24 10:49:45 nanard Exp $ */ /* MiniUPnP project * (c) 2007-2014 Thomas Bernard * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ @@ -34,13 +34,13 @@ int OpenAndConfNATPMPSocket(in_addr_t addr) snatpmp = socket(PF_INET, SOCK_DGRAM, 0/*IPPROTO_UDP*/); if(snatpmp<0) { - syslog(LOG_ERR, "%s: socket(natpmp): %m", + syslog(LOG_ERR, "%s: socket(): %m", "OpenAndConfNATPMPSocket"); return -1; } if(setsockopt(snatpmp, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0) { - syslog(LOG_WARNING, "%s: setsockopt(natpmp, SO_REUSEADDR): %m", + syslog(LOG_WARNING, "%s: setsockopt(SO_REUSEADDR): %m", "OpenAndConfNATPMPSocket"); } if(!set_non_blocking(snatpmp)) @@ -57,7 +57,8 @@ int OpenAndConfNATPMPSocket(in_addr_t addr) natpmp_addr.sin_addr.s_addr = addr; if(bind(snatpmp, (struct sockaddr *)&natpmp_addr, sizeof(natpmp_addr)) < 0) { - syslog(LOG_ERR, "bind(natpmp): %m"); + syslog(LOG_ERR, "%s: bind(): %m", + "OpenAndConfNATPMPSocket"); close(snatpmp); return -1; } @@ -67,22 +68,25 @@ int OpenAndConfNATPMPSocket(in_addr_t addr) int OpenAndConfNATPMPSockets(int * sockets) { - int i, j; + int i; struct lan_addr_s * lan_addr; - for(i = 0, lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next, i++) + for(i = 0, lan_addr = lan_addrs.lh_first; + lan_addr != NULL; + lan_addr = lan_addr->list.le_next) { sockets[i] = OpenAndConfNATPMPSocket(lan_addr->addr.s_addr); if(sockets[i] < 0) - { - for(j=0; j= 0) + { + close(sockets[i]); + sockets[i] = -1; + } + return -1; } static void FillPublicAddressResponse(unsigned char * resp, in_addr_t senderaddr) @@ -124,15 +128,15 @@ static void FillPublicAddressResponse(unsigned char * resp, in_addr_t senderaddr * The sender information is stored in senderaddr. * Returns number of bytes recevied, even if number is negative. */ -int ReceiveNATPMPOrPCPPacket(int s, struct sockaddr_in* senderaddr, - unsigned char *msg_buff, size_t msg_buff_size) +int ReceiveNATPMPOrPCPPacket(int s, struct sockaddr * senderaddr, + socklen_t * senderaddrlen, + unsigned char * msg_buff, size_t msg_buff_size) { - socklen_t senderaddrlen = sizeof(*senderaddr); int n; n = recvfrom(s, msg_buff, msg_buff_size, 0, - (struct sockaddr *)senderaddr, &senderaddrlen); + senderaddr, senderaddrlen); if(n<0) { /* EAGAIN, EWOULDBLOCK and EINTR : silently ignore (retry next time) diff --git a/miniupnpd/natpmp.h b/miniupnpd/natpmp.h index 5f63517..2f6091b 100644 --- a/miniupnpd/natpmp.h +++ b/miniupnpd/natpmp.h @@ -1,4 +1,4 @@ -/* $Id: natpmp.h,v 1.11 2014/02/01 17:17:35 nanard Exp $ */ +/* $Id: natpmp.h,v 1.12 2014/03/24 10:49:46 nanard Exp $ */ /* MiniUPnP project * author : Thomas Bernard * website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ @@ -20,11 +20,12 @@ int OpenAndConfNATPMPSockets(int * sockets); -int ReceiveNATPMPOrPCPPacket(int s, struct sockaddr_in* senderaddr, - unsigned char *msg_buff, size_t msg_buff_size); +int ReceiveNATPMPOrPCPPacket(int s, struct sockaddr * senderaddr, + socklen_t * senderaddrlen, + unsigned char * msg_buff, size_t msg_buff_size); -void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, - struct sockaddr_in *senderaddr); +void ProcessIncomingNATPMPPacket(int s, unsigned char * msg_buff, int len, + struct sockaddr_in * senderaddr); void SendNATPMPPublicAddressChangeNotification(int * sockets, int n_sockets); diff --git a/miniupnpd/pcpserver.c b/miniupnpd/pcpserver.c index e6a62bd..b5074dc 100644 --- a/miniupnpd/pcpserver.c +++ b/miniupnpd/pcpserver.c @@ -1,4 +1,4 @@ -/* $Id: pcpserver.c,v 1.20 2014/03/22 12:06:15 nanard Exp $ */ +/* $Id: pcpserver.c,v 1.24 2014/03/24 11:03:52 nanard Exp $ */ /* MiniUPnP project * Website : http://miniupnp.free.fr/ * Author : Peter Tatrai @@ -53,6 +53,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include "pcpserver.h" +#include "natpmp.h" #include "macros.h" #include "upnpglobalvars.h" #include "pcplearndscp.h" @@ -60,6 +61,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "commonrdr.h" #include "getifaddr.h" #include "asyncsendto.h" +#include "upnputils.h" #include "pcp_msg_struct.h" #ifdef PCP_PEER @@ -117,7 +119,7 @@ typedef struct pcp_info { uint8_t is_peer_op; int thirdp_present; /* indicate presence of the options */ int pfailure_present; - char senderaddrstr[INET_ADDRSTRLEN]; + char senderaddrstr[INET_ADDRSTRLEN]; /* only if IPv4 sender */ } pcp_info_t; @@ -1385,19 +1387,29 @@ static void createPCPResponse(unsigned char *response, pcp_info_t *pcp_msg_info) } int ProcessIncomingPCPPacket(int s, unsigned char *buff, int len, - struct sockaddr_in *senderaddr) + const struct sockaddr * senderaddr) { pcp_info_t pcp_msg_info; +#ifdef DEBUG + char addr_str[64]; +#endif memset(&pcp_msg_info, 0, sizeof(pcp_info_t)); - if(!inet_ntop(AF_INET, &senderaddr->sin_addr, - pcp_msg_info.senderaddrstr, - sizeof(pcp_msg_info.senderaddrstr))) { - syslog(LOG_ERR, "inet_ntop(pcpserver): %m"); + if(senderaddr->sa_family == AF_INET) { + const struct sockaddr_in * senderaddr_v4; + senderaddr_v4 = (const struct sockaddr_in *)senderaddr; + if(!inet_ntop(AF_INET, &senderaddr_v4->sin_addr, + pcp_msg_info.senderaddrstr, + sizeof(pcp_msg_info.senderaddrstr))) { + syslog(LOG_ERR, "inet_ntop(pcpserver): %m"); + } } - syslog(LOG_DEBUG, "PCP request received from %s:%hu %dbytes", - pcp_msg_info.senderaddrstr, ntohs(senderaddr->sin_port), len); +#ifdef DEBUG + if(sockaddr_to_string(senderaddr, addr_str, sizeof(addr_str))) + syslog(LOG_DEBUG, "PCP request received from %s %dbytes", + addr_str, len); +#endif if(buff[1] & 128) { /* discarding PCP responses silently */ @@ -1421,4 +1433,44 @@ int ProcessIncomingPCPPacket(int s, unsigned char *buff, int len, return 0; } + +#ifdef ENABLE_IPV6 +int OpenAndConfPCPv6Socket(void) +{ + int s; + int i = 1; + struct sockaddr_in6 addr; + s = socket(PF_INET6, SOCK_DGRAM, 0/*IPPROTO_UDP*/); + if(s < 0) { + syslog(LOG_ERR, "%s: socket(): %m", "OpenAndConfPCPv6Socket"); + return -1; + } + if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0) { + syslog(LOG_WARNING, "%s: setsockopt(SO_REUSEADDR): %m", + "OpenAndConfPCPv6Socket"); + } +#ifdef IPV6_V6ONLY + /* 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, "%s: setsockopt(IPV6_V6ONLY): %m", + "OpenAndConfPCPv6Socket"); + } +#endif + if(!set_non_blocking(s)) { + syslog(LOG_WARNING, "%s: set_non_blocking(): %m", + "OpenAndConfPCPv6Socket"); + } + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(NATPMP_PORT); + addr.sin6_addr = in6addr_any; + if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + syslog(LOG_ERR, "%s: bind(): %m", "OpenAndConfPCPv6Socket"); + close(s); + return -1; + } + return s; +} +#endif /*ENABLE_IPV6*/ #endif /*ENABLE_PCP*/ diff --git a/miniupnpd/pcpserver.h b/miniupnpd/pcpserver.h index cc295f3..bd03b91 100644 --- a/miniupnpd/pcpserver.h +++ b/miniupnpd/pcpserver.h @@ -1,4 +1,4 @@ -/* $Id: pcpserver.h,v 1.2 2013/12/13 15:48:39 nanard Exp $ */ +/* $Id: pcpserver.h,v 1.3 2014/03/24 10:49:46 nanard Exp $ */ /* MiniUPnP project * Website : http://miniupnp.free.fr/ * Author : Peter Tatrai @@ -36,12 +36,17 @@ POSSIBILITY OF SUCH DAMAGE. #define PCP_MIN_LEN 24 #define PCP_MAX_LEN 1100 -struct sockaddr_in; +struct sockaddr; /* * returns 0 upon success 1 otherwise */ int ProcessIncomingPCPPacket(int s, unsigned char *msg_buff, int len, - struct sockaddr_in *senderaddr); + const struct sockaddr *senderaddr); + +/* + * returns the socket + */ +int OpenAndConfPCPv6Socket(void); #endif /* PCPSERVER_H_INCLUDED */ From d23365563011567510ecc27d05d89b2181e2fa82 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 24 Mar 2014 12:15:50 +0100 Subject: [PATCH 109/127] miniupnpd/pcpserver.c: fix for IPv6 --- miniupnpd/pcpserver.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/miniupnpd/pcpserver.c b/miniupnpd/pcpserver.c index b5074dc..dd15908 100644 --- a/miniupnpd/pcpserver.c +++ b/miniupnpd/pcpserver.c @@ -1,4 +1,4 @@ -/* $Id: pcpserver.c,v 1.24 2014/03/24 11:03:52 nanard Exp $ */ +/* $Id: pcpserver.c,v 1.25 2014/03/24 11:13:04 nanard Exp $ */ /* MiniUPnP project * Website : http://miniupnp.free.fr/ * Author : Peter Tatrai @@ -1424,8 +1424,10 @@ int ProcessIncomingPCPPacket(int s, unsigned char *buff, int len, len = PCP_MIN_LEN; else len = (len + 3) & ~3; /* round up resp. length to multiple of 4 */ - len = sendto_or_schedule(s, buff, len, 0, - (struct sockaddr *)senderaddr, sizeof(struct sockaddr_in)); + len = sendto_or_schedule(s, buff, len, 0, senderaddr, + (senderaddr->sa_family == AF_INET) ? + sizeof(struct sockaddr_in) : + sizeof(struct sockaddr_in6) ); if( len < 0 ) { syslog(LOG_ERR, "sendto(pcpserver): %m"); } From 0decb351e9ed6942bf8084ed5f59d3b297dcab48 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 24 Mar 2014 15:03:12 +0100 Subject: [PATCH 110/127] miniupnpd/pcpserver.c: check source address of PCP request --- miniupnpd/pcpserver.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/miniupnpd/pcpserver.c b/miniupnpd/pcpserver.c index dd15908..bcc701a 100644 --- a/miniupnpd/pcpserver.c +++ b/miniupnpd/pcpserver.c @@ -1,4 +1,4 @@ -/* $Id: pcpserver.c,v 1.25 2014/03/24 11:13:04 nanard Exp $ */ +/* $Id: pcpserver.c,v 1.26 2014/03/24 13:08:52 nanard Exp $ */ /* MiniUPnP project * Website : http://miniupnp.free.fr/ * Author : Peter Tatrai @@ -1390,9 +1390,8 @@ int ProcessIncomingPCPPacket(int s, unsigned char *buff, int len, const struct sockaddr * senderaddr) { pcp_info_t pcp_msg_info; -#ifdef DEBUG + struct lan_addr_s * lan_addr; char addr_str[64]; -#endif memset(&pcp_msg_info, 0, sizeof(pcp_info_t)); @@ -1405,17 +1404,22 @@ int ProcessIncomingPCPPacket(int s, unsigned char *buff, int len, syslog(LOG_ERR, "inet_ntop(pcpserver): %m"); } } -#ifdef DEBUG if(sockaddr_to_string(senderaddr, addr_str, sizeof(addr_str))) syslog(LOG_DEBUG, "PCP request received from %s %dbytes", addr_str, len); -#endif if(buff[1] & 128) { /* discarding PCP responses silently */ return 0; } + lan_addr = get_lan_for_peer(senderaddr); + if(lan_addr == NULL) { + syslog(LOG_WARNING, "SSDP packet sender %s not from a LAN, ignoring", + addr_str); + return 0; + } + if (processPCPRequest(buff, len, &pcp_msg_info) ) { createPCPResponse(buff, &pcp_msg_info); From f6f4e56bdf7fa5b137f5fe52709c66503b3c17bf Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 28 Mar 2014 12:45:39 +0100 Subject: [PATCH 111/127] miniupnpd/portinuse: cleanup --- miniupnpd/TODO | 1 + miniupnpd/portinuse.c | 43 ++++++++++++++++++++++----------------- miniupnpd/testportinuse.c | 2 +- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/miniupnpd/TODO b/miniupnpd/TODO index c34678d..eeb796a 100644 --- a/miniupnpd/TODO +++ b/miniupnpd/TODO @@ -33,3 +33,4 @@ use non blocking sockets everywhere : - NAT-PMP => OK - not needed for miniupnpdctl +implement port_in_use() for NetBSD and FreeBSD diff --git a/miniupnpd/portinuse.c b/miniupnpd/portinuse.c index 4e2118c..78ef8fb 100644 --- a/miniupnpd/portinuse.c +++ b/miniupnpd/portinuse.c @@ -28,14 +28,6 @@ #include #include #include -/* -#include -#include -#include -#include -#include -#include -*/ #endif #if defined(__DragonFly__) @@ -86,7 +78,8 @@ port_in_use(const char *if_name, (proto==IPPROTO_TCP)?"tcp":"udp", eport, if_name, ip_addr_str, (unsigned)ip_addr.s_addr); -#ifdef __linux__ + /* Phase 1 : check for local sockets (would be listed by netstat) */ +#if defined(__linux__) f = fopen((proto==IPPROTO_TCP)?tcpfile:udpfile, "r"); if (!f) { syslog(LOG_ERR, "cannot open %s", (proto==IPPROTO_TCP)?tcpfile:udpfile); @@ -102,7 +95,9 @@ port_in_use(const char *if_name, ) { /* TODO add IPV6 support if enabled * Presently assumes IPV4 */ - // syslog(LOG_DEBUG, "port_in_use check port %d and address %s", tmp_port, eaddr); +#ifdef DEBUG + syslog(LOG_DEBUG, "port_in_use check port %d and address %s", tmp_port, eaddr); +#endif if (tmp_port == eport) { char tmp_addr[4]; struct in_addr *tmp_ip_addr = (struct in_addr *)tmp_addr; @@ -119,9 +114,8 @@ port_in_use(const char *if_name, } } fclose(f); -#endif /* __linux__ */ -#if defined(__OpenBSD__) +#elif defined(__OpenBSD__) static struct nlist list[] = { #if 0 {"_tcpstat", 0, 0, 0, 0}, @@ -141,23 +135,25 @@ static struct nlist list[] = { struct inpcb inpcb; kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errstr); if(!kd) { - syslog(LOG_ERR, "portinuse(): kvm_openfiles(): %s", errstr); + syslog(LOG_ERR, "%s: kvm_openfiles(): %s", + "portinuse()", errstr); return -1; } if(kvm_nlist(kd, list) < 0) { - syslog(LOG_ERR, "portinuse(): kvm_nlist(): %s", kvm_geterr(kd)); + syslog(LOG_ERR, "%s: kvm_nlist(): %s", + "portinuse()", kvm_geterr(kd)); kvm_close(kd); return -1; } n = kvm_read(kd, list[(proto==IPPROTO_TCP)?0:1].n_value, &table, sizeof(table)); if(n < 0) { - syslog(LOG_ERR, "kvm_read(): %s", kvm_geterr(kd)); + syslog(LOG_ERR, "%s: kvm_read(): %s", + "portinuse()", kvm_geterr(kd)); kvm_close(kd); return -1; } - next = CIRCLEQ_FIRST(&table.inpt_queue); /*TAILQ_FIRST(&table.inpt_queue);*/ + next = CIRCLEQ_FIRST(&table.inpt_queue); /*TAILQ_FIRST(&table.inpt_queue);*/ while(next != NULL) { - /* syslog(LOG_DEBUG, "next=0x%08lx", (u_long)next); */ if(((u_long)next & 3) != 0) break; n = kvm_read(kd, (u_long)next, &inpcb, sizeof(inpcb)); if(n < 0) { @@ -165,11 +161,14 @@ static struct nlist list[] = { break; } next = CIRCLEQ_NEXT(&inpcb, inp_queue); /*TAILQ_NEXT(&inpcb, inp_queue);*/ + /* skip IPv6 sockets */ if((inpcb.inp_flags & INP_IPV6) != 0) continue; +#ifdef DEBUG syslog(LOG_DEBUG, "%08lx:%hu %08lx:%hu", (u_long)inpcb.inp_laddr.s_addr, ntohs(inpcb.inp_lport), (u_long)inpcb.inp_faddr.s_addr, ntohs(inpcb.inp_fport)); +#endif if(eport == (unsigned)ntohs(inpcb.inp_lport)) { if(inpcb.inp_laddr.s_addr == INADDR_ANY || inpcb.inp_laddr.s_addr == ip_addr.s_addr) { found++; @@ -178,9 +177,8 @@ static struct nlist list[] = { } } kvm_close(kd); -#endif -#if defined(__DragonFly__) +#elif defined(__DragonFly__) const char *varname; struct xinpcb *xip; struct xtcpcb *xtp; @@ -266,8 +264,15 @@ static struct nlist list[] = { free(buf); buf = NULL; } +/* #elif __NetBSD__ */ +/* #elif __FreeBSD__ */ +/* TODO : FreeBSD / NetBSD / Darwin (OS X) / Solaris code */ +#else +#error "No port_in_use() implementation available for this OS" #endif + /* Phase 2 : check existing mappings + * TODO : implement for pf/ipfw/etc. */ #if defined(USE_NETFILTER) if (!found) { char iaddr_old[16]; diff --git a/miniupnpd/testportinuse.c b/miniupnpd/testportinuse.c index 0efc42f..59977f8 100644 --- a/miniupnpd/testportinuse.c +++ b/miniupnpd/testportinuse.c @@ -1,4 +1,4 @@ -/* $Id $ */ +/* $Id: testportinuse.c,v 1.1.2.5 2014/03/14 11:12:08 nanard Exp $ */ /* MiniUPnP project * (c) 2014 Thomas Bernard * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ From 6a194ffcfb24dca418d55c0bc02bd8462797252c Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 28 Mar 2014 13:15:09 +0100 Subject: [PATCH 112/127] miniupnpd/testportinuse.c: fix compilation with CHECK_PORTINUSE undefined --- miniupnpd/testportinuse.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/miniupnpd/testportinuse.c b/miniupnpd/testportinuse.c index 59977f8..4e2625e 100644 --- a/miniupnpd/testportinuse.c +++ b/miniupnpd/testportinuse.c @@ -1,4 +1,4 @@ -/* $Id: testportinuse.c,v 1.1.2.5 2014/03/14 11:12:08 nanard Exp $ */ +/* $Id: testportinuse.c,v 1.3 2014/03/28 12:13:17 nanard Exp $ */ /* MiniUPnP project * (c) 2014 Thomas Bernard * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ @@ -14,13 +14,11 @@ #include "config.h" #include "portinuse.h" -#ifdef CHECK_PORTINUSE #ifdef USE_NETFILTER const char * miniupnpd_nat_chain = "MINIUPNPD"; const char * miniupnpd_peer_chain = "MINIUPNPD-PCP-PEER"; const char * miniupnpd_forward_chain = "MINIUPNPD"; #endif /* USE_NETFILTER */ -#endif /* CHECK_PORTINUSE */ int main(int argc, char * * argv) { From 3bd2388d4f38be11e15b5d37778b1785016e0d5e Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 1 Apr 2014 11:43:31 +0200 Subject: [PATCH 113/127] miniupnpd/Makefile: remove -ansi flag --- miniupnpd/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miniupnpd/Makefile b/miniupnpd/Makefile index fccf079..b0583de 100644 --- a/miniupnpd/Makefile +++ b/miniupnpd/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.76.2.2 2014/03/14 10:49:08 nanard Exp $ +# $Id: Makefile,v 1.79 2014/03/31 12:21:23 nanard Exp $ # MiniUPnP project # http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ # Author: Thomas Bernard @@ -17,7 +17,7 @@ CFLAGS ?= -pipe -Os #CFLAGS = -pipe -O -g -DDEBUG -CFLAGS += -ansi +#CFLAGS += -ansi CFLAGS += -Wall CFLAGS += -W CFLAGS += -Wstrict-prototypes From 349153585436660b07c2fd2020ebebaa064f47a5 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 1 Apr 2014 11:44:08 +0200 Subject: [PATCH 114/127] miniupnpd/Makefile: Link test programs with LIBS --- miniupnpd/Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/miniupnpd/Makefile b/miniupnpd/Makefile index b0583de..1c72ff9 100644 --- a/miniupnpd/Makefile +++ b/miniupnpd/Makefile @@ -193,19 +193,19 @@ miniupnpdctl: config.h $(MINIUPNPDCTLOBJS) $(CC) $(CFLAGS) -o $@ $(MINIUPNPDCTLOBJS) testupnpdescgen: config.h $(TESTUPNPDESCGENOBJS) - $(CC) $(CFLAGS) -o $@ $(TESTUPNPDESCGENOBJS) + $(CC) $(CFLAGS) -o $@ $(TESTUPNPDESCGENOBJS) $(LIBS) testgetifstats: config.h $(TESTGETIFSTATSOBJS) $(CC) $(CFLAGS) -o $@ $(TESTGETIFSTATSOBJS) $(LIBS) testgetifaddr: config.h $(TESTGETIFADDROBJS) - $(CC) $(CFLAGS) -o $@ $(TESTGETIFADDROBJS) + $(CC) $(CFLAGS) -o $@ $(TESTGETIFADDROBJS) $(LIBS) testupnppermissions: config.h $(TESTUPNPPERMISSIONSOBJS) - $(CC) $(CFLAGS) -o $@ $(TESTUPNPPERMISSIONSOBJS) + $(CC) $(CFLAGS) -o $@ $(TESTUPNPPERMISSIONSOBJS) $(LIBS) testgetroute: config.h $(TESTGETROUTEOBJS) - $(CC) $(CFLAGS) -o $@ $(TESTGETROUTEOBJS) + $(CC) $(CFLAGS) -o $@ $(TESTGETROUTEOBJS) $(LIBS) testasyncsendto: config.h $(TESTASYNCSENDTOOBJS) $(CC) $(CFLAGS) -o $@ $(TESTASYNCSENDTOOBJS) From c4d99670e7a95630410bef219d14a8632283bb74 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 1 Apr 2014 11:44:39 +0200 Subject: [PATCH 115/127] miniupnpd: Use SA_LEN consistently --- miniupnpd/bsd/getroute.c | 6 +++--- miniupnpd/bsd/ifacewatcher.c | 8 ++------ miniupnpd/upnputils.h | 27 ++++++++++++++++++++++++++- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/miniupnpd/bsd/getroute.c b/miniupnpd/bsd/getroute.c index e72f716..e9eda1d 100644 --- a/miniupnpd/bsd/getroute.c +++ b/miniupnpd/bsd/getroute.c @@ -1,4 +1,4 @@ -/* $Id: getroute.c,v 1.3 2013/02/06 13:11:45 nanard Exp $ */ +/* $Id: getroute.c,v 1.4 2014/03/31 12:27:14 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2013 Thomas Bernard @@ -83,7 +83,7 @@ get_src_for_route_to(const struct sockaddr * dst, sa = (struct sockaddr *)p; sockaddr_to_string(sa, tmp, sizeof(tmp)); syslog(LOG_DEBUG, "type=%d sa_len=%d sa_family=%d %s", - i, sa->sa_len, sa->sa_family, tmp); + i, SA_LEN(sa), sa->sa_family, tmp); if((i == RTA_DST || i == RTA_GATEWAY) && (src_len && src)) { size_t len = 0; @@ -113,7 +113,7 @@ get_src_for_route_to(const struct sockaddr * dst, *index = sdl->sdl_index; } #endif - p += sa->sa_len; + p += SA_LEN(sa); } } } diff --git a/miniupnpd/bsd/ifacewatcher.c b/miniupnpd/bsd/ifacewatcher.c index 67d64f4..0756f10 100644 --- a/miniupnpd/bsd/ifacewatcher.c +++ b/miniupnpd/bsd/ifacewatcher.c @@ -1,4 +1,4 @@ -/* $Id: ifacewatcher.c,v 1.5 2012/05/21 08:55:10 nanard Exp $ */ +/* $Id: ifacewatcher.c,v 1.6 2014/03/31 12:27:14 nanard Exp $ */ /* Project MiniUPnP * web : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2011 Thomas BERNARD @@ -15,12 +15,8 @@ #include #include -#if !defined(SA_LEN) -#define SA_LEN(sa) (sa)->sa_len -#endif - #define SALIGN (sizeof(long) - 1) -#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1)) +#define SA_RLEN(sa) (SA_LEN(sa) ? ((SA_LEN(sa) + SALIGN) & ~SALIGN) : (SALIGN + 1)) #include "../upnputils.h" #include "../upnpglobalvars.h" diff --git a/miniupnpd/upnputils.h b/miniupnpd/upnputils.h index 26e2c0b..a25398e 100644 --- a/miniupnpd/upnputils.h +++ b/miniupnpd/upnputils.h @@ -1,4 +1,4 @@ -/* $Id: upnputils.h,v 1.4 2013/02/06 10:50:04 nanard Exp $ */ +/* $Id: upnputils.h,v 1.6 2014/03/31 12:32:57 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2011-2013 Thomas Bernard @@ -29,5 +29,30 @@ set_non_blocking(int fd); struct lan_addr_s * get_lan_for_peer(const struct sockaddr * peer); + +/** + * define portability macros + */ +#if defined(__sun) +static size_t _sa_len(const struct sockaddr *addr) +{ + if (addr->sa_family == AF_INET) + return (sizeof(struct sockaddr_in)); + else if (addr->sa_family == AF_INET6) + return (sizeof(struct sockaddr_in6)); + else + return (sizeof(struct sockaddr)); +} +# define SA_LEN(sa) (_sa_len(sa)) +#else +#if !defined(SA_LEN) +# define SA_LEN(sa) ((sa)->sa_len) +#endif +#endif + +#ifndef MAX +# define MAX(a,b) (((a)>(b))?(a):(b)) +#endif + #endif From a4b29d2c3c6894966b5f37710b9af56b97421016 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 1 Apr 2014 16:47:00 +0200 Subject: [PATCH 116/127] miniupnpc/minihttptestserver.c: use sigaction() instead of signal() now accept() is interrupted by signals --- miniupnpc/minihttptestserver.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/miniupnpc/minihttptestserver.c b/miniupnpc/minihttptestserver.c index b719361..73078a6 100644 --- a/miniupnpc/minihttptestserver.c +++ b/miniupnpc/minihttptestserver.c @@ -1,7 +1,7 @@ -/* $Id: minihttptestserver.c,v 1.13 2012/05/29 13:03:07 nanard Exp $ */ +/* $Id: minihttptestserver.c,v 1.14 2014/04/01 14:42:21 nanard Exp $ */ /* Project : miniUPnP * Author : Thomas Bernard - * Copyright (c) 2011-2012 Thomas Bernard + * Copyright (c) 2011-2014 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. * */ @@ -35,13 +35,11 @@ void handle_signal_chld(int sig) /** * signal handler for SIGINT (CRTL C) */ -#if 0 void handle_signal_int(int sig) { printf("handle_signal_int(%d)\n", sig); quit = 1; } -#endif /** * build a text/plain content of the specified length @@ -338,6 +336,7 @@ int main(int argc, char * * argv) { int child = 0; int status; const char * expected_file_name = NULL; + struct sigaction sa; for(i = 1; i < argc; i++) { if(argv[i][0] == '-') { @@ -364,10 +363,21 @@ int main(int argc, char * * argv) { } srand(time(NULL)); - signal(SIGCHLD, handle_signal_chld); -#if 0 - signal(SIGINT, handle_signal_int); -#endif + + memset(&sa, 0, sizeof(struct sigaction)); + + /*signal(SIGCHLD, handle_signal_chld);*/ + sa.sa_handler = handle_signal_chld; + if(sigaction(SIGCHLD, &sa, NULL) < 0) { + perror("sigaction"); + return 1; + } + /*signal(SIGINT, handle_signal_int);*/ + sa.sa_handler = handle_signal_int; + if(sigaction(SIGINT, &sa, NULL) < 0) { + perror("sigaction"); + return 1; + } s = socket(ipv6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0); if(s < 0) { @@ -442,12 +452,12 @@ int main(int argc, char * * argv) { } --child_to_wait_for; } - /* TODO : add a select() call in order to handle the case - * when a signal is caught */ client_addrlen = sizeof(struct sockaddr_storage); c = accept(s, (struct sockaddr *)&client_addr, &client_addrlen); if(c < 0) { + if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) + continue; perror("accept"); return 1; } From 1c451f31bc4d4485473f3568c6397b7fd90d05f1 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 1 Apr 2014 16:47:57 +0200 Subject: [PATCH 117/127] miniupnpc/minihttptestserver.c: Have fun with favicon ;) --- miniupnpc/minihttptestserver.c | 134 ++++++++++++++++++++++++++++++++- 1 file changed, 132 insertions(+), 2 deletions(-) diff --git a/miniupnpc/minihttptestserver.c b/miniupnpc/minihttptestserver.c index 73078a6..a52c262 100644 --- a/miniupnpc/minihttptestserver.c +++ b/miniupnpc/minihttptestserver.c @@ -92,7 +92,8 @@ void build_crap(char * p, int n) * build chunked response. * return a malloc'ed buffer */ -char * build_chunked_response(int content_length, int * response_len) { +char * build_chunked_response(int content_length, int * response_len) +{ char * response_buffer; char * content_buffer; int buffer_length; @@ -139,7 +140,115 @@ char * build_chunked_response(int content_length, int * response_len) { return response_buffer; } -enum modes { MODE_INVALID, MODE_CHUNKED, MODE_ADDCRAP, MODE_NORMAL }; +/* favicon.ico generator */ +#ifdef OLD_HEADER +#define FAVICON_LENGTH (6 + 16 + 12 + 8 + 32 * 4) +#else +#define FAVICON_LENGTH (6 + 16 + 40 + 8 + 32 * 4) +#endif +void build_favicon_content(char * p, int n) +{ + int i; + if(n < FAVICON_LENGTH) + return; + /* header : 6 bytes */ + *p++ = 0; + *p++ = 0; + *p++ = 1; /* type : ICO */ + *p++ = 0; + *p++ = 1; /* number of images in file */ + *p++ = 0; + /* image directory (1 entry) : 16 bytes */ + *p++ = 16; /* width */ + *p++ = 16; /* height */ + *p++ = 2; /* number of colors in the palette. 0 = no palette */ + *p++ = 0; /* reserved */ + *p++ = 1; /* color planes */ + *p++ = 0; /* " */ + *p++ = 1; /* bpp */ + *p++ = 0; /* " */ +#ifdef OLD_HEADER + *p++ = 12 + 8 + 32 * 4; /* bmp size */ +#else + *p++ = 40 + 8 + 32 * 4; /* bmp size */ +#endif + *p++ = 0; /* " */ + *p++ = 0; /* " */ + *p++ = 0; /* " */ + *p++ = 6 + 16; /* bmp offset */ + *p++ = 0; /* " */ + *p++ = 0; /* " */ + *p++ = 0; /* " */ + /* BMP */ +#ifdef OLD_HEADER + /* BITMAPCOREHEADER */ + *p++ = 12; /* size of this header */ + *p++ = 0; /* " */ + *p++ = 0; /* " */ + *p++ = 0; /* " */ + *p++ = 16; /* width */ + *p++ = 0; /* " */ + *p++ = 16 * 2; /* height x 2 ! */ + *p++ = 0; /* " */ + *p++ = 1; /* color planes */ + *p++ = 0; /* " */ + *p++ = 1; /* bpp */ + *p++ = 0; /* " */ +#else + /* BITMAPINFOHEADER */ + *p++ = 40; /* size of this header */ + *p++ = 0; /* " */ + *p++ = 0; /* " */ + *p++ = 0; /* " */ + *p++ = 16; /* width */ + *p++ = 0; /* " */ + *p++ = 0; /* " */ + *p++ = 0; /* " */ + *p++ = 16 * 2; /* height x 2 ! */ + *p++ = 0; /* " */ + *p++ = 0; /* " */ + *p++ = 0; /* " */ + *p++ = 1; /* color planes */ + *p++ = 0; /* " */ + *p++ = 1; /* bpp */ + *p++ = 0; /* " */ + /* compression method, image size, ppm x, ppm y */ + /* colors in the palette ? */ + /* important colors */ + for(i = 4 * 6; i > 0; --i) + *p++ = 0; +#endif + /* palette */ + *p++ = 0; /* b */ + *p++ = 0; /* g */ + *p++ = 0; /* r */ + *p++ = 0; /* reserved */ + *p++ = 255; /* b */ + *p++ = 255; /* g */ + *p++ = 255; /* r */ + *p++ = 0; /* reserved */ + /* pixel data */ + for(i = 16; i > 0; --i) { + if(i & 1) { + *p++ = 0125; + *p++ = 0125; + } else { + *p++ = 0252; + *p++ = 0252; + } + *p++ = 0; + *p++ = 0; + } + /* Opacity MASK */ + for(i = 16 * 4; i > 0; --i) { + *p++ = 0; + } +} + +enum modes { + MODE_INVALID, MODE_CHUNKED, MODE_ADDCRAP, MODE_NORMAL, MODE_FAVICON +}; + const struct { const enum modes mode; const char * text; @@ -147,6 +256,7 @@ const struct { {MODE_CHUNKED, "chunked"}, {MODE_ADDCRAP, "addcrap"}, {MODE_NORMAL, "normal"}, + {MODE_FAVICON, "favicon.ico"}, {MODE_INVALID, NULL} }; @@ -290,6 +400,8 @@ void handle_http_connection(int c) case MODE_ADDCRAP: response_len = content_length+256; response_buffer = malloc(response_len); + if(!response_buffer) + break; n = snprintf(response_buffer, response_len, "HTTP/1.1 200 OK\r\n" "Server: minihttptestserver\r\n" @@ -301,9 +413,27 @@ void handle_http_connection(int c) build_content(response_buffer + n, content_length); build_crap(response_buffer + n + content_length, CRAP_LENGTH); break; + case MODE_FAVICON: + content_length = FAVICON_LENGTH; + response_len = content_length + 256; + response_buffer = malloc(response_len); + if(!response_buffer) + break; + n = snprintf(response_buffer, response_len, + "HTTP/1.1 200 OK\r\n" + "Server: minihttptestserver\r\n" + "Content-Type: image/vnd.microsoft.icon\r\n" + "Content-Length: %d\r\n" + "\r\n", content_length); + /* image/x-icon */ + build_favicon_content(response_buffer + n, content_length); + response_len = content_length + n; + break; default: response_len = content_length+256; response_buffer = malloc(response_len); + if(!response_buffer) + break; n = snprintf(response_buffer, response_len, "HTTP/1.1 200 OK\r\n" "Server: minihttptestserver\r\n" From 0a46cb161622bbb510b9233914ac90704ddd4367 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 1 Apr 2014 17:24:19 +0200 Subject: [PATCH 118/127] miniupnpc/minihttptestserver.c: small improvements --- miniupnpc/minihttptestserver.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/miniupnpc/minihttptestserver.c b/miniupnpc/minihttptestserver.c index a52c262..fb77965 100644 --- a/miniupnpc/minihttptestserver.c +++ b/miniupnpc/minihttptestserver.c @@ -1,4 +1,4 @@ -/* $Id: minihttptestserver.c,v 1.14 2014/04/01 14:42:21 nanard Exp $ */ +/* $Id: minihttptestserver.c,v 1.16 2014/04/01 15:08:28 nanard Exp $ */ /* Project : miniUPnP * Author : Thomas Bernard * Copyright (c) 2011-2014 Thomas Bernard @@ -28,7 +28,8 @@ volatile sig_atomic_t child_to_wait_for = 0; */ void handle_signal_chld(int sig) { - printf("handle_signal_chld(%d)\n", sig); + (void)sig; + /* printf("handle_signal_chld(%d)\n", sig); */ ++child_to_wait_for; } @@ -37,7 +38,8 @@ void handle_signal_chld(int sig) */ void handle_signal_int(int sig) { - printf("handle_signal_int(%d)\n", sig); + (void)sig; + /* printf("handle_signal_int(%d)\n", sig); */ quit = 1; } @@ -309,6 +311,8 @@ void handle_http_connection(int c) request_buffer + request_len, sizeof(request_buffer) - request_len); if(n < 0) { + if(errno == EINTR) + continue; perror("read"); return; } else if(n==0) { @@ -327,6 +331,7 @@ void handle_http_connection(int c) } if(!headers_found) { /* error */ + printf("no HTTP header found in the request\n"); return; } printf("headers :\n%.*s", request_len, request_buffer); From 29e951c1e55c9c7105438cd44515644e086dc62c Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 7 Apr 2014 12:39:05 +0200 Subject: [PATCH 119/127] miniupnpd/Makefile: improve ipfw detection --- miniupnpd/Makefile | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/miniupnpd/Makefile b/miniupnpd/Makefile index 1c72ff9..d24806b 100644 --- a/miniupnpd/Makefile +++ b/miniupnpd/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.79 2014/03/31 12:21:23 nanard Exp $ +# $Id: Makefile,v 1.80 2014/04/07 10:32:20 nanard Exp $ # MiniUPnP project # http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ # Author: Thomas Bernard @@ -45,7 +45,8 @@ FWNAME = ipf .if $(OSNAME) == "FreeBSD" FWNAME != . /etc/rc.subr; . /etc/rc.conf; \ if checkyesno ipfilter_enable; then \ - echo "ipf"; else echo "pf"; fi + echo "ipf"; elif checkyesno pf_enable; then \ + echo "pf"; else echo "ipfw"; fi .endif .if $(OSNAME) == "NetBSD" @@ -57,7 +58,8 @@ FWNAME != . /etc/rc.subr; . /etc/rc.conf; \ .if $(OSNAME) == "DragonFly" FWNAME != . /etc/rc.subr; . /etc/rc.conf; \ if checkyesno ipfilter; then \ - echo "ipf"; else echo "pf"; fi + echo "ipf"; elif checkyesno pf_enable; then \ + echo "pf"; else echo "ipfw"; fi .endif .endif From f789a3bab755850d22335f292766ea9c051ed45b Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 11 Apr 2014 00:03:13 +0200 Subject: [PATCH 120/127] miniupnpd/getifaddr.c: check if interface is up --- miniupnpd/getifaddr.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/miniupnpd/getifaddr.c b/miniupnpd/getifaddr.c index be57050..f9e2c6d 100644 --- a/miniupnpd/getifaddr.c +++ b/miniupnpd/getifaddr.c @@ -47,6 +47,19 @@ getifaddr(const char * ifname, char * buf, int len, return -1; } strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + if(ioctl(s, SIOCGIFFLAGS, &ifr, &ifrlen) < 0) + { + syslog(LOG_DEBUG, "ioctl(s, SIOCGIFFLAGS, ...): %m"); + close(s); + return -1; + } + if ((ifr.ifr_flags & IFF_UP) == 0) + { + syslog(LOG_DEBUG, "network interface %s is down", ifname); + close(s); + return -1; + } + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); if(ioctl(s, SIOCGIFADDR, &ifr, &ifrlen) < 0) { syslog(LOG_ERR, "ioctl(s, SIOCGIFADDR, ...): %m"); From 4f230c809b3b66fafa34d387eead32fe242c49ee Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 11 Apr 2014 09:31:02 +0200 Subject: [PATCH 121/127] miniupnpd/asyncsendto.c: improve error handling in try_sendto() to help investigate issue #64 --- miniupnpd/asyncsendto.c | 32 ++++++++++++++++++++------------ miniupnpd/miniupnpd.c | 5 +++-- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/miniupnpd/asyncsendto.c b/miniupnpd/asyncsendto.c index 8c83e25..a50718b 100644 --- a/miniupnpd/asyncsendto.c +++ b/miniupnpd/asyncsendto.c @@ -15,6 +15,7 @@ #include #include "asyncsendto.h" +#include "upnputils.h" /* state diagram for a packet : * @@ -159,6 +160,7 @@ int get_sendto_fds(fd_set * writefds, int * max_fd, const struct timeval * now) /* executed sendto() when needed */ int try_sendto(fd_set * writefds) { + int ret = 0; ssize_t n; struct scheduled_send * elt; struct scheduled_send * next; @@ -166,8 +168,8 @@ int try_sendto(fd_set * writefds) next = elt->entries.le_next; if((elt->state == ESENDNOW) || (elt->state == EWAITREADY && FD_ISSET(elt->sockfd, writefds))) { - syslog(LOG_DEBUG, "try_sendto(): %d bytes on socket %d", - (int)elt->len, elt->sockfd); + syslog(LOG_DEBUG, "%s: %d bytes on socket %d", + "try_sendto", (int)elt->len, elt->sockfd); n = sendto(elt->sockfd, elt->buf, elt->len, elt->flags, elt->dest_addr, elt->addrlen); if(n < 0) { @@ -179,20 +181,26 @@ int try_sendto(fd_set * writefds) /* retry once the socket is ready for writing */ elt->state = EWAITREADY; continue; + } else { + char addr_str[64]; + /* uncatched error */ + if(sockaddr_to_string(elt->dest_addr, addr_str, sizeof(addr_str)) <= 0) + addr_str[0] = '\0'; + syslog(LOG_ERR, "%s(sock=%d, len=%u, dest=%s): sendto: %m", + "try_sendto", elt->sockfd, (unsigned)elt->len, + addr_str); + ret--; } - /* uncatched error */ - /* remove from the list */ - LIST_REMOVE(elt, entries); - free(elt); - return n; - } else { - /* remove from the list */ - LIST_REMOVE(elt, entries); - free(elt); + } else if((int)n != (int)elt->len) { + syslog(LOG_WARNING, "%s: %d bytes sent out of %d", + "try_sendto", (int)n, (int)elt->len); } + /* remove from the list */ + LIST_REMOVE(elt, entries); + free(elt); } } - return 0; + return ret; } /* maximum execution time for finalize_sendto() in milliseconds */ diff --git a/miniupnpd/miniupnpd.c b/miniupnpd/miniupnpd.c index 42829fb..151d79a 100644 --- a/miniupnpd/miniupnpd.c +++ b/miniupnpd/miniupnpd.c @@ -1914,8 +1914,9 @@ main(int argc, char * * argv) syslog(LOG_ERR, "Failed to select open sockets. EXITING"); return 1; /* very serious cause of error */ } - if(try_sendto(&writeset) < 0) { - syslog(LOG_ERR, "try_sendto: %m"); + i = try_sendto(&writeset); + if(i < 0) { + syslog(LOG_ERR, "try_sendto failed to send %d packets", -i); } #ifdef USE_MINIUPNPDCTL for(ectl = ctllisthead.lh_first; ectl;) From 140ee8d2204b383279f854802b27bdb41c1d5d1a Mon Sep 17 00:00:00 2001 From: Thomas BERNARD Date: Sat, 12 Apr 2014 10:05:42 +0200 Subject: [PATCH 122/127] minissdpd.c: Initialize pointers to NULL (fix) --- minissdpd/minissdpd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/minissdpd/minissdpd.c b/minissdpd/minissdpd.c index 2421a42..5e79293 100644 --- a/minissdpd/minissdpd.c +++ b/minissdpd/minissdpd.c @@ -658,6 +658,7 @@ void processRequest(struct reqelem * req) syslog(LOG_ERR, "cannot allocate memory"); goto error; } + memset(newserv, 0, sizeof(struct service)); /* set pointers to NULL */ if(containsForbiddenChars(p, l)) { syslog(LOG_ERR, "bad request (st contains forbidden chars)"); goto error; From 2c18850bebf39435f16bd4fd45bbe3c7acc28613 Mon Sep 17 00:00:00 2001 From: Thomas BERNARD Date: Sat, 12 Apr 2014 10:06:32 +0200 Subject: [PATCH 123/127] testminissdpd.c: test for truncated response --- minissdpd/testminissdpd.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/minissdpd/testminissdpd.c b/minissdpd/testminissdpd.c index 30ee92d..52ceb6e 100644 --- a/minissdpd/testminissdpd.c +++ b/minissdpd/testminissdpd.c @@ -30,19 +30,34 @@ void printresponse(const unsigned char * resp, int n) nresp = resp[0]; p = resp + 1; for(i = 0; i < (int)nresp; i++) { + if(p >= resp + n) + goto error; /*l = *(p++);*/ DECODELENGTH(l, p); + if(p + l > resp + n) + goto error; printf("%d - %.*s\n", i, l, p); p += l; + if(p >= resp + n) + goto error; /*l = *(p++);*/ DECODELENGTH(l, p); + if(p + l > resp + n) + goto error; printf(" %.*s\n", l, p); p += l; + if(p >= resp + n) + goto error; /*l = *(p++);*/ DECODELENGTH(l, p); + if(p + l > resp + n) + goto error; printf(" %.*s\n", l, p); p += l; } + return; +error: + printf("*** WARNING : TRUNCATED RESPONSE ***\n"); } #define SENDCOMMAND(command, size) write(s, command, size); \ From 1576c07058d455772fef9aa486b49c91e42683d8 Mon Sep 17 00:00:00 2001 From: Thomas BERNARD Date: Sat, 12 Apr 2014 10:06:53 +0200 Subject: [PATCH 124/127] use bigger buffers for minissdpd responses --- minissdpd/testminissdpd.c | 2 +- miniupnpc/minissdpc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/minissdpd/testminissdpd.c b/minissdpd/testminissdpd.c index 52ceb6e..5670783 100644 --- a/minissdpd/testminissdpd.c +++ b/minissdpd/testminissdpd.c @@ -92,7 +92,7 @@ main(int argc, char * * argv) char overflow[] = { 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; int s; int i; - unsigned char buf[2048]; + unsigned char buf[16*1024]; ssize_t n; const char * sockpath = "/var/run/minissdpd.sock"; diff --git a/miniupnpc/minissdpc.c b/miniupnpc/minissdpc.c index a540341..8b7421b 100644 --- a/miniupnpc/minissdpc.c +++ b/miniupnpc/minissdpc.c @@ -46,7 +46,7 @@ getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath) { struct UPNPDev * tmp; struct UPNPDev * devlist = NULL; - unsigned char buffer[2048]; + unsigned char buffer[4*1024]; /* is that enough ? */ ssize_t n; unsigned char * p; unsigned char * url; From 90cc5ad3e7d4b56ec2f84f3fd244691f7b14b392 Mon Sep 17 00:00:00 2001 From: Daniel Becker Date: Sun, 13 Apr 2014 04:15:58 -0700 Subject: [PATCH 125/127] miniupnpd/portinuse.c: add FreeBSD support for CHECK_PORTINUSE --- miniupnpd/portinuse.c | 108 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 104 insertions(+), 4 deletions(-) diff --git a/miniupnpd/portinuse.c b/miniupnpd/portinuse.c index 78ef8fb..2fa5974 100644 --- a/miniupnpd/portinuse.c +++ b/miniupnpd/portinuse.c @@ -4,10 +4,12 @@ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ -#if defined(__DragonFly__) + +#if defined(__DragonFly__) || defined(__FreeBSD__) #include #include #endif + #include #include #include @@ -18,6 +20,7 @@ #include #include #include + #if defined(__OpenBSD__) #include #include @@ -30,7 +33,7 @@ #include #endif -#if defined(__DragonFly__) +#if defined(__DragonFly__) || defined(__FreeBSD__) #include #include /* sys/socketvar.h must be included above the following headers */ @@ -265,9 +268,106 @@ static struct nlist list[] = { buf = NULL; } /* #elif __NetBSD__ */ -/* #elif __FreeBSD__ */ -/* TODO : FreeBSD / NetBSD / Darwin (OS X) / Solaris code */ +#elif defined(__FreeBSD__) + const char *varname; + struct xinpgen *xig, *exig; + struct xinpcb *xip; + struct xtcpcb *xtp; + struct inpcb *inp; + void *buf = NULL; + size_t len; + + switch (proto) { + case IPPROTO_TCP: + varname = "net.inet.tcp.pcblist"; + break; + case IPPROTO_UDP: + varname = "net.inet.udp.pcblist"; + break; + default: + syslog(LOG_ERR, "port_in_use() unknown proto=%d", proto); + return -1; + } + + if (sysctlbyname(varname, NULL, &len, NULL, 0) < 0) { + syslog(LOG_ERR, "sysctlbyname(%s, NULL, ...): %m", varname); + return -1; + } + buf = malloc(len); + if (buf == NULL) { + syslog(LOG_ERR, "malloc(%u) failed", (unsigned)len); + return -1; + } + if (sysctlbyname(varname, buf, &len, NULL, 0) < 0) { + syslog(LOG_ERR, "sysctlbyname(%s, buf, ...): %m", varname); + free(buf); + return -1; + } + + xig = (struct xinpgen *)buf; + exig = (struct xinpgen *)(void *)((char *)buf + len - sizeof *exig); + if (xig->xig_len != sizeof *xig) { + syslog(LOG_WARNING, "struct xinpgen size mismatch; %ld vs %ld", + (long)xig->xig_len, sizeof *xig); + free(buf); + return -1; + } + if (exig->xig_len != sizeof *exig) { + syslog(LOG_WARNING, "struct xinpgen size mismatch; %ld vs %ld", + (long)exig->xig_len, sizeof *exig); + free(buf); + return -1; + } + + while (1) { + xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len); + if (xig >= exig) + break; + switch (proto) { + case IPPROTO_TCP: + xtp = (struct xtcpcb *)xig; + if (xtp->xt_len != sizeof *xtp) { + syslog(LOG_WARNING, "struct xtcpcb size mismatch; %ld vs %ld", + (long)xtp->xt_len, sizeof *xtp); + free(buf); + return -1; + } + inp = &xtp->xt_inp; + break; + case IPPROTO_UDP: + xip = (struct xinpcb *)xig; + if (xip->xi_len != sizeof *xip) { + syslog(LOG_WARNING, "struct xinpcb size mismatch : %ld vs %ld", + (long)xip->xi_len, sizeof *xip); + free(buf); + return -1; + } + inp = &xip->xi_inp; + break; + default: + abort(); + } + /* no support for IPv6 */ + if ((inp->inp_vflag & INP_IPV6) != 0) + continue; + syslog(LOG_DEBUG, "%08lx:%hu %08lx:%hu <=> %hu %08lx:%hu", + (u_long)inp->inp_laddr.s_addr, ntohs(inp->inp_lport), + (u_long)inp->inp_faddr.s_addr, ntohs(inp->inp_fport), + eport, (u_long)ip_addr.s_addr, iport + ); + if (eport == (unsigned)ntohs(inp->inp_lport)) { + if (inp->inp_laddr.s_addr == INADDR_ANY || inp->inp_laddr.s_addr == ip_addr.s_addr) { + found++; + break; /* don't care how many, just that we found at least one */ + } + } + } + if(buf) { + free(buf); + buf = NULL; + } #else +/* TODO : NetBSD / Darwin (OS X) / Solaris code */ #error "No port_in_use() implementation available for this OS" #endif From eea9188eeffc9ea876cb7adbcbb7e9fb4302f6d0 Mon Sep 17 00:00:00 2001 From: Daniel Becker Date: Sun, 13 Apr 2014 04:28:47 -0700 Subject: [PATCH 126/127] miniupnpd/portinuse.c: whitespace cleanup --- miniupnpd/portinuse.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/miniupnpd/portinuse.c b/miniupnpd/portinuse.c index 2fa5974..4fb0633 100644 --- a/miniupnpd/portinuse.c +++ b/miniupnpd/portinuse.c @@ -281,8 +281,8 @@ static struct nlist list[] = { case IPPROTO_TCP: varname = "net.inet.tcp.pcblist"; break; - case IPPROTO_UDP: - varname = "net.inet.udp.pcblist"; + case IPPROTO_UDP: + varname = "net.inet.udp.pcblist"; break; default: syslog(LOG_ERR, "port_in_use() unknown proto=%d", proto); @@ -302,8 +302,8 @@ static struct nlist list[] = { syslog(LOG_ERR, "sysctlbyname(%s, buf, ...): %m", varname); free(buf); return -1; - } - + } + xig = (struct xinpgen *)buf; exig = (struct xinpgen *)(void *)((char *)buf + len - sizeof *exig); if (xig->xig_len != sizeof *xig) { @@ -318,8 +318,8 @@ static struct nlist list[] = { free(buf); return -1; } - - while (1) { + + while (1) { xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len); if (xig >= exig) break; @@ -333,7 +333,7 @@ static struct nlist list[] = { return -1; } inp = &xtp->xt_inp; - break; + break; case IPPROTO_UDP: xip = (struct xinpcb *)xig; if (xip->xi_len != sizeof *xip) { @@ -362,7 +362,7 @@ static struct nlist list[] = { } } } - if(buf) { + if (buf) { free(buf); buf = NULL; } From 1140e1bddb8ceac095c41276bfc826b32da68e08 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 14 Apr 2014 09:17:10 +0200 Subject: [PATCH 127/127] miniupnpd/portinuse.c: minor cosmetic changes --- miniupnpd/portinuse.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miniupnpd/portinuse.c b/miniupnpd/portinuse.c index 4fb0633..7556559 100644 --- a/miniupnpd/portinuse.c +++ b/miniupnpd/portinuse.c @@ -263,11 +263,10 @@ static struct nlist list[] = { } } } - if(buf) { + if (buf) { free(buf); buf = NULL; } -/* #elif __NetBSD__ */ #elif defined(__FreeBSD__) const char *varname; struct xinpgen *xig, *exig; @@ -366,6 +365,7 @@ static struct nlist list[] = { free(buf); buf = NULL; } +/* #elif __NetBSD__ */ #else /* TODO : NetBSD / Darwin (OS X) / Solaris code */ #error "No port_in_use() implementation available for this OS"