bool Mapper_MiniUPnPc::init() { if(!url.empty()) return true; #if MINIUPNPC_API_VERSION < 14 UPNPDev* devices = upnpDiscover(2000, localIp.empty() ? nullptr : localIp.c_str(), 0, 0, v6, 0); #else UPNPDev* devices = upnpDiscover(2000, localIp.empty() ? nullptr : localIp.c_str(), 0, 0, v6, 2, 0); #endif if(!devices) return false; UPNPUrls urls; IGDdatas data; auto ret = UPNP_GetValidIGD(devices, &urls, &data, 0, 0); bool ok = ret == 1; if(ok) { if (localIp.empty()) { // We have no bind address configured in settings // Try to avoid choosing a random adapter for port mapping // Parse router IP from the control URL address auto controlUrl = string(string(data.urlbase).empty() ? urls.controlURL : data.urlbase); string routerIp, portTmp, protoTmp, pathTmp, queryTmp, fragmentTmp; Util::decodeUrl(controlUrl, protoTmp, routerIp, portTmp, pathTmp, queryTmp, fragmentTmp); routerIp = Socket::resolve(routerIp, v6 ? AF_INET6 : AF_INET); if (!routerIp.empty()) { auto adapters = AirUtil::getNetworkAdapters(v6); // Find a local IP that is within the same subnet auto p = boost::find_if(adapters, [&routerIp, this](const AirUtil::AdapterInfo& aInfo) { return isIPInRange(aInfo.ip, routerIp, aInfo.prefix, v6); }); if (p != adapters.end()) { localIp = p->ip; } } } url = urls.controlURL; service = data.first.servicetype; #ifdef _WIN32 device = data.CIF.friendlyName; #else // Doesn't work on Linux device = "Generic"; #endif } if(ret) { FreeUPNPUrls(&urls); freeUPNPDevlist(devices); } return ok; }
bool Mapper_MiniUPnPc::init() { if(!url.empty()) return true; #ifdef HAVE_OLD_MINIUPNPC UPNPDev* devices = upnpDiscover(2000, localIp.empty() ? nullptr : localIp.c_str(), 0, 0); #else UPNPDev* devices = upnpDiscover(2000, localIp.empty() ? nullptr : localIp.c_str(), 0, 0, v6, 0); #endif if(!devices) return false; UPNPUrls urls; IGDdatas data; auto ret = UPNP_GetValidIGD(devices, &urls, &data, 0, 0); bool ok = ret == 1; if(ok) { if (localIp.empty()) { AirUtil::IpList addresses; AirUtil::getIpAddresses(addresses, v6); auto remoteIP = string(string(data.urlbase).empty() ? urls.controlURL : data.urlbase); auto start = remoteIP.find("//"); if (start != string::npos) { start = start+2; auto end = remoteIP.find(":", start); if (end != string::npos) { remoteIP = Socket::resolve(remoteIP.substr(start, end-start), v6 ? AF_INET6 : AF_INET); if (!remoteIP.empty()) { auto p = boost::find_if(addresses, [&remoteIP, this](const AirUtil::AddressInfo& aInfo) { return isIPInRange(aInfo.ip, remoteIP, aInfo.prefix, v6); }); if (p != addresses.end()) { localIp = p->ip; } } } } } url = urls.controlURL; service = data.first.servicetype; #ifdef _WIN32 device = data.CIF.friendlyName; #else // Doesn't work on Linux device = "Generic"; #endif } if(ret) { FreeUPNPUrls(&urls); freeUPNPDevlist(devices); } return ok; }