Fix PinholeVerification()

see https://miniupnp.tuxfamily.org/forum/viewtopic.php?p=5847
This commit is contained in:
Thomas Bernard 2023-02-04 11:32:29 +01:00
parent f818ff39fe
commit 99fc9941aa
No known key found for this signature in database
GPG Key ID: DB511043A31ACAAF
2 changed files with 58 additions and 31 deletions

View File

@ -1,4 +1,7 @@
$Id: Changelog.txt,v 1.495 2023/01/19 23:28:24 nanard Exp $ $Id: Changelog.txt,v 1.497 2023/02/04 10:36:33 nanard Exp $
2023/02/04:
Fix PinholeVerification()
2023/01/28 2023/01/28
Fix updating of existing pinhole leasetime by AddPinhole Fix updating of existing pinhole leasetime by AddPinhole

View File

@ -1,8 +1,8 @@
/* $Id: upnpsoap.c,v 1.157 2020/05/30 08:28:22 nanard Exp $ */ /* $Id: upnpsoap.c,v 1.163 2023/02/04 10:36:34 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab /* vim: tabstop=4 shiftwidth=4 noexpandtab
* MiniUPnP project * MiniUPnP project
* http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
* (c) 2006-2021 Thomas Bernard * (c) 2006-2023 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 */
@ -1559,77 +1559,101 @@ static int connecthostport(const char * host, unsigned short port, char * result
} }
#endif #endif
/* Check the security policy right */ /* Check the security policy rights
* Pinhole InternalClient address must correspond to the action sender
* returns 1 if it passes.
* call SoapError() and returns 0 if it fails
* Side effect : if int_ip is a hostname, convert it to litteral ipv6 */
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; char clientaddr_str[INET6_ADDRSTRLEN];
char senderAddr[INET6_ADDRSTRLEN]="";
struct addrinfo hints, *ai, *p;
struct in6_addr result_ip; 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)");
hints.ai_socktype = SOCK_STREAM;
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) if (inet_pton(AF_INET6, int_ip, &result_ip) <= 0)
{ {
n = getaddrinfo(int_ip, NULL, &hints, &ai); int r;
if (n == 0) struct addrinfo hints, *ai, *p;
syslog(LOG_INFO, "%s: InternalClient %s is not an IPv6, assume hostname and convert",
"PinholeVerification", int_ip);
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0; /* we may indicate which protocol IPPROTO_UDP / IPPROTO_TCP / IPPROTO_SCTP / IPPROTO_UDPLITE */
r = getaddrinfo(int_ip, NULL, &hints, &ai);
if (r == 0)
{ {
int found = 0; int found = 0;
for(p = ai; p; p = p->ai_next) for(p = ai; p; p = p->ai_next)
{ {
if(p->ai_family == AF_INET6) if(p->ai_family == AF_INET6)
{ {
inet_ntop(AF_INET6, (struct in6_addr *) p, int_ip, sizeof(struct in6_addr)); if (!found)
result_ip = *((struct in6_addr *) p); {
result_ip = ((struct sockaddr_in6 *)p->ai_addr)->sin6_addr;
if (inet_ntop(AF_INET6, &result_ip, int_ip, sizeof(struct in6_addr)) == NULL)
syslog(LOG_WARNING, "%s: inet_ntop(): %m", "PinholeVerification");
syslog(LOG_INFO, "%s: InternalClient resolved as %s",
"PinholeVerification", int_ip);
found = 1; found = 1;
/* TODO : deal with more than one ip per hostname */ }
break; else
{
char tmp[48];
sockaddr_to_string(p->ai_addr, tmp, sizeof(tmp));
syslog(LOG_INFO, "%s: additionnal IPv6: %s",
"PinholeVerification", tmp);
}
} }
} }
freeaddrinfo(ai); freeaddrinfo(ai);
if (!found) if (!found)
{ {
syslog(LOG_NOTICE, "No IPv6 address for hostname '%s'", int_ip); syslog(LOG_NOTICE, "%s: No IPv6 address for hostname '%s'",
"PinholeVerification", int_ip);
SoapError(h, 402, "Invalid Args"); SoapError(h, 402, "Invalid Args");
return -1; return -1;
} }
} }
else else
{ {
syslog(LOG_WARNING, "Failed to convert hostname '%s' to IP address : %s", syslog(LOG_WARNING, "%s: Failed to convert hostname '%s' to IP address : %s",
int_ip, gai_strerror(n)); "PinholeVerification", int_ip, gai_strerror(r));
SoapError(h, 402, "Invalid Args"); SoapError(h, 402, "Invalid Args");
return -1; return -1;
} }
} }
if(inet_ntop(AF_INET6, &(h->clientaddr_v6), senderAddr, INET6_ADDRSTRLEN) == NULL) if(inet_ntop(AF_INET6, &(h->clientaddr_v6), clientaddr_str, INET6_ADDRSTRLEN) == NULL)
{ {
syslog(LOG_ERR, "inet_ntop: %m"); syslog(LOG_ERR, "inet_ntop: %m");
strncpy(clientaddr_str, "*ERROR*", sizeof(clientaddr_str));
} }
#ifdef DEBUG
printf("\tPinholeVerification:\n\t\tCompare sender @: %s\n\t\t to intClient @: %s\n", senderAddr, int_ip);
#endif
if(strcmp(senderAddr, int_ip) != 0)
if(h->clientaddr_v6.s6_addr != result_ip.s6_addr) if(h->clientaddr_v6.s6_addr != result_ip.s6_addr)
{ {
syslog(LOG_INFO, "Client %s tried to access pinhole for internal %s and is not authorized to do it", syslog(LOG_INFO, "%s: Client %s tried to access pinhole for internal %s and is not authorized",
senderAddr, int_ip); "PinholeVerification", clientaddr_str, int_ip);
SoapError(h, 606, "Action not authorized"); SoapError(h, 606, "Action not authorized");
return 0; return 0;
} }
#ifdef DEBUG
else
{
syslog(LOG_DEBUG, "%s: sender %s == InternalClient %s",
"PinholeVerification", clientaddr_str, int_ip);
}
#endif
/* 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); clientaddr_str);
SoapError(h, 606, "Action not authorized"); SoapError(h, 606, "Action not authorized");
return 0; return 0;
} }