/* 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); } }
/* AddAnyPortMapping(externalPort, protocol, internalHost, internalPort, desc, * remoteHost) * protocol is 'UDP' or 'TCP' */ static PyObject * UPnP_addanyportmapping(UPnPObject *self, PyObject *args) { char extPort[6]; unsigned short ePort; char inPort[6]; unsigned short iPort; char reservedPort[6]; const char * proto; const char * host; const char * desc; const char * remoteHost; const char * leaseDuration = "0"; int r; if (!PyArg_ParseTuple(args, "HssHss", &ePort, &proto, &host, &iPort, &desc, &remoteHost)) return NULL; Py_BEGIN_ALLOW_THREADS sprintf(extPort, "%hu", ePort); sprintf(inPort, "%hu", iPort); r = UPNP_AddAnyPortMapping(self->urls.controlURL, self->data.first.servicetype, extPort, inPort, host, desc, proto, remoteHost, leaseDuration, reservedPort); Py_END_ALLOW_THREADS if(r==UPNPCOMMAND_SUCCESS) { return Py_BuildValue("i", atoi(reservedPort)); } else { /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } }
static PyObject * UPnP_statusinfo(UPnPObject *self) { char status[64]; char lastconnerror[64]; unsigned int uptime = 0; int r; status[0] = '\0'; lastconnerror[0] = '\0'; Py_BEGIN_ALLOW_THREADS r = UPNP_GetStatusInfo(self->urls.controlURL, self->data.first.servicetype, status, &uptime, lastconnerror); Py_END_ALLOW_THREADS if(r==UPNPCOMMAND_SUCCESS) { #if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3) return Py_BuildValue("(s,I,s)", status, uptime, lastconnerror); #else return Py_BuildValue("(s,i,s)", status, (int)uptime, lastconnerror); #endif } else { /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } }
/* DeletePortMappingRange(extPort, proto, removeHost='') * proto = 'UDP', 'TCP' */ static PyObject * UPnP_deleteportmappingrange(UPnPObject *self, PyObject *args) { char extPortStart[6]; unsigned short ePortStart; char extPortEnd[6]; unsigned short ePortEnd; const char * proto; unsigned char manage; char manageStr[1]; int r; if(!PyArg_ParseTuple(args, "HHsb", &ePortStart, &ePortEnd, &proto, &manage)) return NULL; Py_BEGIN_ALLOW_THREADS sprintf(extPortStart, "%hu", ePortStart); sprintf(extPortEnd, "%hu", ePortEnd); sprintf(manageStr, "%hhu", manage); r = UPNP_DeletePortMappingRange(self->urls.controlURL, self->data.first.servicetype, extPortStart, extPortEnd, proto, manageStr); Py_END_ALLOW_THREADS if(r==UPNPCOMMAND_SUCCESS) { Py_RETURN_TRUE; } else { /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } }
/* AddPortMapping(externalPort, protocol, internalHost, internalPort, desc, * remoteHost) * protocol is 'UDP' or 'TCP' */ static PyObject * UPnP_addportmapping(UPnPObject *self, PyObject *args) { char extPort[6]; unsigned short ePort; char inPort[6]; unsigned short iPort; const char * proto; const char * host; const char * desc; const char * remoteHost; int r; if (!PyArg_ParseTuple(args, "HssHss", &ePort, &proto, &host, &iPort, &desc, &remoteHost)) return NULL; sprintf(extPort, "%hu", ePort); sprintf(inPort, "%hu", iPort); r = UPNP_AddPortMapping(self->urls.controlURL, self->data.servicetype, extPort, inPort, host, desc, proto, remoteHost); if(r==UPNPCOMMAND_SUCCESS) { Py_RETURN_TRUE; } else { // TODO: RAISE an Exception. See upnpcommands.h for errors codes. // upnperrors.c //Py_RETURN_FALSE; /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } }
void C4Network2UPnPP::RemovePortMapping(const PortMapping& mapping) { if(!initialized) return; // Catches the case that UPnP initialization failed auto eport = std::to_string(mapping.external_port); int r = UPNP_DeletePortMapping(upnp_urls.controlURL, igd_data.first.servicetype, eport.c_str(), mapping.protocol.c_str(), 0); if (r == UPNPCOMMAND_SUCCESS) ThreadLogS("UPnP: Removed mapping %s %s", mapping.protocol.c_str(), eport.c_str()); else ThreadLog("UPnP: DeletePortMapping failed with code %d (%s)", r, strupnperror(r)); }
/* Test function * 1 - Check if pinhole is working from the IGD side * 2 - Update pinhole */ static void GetPinholeAndUpdate(struct UPNPUrls * urls, struct IGDdatas * data, const char * uniqueID, const char * lease_time) { int isWorking = 0; int r; if(!uniqueID || !lease_time) { fprintf(stderr, "Wrong arguments\n"); return; } r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking); printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No"); if(r!=UPNPCOMMAND_SUCCESS) printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r)); if(isWorking || r==709) { r = UPNP_UpdatePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, lease_time); printf("UpdatePinhole: Pinhole ID = %s with Lease Time: %s\n", uniqueID, lease_time); if(r!=UPNPCOMMAND_SUCCESS) printf("UpdatePinhole: ID (%s) failed with code %d (%s)\n", uniqueID, r, strupnperror(r)); } }
/* Test function * 1 - Add pinhole * 2 - Check if pinhole is working from the IGD side */ static void SetPinholeAndTest(struct UPNPUrls * urls, struct IGDdatas * data, const char * remoteaddr, const char * eport, const char * intaddr, const char * iport, const char * proto, const char * lease_time) { char uniqueID[8]; /*int isWorking = 0;*/ int r; char proto_tmp[8]; if(!intaddr || !remoteaddr || !iport || !eport || !proto || !lease_time) { fprintf(stderr, "Wrong arguments\n"); return; } if(atoi(proto) == 0) { const char * protocol; protocol = protofix(proto); if(protocol && (strcmp("TCP", protocol) == 0)) { snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_TCP); proto = proto_tmp; } else if(protocol && (strcmp("UDP", protocol) == 0)) { snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_UDP); proto = proto_tmp; } else { fprintf(stderr, "invalid protocol\n"); return; } } r = UPNP_AddPinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, lease_time, uniqueID); if(r!=UPNPCOMMAND_SUCCESS) printf("AddPinhole([%s]:%s -> [%s]:%s) failed with code %d (%s)\n", remoteaddr, eport, intaddr, iport, r, strupnperror(r)); else { printf("AddPinhole: ([%s]:%s -> [%s]:%s) / Pinhole ID = %s\n", remoteaddr, eport, intaddr, iport, uniqueID); /*r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->servicetype_6FC, uniqueID, &isWorking); if(r!=UPNPCOMMAND_SUCCESS) printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r)); printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");*/ } }
static void ListRedirections(struct UPNPUrls * urls, struct IGDdatas * data) { int r; int i = 0; char index[6]; char intClient[16]; char intPort[6]; char extPort[6]; char protocol[4]; char desc[80]; char enabled[6]; char rHost[64]; char duration[16]; /*unsigned int num=0; UPNP_GetPortMappingNumberOfEntries(urls->controlURL, data->servicetype, &num); printf("PortMappingNumberOfEntries : %u\n", num);*/ do { snprintf(index, 6, "%d", i); rHost[0] = '\0'; enabled[0] = '\0'; duration[0] = '\0'; desc[0] = '\0'; extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0'; r = UPNP_GetGenericPortMappingEntry(urls->controlURL, data->first.servicetype, index, extPort, intClient, intPort, protocol, desc, enabled, rHost, duration); if(r==0) /* printf("%02d - %s %s->%s:%s\tenabled=%s leaseDuration=%s\n" " desc='%s' rHost='%s'\n", i, protocol, extPort, intClient, intPort, enabled, duration, desc, rHost); */ printf("%2d %s %5s->%s:%-5s '%s' '%s'\n", i, protocol, extPort, intClient, intPort, desc, rHost); else printf("GetGenericPortMappingEntry() returned %d (%s)\n", r, strupnperror(r)); i++; } while(r==0); }
static PyObject * UPnP_getportmappingnumberofentries(UPnPObject *self) { unsigned int n = 0; int r; r = UPNP_GetPortMappingNumberOfEntries(self->urls.controlURL, self->data.servicetype, &n); if(r==UPNPCOMMAND_SUCCESS) { return Py_BuildValue("I", n); } else { /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } }
static void GetPinholePackets(struct UPNPUrls * urls, struct IGDdatas * data, const char * uniqueID) { int r, pinholePackets = 0; if(!uniqueID) { fprintf(stderr, "invalid arguments\n"); return; } r = UPNP_GetPinholePackets(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &pinholePackets); if(r!=UPNPCOMMAND_SUCCESS) printf("GetPinholePackets() failed with code %d (%s)\n", r, strupnperror(r)); else printf("GetPinholePackets: Pinhole ID = %s / PinholePackets = %d\n", uniqueID, pinholePackets); }
static void CheckPinhole(struct UPNPUrls * urls, struct IGDdatas * data, const char * uniqueID) { int r, isWorking = 0; if(!uniqueID) { fprintf(stderr, "invalid arguments\n"); return; } r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking); if(r!=UPNPCOMMAND_SUCCESS) printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r)); else printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No"); }
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; } }
static PyObject * UPnP_connectiontype(UPnPObject *self) { char connectionType[64]; int r; connectionType[0] = '\0'; r = UPNP_GetConnectionTypeInfo(self->urls.controlURL, self->data.servicetype, connectionType); if(r==UPNPCOMMAND_SUCCESS) { return Py_BuildValue("s", connectionType); } else { /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } }
/* AddPortMapping(externalPort, protocol, internalHost, internalPort, desc, * remoteHost, leaseDuration) * protocol is 'UDP' or 'TCP' */ static PyObject * UPnP_addportmapping(UPnPObject *self, PyObject *args) { char extPort[6]; unsigned short ePort; char inPort[6]; unsigned short iPort; const char * proto; const char * host; const char * desc; const char * remoteHost; unsigned int intLeaseDuration = 0; char strLeaseDuration[12]; int r; #if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3) if (!PyArg_ParseTuple(args, "HssHzz|I", &ePort, &proto, &host, &iPort, &desc, &remoteHost, &intLeaseDuration)) #else if (!PyArg_ParseTuple(args, "HssHzz|i", &ePort, &proto, &host, &iPort, &desc, &remoteHost, (int *)&intLeaseDuration)) #endif return NULL; Py_BEGIN_ALLOW_THREADS sprintf(extPort, "%hu", ePort); sprintf(inPort, "%hu", iPort); sprintf(strLeaseDuration, "%u", intLeaseDuration); r = UPNP_AddPortMapping(self->urls.controlURL, self->data.first.servicetype, extPort, inPort, host, desc, proto, remoteHost, strLeaseDuration); Py_END_ALLOW_THREADS if(r==UPNPCOMMAND_SUCCESS) { Py_RETURN_TRUE; } else { // TODO: RAISE an Exception. See upnpcommands.h for errors codes. // upnperrors.c //Py_RETURN_FALSE; /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } }
static PyObject * UPnP_statusinfo(UPnPObject *self) { char status[64]; char lastconnerror[64]; unsigned int uptime = 0; int r; status[0] = '\0'; lastconnerror[0] = '\0'; r = UPNP_GetStatusInfo(self->urls.controlURL, self->data.servicetype, status, &uptime, lastconnerror); if(r==UPNPCOMMAND_SUCCESS) { return Py_BuildValue("(s,I,s)", status, uptime, lastconnerror); } else { /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } }
/* DeletePortMapping(extPort, proto) * proto = 'UDP', 'TCP' */ static PyObject * UPnP_deleteportmapping(UPnPObject *self, PyObject *args) { char extPort[6]; unsigned short ePort; const char * proto; int r; if(!PyArg_ParseTuple(args, "Hs", &ePort, &proto)) return NULL; sprintf(extPort, "%hu", ePort); r = UPNP_DeletePortMapping(self->urls.controlURL, self->data.servicetype, extPort, proto); if(r==UPNPCOMMAND_SUCCESS) { Py_RETURN_TRUE; } else { /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } }
/* Test function * Get pinhole timeout */ static void GetPinholeOutboundTimeout(struct UPNPUrls * urls, struct IGDdatas * data, const char * remoteaddr, const char * eport, const char * intaddr, const char * iport, const char * proto) { int timeout = 0; int r; if(!intaddr || !remoteaddr || !iport || !eport || !proto) { fprintf(stderr, "Wrong arguments\n"); return; } r = UPNP_GetOutboundPinholeTimeout(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, &timeout); if(r!=UPNPCOMMAND_SUCCESS) printf("GetOutboundPinholeTimeout([%s]:%s -> [%s]:%s) failed with code %d (%s)\n", intaddr, iport, remoteaddr, eport, r, strupnperror(r)); else printf("GetOutboundPinholeTimeout: ([%s]:%s -> [%s]:%s) / Timeout = %d\n", intaddr, iport, remoteaddr, eport, timeout); }
static PyObject * UPnP_getportmappingnumberofentries(UPnPObject *self) { unsigned int n = 0; int r; Py_BEGIN_ALLOW_THREADS r = UPNP_GetPortMappingNumberOfEntries(self->urls.controlURL, self->data.first.servicetype, &n); Py_END_ALLOW_THREADS if(r==UPNPCOMMAND_SUCCESS) { #if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3) return Py_BuildValue("I", n); #else return Py_BuildValue("i", (int)n); #endif } else { /* TODO: have our own exception type ! */ PyErr_SetString(PyExc_Exception, strupnperror(r)); return NULL; } }
// 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* 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 void NewListRedirections(struct UPNPUrls * urls, struct IGDdatas * data) { int r; int i = 0; struct PortMappingParserData pdata; struct PortMapping * pm; memset(&pdata, 0, sizeof(struct PortMappingParserData)); r = UPNP_GetListOfPortMappings(urls->controlURL, data->first.servicetype, "0", "65535", "TCP", "1000", &pdata); if(r == UPNPCOMMAND_SUCCESS) { printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n"); for(pm = pdata.l_head; pm != NULL; pm = pm->l_next) { printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n", i, pm->protocol, pm->externalPort, pm->internalClient, pm->internalPort, pm->description, pm->remoteHost, (unsigned)pm->leaseTime); i++; } FreePortListing(&pdata); } else { printf("GetListOfPortMappings() returned %d (%s)\n", r, strupnperror(r)); } r = UPNP_GetListOfPortMappings(urls->controlURL, data->first.servicetype, "0", "65535", "UDP", "1000", &pdata); if(r == UPNPCOMMAND_SUCCESS) { for(pm = pdata.l_head; pm != NULL; pm = pm->l_next) { printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n", i, pm->protocol, pm->externalPort, pm->internalClient, pm->internalPort, pm->description, pm->remoteHost, (unsigned)pm->leaseTime); i++; } FreePortListing(&pdata); } else { printf("GetListOfPortMappings() returned %d (%s)\n", r, strupnperror(r)); } }
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" ); }