From e252acef88600544686a9e54f914b37c532acd76 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Mon, 18 Jan 2016 20:16:06 +0100 Subject: [PATCH] PCP: check pinhole before adding in CreatePCPMap_FW() fixes #188 --- miniupnpd/netfilter/iptpinhole.c | 34 +++++++++++++++++++++++++++++++- miniupnpd/netfilter/iptpinhole.h | 8 +++++++- miniupnpd/pcpserver.c | 33 +++++++++++++++++++++++-------- miniupnpd/upnppinhole.c | 17 +++++++++++++++- miniupnpd/upnppinhole.h | 19 ++++++++++++++---- 5 files changed, 96 insertions(+), 15 deletions(-) diff --git a/miniupnpd/netfilter/iptpinhole.c b/miniupnpd/netfilter/iptpinhole.c index 1b4c7f6..a277b38 100644 --- a/miniupnpd/netfilter/iptpinhole.c +++ b/miniupnpd/netfilter/iptpinhole.c @@ -1,7 +1,7 @@ /* $Id: iptpinhole.c,v 1.14 2015/02/10 15:01:03 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2012-2015 Thomas Bernard + * (c) 2012-2016 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -13,6 +13,7 @@ #include #include "../config.h" +#include "../macros.h" #include "iptpinhole.h" #include "../upnpglobalvars.h" @@ -262,6 +263,37 @@ int add_pinhole(const char * ifname, return uid; } +int +find_pinhole(const char * ifname, + const char * rem_host, unsigned short rem_port, + const char * int_client, unsigned short int_port, + int proto, + char *desc, int desc_len, unsigned int * timestamp) +{ + struct pinhole_t * p; + struct in6_addr saddr; + struct in6_addr daddr; + UNUSED(ifname); + + if(rem_host && (rem_host[0] != '\0')) { + inet_pton(AF_INET6, rem_host, &saddr); + } else { + memset(&saddr, 0, sizeof(struct in6_addr)); + } + inet_pton(AF_INET6, int_client, &daddr); + for(p = pinhole_list.lh_first; p != NULL; p = p->entries.le_next) { + if((proto == p->proto) && (rem_port == p->sport) && + (0 == memcmp(&saddr, &p->saddr, sizeof(struct in6_addr))) && + (int_port == p->dport) && + (0 == memcmp(&daddr, &p->daddr, sizeof(struct in6_addr)))) { + if(desc) strncpy(desc, p->desc, desc_len); + if(timestamp) *timestamp = p->timestamp; + return (int)p->uid; + } + } + return -1; /* not found */ +} + int delete_pinhole(unsigned short uid) { diff --git a/miniupnpd/netfilter/iptpinhole.h b/miniupnpd/netfilter/iptpinhole.h index 1c84221..55f91a6 100644 --- a/miniupnpd/netfilter/iptpinhole.h +++ b/miniupnpd/netfilter/iptpinhole.h @@ -1,7 +1,7 @@ /* $Id: iptpinhole.h,v 1.5 2012/05/08 20:41:45 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2012 Thomas Bernard + * (c) 2012-2016 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ #ifndef IPTPINHOLE_H_INCLUDED @@ -10,6 +10,12 @@ #ifdef ENABLE_UPNPPINHOLE #include +int find_pinhole(const char * ifname, + const char * rem_host, unsigned short rem_port, + const char * int_client, unsigned short int_port, + int proto, + char *desc, int desc_len, unsigned int * timestamp); + int add_pinhole(const char * ifname, const char * rem_host, unsigned short rem_port, const char * int_client, unsigned short int_port, diff --git a/miniupnpd/pcpserver.c b/miniupnpd/pcpserver.c index 91501eb..d1742e0 100644 --- a/miniupnpd/pcpserver.c +++ b/miniupnpd/pcpserver.c @@ -989,17 +989,34 @@ static int CreatePCPMap_FW(pcp_info_t *pcp_msg_info) { #ifdef ENABLE_UPNPPINHOLE int uid; - int r = upnp_add_inboundpinhole(NULL, 0, + int r; + /* first check if pinhole already exists */ + uid = upnp_find_inboundpinhole(NULL, 0, pcp_msg_info->mapped_str, pcp_msg_info->int_port, pcp_msg_info->protocol, - pcp_msg_info->desc, - pcp_msg_info->lifetime, - &uid); - if (r < 0) - return PCP_ERR_NO_RESOURCES; - pcp_msg_info->ext_port = pcp_msg_info->int_port; - return PCP_SUCCESS; + NULL, 0, /* desc */ + NULL /* lifetime */); + if(uid >= 0) { + /* pinhole already exists, updating */ + syslog(LOG_INFO, "updating pinhole to %s:%hu %s", + pcp_msg_info->mapped_str, pcp_msg_info->int_port, + (pcp_msg_info->protocol == IPPROTO_TCP)?"TCP":"UDP"); + r = upnp_update_inboundpinhole((unsigned short)uid, pcp_msg_info->lifetime); + return r >= 0 ? PCP_SUCCESS : PCP_ERR_NO_RESOURCES; + } else { + r = upnp_add_inboundpinhole(NULL, 0, + pcp_msg_info->mapped_str, + pcp_msg_info->int_port, + pcp_msg_info->protocol, + pcp_msg_info->desc, + pcp_msg_info->lifetime, + &uid); + if (r < 0) + return PCP_ERR_NO_RESOURCES; + pcp_msg_info->ext_port = pcp_msg_info->int_port; + return PCP_SUCCESS; + } #else UNUSED(pcp_msg_info); return PCP_ERR_NO_RESOURCES; diff --git a/miniupnpd/upnppinhole.c b/miniupnpd/upnppinhole.c index 932bc11..c4320d9 100644 --- a/miniupnpd/upnppinhole.c +++ b/miniupnpd/upnppinhole.c @@ -1,7 +1,7 @@ /* $Id: upnppinhole.c,v 1.7 2014/12/09 09:13:53 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2012 Thomas Bernard + * (c) 2006-2016 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -87,6 +87,21 @@ upnp_check_outbound_pinhole(int proto, int * timeout) } #endif +int +upnp_find_inboundpinhole(const char * raddr, unsigned short rport, + const char * iaddr, unsigned short iport, + int proto, char * desc, int desc_len, unsigned int * leasetime) +{ +#if defined(USE_PF) || defined(USE_NETFILTER) + int uid; + uid = find_pinhole(NULL, raddr, rport, iaddr, iport, proto, + desc, desc_len, leasetime); + return uid; +#else + return -42; +#endif +} + /* upnp_add_inboundpinhole() * returns: 1 on success * -1 Pinhole space exhausted diff --git a/miniupnpd/upnppinhole.h b/miniupnpd/upnppinhole.h index 7c83067..c979401 100644 --- a/miniupnpd/upnppinhole.h +++ b/miniupnpd/upnppinhole.h @@ -1,7 +1,8 @@ /* $Id: upnppinhole.h,v 1.2 2012/09/18 08:29:49 nanard Exp $ */ -/* MiniUPnP project +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2012 Thomas Bernard + * (c) 2006-2016 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -12,7 +13,8 @@ #ifdef ENABLE_UPNPPINHOLE -/* functions to be used by WANIPv6_FirewallControl implementation */ +/* functions to be used by WANIPv6_FirewallControl implementation + * and PCP (IPv6) */ #if 0 /* retrieve outbound pinhole timeout */ @@ -20,6 +22,15 @@ int upnp_check_outbound_pinhole(int proto, int * timeout); #endif +/* find an inbound pinhole base on remove host:port / local host:port + * return the (positive) uid or a negative value if not found */ +int +upnp_find_inboundpinhole(const char * raddr, unsigned short rport, + const char * iaddr, unsigned short iport, + int proto, + char * desc, int desc_len, unsigned int * leasetime); + + /* add an inbound pinehole * return value : * 1 = success @@ -31,7 +42,7 @@ upnp_add_inboundpinhole(const char * raddr, unsigned short rport, int proto, char * desc, unsigned int leasetime, int * uid); -/* +/* get from uid * return values : * -1 not found * */