Improve code for WANIPv6FirewallControl

This commit is contained in:
Thomas Bernard 2012-04-21 00:09:52 +02:00
parent 8148acc55c
commit c9cf40633d
3 changed files with 82 additions and 103 deletions

View File

@ -1,4 +1,4 @@
/* $Id: upnpredirect.c,v 1.66 2012/04/20 14:38:38 nanard Exp $ */ /* $Id: upnpredirect.c,v 1.67 2012/04/20 21:52:57 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-2012 Thomas Bernard * (c) 2006-2012 Thomas Bernard
@ -634,7 +634,7 @@ upnp_add_inboundpinhole(const char * raddr,
unsigned short rport, unsigned short rport,
const char * iaddr, const char * iaddr,
unsigned short iport, unsigned short iport,
const char * protocol, int proto,
unsigned int leasetime, unsigned int leasetime,
int * uid) int * uid)
{ {
@ -646,15 +646,12 @@ upnp_add_inboundpinhole(const char * raddr,
time_t current; time_t current;
unsigned int timestamp; unsigned int timestamp;
struct in6_addr address; /* IPv6 Modification*/ struct in6_addr address; /* IPv6 Modification*/
int proto;
if(inet_pton(AF_INET6, iaddr, &address) < 0) /* IPv6 Modification */ if(inet_pton(AF_INET6, iaddr, &address) < 0) /* IPv6 Modification */
{ {
syslog(LOG_ERR, "inet_pton(%s) : %m", iaddr); syslog(LOG_ERR, "inet_pton(%s) : %m", iaddr);
return 0; return 0;
} }
proto = atoi(protocol); /* for WANIPv6FirewallControl AddPinhole, the protocol argument
* is passed as an integer, not a string */
current = time(NULL); current = time(NULL);
timestamp = current + leasetime; timestamp = current + leasetime;
#if 0 #if 0
@ -673,7 +670,7 @@ upnp_add_inboundpinhole(const char * raddr,
else else
#endif #endif
{ {
syslog(LOG_INFO, "Adding pinhole for inbound traffic from [%s]:%hu to [%s]:%hu with protocol %s and %u lease time.", raddr, rport, iaddr, iport, protocol, leasetime); syslog(LOG_INFO, "Adding pinhole for inbound traffic from [%s]:%hu to [%s]:%hu with proto %d and %u lease time.", raddr, rport, iaddr, iport, proto, leasetime);
#ifdef USE_PF #ifdef USE_PF
*uid = add_pinhole (0/*ext_if_name*/, raddr, rport, iaddr, iport, proto, timestamp); *uid = add_pinhole (0/*ext_if_name*/, raddr, rport, iaddr, iport, proto, timestamp);
return 1; return 1;

View File

@ -1,7 +1,7 @@
/* $Id: upnpredirect.h,v 1.24 2011/06/22 20:34:39 nanard Exp $ */ /* $Id: upnpredirect.h,v 1.27 2012/04/20 21:52:58 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-2011 Thomas Bernard * (c) 2006-2012 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 */
@ -123,7 +123,7 @@ upnp_check_outbound_pinhole(int proto, int * timeout);
int int
upnp_add_inboundpinhole(const char * raddr, unsigned short rport, upnp_add_inboundpinhole(const char * raddr, unsigned short rport,
const char * iaddr, unsigned short iport, const char * iaddr, unsigned short iport,
const char * protocol, const char * leaseTime, int * uid); int proto, unsigned int leasetime, int * uid);
int int
upnp_add_inboundpinhole_internal(const char * raddr, unsigned short rport, upnp_add_inboundpinhole_internal(const char * raddr, unsigned short rport,

View File

@ -1,4 +1,4 @@
/* $Id: upnpsoap.c,v 1.96 2012/04/20 14:38:39 nanard Exp $ */ /* $Id: upnpsoap.c,v 1.97 2012/04/20 21:52:58 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-2012 Thomas Bernard * (c) 2006-2012 Thomas Bernard
@ -8,6 +8,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <errno.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <unistd.h> #include <unistd.h>
#include <syslog.h> #include <syslog.h>
@ -1144,62 +1145,6 @@ CheckStatus(struct upnphttp * h)
return 1; return 1;
} }
static int
DataVerification(struct upnphttp * h, char * int_ip, unsigned short * int_port, const char * protocol, char * leaseTime)
{
/* ** Internal IP can't be wildcarded */
if (!int_ip)
{
SoapError(h, 708, "WildCardNotPermittedInSrcIP");
return 0;
}
if (!strchr(int_ip, ':'))
{
SoapError(h, 402, "Invalid Args");
return 0;
}
/* ** Internal port can't be wilcarded. */
/* printf("\tint_port: *%d*\n", *int_port); */
if (*int_port == 0)
{
SoapError(h, 706, "InternalPortWilcardingNotAllowed");
return 0;
}
/* ** Protocol can't be wilcarded and can't be an unknown port
* (here deal with only UDP, TCP, UDPLITE) */
/* printf("\tprotocol: *%s*\n", protocol); */
if (atoi(protocol) == 65535)
{
SoapError(h, 707, "ProtocolWilcardingNotAllowed");
return 0;
}
else if (atoi(protocol) != IPPROTO_UDP
&& atoi(protocol) != IPPROTO_TCP
#ifdef IPPROTO_UDPITE
&& atoi(protocol) != IPPROTO_UDPLITE
#endif
)
{
SoapError(h, 705, "ProtocolNotSupported");
return 0;
}
/* ** Lease Time can't be wilcarded nor >86400. */
/* printf("\tlease time: %s\n", leaseTime); */
if(!leaseTime || !atoi(leaseTime) || atoi(leaseTime)>86400)
{
/* lease duration is never infinite, nor wilcarded. In this case, use default value */
syslog(LOG_WARNING, "LeaseTime=%s not supported, (ip=%s)", leaseTime, int_ip);
SoapError(h, 402, "Invalid Args");
return 0;
}
return 1;
}
#if 0 #if 0
static int connecthostport(const char * host, unsigned short port, char * result) static int connecthostport(const char * host, unsigned short port, char * result)
{ {
@ -1256,18 +1201,12 @@ static int connecthostport(const char * host, unsigned short port, char * result
/* Check the security policy right */ /* Check the security policy right */
static int static int
PinholeVerification(struct upnphttp * h, char * int_ip, unsigned short * int_port) PinholeVerification(struct upnphttp * h, char * int_ip, unsigned short int_port)
{ {
int n; int n;
char senderAddr[INET6_ADDRSTRLEN]=""; char senderAddr[INET6_ADDRSTRLEN]="";
#if 0
//char str[INET6_ADDRSTRLEN]="";
//connecthostport(int_ip, *int_port, str);
//printf("int_ip: %s / str: %s\n", int_ip, str);
#endif
struct addrinfo hints, *ai, *p; struct addrinfo hints, *ai, *p;
struct in6_addr result_ip;/*unsigned char result_ip[16];*/ /* inet_pton() */ struct in6_addr result_ip;
/* Pinhole InternalClient address must correspond to the action sender */ /* Pinhole InternalClient address must correspond to the action sender */
syslog(LOG_INFO, "Checking internal IP@ and port (Security policy purpose)"); syslog(LOG_INFO, "Checking internal IP@ and port (Security policy purpose)");
@ -1276,17 +1215,16 @@ PinholeVerification(struct upnphttp * h, char * int_ip, unsigned short * int_por
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
/* if ip not valid assume hostname and convert */ /* if ip not valid assume hostname and convert */
if (inet_pton(AF_INET6, int_ip, &result_ip) <= 0) /*IPv6 Modification*/ if (inet_pton(AF_INET6, int_ip, &result_ip) <= 0)
{ {
n = getaddrinfo(int_ip, NULL, &hints, &ai);
n = getaddrinfo(int_ip, NULL, &hints, &ai);/*hp = gethostbyname(int_ip);*/ if(!n && ai->ai_family == AF_INET6)
if(!n && ai->ai_family == AF_INET6) /*IPv6 Modification*/
{ {
for(p = ai; p; p = p->ai_next)/*ptr = hp->h_addr_list; ptr && *ptr; ptr++)*/ for(p = ai; p; p = p->ai_next)
{ {
inet_ntop(AF_INET6, (struct in6_addr *) p, int_ip, sizeof(struct in6_addr)); /*IPv6 Modification*/ inet_ntop(AF_INET6, (struct in6_addr *) p, int_ip, sizeof(struct in6_addr));
result_ip = *((struct in6_addr *) p); result_ip = *((struct in6_addr *) p);
fprintf(stderr, "upnpsoap / AddPinhole: assuming int addr = %s", int_ip); /* fprintf(stderr, "upnpsoap / AddPinhole: assuming int addr = %s", int_ip); */
/* TODO : deal with more than one ip per hostname */ /* TODO : deal with more than one ip per hostname */
break; break;
} }
@ -1317,7 +1255,7 @@ PinholeVerification(struct upnphttp * h, char * int_ip, unsigned short * int_por
} }
/* Pinhole InternalPort must be greater than or equal to 1024 */ /* Pinhole InternalPort must be greater than or equal to 1024 */
if (*int_port < 1024) if (int_port < 1024)
{ {
syslog(LOG_INFO, "Client %s tried to access pinhole with port < 1024 and is not authorized to do it", syslog(LOG_INFO, "Client %s tried to access pinhole with port < 1024 and is not authorized to do it",
senderAddr); senderAddr);
@ -1343,6 +1281,7 @@ AddPinhole(struct upnphttp * h, const char * action)
int uid = 0; int uid = 0;
unsigned short iport, rport; unsigned short iport, rport;
int ltime; int ltime;
long proto;
if(CheckStatus(h)==0) if(CheckStatus(h)==0)
return; return;
@ -1357,7 +1296,19 @@ AddPinhole(struct upnphttp * h, const char * action)
rport = (unsigned short)(rem_port ? atoi(rem_port) : 0); rport = (unsigned short)(rem_port ? atoi(rem_port) : 0);
iport = (unsigned short)(int_port ? atoi(int_port) : 0); iport = (unsigned short)(int_port ? atoi(int_port) : 0);
ltime = atoi(leaseTime); ltime = leaseTime ? atoi(leaseTime) : -1;
errno = 0;
proto = protocol ? strtol(protocol, NULL, 0) : -1;
if(errno != 0 || proto > 65535 || proto < 0)
{
SoapError(h, 402, "Invalid Args");
goto clear_and_exit;
}
if(iport == 0)
{
SoapError(h, 706, "InternalPortWilcardingNotAllowed");
goto clear_and_exit;
}
/* In particular, [IGD2] RECOMMENDS that unauthenticated and /* In particular, [IGD2] RECOMMENDS that unauthenticated and
* unauthorized control points are only allowed to invoke * unauthorized control points are only allowed to invoke
@ -1366,37 +1317,59 @@ AddPinhole(struct upnphttp * h, const char * action)
* - InternalClient value equals to the control point's IP address. * - InternalClient value equals to the control point's IP address.
* It is REQUIRED that InternalClient cannot be one of IPv6 * It is REQUIRED that InternalClient cannot be one of IPv6
* addresses used by the gateway. */ * addresses used by the gateway. */
/* ** As there is no security policy, InternalClient must be equal if(!int_ip || 0 == strlen(int_ip) || 0 == strcmp(int_ip, "*"))
* to the CP's IP address. */
if(DataVerification(h, int_ip, &iport, protocol, leaseTime) == 0
|| PinholeVerification(h, int_ip, &iport) <= 0)
{ {
ClearNameValueList(&data); SoapError(h, 708, "WildCardNotPermittedInSrcIP");
return ; goto clear_and_exit;
} }
/* TODO : convert int_ip to literal ipv6 address ? */
/* TODO : rem_host should be converted to literal ipv6 ? */
/* ** RemoteHost can be wilcarded or an IDN. */ if(proto == 65535)
/*printf("\trem_host: %s\n", rem_host);*/
if (rem_host!=NULL && !strchr(rem_host, ':'))
{ {
ClearNameValueList(&data); SoapError(h, 707, "ProtocolWilcardingNotAllowed");
goto clear_and_exit;
}
if(proto != IPPROTO_UDP && proto != IPPROTO_TCP
#ifdef IPPROTO_UDPITE
&& atoi(protocol) != IPPROTO_UDPLITE
#endif
)
{
SoapError(h, 705, "ProtocolNotSupported");
goto clear_and_exit;
}
if(ltime < 1 || ltime > 86400)
{
syslog(LOG_WARNING, "%s: LeaseTime=%d not supported, (ip=%s)",
action, ltime, int_ip);
SoapError(h, 402, "Invalid Args"); SoapError(h, 402, "Invalid Args");
return; goto clear_and_exit;
} }
/*printf("\tAddr check passed.\n");*/
syslog(LOG_INFO, "%s: (inbound) from [%s]:%hu to [%s]:%hu with protocol %s during %ssec", action, rem_host?rem_host:"anywhere", rport, int_ip, iport, protocol, leaseTime); if(PinholeVerification(h, int_ip, iport) <= 0)
{
goto clear_and_exit;
}
syslog(LOG_INFO, "%s: (inbound) from [%s]:%hu to [%s]:%hu with proto %ld during %d sec",
action, rem_host?rem_host:"any",
rport, int_ip, iport,
proto, ltime);
/* In cases where the RemoteHost, RemotePort, InternalPort, /* In cases where the RemoteHost, RemotePort, InternalPort,
* InternalClient and Protocol are the same than an existing pinhole, * InternalClient and Protocol are the same than an existing pinhole,
* but LeaseTime is different, the device MUST extend the existing * but LeaseTime is different, the device MUST extend the existing
* pinhole's lease time and return the UniqueID of the existing pinhole. */ * pinhole's lease time and return the UniqueID of the existing pinhole. */
r = upnp_add_inboundpinhole(rem_host, rport, int_ip, iport, protocol, ltime, &uid); r = upnp_add_inboundpinhole(rem_host, rport, int_ip, iport, proto, ltime, &uid);
switch(r) switch(r)
{ {
case 1: /* success */ case 1: /* success */
bodylen = snprintf(body, sizeof(body), resp, action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", uid, action); bodylen = snprintf(body, sizeof(body),
resp, action,
"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
uid, action);
BuildSendAndCloseSoapResp(h, body, bodylen); BuildSendAndCloseSoapResp(h, body, bodylen);
break; break;
case -1: /* not permitted */ case -1: /* not permitted */
@ -1406,6 +1379,15 @@ AddPinhole(struct upnphttp * h, const char * action)
SoapError(h, 501, "ActionFailed"); SoapError(h, 501, "ActionFailed");
break; break;
} }
/* 606 Action not authorized
* 701 PinholeSpaceExhausted
* 702 FirewallDisabled
* 703 InboundPinholeNotAllowed
* 705 ProtocolNotSupported
* 706 InternalPortWildcardingNotAllowed
* 707 ProtocolWildcardingNotAllowed
* 708 WildCardNotPermittedInSrcIP */
clear_and_exit:
ClearNameValueList(&data); ClearNameValueList(&data);
} }
@ -1444,7 +1426,7 @@ UpdatePinhole(struct upnphttp * h, const char * action)
n = upnp_get_pinhole_info(0, 0, iaddr, &iport, proto, uid, lt); n = upnp_get_pinhole_info(0, 0, iaddr, &iport, proto, uid, lt);
if (n > 0) if (n > 0)
{ {
if(PinholeVerification(h, iaddr, &iport)==0) if(PinholeVerification(h, iaddr, iport)==0)
{ {
ClearNameValueList(&data); ClearNameValueList(&data);
return ; return ;
@ -1556,7 +1538,7 @@ DeletePinhole(struct upnphttp * h, const char * action)
n = upnp_get_pinhole_info(0, 0, iaddr, &iport, proto, uid, lt); n = upnp_get_pinhole_info(0, 0, iaddr, &iport, proto, uid, lt);
if (n > 0) if (n > 0)
{ {
if(PinholeVerification(h, iaddr, &iport)==0) if(PinholeVerification(h, iaddr, iport)==0)
{ {
ClearNameValueList(&data); ClearNameValueList(&data);
return ; return ;
@ -1620,7 +1602,7 @@ CheckPinholeWorking(struct upnphttp * h, const char * action)
r = upnp_get_pinhole_info(eaddr, eport, iaddr, &iport, proto, uid, lt); r = upnp_get_pinhole_info(eaddr, eport, iaddr, &iport, proto, uid, lt);
if (r > 0) if (r > 0)
{ {
if(PinholeVerification(h, iaddr, &iport)==0) if(PinholeVerification(h, iaddr, iport)==0)
{ {
ClearNameValueList(&data); ClearNameValueList(&data);
return ; return ;
@ -1719,7 +1701,7 @@ GetPinholePackets(struct upnphttp * h, const char * action)
r = upnp_get_pinhole_info(0, 0, iaddr, &iport, proto, uid, lt); r = upnp_get_pinhole_info(0, 0, iaddr, &iport, proto, uid, lt);
if (r > 0) if (r > 0)
{ {
if(PinholeVerification(h, iaddr, &iport)==0) if(PinholeVerification(h, iaddr, iport)==0)
{ {
ClearNameValueList(&data); ClearNameValueList(&data);
return ; return ;