Merge branch 'issue-465' into master

This commit is contained in:
Thomas Bernard 2020-10-28 19:38:52 +01:00
commit 1008ed1117
3 changed files with 86 additions and 21 deletions

View File

@ -1,7 +1,7 @@
/* $Id: upnppermissions.c,v 1.18 2014/03/07 10:43:29 nanard Exp $ */ /* $Id: upnppermissions.c,v 1.18 2014/03/07 10:43:29 nanard Exp $ */
/* MiniUPnP project /* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2014 Thomas Bernard * (c) 2006-2020 Thomas Bernard
* This software is subject to the conditions detailed * This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */ * in the LICENCE file provided within the distribution */
@ -262,3 +262,44 @@ check_upnp_rule_against_permissions(const struct upnpperm * permary,
return 1; /* Default : accept */ return 1; /* Default : accept */
} }
void
get_permitted_ext_ports(uint32_t * allowed,
const struct upnpperm * permary, int n_perms,
in_addr_t addr, u_short iport)
{
int i, j;
/* build allowed external ports array */
memset(allowed, 0xff, 65536 / 8); /* everything allowed by default */
for (i = n_perms - 1; i >= 0; i--)
{
if( (addr & permary[i].mask.s_addr)
!= (permary[i].address.s_addr & permary[i].mask.s_addr) )
continue;
if( (iport < permary[i].iport_min) || (permary[i].iport_max < iport))
continue;
for (j = (int)permary[i].eport_min ; j <= (int)permary[i].eport_max; )
{
if ((j % 32) == 0 && ((int)permary[i].eport_max >= (j + 31)))
{
/* 32bits at once */
allowed[j / 32] = (permary[i].type == UPNPPERM_ALLOW) ? 0xffffffff : 0;
j += 32;
}
else
{
do
{
/* one bit at once */
if (permary[i].type == UPNPPERM_ALLOW)
allowed[j / 32] |= (1 << (j % 32));
else
allowed[j / 32] &= ~(1 << (j % 32));
j++;
}
while ((j % 32) != 0 && (j <= (int)permary[i].eport_max));
}
}
}
}

View File

@ -1,7 +1,7 @@
/* $Id: upnppermissions.h,v 1.10 2014/03/07 10:43:29 nanard Exp $ */ /* $Id: upnppermissions.h,v 1.10 2014/03/07 10:43:29 nanard Exp $ */
/* MiniUPnP project /* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2014 Thomas Bernard * (c) 2006-2020 Thomas Bernard
* This software is subject to the conditions detailed * This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */ * in the LICENCE file provided within the distribution */
@ -45,6 +45,14 @@ check_upnp_rule_against_permissions(const struct upnpperm * permary,
u_short eport, struct in_addr address, u_short eport, struct in_addr address,
u_short iport); u_short iport);
/**
* Build an array of all allowed external ports (for the address and internal port)
*/
void
get_permitted_ext_ports(uint32_t * allowed,
const struct upnpperm * permary, int n_perms,
in_addr_t addr, u_short iport);
#ifdef USE_MINIUPNPDCTL #ifdef USE_MINIUPNPDCTL
void void
write_permlist(int fd, const struct upnpperm * permary, write_permlist(int fd, const struct upnpperm * permary,

View File

@ -27,6 +27,7 @@
#include "upnpsoap.h" #include "upnpsoap.h"
#include "upnpreplyparse.h" #include "upnpreplyparse.h"
#include "upnpredirect.h" #include "upnpredirect.h"
#include "upnppermissions.h"
#include "upnppinhole.h" #include "upnppinhole.h"
#include "getifaddr.h" #include "getifaddr.h"
#include "getifstats.h" #include "getifstats.h"
@ -586,7 +587,7 @@ AddAnyPortMapping(struct upnphttp * h, const char * action, const char * ns)
struct NameValueParserData data; struct NameValueParserData data;
const char * int_ip, * int_port, * ext_port, * protocol, * desc; const char * int_ip, * int_port, * ext_port, * protocol, * desc;
const char * r_host; const char * r_host;
unsigned short iport, eport, eport_below, eport_above; unsigned short iport, eport;
const char * leaseduration_str; const char * leaseduration_str;
unsigned int leaseduration; unsigned int leaseduration;
@ -674,26 +675,41 @@ AddAnyPortMapping(struct upnphttp * h, const char * action, const char * ns)
/* first try the port asked in request, then /* first try the port asked in request, then
* try +1, -1, +2, -2, etc. */ * try +1, -1, +2, -2, etc. */
eport_above = eport_below = eport; r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration);
for(;;) { if (r != 0 && r != -1) {
r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration); unsigned short eport_below, eport_above;
if (r == 0 || r == -1) { struct in_addr address;
/* OK or failure : Stop */ uint32_t allowed_eports[65536 / 32];
break;
if(inet_aton(int_ip, &address) <= 0) {
syslog(LOG_ERR, "inet_aton(%s) FAILED", int_ip);
} }
/* r : -2 / -4 already redirected or -3 permission check failed */ get_permitted_ext_ports(allowed_eports, upnppermlist, num_upnpperm,
if (eport_below <= 1 && eport_above == 65535) { address.s_addr, iport);
/* all possible ports tried */ eport_above = eport_below = eport;
r = 1; for(;;) {
break; /* loop invariant
* eport is equal to either eport_below or eport_above (or both) */
if (eport_below <= 1 && eport_above == 65535) {
/* all possible ports tried */
r = 1;
break;
}
if (eport_above == 65535 || (eport > eport_below && eport_below > 1)) {
eport = --eport_below;
} else {
eport = ++eport_above;
}
if (!(allowed_eports[eport / 32] & ((uint32_t)1U << (eport % 32))))
continue; /* not allowed */
r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration);
if (r == 0 || r == -1) {
/* OK or failure : Stop */
break;
}
/* r : -2 / -4 already redirected or -3 permission check failed :
* continue */
} }
if (eport_above == 65535 || (eport > eport_below && eport_below > 1)) {
eport = --eport_below;
} else {
eport = ++eport_above;
}
/* loop invariant :
* eport is equal to either eport_below or eport_above (or both) */
} }
ClearNameValueList(&data); ClearNameValueList(&data);