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