From 1a6b54b37ac16d91d3d75ef1017a6ee5971a855f Mon Sep 17 00:00:00 2001 From: Alaric Senat Date: Tue, 15 Jun 2021 16:29:07 +0200 Subject: [PATCH] Revert "upnpapi.c: assume that getifaddrs is available" This reverts commit aa0166c9a87a6f02632a0c55fb6174b6a1bf8289. --- upnp/src/api/upnpapi.c | 227 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 225 insertions(+), 2 deletions(-) diff --git a/upnp/src/api/upnpapi.c b/upnp/src/api/upnpapi.c index 2e95bbfc..3d524941 100644 --- a/upnp/src/api/upnpapi.c +++ b/upnp/src/api/upnpapi.c @@ -3558,6 +3558,7 @@ int UpnpDownloadXmlDoc(const char *url, IXML_Document **xmlDoc) } } +#if (defined(BSD) && BSD >= 199306) || defined(__FreeBSD_kernel__) /*! * \brief Computes prefix length from IPv6 netmask. * @@ -3580,6 +3581,7 @@ static unsigned UpnpComputeIpv6PrefixLength(struct sockaddr_in6 *Netmask) return prefix_length; } +#endif int UpnpGetIfInfo(const char *IfName) { @@ -3743,7 +3745,8 @@ int UpnpGetIfInfo(const char *IfName) } inet_ntop(AF_INET, &v4_addr, gIF_IPV4, sizeof(gIF_IPV4)); inet_ntop(AF_INET6, &v6_addr, gIF_IPV6, sizeof(gIF_IPV6)); -#else +#elif (defined(BSD) && BSD >= 199306) || \ + defined(__FreeBSD_kernel__) /* _WIN32 */ struct ifaddrs *ifap, *ifa; struct in_addr v4_addr = {0}; struct in_addr v4_netmask = {0}; @@ -3904,7 +3907,227 @@ int UpnpGetIfInfo(const char *IfName) gIF_IPV6_ULA_GUA_PREFIX_LENGTH = v6ulagua_prefix; } } -#endif +#else /* (defined(BSD) && BSD >= 199306) || defined(__FreeBSD_kernel__) */ /* _WIN32 */ + struct ifreq ifArray[MAX_INTERFACES]; + struct ifconf ifConf; + struct ifreq ifReq; + FILE *inet6_procfd; + int i; + int LocalSock; + struct in6_addr v6_addr; + unsigned if_idx; + unsigned if_prefix; + char addr6[8][5]; + char buf[INET6_ADDRSTRLEN]; + int ifname_found = 0; + int valid_addr_found = 0; + + /* Copy interface name, if it was provided. */ + if (IfName != NULL) { + if (strlen(IfName) > sizeof(gIF_NAME)) + return UPNP_E_INVALID_INTERFACE; + + memset(gIF_NAME, 0, sizeof(gIF_NAME)); + strncpy(gIF_NAME, IfName, sizeof(gIF_NAME) - 1); + ifname_found = 1; + } + /* Create an unbound datagram socket to do the SIOCGIFADDR ioctl on. */ + if ((LocalSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == + INVALID_SOCKET) { + UpnpPrintf(UPNP_ALL, + API, + __FILE__, + __LINE__, + "Can't create addrlist socket\n"); + return UPNP_E_INIT; + } + /* Get the interface configuration information... */ + ifConf.ifc_len = (int)sizeof ifArray; + ifConf.ifc_ifcu.ifcu_buf = (char *)ifArray; + + if (ioctl(LocalSock, SIOCGIFCONF, &ifConf) < 0) { + UpnpPrintf(UPNP_ALL, + API, + __FILE__, + __LINE__, + "DiscoverInterfaces: SIOCGIFCONF returned error\n"); + close(LocalSock); + return UPNP_E_INIT; + } + if (ifConf.ifc_len == sizeof ifArray) { + UpnpPrintf(UPNP_ALL, + API, + __FILE__, + __LINE__, + "DiscoverInterfaces: ifConf.ifc_len == sizeof ifArray, " + "an overflow might have occurred, " + "operation should be retried with a bigger buffer.\n"); + } + /* Cycle through the list of interfaces looking for IP addresses. */ + for (i = 0; i < ifConf.ifc_len; i += (int)(sizeof(struct ifreq))) { + struct ifreq *pifReq = (struct ifreq *)(ifConf.ifc_buf + i); + /* See if this is the sort of interface we want to deal with. */ + memset(ifReq.ifr_name, 0, sizeof(ifReq.ifr_name)); + strncpy(ifReq.ifr_name, + pifReq->ifr_name, + sizeof(ifReq.ifr_name) - 1); + if (ioctl(LocalSock, SIOCGIFFLAGS, &ifReq) < 0) { + UpnpPrintf(UPNP_ALL, + API, + __FILE__, + __LINE__, + "Can't get interface flags for %s:\n", + ifReq.ifr_name); + } + /* Skip LOOPBACK interfaces, DOWN interfaces and interfaces that + * don't support MULTICAST. */ + if ((ifReq.ifr_flags & IFF_LOOPBACK) || + (!(ifReq.ifr_flags & IFF_UP)) || + (!(ifReq.ifr_flags & IFF_MULTICAST))) { + continue; + } + if (ifname_found == 0) { + /* We have found a valid interface name. Keep it. */ + memset(gIF_NAME, 0, sizeof(gIF_NAME)); + strncpy(gIF_NAME, + pifReq->ifr_name, + sizeof(gIF_NAME) - 1); + ifname_found = 1; + } else { + if (strncmp(gIF_NAME, + pifReq->ifr_name, + sizeof(gIF_NAME)) != 0) { + /* This is not the interface we're looking for. + */ + continue; + } + } + /* Check address family. */ + if (pifReq->ifr_addr.sa_family == AF_INET) { + /* Copy interface name, IPv4 address, IPv4 netmask and + * interface index. */ + memset(gIF_NAME, 0, sizeof(gIF_NAME)); + strncpy(gIF_NAME, + pifReq->ifr_name, + sizeof(gIF_NAME) - 1); + inet_ntop(AF_INET, + &((struct sockaddr_in *)&pifReq->ifr_addr) + ->sin_addr, + gIF_IPV4, + sizeof(gIF_IPV4)); + if (ioctl(LocalSock, SIOCGIFNETMASK, &ifReq) < 0) { + UpnpPrintf(UPNP_ALL, + API, + __FILE__, + __LINE__, + "Can't get interface netmask for %s:\n", + ifReq.ifr_name); + } + inet_ntop(AF_INET, + &((struct sockaddr_in *)&ifReq.ifr_netmask) + ->sin_addr, + gIF_IPV4_NETMASK, + sizeof(gIF_IPV4_NETMASK)); + gIF_INDEX = if_nametoindex(gIF_NAME); + valid_addr_found = 1; + break; + } else { + /* Address is not IPv4 */ + ifname_found = 0; + } + } + close(LocalSock); + /* Failed to find a valid interface, or valid address. */ + if (ifname_found == 0 || valid_addr_found == 0) { + UpnpPrintf(UPNP_CRITICAL, + API, + __FILE__, + __LINE__, + "Failed to find an adapter with valid IP addresses for " + "use.\n"); + + return UPNP_E_INVALID_INTERFACE; + } + /* Try to get the IPv6 address for the same interface */ + /* from "/proc/net/if_inet6", if possible. */ + inet6_procfd = fopen("/proc/net/if_inet6", "r"); + if (inet6_procfd) { + while (fscanf(inet6_procfd, + "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %*02x " + "%*02x %*20s\n", + addr6[0], + addr6[1], + addr6[2], + addr6[3], + addr6[4], + addr6[5], + addr6[6], + addr6[7], + &if_idx, + &if_prefix) != EOF) { + /* Get same interface as IPv4 address retrieved. */ + if (gIF_INDEX == if_idx) { + snprintf(buf, + sizeof(buf), + "%s:%s:%s:%s:%s:%s:%s:%s", + addr6[0], + addr6[1], + addr6[2], + addr6[3], + addr6[4], + addr6[5], + addr6[6], + addr6[7]); + /* Validate formed address and check for + * link-local. */ + if (inet_pton(AF_INET6, buf, &v6_addr) > 0) { + if (IN6_IS_ADDR_ULA(&v6_addr)) { + /* Got valid IPv6 ula. */ + memset(gIF_IPV6_ULA_GUA, + 0, + sizeof(gIF_IPV6_ULA_GUA)); + strncpy(gIF_IPV6_ULA_GUA, + buf, + sizeof(gIF_IPV6_ULA_GUA) - + 1); + gIF_IPV6_ULA_GUA_PREFIX_LENGTH = + if_prefix; + } else if (IN6_IS_ADDR_GLOBAL( + &v6_addr) && + strlen(gIF_IPV6_ULA_GUA) == + (size_t)0) { + /* got a GUA, should store it + * while no ULA is found */ + memset(gIF_IPV6_ULA_GUA, + 0, + sizeof(gIF_IPV6_ULA_GUA)); + strncpy(gIF_IPV6_ULA_GUA, + buf, + sizeof(gIF_IPV6_ULA_GUA) - + 1); + gIF_IPV6_ULA_GUA_PREFIX_LENGTH = + if_prefix; + } else if (IN6_IS_ADDR_LINKLOCAL( + &v6_addr) && + strlen(gIF_IPV6) == + (size_t)0) { + /* got a Link local IPv6 + * address. */ + memset(gIF_IPV6, + 0, + sizeof(gIF_IPV6)); + strncpy(gIF_IPV6, + buf, + sizeof(gIF_IPV6) - 1); + gIF_IPV6_PREFIX_LENGTH = + if_prefix; + } + } + } + } + fclose(inet6_procfd); + } +#endif /* (defined(BSD) && BSD >= 199306) || defined(__FreeBSD_kernel__) */ /* _WIN32 */ UpnpPrintf(UPNP_INFO, API, __FILE__, -- 2.31.1