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
This commit is contained in:
Thomas Bernard 2014-03-07 11:48:17 +01:00
parent f49a70aab0
commit e385db03b9
4 changed files with 75 additions and 18 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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<n_perms; i++)
{
if(permary[i].type == UPNPPERM_ALLOW
&& match_permission_internal(permary + i, address, iport)) {
*allowed_eport = permary[i].eport_min;
return 1;
}
}
return 0; /* no eport found */
}

View File

@ -1,7 +1,7 @@
/* $Id: upnppermissions.h,v 1.7 2007/02/28 18:13:18 nanard Exp $ */
/* $Id: upnppermissions.h,v 1.10 2014/03/07 10:43:29 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 */
@ -45,6 +45,15 @@ check_upnp_rule_against_permissions(const struct upnpperm * permary,
u_short eport, struct in_addr address,
u_short iport);
/* find_allowed_eport()
* returns: 0 if no allowed eport for (address, iport) was found
* 1 and allowed_eport filled */
int
find_allowed_eport(const struct upnpperm * permary,
int n_perms,
struct in_addr address, u_short iport,
u_short *allowed_eport);
#ifdef USE_MINIUPNPDCTL
void
write_permlist(int fd, const struct upnpperm * permary,