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",