diff --git a/miniupnpd/Changelog.txt b/miniupnpd/Changelog.txt index 74fe748..d84c0e9 100644 --- a/miniupnpd/Changelog.txt +++ b/miniupnpd/Changelog.txt @@ -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 Fix updating of existing pinhole leasetime by AddPinhole diff --git a/miniupnpd/upnpsoap.c b/miniupnpd/upnpsoap.c index 0d0181c..f1d0d2f 100644 --- a/miniupnpd/upnpsoap.c +++ b/miniupnpd/upnpsoap.c @@ -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 * MiniUPnP project * 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 * in the LICENCE file provided within the distribution */ @@ -1559,77 +1559,101 @@ static int connecthostport(const char * host, unsigned short port, char * result } #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 PinholeVerification(struct upnphttp * h, char * int_ip, unsigned short int_port) { - int n; - char senderAddr[INET6_ADDRSTRLEN]=""; - struct addrinfo hints, *ai, *p; + char clientaddr_str[INET6_ADDRSTRLEN]; 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 (inet_pton(AF_INET6, int_ip, &result_ip) <= 0) { - n = getaddrinfo(int_ip, NULL, &hints, &ai); - if (n == 0) + int r; + 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; for(p = ai; p; p = p->ai_next) { if(p->ai_family == AF_INET6) { - inet_ntop(AF_INET6, (struct in6_addr *) p, int_ip, sizeof(struct in6_addr)); - result_ip = *((struct in6_addr *) p); - found = 1; - /* TODO : deal with more than one ip per hostname */ - break; + if (!found) + { + 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; + } + else + { + char tmp[48]; + sockaddr_to_string(p->ai_addr, tmp, sizeof(tmp)); + syslog(LOG_INFO, "%s: additionnal IPv6: %s", + "PinholeVerification", tmp); + } } } freeaddrinfo(ai); 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"); return -1; } } else { - syslog(LOG_WARNING, "Failed to convert hostname '%s' to IP address : %s", - int_ip, gai_strerror(n)); + syslog(LOG_WARNING, "%s: Failed to convert hostname '%s' to IP address : %s", + "PinholeVerification", int_ip, gai_strerror(r)); SoapError(h, 402, "Invalid Args"); 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"); + 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) { - syslog(LOG_INFO, "Client %s tried to access pinhole for internal %s and is not authorized to do it", - senderAddr, int_ip); + syslog(LOG_INFO, "%s: Client %s tried to access pinhole for internal %s and is not authorized", + "PinholeVerification", clientaddr_str, int_ip); SoapError(h, 606, "Action not authorized"); 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 */ if (int_port < 1024) { 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"); return 0; }