/** Fetch our likely public IP from our upstream UPnP IGD enabled NAT device. * Use the connection context stored in <b>backend_state</b>. */ int tor_upnp_fetch_public_ip(tor_fw_options_t *options, void *backend_state) { miniupnpc_state_t *state = (miniupnpc_state_t *) backend_state; int r; char externalIPAddress[16]; if (!state->init) { r = tor_upnp_init(options, state); if (r != UPNP_ERR_SUCCESS) return r; } r = UPNP_GetExternalIPAddress(state->urls.controlURL, state->data.first.servicetype, externalIPAddress); if (r != UPNPCOMMAND_SUCCESS) goto err; if (externalIPAddress[0]) { fprintf(stderr, "tor-fw-helper: ExternalIPAddress = %s\n", externalIPAddress); tor_upnp_cleanup(options, state); options->public_ip_status = 1; return UPNP_ERR_SUCCESS; } else { goto err; } err: tor_upnp_cleanup(options, state); return UPNP_ERR_GETEXTERNALIP; }
string UPNPCheckDlg::MiniUPnPc_getExternalIP(string& url, string& service) { char buf[16] = { 0 }; if (UPNP_GetExternalIPAddress(url.c_str(), service.c_str(), buf) == UPNPCOMMAND_SUCCESS) return buf; return Util::emptyString; }
/* Test function * 1 - get connection type * 2 - get extenal ip address * 3 - Add port mapping * 4 - get this port mapping from the IGD */ static void SetRedirectAndTest(struct UPNPUrls * urls, struct IGDdatas * data, const char * iaddr, const char * iport, const char * eport, const char * proto, const char * leaseDuration, const char * description) { char externalIPAddress[40]; char intClient[40]; char intPort[6]; char duration[16]; int r; if(!iaddr || !iport || !eport || !proto) { fprintf(stderr, "Wrong arguments\n"); return; } proto = protofix(proto); if(!proto) { fprintf(stderr, "invalid protocol\n"); return; } UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, externalIPAddress); if(externalIPAddress[0]) printf("ExternalIPAddress = %s\n", externalIPAddress); else printf("GetExternalIPAddress failed.\n"); r = UPNP_AddPortMapping(urls->controlURL, data->first.servicetype, eport, iport, iaddr, description, proto, 0, leaseDuration); if(r!=UPNPCOMMAND_SUCCESS) printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", eport, iport, iaddr, r, strupnperror(r)); r = UPNP_GetSpecificPortMappingEntry(urls->controlURL, data->first.servicetype, eport, proto, NULL/*remoteHost*/, intClient, intPort, NULL/*desc*/, NULL/*enabled*/, duration); if(r!=UPNPCOMMAND_SUCCESS) printf("GetSpecificPortMappingEntry() failed with code %d (%s)\n", r, strupnperror(r)); if(intClient[0]) { printf("InternalIP:Port = %s:%s\n", intClient, intPort); printf("external %s:%s %s is redirected to internal %s:%s (duration=%s)\n", externalIPAddress, eport, proto, intClient, intPort, duration); } }
static PyObject * UPnP_externalipaddress(UPnPObject *self) { char externalIPAddress[16]; externalIPAddress[0] = '\0'; UPNP_GetExternalIPAddress(self->urls.controlURL, self->data.servicetype, externalIPAddress); return Py_BuildValue("s", externalIPAddress); }
bool Gateway::_getExternalIPAddress() { if (UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, tmp) != 0) { return false; } externalIPAddress = CString(tmp); return true; }
static void DisplayInfos(struct UPNPUrls * urls, struct IGDdatas * data) { char externalIPAddress[40]; char connectionType[64]; char status[64]; char lastconnerr[64]; unsigned int uptime = 0; unsigned int brUp, brDown; time_t timenow, timestarted; int r; if(UPNP_GetConnectionTypeInfo(urls->controlURL, data->first.servicetype, connectionType) != UPNPCOMMAND_SUCCESS) printf("GetConnectionTypeInfo failed.\n"); else printf("Connection Type : %s\n", connectionType); if(UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype, status, &uptime, lastconnerr) != UPNPCOMMAND_SUCCESS) printf("GetStatusInfo failed.\n"); else printf("Status : %s, uptime=%us, LastConnectionError : %s\n", status, uptime, lastconnerr); if(uptime > 0) { timenow = time(NULL); timestarted = timenow - uptime; printf(" Time started : %s", ctime(×tarted)); } if(UPNP_GetLinkLayerMaxBitRates(urls->controlURL_CIF, data->CIF.servicetype, &brDown, &brUp) != UPNPCOMMAND_SUCCESS) { printf("GetLinkLayerMaxBitRates failed.\n"); } else { printf("MaxBitRateDown : %u bps", brDown); if(brDown >= 1000000) { printf(" (%u.%u Mbps)", brDown / 1000000, (brDown / 100000) % 10); } else if(brDown >= 1000) { printf(" (%u Kbps)", brDown / 1000); } printf(" MaxBitRateUp %u bps", brUp); if(brUp >= 1000000) { printf(" (%u.%u Mbps)", brUp / 1000000, (brUp / 100000) % 10); } else if(brUp >= 1000) { printf(" (%u Kbps)", brUp / 1000); } printf("\n"); } r = UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, externalIPAddress); if(r != UPNPCOMMAND_SUCCESS) { printf("GetExternalIPAddress failed. (errorcode=%d)\n", r); } else { printf("ExternalIPAddress = %s\n", externalIPAddress); } }
boost::optional<HostAddress> MiniUPnPInterface::getPublicIP() { if (!p->isValid) { return boost::optional<HostAddress>(); } char externalIPAddress[40]; int ret = UPNP_GetExternalIPAddress(p->urls.controlURL, p->data.first.servicetype, externalIPAddress); if (ret != UPNPCOMMAND_SUCCESS) { return boost::optional<HostAddress>(); } else { return HostAddress(std::string(externalIPAddress)); } }
static switch_status_t get_upnp_pubaddr(char *pub_addr) { if (UPNP_GetExternalIPAddress(nat_globals.urls.controlURL, nat_globals.data.servicetype, pub_addr) == UPNPCOMMAND_SUCCESS) { if (!strcmp(pub_addr, "0.0.0.0") || zstr_buf(pub_addr)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "uPNP Device (url: %s) returned an invalid external address of '%s'. Disabling uPNP\n", nat_globals.urls.controlURL, pub_addr); return SWITCH_STATUS_GENERR; } } else { return SWITCH_STATUS_GENERR; } return SWITCH_STATUS_SUCCESS; }
static PyObject * UPnP_externalipaddress(UPnPObject *self) { char externalIPAddress[16]; int r; externalIPAddress[0] = '\0'; r = UPNP_GetExternalIPAddress(self->urls.controlURL, self->data.servicetype, externalIPAddress); if(r==UPNPCOMMAND_SUCCESS) { return Py_BuildValue("s", externalIPAddress); } else { /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } }
void UPnP::Discover () { int nerror = 0; #if MINIUPNPC_API_VERSION >= 14 m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, 2, &nerror); #else m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, &nerror); #endif { // notify satrting thread std::unique_lock<std::mutex> l(m_StartedMutex); m_Started.notify_all (); } int r; r = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr)); if (r == 1) { r = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress); if(r != UPNPCOMMAND_SUCCESS) { LogPrint (eLogError, "UPnP: UPNP_GetExternalIPAddress() returned ", r); return; } else { if (!m_externalIPAddress[0]) { LogPrint (eLogError, "UPnP: GetExternalIPAddress() failed."); return; } } } else { LogPrint (eLogError, "UPnP: GetValidIGD() failed."); return; } // UPnP discovered LogPrint (eLogDebug, "UPnP: ExternalIPAddress is ", m_externalIPAddress); i2p::context.UpdateAddress (boost::asio::ip::address::from_string (m_externalIPAddress)); // port mapping PortMapping (); }
void Portfwd::get_status() { // get connection speed UPNP_GetLinkLayerMaxBitRates( urls->controlURL_CIF, data->servicetype_CIF, &m_downbps, &m_upbps); // get external IP adress char ip[16]; if( 0 != UPNP_GetExternalIPAddress( urls->controlURL, data->servicetype, (char*)&ip ) ) { m_externalip = ""; //failed }else{ m_externalip = std::string(ip); } }
gchar * vino_upnp_get_external_ip (VinoUpnp *upnp) { gchar ip[16]; g_return_val_if_fail (VINO_IS_UPNP (upnp), NULL); if (!update_upnp_status (upnp)) return NULL; UPNP_GetExternalIPAddress (upnp->priv->urls->controlURL, upnp->priv->data->servicetype, ip); if (ip[0]) if (strcmp (ip, "0.0.0.0") == 0) return NULL; else return g_strdup (ip); else return NULL; }
static void DisplayInfos(struct UPNPUrls * urls, struct IGDdatas * data) { char externalIPAddress[16]; char connectionType[64]; char status[64]; char lastconnerr[64]; unsigned int uptime; unsigned int brUp, brDown; time_t timenow, timestarted; int r; UPNP_GetConnectionTypeInfo(urls->controlURL, data->first.servicetype, connectionType); if(connectionType[0]) printf("Connection Type : %s\n", connectionType); else printf("GetConnectionTypeInfo failed.\n"); UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype, status, &uptime, lastconnerr); printf("Status : %s, uptime=%us, LastConnectionError : %s\n", status, uptime, lastconnerr); timenow = time(NULL); timestarted = timenow - uptime; printf(" Time started : %s", ctime(×tarted)); UPNP_GetLinkLayerMaxBitRates(urls->controlURL_CIF, data->CIF.servicetype, &brDown, &brUp); printf("MaxBitRateDown : %u bps MaxBitRateUp %u bps\n", brDown, brUp); r = UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, externalIPAddress); if(r != UPNPCOMMAND_SUCCESS) printf("GetExternalIPAddress() returned %d\n", r); if(externalIPAddress[0]) printf("ExternalIPAddress = %s\n", externalIPAddress); else printf("GetExternalIPAddress failed.\n"); }
/* UPNP_GetValidIGD() : * return values : * -1 = Internal error * 0 = NO IGD found * 1 = A valid connected IGD has been found * 2 = A valid IGD has been found but it reported as * not connected * 3 = an UPnP device has been found but was not recognized as an IGD * * In any positive non zero return case, the urls and data structures * passed as parameters are set. Don't forget to call FreeUPNPUrls(urls) to * free allocated memory. */ MINIUPNP_LIBSPEC int UPNP_GetValidIGD(struct UPNPDev * devlist, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen) { struct xml_desc { char * xml; int size; int is_igd; } * desc = NULL; struct UPNPDev * dev; int ndev = 0; int i; int state = -1; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */ char extIpAddr[16]; char myLanAddr[40]; int status_code = -1; if(!devlist) { #ifdef DEBUG printf("Empty devlist\n"); #endif return 0; } /* counting total number of devices in the list */ for(dev = devlist; dev; dev = dev->pNext) ndev++; /* ndev is always > 0 */ desc = calloc(ndev, sizeof(struct xml_desc)); if(!desc) return -1; /* memory allocation error */ /* Step 1 : downloading descriptions and testing type */ for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) { /* we should choose an internet gateway device. * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */ desc[i].xml = miniwget_getaddr(dev->descURL, &(desc[i].size), myLanAddr, sizeof(myLanAddr), dev->scope_id, &status_code); #ifdef DEBUG if(!desc[i].xml) { printf("error getting XML description %s\n", dev->descURL); } #endif if(desc[i].xml) { memset(data, 0, sizeof(struct IGDdatas)); memset(urls, 0, sizeof(struct UPNPUrls)); parserootdesc(desc[i].xml, desc[i].size, data); if(COMPARE(data->CIF.servicetype, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:")) { desc[i].is_igd = 1; if(lanaddr) strncpy(lanaddr, myLanAddr, lanaddrlen); } } } /* iterate the list to find a device depending on state */ for(state = 1; state <= 3; state++) { for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) { if(desc[i].xml) { memset(data, 0, sizeof(struct IGDdatas)); memset(urls, 0, sizeof(struct UPNPUrls)); parserootdesc(desc[i].xml, desc[i].size, data); if(desc[i].is_igd || state >= 3 ) { int is_connected; GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); /* in state 2 and 3 we don't test if device is connected ! */ if(state >= 2) goto free_and_return; is_connected = UPNPIGD_IsConnected(urls, data); #ifdef DEBUG printf("UPNPIGD_IsConnected(%s) = %d\n", urls->controlURL, is_connected); #endif /* checks that status is connected AND there is a external IP address assigned */ if(is_connected && (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) { if(!is_rfc1918addr(extIpAddr) && (extIpAddr[0] != '\0') && (0 != strcmp(extIpAddr, "0.0.0.0"))) goto free_and_return; } FreeUPNPUrls(urls); if(data->second.servicetype[0] != '\0') { #ifdef DEBUG printf("We tried %s, now we try %s !\n", data->first.servicetype, data->second.servicetype); #endif /* swaping WANPPPConnection and WANIPConnection ! */ memcpy(&data->tmp, &data->first, sizeof(struct IGDdatas_service)); memcpy(&data->first, &data->second, sizeof(struct IGDdatas_service)); memcpy(&data->second, &data->tmp, sizeof(struct IGDdatas_service)); GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); is_connected = UPNPIGD_IsConnected(urls, data); #ifdef DEBUG printf("UPNPIGD_IsConnected(%s) = %d\n", urls->controlURL, is_connected); #endif if(is_connected && (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) { if(!is_rfc1918addr(extIpAddr) && (extIpAddr[0] != '\0') && (0 != strcmp(extIpAddr, "0.0.0.0"))) goto free_and_return; } FreeUPNPUrls(urls); } } memset(data, 0, sizeof(struct IGDdatas)); } } } state = 0; free_and_return: for(i = 0; i < ndev; i++) free(desc[i].xml); free(desc); return state; }
// redirect port on external upnp enabled router to port on *this* host int upnpredirect(const char* eport, const char* iport, const char* proto, const char* description) { // Discovery parameters struct UPNPDev * devlist = 0; struct UPNPUrls urls; struct IGDdatas data; int i; char lanaddr[64]; // my ip address on the LAN const char* leaseDuration="0"; // Redirect & test parameters char intClient[40]; char intPort[6]; char externalIPAddress[40]; char duration[16]; int error=0; // Find UPNP devices on the network if ((devlist=upnpDiscover(2000, 0, 0,0, 0, &error))) { struct UPNPDev * device = 0; printf("UPNP INIALISED: List of UPNP devices found on the network.\n"); for(device = devlist; device; device = device->pNext) { printf("UPNP INFO: dev [%s] \n\t st [%s]\n", device->descURL, device->st); } } else { printf("UPNP ERROR: no device found - MANUAL PORTMAP REQUIRED\n"); return 0; } // Output whether we found a good one or not. if((error = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)))) { switch(error) { case 1: printf("UPNP OK: Found valid IGD : %s\n", urls.controlURL); break; case 2: printf("UPNP WARN: Found a (not connected?) IGD : %s\n", urls.controlURL); break; case 3: printf("UPNP WARN: UPnP device found. Is it an IGD ? : %s\n", urls.controlURL); break; default: printf("UPNP WARN: Found device (igd ?) : %s\n", urls.controlURL); } printf("UPNP OK: Local LAN ip address : %s\n", lanaddr); } else { printf("UPNP ERROR: no device found - MANUAL PORTMAP REQUIRED\n"); return 0; } // Get the external IP address (just because we can really...) if(UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress)!=UPNPCOMMAND_SUCCESS) printf("UPNP WARN: GetExternalIPAddress failed.\n"); else printf("UPNP OK: ExternalIPAddress = %s\n", externalIPAddress); // Check for existing supernet mapping - from this host and another host // In theory I can adapt this so multiple nodes can exist on same lan and choose a different portmap // for each one :) // At the moment just delete a conflicting portmap and override with the one requested. i=0; error=0; do { char index[6]; char extPort[6]; char desc[80]; char enabled[6]; char rHost[64]; char protocol[4]; snprintf(index, 6, "%d", i++); if(!(error=UPNP_GetGenericPortMappingEntry(urls.controlURL, data.first.servicetype, index, extPort, intClient, intPort, protocol, desc, enabled, rHost, duration))) { // printf("%2d %s %5s->%s:%-5s '%s' '%s' %s\n",i, protocol, extPort, intClient, intPort,desc, rHost, duration); // check for an existing supernet mapping on this host if(!strcmp(lanaddr, intClient)) { // same host if(!strcmp(protocol,proto)) { //same protocol if(!strcmp(intPort,iport)) { // same port printf("UPNP WARN: existing mapping found (%s:%s)\n",lanaddr,iport); if(!strcmp(extPort,eport)) { printf("UPNP OK: exact mapping already in place (%s:%s->%s)\n", lanaddr, iport, eport); FreeUPNPUrls(&urls); freeUPNPDevlist(devlist); return 1; } else { // delete old mapping printf("UPNP WARN: deleting existing mapping (%s:%s->%s)\n",lanaddr, iport, extPort); if(UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, extPort, proto, rHost)) printf("UPNP WARN: error deleting old mapping (%s:%s->%s) continuing\n", lanaddr, iport, extPort); else printf("UPNP OK: old mapping deleted (%s:%s->%s)\n",lanaddr, iport, extPort); } } } } else { // ipaddr different - check to see if requested port is already mapped if(!strcmp(protocol,proto)) { if(!strcmp(extPort,eport)) { printf("UPNP WARN: EXT port conflict mapped to another ip (%s-> %s vs %s)\n", extPort, lanaddr, intClient); if(UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, extPort, proto, rHost)) printf("UPNP WARN: error deleting conflict mapping (%s:%s) continuing\n", intClient, extPort); else printf("UPNP OK: conflict mapping deleted (%s:%s)\n",intClient, extPort); } } } } else printf("UPNP OK: GetGenericPortMappingEntry() End-of-List (%d entries) \n", i); } while(error==0); // Set the requested port mapping if((i=UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, eport, iport, lanaddr, description, proto, 0, leaseDuration))!=UPNPCOMMAND_SUCCESS) { printf("UPNP ERROR: AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", eport, iport, lanaddr, i, strupnperror(i)); FreeUPNPUrls(&urls); freeUPNPDevlist(devlist); return 0; //error - adding the port map primary failure } if((i=UPNP_GetSpecificPortMappingEntry(urls.controlURL, data.first.servicetype, eport, proto, NULL/*remoteHost*/, intClient, intPort, NULL/*desc*/, NULL/*enabled*/, duration))!=UPNPCOMMAND_SUCCESS) { printf("UPNP ERROR: GetSpecificPortMappingEntry(%s, %s, %s) failed with code %d (%s)\n", eport, iport, lanaddr, i, strupnperror(i)); FreeUPNPUrls(&urls); freeUPNPDevlist(devlist); return 0; //error - port map wasnt returned by query so likely failed. } else printf("UPNP OK: EXT (%s:%s) %s redirected to INT (%s:%s) (duration=%s)\n",externalIPAddress, eport, proto, intClient, intPort, duration); FreeUPNPUrls(&urls); freeUPNPDevlist(devlist); return 1; //ok - we are mapped:) }
void threadMain() throw() { char lanaddr[4096]; char externalip[4096]; // no range checking? so make these buffers larger than any UDP packet a uPnP server could send us as a precaution :P char inport[16]; char outport[16]; struct UPNPUrls urls; struct IGDdatas data; #ifdef ZT_UPNP_TRACE fprintf(stderr,"UPNPClient: started for UDP port %d"ZT_EOL_S,localPort); #endif unsigned int tryPortStart = 0; Utils::getSecureRandom(&tryPortStart,sizeof(tryPortStart)); tryPortStart = (tryPortStart % (65535 - 1025)) + 1025; while (run) { { int upnpError = 0; UPNPDev *devlist = upnpDiscover(2000,(const char *)0,(const char *)0,0,0,0,&upnpError); if (devlist) { #ifdef ZT_UPNP_TRACE { UPNPDev *dev = devlist; while (dev) { fprintf(stderr,"UPNPClient: found device at URL '%s': %s"ZT_EOL_S,dev->descURL,dev->st); dev = dev->pNext; } } #endif memset(lanaddr,0,sizeof(lanaddr)); memset(externalip,0,sizeof(externalip)); memset(&urls,0,sizeof(urls)); memset(&data,0,sizeof(data)); Utils::snprintf(inport,sizeof(inport),"%d",localPort); if ((UPNP_GetValidIGD(devlist,&urls,&data,lanaddr,sizeof(lanaddr)))&&(lanaddr[0])) { #ifdef ZT_UPNP_TRACE fprintf(stderr,"UPNPClient: my LAN IP address: %s"ZT_EOL_S,lanaddr); #endif if ((UPNP_GetExternalIPAddress(urls.controlURL,data.first.servicetype,externalip) == UPNPCOMMAND_SUCCESS)&&(externalip[0])) { #ifdef ZT_UPNP_TRACE fprintf(stderr,"UPNPClient: my external IP address: %s"ZT_EOL_S,externalip); #endif for(int tries=0;tries<64;++tries) { int tryPort = (int)tryPortStart + tries; if (tryPort >= 65535) tryPort = (tryPort - 65535) + 1025; Utils::snprintf(outport,sizeof(outport),"%u",tryPort); int mapResult = 0; if ((mapResult = UPNP_AddPortMapping(urls.controlURL,data.first.servicetype,outport,inport,lanaddr,"ZeroTier","UDP",(const char *)0,"0")) == UPNPCOMMAND_SUCCESS) { #ifdef ZT_UPNP_TRACE fprintf(stderr,"UPNPClient: reserved external port: %s"ZT_EOL_S,outport); #endif { Mutex::Lock sl(surface_l); surface.clear(); InetAddress tmp(externalip); tmp.setPort(tryPort); surface.push_back(tmp); } break; } else { #ifdef ZT_UPNP_TRACE fprintf(stderr,"UPNPClient: UPNP_AddAnyPortMapping(%s) failed: %d"ZT_EOL_S,outport,mapResult); #endif Thread::sleep(1000); } } } else { #ifdef ZT_UPNP_TRACE fprintf(stderr,"UPNPClient: UPNP_GetExternalIPAddress failed"ZT_EOL_S); #endif } } else { #ifdef ZT_UPNP_TRACE fprintf(stderr,"UPNPClient: UPNP_GetValidIGD failed"ZT_EOL_S); #endif } freeUPNPDevlist(devlist); } else { #ifdef ZT_UPNP_TRACE fprintf(stderr,"UPNPClient: upnpDiscover error code: %d"ZT_EOL_S,upnpError); #endif } } #ifdef ZT_UPNP_TRACE fprintf(stderr,"UPNPClient: rescanning in %d ms"ZT_EOL_S,ZT_UPNP_CLIENT_REFRESH_DELAY); #endif Thread::sleep(ZT_UPNP_CLIENT_REFRESH_DELAY); } delete this; }
void upnp_service::map_port( uint16_t local_port ) { std::string port = fc::variant(local_port).as_string(); my->map_port_complete = my->upnp_thread.async( [=]() { const char * multicastif = 0; const char * minissdpdpath = 0; struct UPNPDev * devlist = 0; char lanaddr[64]; /* miniupnpc 1.6 */ int error = 0; devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error); struct UPNPUrls urls; memset( &urls, 0, sizeof(urls) ); struct IGDdatas data; memset( &data, 0, sizeof(data) ); int r; r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)); bool port_mapping_added = false; bool port_mapping_added_successfully = false; if (r == 1) { if (true) // TODO config this ? fDiscover) { char externalIPAddress[40]; r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress); if(r != UPNPCOMMAND_SUCCESS) wlog("UPnP: GetExternalIPAddress() returned ${code}", ("code", r)); else { if(externalIPAddress[0]) { ulog("UPnP: ExternalIPAddress = ${address}", ("address", externalIPAddress)); my->external_ip = fc::ip::address( std::string(externalIPAddress) ); // AddLocal(CNetAddr(externalIPAddress), LOCAL_UPNP); } else wlog("UPnP: GetExternalIPAddress failed."); } } std::string strDesc = "BitShares 0.0"; // TODO + FormatFullVersion(); // try { while(!my->done) // TODO provide way to exit cleanly { /* miniupnpc 1.6 */ r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0, "0"); port_mapping_added = true; if(r!=UPNPCOMMAND_SUCCESS) wlog("AddPortMapping(${port}, ${port}, ${addr}) failed with code ${code} (${string})", ("port", port)("addr", lanaddr)("code", r)("string", strupnperror(r))); else { if (!port_mapping_added_successfully) ulog("UPnP Port Mapping successful"); port_mapping_added_successfully = true; my->mapped_port = local_port; } fc::usleep( fc::seconds(60*20) ); // Refresh every 20 minutes } } // catch (boost::thread_interrupted) { if( port_mapping_added ) { r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "TCP", 0); ilog("UPNP_DeletePortMapping() returned : ${r}", ("r",r)); freeUPNPDevlist(devlist); devlist = 0; FreeUPNPUrls(&urls); } // throw; } } else { //printf("No valid UPnP IGDs found\n"); wlog("No valid UPnP IGDs found"); freeUPNPDevlist(devlist); devlist = 0; if (r != 0) { FreeUPNPUrls(&urls); } } }, "upnp::map_port" ); }
string Mapper_MiniUPnPc::getExternalIP() { char buf[16] = { 0 }; if(UPNP_GetExternalIPAddress(url.c_str(), service.c_str(), buf) == UPNPCOMMAND_SUCCESS) return buf; return Util::emptyString; }
void init_upnp (void) { struct UPNPDev * devlist; struct UPNPDev * dev; char * descXML; int descXMLsize = 0; int res = 0; char IPAddress[40]; int r; if (!sv_upnp) return; memset(&urls, 0, sizeof(struct UPNPUrls)); memset(&data, 0, sizeof(struct IGDdatas)); Printf(PRINT_HIGH, "UPnP: Discovering router (max 1 unit supported)\n"); devlist = upnpDiscover(sv_upnp_discovertimeout.asInt(), NULL, NULL, 0, 0, &res); if (!devlist || res != UPNPDISCOVER_SUCCESS) { Printf(PRINT_HIGH, "UPnP: Router not found or timed out, error %d\n", res); is_upnp_ok = false; return; } dev = devlist; while (dev) { if (strstr (dev->st, "InternetGatewayDevice")) break; dev = dev->pNext; } if (!dev) dev = devlist; /* defaulting to first device */ //Printf(PRINT_HIGH, "UPnP device :\n" // " desc: %s\n st: %s\n", // dev->descURL, dev->st); descXML = (char *)miniwget(dev->descURL, &descXMLsize, 0); if (descXML) { parserootdesc (descXML, descXMLsize, &data); free (descXML); descXML = NULL; GetUPNPUrls (&urls, &data, dev->descURL, 0); } freeUPNPDevlist(devlist); r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, IPAddress); if (r != 0) { Printf(PRINT_HIGH, "UPnP: Router found but unable to get external IP address\n"); is_upnp_ok = false; } else { Printf(PRINT_HIGH, "UPnP: Router found, external IP address is: %s\n", IPAddress); // Store ip address just in case admin wants it sv_upnp_externalip.ForceSet(IPAddress); is_upnp_ok = true; } }
/* UPNP_GetValidIGDe) : * return values : * -1 = Internal error * 0 = NO IGD found * 1 = A valid connected IGD has been found * 2 = A valid IGD has been found but it reported as * not connected * 3 = an UPnP device has been found but was not recognized as an IGD * * In any positive non zero return case, the urls and data structures * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to * free allocated memory. */ MINIUPNP_LIBSPEC int UPNP_GetValidIGD(struct UPNPDev * devlist, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen) { struct xml_desc { char * xml; int size; int is_igd; } * desc = NULL; struct UPNPDev * dev; int ndev = 0; int i; int state = -1; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */ int n_igd = 0; char extIpAddr[16]; struct UPNPDevInfo IGDInfo; char *dut_lanaddr; char IGDDescURL[256]; if(!devlist) { #ifdef DEBUG printf("Empty devlist\n"); #endif return 0; } /* counting total number of devices in the list */ for(dev = devlist; dev; dev = dev->pNext) ndev++; if(ndev > 0) { desc = calloc(ndev, sizeof(struct xml_desc)); if(!desc) return -1; /* memory allocation error */ } dut_lanaddr = get_lan_ipaddr(); /* Step 1 : downloading descriptions and testing type */ for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) { memset(&IGDInfo, 0, sizeof(struct UPNPDevInfo)); /* we should choose an internet gateway device. * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */ strcpy(IGDDescURL, dev->descURL); desc[i].xml = miniwget_getaddr(dev->descURL, &(desc[i].size), lanaddr, lanaddrlen, dev->scope_id, &IGDInfo, dut_lanaddr); #ifdef DEBUG if(!desc[i].xml) { printf("error getting XML description %s\n", dev->descURL); } #endif if(desc[i].xml) { memset(data, 0, sizeof(struct IGDdatas)); memset(urls, 0, sizeof(struct UPNPUrls)); /* parserootdesc(desc[i].xml, desc[i].size, data); */ #ifdef DEBUG FILE *xml_fd; xml_fd = fopen("/tmp/upnpc_xml.log", "w"); fprintf(xml_fd, "============= XML ==============\n"); fprintf(xml_fd, "%s\n", desc[i].xml); parsedescxml(desc[i].xml, &IGDInfo.friendlyName, &IGDInfo.iconUrl); fprintf(xml_fd, " HostName: %s\n", IGDInfo.hostname); fprintf(xml_fd, " type: %s\n", IGDInfo.type); fprintf(xml_fd, " F Name: %s\n", IGDInfo.friendlyName); fprintf(xml_fd, " Icon URL: %s\n", IGDInfo.iconUrl); fprintf(xml_fd, "================================\n\n"); syslog(LOG_NOTICE, "parse icon url: %s", IGDInfo.iconUrl); #endif strcpy(dev->DevInfo.hostname, IGDInfo.hostname); strcpy(dev->DevInfo.type, IGDInfo.type); strcpy(dev->DevInfo.friendlyName, IGDInfo.friendlyName); strcpy(dev->DevInfo.iconUrl, IGDInfo.iconUrl); #ifdef RTCONFIG_JFFS2USERICON if(strcmp(IGDInfo.iconUrl, "") != NULL) { char realIconUrl[158], iconFile[32], iconBuf[512]; char *ico_head, *ico_end; char *icon, *p, *q; int iconSize, i = 0, iconCheck = 0; FILE *ico_fd; memset(realIconUrl, 0, 158); if(strstr(IGDInfo.iconUrl, "http://")) { strcpy(realIconUrl, IGDInfo.iconUrl); } else { q = IGDDescURL; while(q = strchr(q, '/')) { i++; if(i == 3) { p = IGDDescURL; i = 0; while ( p < q ) { realIconUrl[i++] = *p++; } strcat(realIconUrl, IGDInfo.iconUrl); #ifdef DEBUG printf("\n*** Real URL=%s=\n\n", realIconUrl); #endif break; } q++; } } get_icon: #ifdef DEBUG syslog(LOG_NOTICE, "Real icon url: %s", realIconUrl); fprintf(xml_fd, "Real icon url: %s\n", realIconUrl); #endif sprintf(iconFile, "/tmp/upnpicon/%s.ico", IGDInfo.hostname); icon = miniwget_getaddr(realIconUrl, &iconSize, lanaddr, lanaddrlen, 0, &IGDInfo, dut_lanaddr); if( iconSize > 512 ) { ico_fd = fopen(iconFile, "w"); if(ico_fd) { fwrite(icon, sizeof(char), iconSize, ico_fd); fclose(ico_fd); } } else if(iconSize > 0) { ico_head = strstr(icon, "<a href="); if(ico_head) { ico_head = ico_head+9; ico_end = strstr(icon, "\">"); if(ico_end) { *ico_end = '\0'; strcpy(realIconUrl, ico_head); goto get_icon; } } } } #endif if(COMPARE(data->CIF.servicetype, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:")) { desc[i].is_igd = 1; n_igd++; } #ifdef DEBUG fclose(xml_fd); #endif } else memset(dev->DevInfo.hostname, 0, 65); } /* iterate the list to find a device depending on state */ for(state = 1; state <= 3; state++) /*if(0)*/ { for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) { if(desc[i].xml) { memset(data, 0, sizeof(struct IGDdatas)); memset(urls, 0, sizeof(struct UPNPUrls)); parserootdesc(desc[i].xml, desc[i].size, data); if(desc[i].is_igd || state >= 3 ) { GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); /* in state 2 and 3 we dont test if device is connected ! */ if(state >= 2) goto free_and_return; #ifdef DEBUG printf("UPNPIGD_IsConnected(%s) = %d\n", urls->controlURL, UPNPIGD_IsConnected(urls, data)); #endif /* checks that status is connected AND there is a external IP address assigned */ if(UPNPIGD_IsConnected(urls, data) && (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) goto free_and_return; FreeUPNPUrls(urls); if(data->second.servicetype[0] != '\0') { #ifdef DEBUG printf("We tried %s, now we try %s !\n", data->first.servicetype, data->second.servicetype); #endif /* swaping WANPPPConnection and WANIPConnection ! */ memcpy(&data->tmp, &data->first, sizeof(struct IGDdatas_service)); memcpy(&data->first, &data->second, sizeof(struct IGDdatas_service)); memcpy(&data->second, &data->tmp, sizeof(struct IGDdatas_service)); GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); #ifdef DEBUG printf("UPNPIGD_IsConnected(%s) = %d\n", urls->controlURL, UPNPIGD_IsConnected(urls, data)); #endif if(UPNPIGD_IsConnected(urls, data) && (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) goto free_and_return; FreeUPNPUrls(urls); } } memset(data, 0, sizeof(struct IGDdatas)); } } } state = 0; free_and_return: if(desc) { for(i = 0; i < ndev; i++) { if(desc[i].xml) { free(desc[i].xml); } } free(desc); } return state; }
void* CNetServerWorker::SetupUPnP(void*) { // Values we want to set. char psPort[6]; sprintf_s(psPort, ARRAY_SIZE(psPort), "%d", PS_DEFAULT_PORT); const char* leaseDuration = "0"; // Indefinite/permanent lease duration. const char* description = "0AD Multiplayer"; const char* protocall = "UDP"; char internalIPAddress[64]; char externalIPAddress[40]; // Variables to hold the values that actually get set. char intClient[40]; char intPort[6]; char duration[16]; // Intermediate variables. struct UPNPUrls urls; struct IGDdatas data; struct UPNPDev* devlist = NULL; // Cached root descriptor URL. std::string rootDescURL; CFG_GET_VAL("network.upnprootdescurl", rootDescURL); if (!rootDescURL.empty()) LOGMESSAGE("Net server: attempting to use cached root descriptor URL: %s", rootDescURL.c_str()); int ret = 0; bool allocatedUrls = false; // Try a cached URL first if (!rootDescURL.empty() && UPNP_GetIGDFromUrl(rootDescURL.c_str(), &urls, &data, internalIPAddress, sizeof(internalIPAddress))) { LOGMESSAGE("Net server: using cached IGD = %s", urls.controlURL); ret = 1; } // No cached URL, or it did not respond. Try getting a valid UPnP device for 10 seconds. else if ((devlist = upnpDiscover(10000, 0, 0, 0, 0, 0)) != NULL) { ret = UPNP_GetValidIGD(devlist, &urls, &data, internalIPAddress, sizeof(internalIPAddress)); allocatedUrls = ret != 0; // urls is allocated on non-zero return values } else { LOGMESSAGE("Net server: upnpDiscover failed and no working cached URL."); return NULL; } switch (ret) { case 0: LOGMESSAGE("Net server: No IGD found"); break; case 1: LOGMESSAGE("Net server: found valid IGD = %s", urls.controlURL); break; case 2: LOGMESSAGE("Net server: found a valid, not connected IGD = %s, will try to continue anyway", urls.controlURL); break; case 3: LOGMESSAGE("Net server: found a UPnP device unrecognized as IGD = %s, will try to continue anyway", urls.controlURL); break; default: debug_warn(L"Unrecognized return value from UPNP_GetValidIGD"); } // Try getting our external/internet facing IP. TODO: Display this on the game-setup page for conviniance. ret = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress); if (ret != UPNPCOMMAND_SUCCESS) { LOGMESSAGE("Net server: GetExternalIPAddress failed with code %d (%s)", ret, strupnperror(ret)); return NULL; } LOGMESSAGE("Net server: ExternalIPAddress = %s", externalIPAddress); // Try to setup port forwarding. ret = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, psPort, psPort, internalIPAddress, description, protocall, 0, leaseDuration); if (ret != UPNPCOMMAND_SUCCESS) { LOGMESSAGE("Net server: AddPortMapping(%s, %s, %s) failed with code %d (%s)", psPort, psPort, internalIPAddress, ret, strupnperror(ret)); return NULL; } // Check that the port was actually forwarded. ret = UPNP_GetSpecificPortMappingEntry(urls.controlURL, data.first.servicetype, psPort, protocall, #if defined(MINIUPNPC_API_VERSION) && MINIUPNPC_API_VERSION >= 10 NULL/*remoteHost*/, #endif intClient, intPort, NULL/*desc*/, NULL/*enabled*/, duration); if (ret != UPNPCOMMAND_SUCCESS) { LOGMESSAGE("Net server: GetSpecificPortMappingEntry() failed with code %d (%s)", ret, strupnperror(ret)); return NULL; } LOGMESSAGE("Net server: External %s:%s %s is redirected to internal %s:%s (duration=%s)", externalIPAddress, psPort, protocall, intClient, intPort, duration); // Cache root descriptor URL to try to avoid discovery next time. g_ConfigDB.SetValueString(CFG_USER, "network.upnprootdescurl", urls.controlURL); g_ConfigDB.WriteFile(CFG_USER); LOGMESSAGE("Net server: cached UPnP root descriptor URL as %s", urls.controlURL); // Make sure everything is properly freed. if (allocatedUrls) FreeUPNPUrls(&urls); freeUPNPDevlist(devlist); return NULL; }
static bool natt_open_port(struct natt_status *status, struct sockaddr *addr, socklen_t addrlen, enum socket_protocol proto) { #ifndef HAVE_SOCKET_LEGACY #if HAVE_MINIUPNPC int r; char host[PATH_MAX_LENGTH], ext_host[PATH_MAX_LENGTH], port_str[6], ext_port_str[6]; struct addrinfo hints = {0}; const char *proto_str = NULL; struct addrinfo *ext_addrinfo = NULL; /* if NAT traversal is uninitialized or unavailable, oh well */ if (!urls.controlURL || !urls.controlURL[0]) return false; /* figure out the internal info */ if (getnameinfo(addr, addrlen, host, PATH_MAX_LENGTH, port_str, 6, NI_NUMERICHOST|NI_NUMERICSERV) != 0) return false; proto_str = (proto == SOCKET_PROTOCOL_UDP) ? "UDP" : "TCP"; /* add the port mapping */ r = UPNP_AddAnyPortMapping(urls.controlURL, data.first.servicetype, port_str, port_str, host, "retroarch", proto_str, NULL, "3600", ext_port_str); if (r != 0) { /* try the older AddPortMapping */ memcpy(ext_port_str, port_str, 6); r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, port_str, port_str, host, "retroarch", proto_str, NULL, "3600"); } if (r != 0) return false; /* get the external IP */ r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, ext_host); if (r != 0) return false; /* update the status */ if (getaddrinfo_retro(ext_host, ext_port_str, &hints, &ext_addrinfo) != 0) return false; if (ext_addrinfo->ai_family == AF_INET && ext_addrinfo->ai_addrlen >= sizeof(struct sockaddr_in)) { status->have_inet4 = true; status->ext_inet4_addr = *((struct sockaddr_in *) ext_addrinfo->ai_addr); } #if defined(AF_INET6) && !defined(HAVE_SOCKET_LEGACY) else if (ext_addrinfo->ai_family == AF_INET6 && ext_addrinfo->ai_addrlen >= sizeof(struct sockaddr_in6)) { status->have_inet6 = true; status->ext_inet6_addr = *((struct sockaddr_in6 *) ext_addrinfo->ai_addr); } #endif else { freeaddrinfo_retro(ext_addrinfo); return false; } freeaddrinfo_retro(ext_addrinfo); return true; #else return false; #endif #else return false; #endif }
bool UPnP::start() { int error = 0; UPNPDev *devlist = ::upnpDiscover(2000, NULL, NULL, FALSE, FALSE, &error); UPNPDev *devlistBegin = devlist; // get interface list /*foreach(interface, interfaces) { newdevlist = ::upnpDiscover(2000, interface, NULL, FALSE, FALSE, &error); // go to end of list and append }*/ while (devlist) { UPNPUrls urls; IGDdatas data; char lanaddr[64]; UPnPHash resultHash; int code = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)); if (code > 0) // TODO maybe distinguish between the return codes (1,2,3) to add information what happend to the result { resultHash.insert(LanIpAddress, QLatin1String(lanaddr)); char externalIP[40]; if (UPNPCOMMAND_SUCCESS == UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIP)) { resultHash.insert(ExternalIpAddress, QLatin1String(externalIP)); } char connectionType[64]; if (UPNPCOMMAND_SUCCESS == UPNP_GetConnectionTypeInfo(urls.controlURL, data.first.servicetype, connectionType)) { resultHash.insert(ConnectionType, QLatin1String(connectionType)); } quint32 uplink, downlink; if (UPNPCOMMAND_SUCCESS == UPNP_GetLinkLayerMaxBitRates(urls.controlURL_CIF, data.CIF.servicetype, &downlink, &uplink)) { resultHash.insert(LinkLayerMaxDownload, downlink); resultHash.insert(LinkLayerMaxUpload, uplink); } quint32 bytesSent, bytesReceived, packetsSent, packetsReceived; bytesSent = UPNP_GetTotalBytesSent(urls.controlURL_CIF, data.CIF.servicetype); if ((unsigned int)UPNPCOMMAND_HTTP_ERROR != bytesSent) { resultHash.insert(TotalBytesSent, bytesSent); } bytesReceived = UPNP_GetTotalBytesReceived(urls.controlURL_CIF, data.CIF.servicetype); if ((unsigned int)UPNPCOMMAND_HTTP_ERROR != bytesReceived) { resultHash.insert(TotalBytesReceived, bytesReceived); } packetsSent = UPNP_GetTotalPacketsSent(urls.controlURL_CIF, data.CIF.servicetype); if ((unsigned int)UPNPCOMMAND_HTTP_ERROR != packetsSent) { resultHash.insert(TotalPacketsSent, packetsSent); } packetsReceived = UPNP_GetTotalPacketsReceived(urls.controlURL_CIF, data.CIF.servicetype); if ((unsigned int)UPNPCOMMAND_HTTP_ERROR != packetsReceived) { resultHash.insert(TotalPacketsReceived, packetsReceived); } char status[100]; unsigned int uptime = 0; char lastConnectionError[128]; if (UPNPCOMMAND_SUCCESS == UPNP_GetStatusInfo(urls.controlURL, data.first.servicetype, status, &uptime, lastConnectionError)) { resultHash.insert(Status, status); resultHash.insert(Uptime, uptime); resultHash.insert(LastConnectionError, lastConnectionError); } quint32 num; if (UPNPCOMMAND_SUCCESS == UPNP_GetPortMappingNumberOfEntries(urls.controlURL, data.first.servicetype, &num)) { resultHash.insert(NumberOfPortMappings, num); } // TODO GetListOfPortMappings do we need this? int firewallEnabled, inboundPinholeAllowed; if (UPNPCOMMAND_SUCCESS == UPNP_GetFirewallStatus(urls.controlURL, data.first.servicetype, &firewallEnabled, &inboundPinholeAllowed)) { resultHash.insert(FirewallEnabled, firewallEnabled); resultHash.insert(InboundPinholeAllowed, inboundPinholeAllowed); } int bufferSize = 0; if (char *buffer = (char *)miniwget(urls.rootdescURL, &bufferSize, 0)) { NameValueParserData pdata; ParseNameValue(buffer, bufferSize, &pdata); free(buffer); buffer = NULL; QStringList modelName = GetValuesFromNameValueList(&pdata, "modelName"); if (!modelName.isEmpty()) { resultHash.insert(ModelName, modelName.last()); } QStringList manufacturer = GetValuesFromNameValueList(&pdata, "manufacturer"); if (!manufacturer.isEmpty()) { resultHash.insert(Manufacturer, manufacturer.last()); } QStringList friendlyName = GetValuesFromNameValueList(&pdata, "friendlyName"); if (!friendlyName.isEmpty()) { resultHash.insert(FriendlyName, friendlyName.last()); } ClearNameValueList(&pdata); } } FreeUPNPUrls(&urls); results.append(resultHash); devlist = devlist->pNext; } freeUPNPDevlist(devlistBegin); emit finished(); return true; // TODO return false if something went wrong or if there are no results }