diff --git a/miniupnpd/upnpredirect.c b/miniupnpd/upnpredirect.c index c61e882..10dece4 100644 --- a/miniupnpd/upnpredirect.c +++ b/miniupnpd/upnpredirect.c @@ -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 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2012 Thomas Bernard @@ -634,7 +634,7 @@ upnp_add_inboundpinhole(const char * raddr, unsigned short rport, const char * iaddr, unsigned short iport, - const char * protocol, + int proto, unsigned int leasetime, int * uid) { @@ -646,15 +646,12 @@ upnp_add_inboundpinhole(const char * raddr, time_t current; unsigned int timestamp; struct in6_addr address; /* IPv6 Modification*/ - int proto; if(inet_pton(AF_INET6, iaddr, &address) < 0) /* IPv6 Modification */ { syslog(LOG_ERR, "inet_pton(%s) : %m", iaddr); return 0; } - proto = atoi(protocol); /* for WANIPv6FirewallControl AddPinhole, the protocol argument - * is passed as an integer, not a string */ current = time(NULL); timestamp = current + leasetime; #if 0 @@ -673,7 +670,7 @@ upnp_add_inboundpinhole(const char * raddr, else #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 *uid = add_pinhole (0/*ext_if_name*/, raddr, rport, iaddr, iport, proto, timestamp); return 1; diff --git a/miniupnpd/upnpredirect.h b/miniupnpd/upnpredirect.h index 916785e..fd01687 100644 --- a/miniupnpd/upnpredirect.h +++ b/miniupnpd/upnpredirect.h @@ -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 * 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 * in the LICENCE file provided within the distribution */ @@ -123,7 +123,7 @@ upnp_check_outbound_pinhole(int proto, int * timeout); int upnp_add_inboundpinhole(const char * raddr, unsigned short rport, const char * iaddr, unsigned short iport, - const char * protocol, const char * leaseTime, int * uid); + int proto, unsigned int leasetime, int * uid); int upnp_add_inboundpinhole_internal(const char * raddr, unsigned short rport, diff --git a/miniupnpd/upnpsoap.c b/miniupnpd/upnpsoap.c index 7d4ccc6..259f267 100644 --- a/miniupnpd/upnpsoap.c +++ b/miniupnpd/upnpsoap.c @@ -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 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2012 Thomas Bernard @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -1144,62 +1145,6 @@ CheckStatus(struct upnphttp * h) 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 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 */ 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; 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 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 */ 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; /* 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);/*hp = gethostbyname(int_ip);*/ - if(!n && ai->ai_family == AF_INET6) /*IPv6 Modification*/ + n = getaddrinfo(int_ip, NULL, &hints, &ai); + if(!n && ai->ai_family == AF_INET6) { - for(p = ai; p; p = p->ai_next)/*ptr = hp->h_addr_list; ptr && *ptr; ptr++)*/ - { - inet_ntop(AF_INET6, (struct in6_addr *) p, int_ip, sizeof(struct in6_addr)); /*IPv6 Modification*/ + for(p = ai; p; p = p->ai_next) + { + inet_ntop(AF_INET6, (struct in6_addr *) p, int_ip, sizeof(struct in6_addr)); 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 */ 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 */ - 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", senderAddr); @@ -1343,6 +1281,7 @@ AddPinhole(struct upnphttp * h, const char * action) int uid = 0; unsigned short iport, rport; int ltime; + long proto; if(CheckStatus(h)==0) return; @@ -1357,7 +1296,19 @@ AddPinhole(struct upnphttp * h, const char * action) rport = (unsigned short)(rem_port ? atoi(rem_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 * 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. * It is REQUIRED that InternalClient cannot be one of IPv6 * addresses used by the gateway. */ - /* ** As there is no security policy, InternalClient must be equal - * to the CP's IP address. */ - if(DataVerification(h, int_ip, &iport, protocol, leaseTime) == 0 - || PinholeVerification(h, int_ip, &iport) <= 0) + if(!int_ip || 0 == strlen(int_ip) || 0 == strcmp(int_ip, "*")) { - ClearNameValueList(&data); - return ; + SoapError(h, 708, "WildCardNotPermittedInSrcIP"); + 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. */ - /*printf("\trem_host: %s\n", rem_host);*/ - if (rem_host!=NULL && !strchr(rem_host, ':')) + if(proto == 65535) { - 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"); - 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, * InternalClient and Protocol are the same than an existing pinhole, * but LeaseTime is different, the device MUST extend the existing * 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) { 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); break; case -1: /* not permitted */ @@ -1406,6 +1379,15 @@ AddPinhole(struct upnphttp * h, const char * action) SoapError(h, 501, "ActionFailed"); break; } + /* 606 Action not authorized + * 701 PinholeSpaceExhausted + * 702 FirewallDisabled + * 703 InboundPinholeNotAllowed + * 705 ProtocolNotSupported + * 706 InternalPortWildcardingNotAllowed + * 707 ProtocolWildcardingNotAllowed + * 708 WildCardNotPermittedInSrcIP */ +clear_and_exit: 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); if (n > 0) { - if(PinholeVerification(h, iaddr, &iport)==0) + if(PinholeVerification(h, iaddr, iport)==0) { ClearNameValueList(&data); return ; @@ -1556,7 +1538,7 @@ DeletePinhole(struct upnphttp * h, const char * action) n = upnp_get_pinhole_info(0, 0, iaddr, &iport, proto, uid, lt); if (n > 0) { - if(PinholeVerification(h, iaddr, &iport)==0) + if(PinholeVerification(h, iaddr, iport)==0) { ClearNameValueList(&data); return ; @@ -1620,7 +1602,7 @@ CheckPinholeWorking(struct upnphttp * h, const char * action) r = upnp_get_pinhole_info(eaddr, eport, iaddr, &iport, proto, uid, lt); if (r > 0) { - if(PinholeVerification(h, iaddr, &iport)==0) + if(PinholeVerification(h, iaddr, iport)==0) { ClearNameValueList(&data); return ; @@ -1719,7 +1701,7 @@ GetPinholePackets(struct upnphttp * h, const char * action) r = upnp_get_pinhole_info(0, 0, iaddr, &iport, proto, uid, lt); if (r > 0) { - if(PinholeVerification(h, iaddr, &iport)==0) + if(PinholeVerification(h, iaddr, iport)==0) { ClearNameValueList(&data); return ;