From 013b0df38870d4735919bf16dc5c2def6122ca6c Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Tue, 10 Jul 2012 23:25:29 +0200 Subject: [PATCH 01/12] 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 c4e63048c43912fd016fe95b41e1bc37838c2fa5 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 13 Mar 2014 14:48:52 +0100 Subject: [PATCH 02/12] 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 03/12] 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 04/12] 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 dcce22647d9f867e56c8f2485b53a4ea3f7d0186 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 14 Mar 2014 12:07:03 +0100 Subject: [PATCH 05/12] 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 06/12] 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 ba448fd7dd0847cc1ae929b31e6a7e40e8e066ac Mon Sep 17 00:00:00 2001 From: Thomas BERNARD Date: Mon, 17 Mar 2014 15:35:18 +0100 Subject: [PATCH 07/12] 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 08/12] 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 aea062a7baf82c3b8bea9f2824ed966162f43544 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Thu, 20 Mar 2014 13:40:53 +0100 Subject: [PATCH 09/12] 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 10/12] 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 11/12] 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 f6f4e56bdf7fa5b137f5fe52709c66503b3c17bf Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 28 Mar 2014 12:45:39 +0100 Subject: [PATCH 12/12] 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/