Wire up PortMapper in Android

Enables UPnP port mapping for Android client on networks with UPnP routers
This commit is contained in:
Grant Limberg 2017-07-17 16:15:13 -07:00
parent b9e1d53d7a
commit bcf697cc2b
5 changed files with 89 additions and 20 deletions

View File

@ -26,6 +26,12 @@
#define UPNP_VERSION_STRING "UPnP/1.1"
#endif
#ifdef __ANDROID__
#define OS_STRING "Android"
#define MINIUPNPC_VERSION_STRING "2.0"
#define UPNP_VERSION_STRING "UPnP/1.1"
#endif
/* only for malloc */
#include <stdlib.h>

View File

@ -55,6 +55,12 @@
#define UPNP_VERSION_STRING "UPnP/1.1"
#endif
#ifdef __ANDROID__
#define OS_STRING "Android"
#define MINIUPNPC_VERSION_STRING "2.0"
#define UPNP_VERSION_STRING "UPnP/1.1"
#endif
#include "miniwget.h"
#include "connecthostport.h"
#include "receivedata.h"

View File

@ -3,14 +3,21 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ZeroTierOneJNI
LOCAL_C_INCLUDES := $(ZT1)/include
LOCAL_C_INCLUDES += $(ZT1)/node
LOCAL_C_INCLUDES := \
$(ZT1)/include \
$(ZT1)/node \
$(ZT1)/osdep \
$(ZT1)/ext/miniupnpc \
$(ZT1)/ext/libnatpmp
LOCAL_LDLIBS := -llog -latomic
# LOCAL_CFLAGS := -g
LOCAL_CFLAGS := -DZT_USE_MINIUPNPC
# ZeroTierOne SDK source files
LOCAL_SRC_FILES := \
$(ZT1)/node/C25519.cpp \
$(ZT1)/node/C25519.cpp \
$(ZT1)/node/Capability.cpp \
$(ZT1)/node/CertificateOfMembership.cpp \
$(ZT1)/node/CertificateOfOwnership.cpp \
@ -35,8 +42,27 @@ LOCAL_SRC_FILES := \
$(ZT1)/node/Tag.cpp \
$(ZT1)/node/Topology.cpp \
$(ZT1)/node/Trace.cpp \
$(ZT1)/node/Utils.cpp
$(ZT1)/node/Utils.cpp \
$(ZT1)/osdep/OSUtils.cpp \
$(ZT1)/osdep/PortMapper.cpp
# libminiupnpc and libnatpmp files
LOCAL_SRC_FILES += \
$(ZT1)/ext/miniupnpc/connecthostport.c \
$(ZT1)/ext/miniupnpc/igd_desc_parse.c \
$(ZT1)/ext/miniupnpc/minisoap.c \
$(ZT1)/ext/miniupnpc/minissdpc.c \
$(ZT1)/ext/miniupnpc/miniupnpc.c \
$(ZT1)/ext/miniupnpc/miniwget.c \
$(ZT1)/ext/miniupnpc/minixml.c \
$(ZT1)/ext/miniupnpc/portlistingparse.c \
$(ZT1)/ext/miniupnpc/receivedata.c \
$(ZT1)/ext/miniupnpc/upnpcommands.c \
$(ZT1)/ext/miniupnpc/upnpdev.c \
$(ZT1)/ext/miniupnpc/upnperrors.c \
$(ZT1)/ext/miniupnpc/upnpreplyparse.c \
$(ZT1)/ext/libnatpmp/natpmp.c \
$(ZT1)/ext/libnatpmp/getgateway.c
# JNI Files
LOCAL_SRC_FILES += \

View File

@ -32,6 +32,8 @@
#include <ZeroTierOne.h>
#include "Mutex.hpp"
#include "PortMapper.hpp"
#include <map>
#include <string>
#include <assert.h>
@ -58,6 +60,7 @@ namespace {
, configListener(NULL)
, pathChecker(NULL)
, callbacks(NULL)
, portMapper(NULL)
{
callbacks = (ZT_Node_Callbacks*)malloc(sizeof(ZT_Node_Callbacks));
memset(callbacks, 0, sizeof(ZT_Node_Callbacks));
@ -78,6 +81,9 @@ namespace {
free(callbacks);
callbacks = NULL;
delete portMapper;
portMapper = NULL;
}
uint64_t id;
@ -95,6 +101,8 @@ namespace {
jobject pathChecker;
ZT_Node_Callbacks *callbacks;
ZeroTier::PortMapper *portMapper;
};
@ -833,11 +841,17 @@ JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_node_1init(
return resultObject;
}
uint64_t nodeId = ZT_Node_address(node);
if (nodeId != 0) {
char uniqueName[64];
snprintf(uniqueName, sizeof(uniqueName), "ZeroTier Android/%.10llx@%u", (unsigned long long)nodeId, 9993);
ref->portMapper = new ZeroTier::PortMapper(9993, uniqueName);
}
ZeroTier::Mutex::Lock lock(nodeMapMutex);
ref->node = node;
nodeMap.insert(std::make_pair(ref->id, ref));
return resultObject;
}

View File

@ -29,6 +29,13 @@
// Uncomment to dump debug messages
//#define ZT_PORTMAPPER_TRACE 1
#ifdef __ANDROID__
#include <android/log.h>
#define PM_TRACE(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, "PortMapper", __VA_ARGS__))
#else
#define PM_TRACE(...) fprintf(stderr, __VA_ARGS__)
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -53,15 +60,24 @@
#include <miniupnpc/miniupnpc.h>
#include <miniupnpc/upnpcommands.h>
#else
#ifdef __ANDROID__
#include "miniupnpc.h"
#include "upnpcommands.h"
#else
#include "../ext/miniupnpc/miniupnpc.h"
#include "../ext/miniupnpc/upnpcommands.h"
#endif
#endif
#ifdef ZT_USE_SYSTEM_NATPMP
#include <natpmp.h>
#else
#ifdef __ANDROID__
#include "natpmp.h"
#else
#include "../ext/libnatpmp/natpmp.h"
#endif
#endif
namespace ZeroTier {
@ -83,7 +99,7 @@ public:
int mode = 0; // 0 == NAT-PMP, 1 == UPnP
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: started for UDP port %d"ZT_EOL_S,localPort);
fprintf(stderr,"PortMapper: started for UDP port %d" ZT_EOL_S,localPort);
#endif
while (run) {
@ -108,7 +124,7 @@ public:
if (initnatpmp(&natpmp,0,0) != 0) {
mode = 1;
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: NAT-PMP: init failed, switching to UPnP mode"ZT_EOL_S);
PM_TRACE("PortMapper: NAT-PMP: init failed, switching to UPnP mode" ZT_EOL_S);
#endif
break;
}
@ -131,7 +147,7 @@ public:
publicAddress = InetAddress((uint32_t)response.pnu.publicaddress.addr.s_addr,0);
} else {
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: NAT-PMP: request for external address failed, aborting..."ZT_EOL_S);
PM_TRACE("PortMapper: NAT-PMP: request for external address failed, aborting..." ZT_EOL_S);
#endif
closenatpmp(&natpmp);
break;
@ -153,7 +169,8 @@ public:
if (r == 0) {
publicAddress.setPort(response.pnu.newportmapping.mappedpublicport);
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: NAT-PMP: mapped %u to %s"ZT_EOL_S,(unsigned int)localPort,publicAddress.toString().c_str());
char paddr[128];
PM_TRACE("PortMapper: NAT-PMP: mapped %u to %s" ZT_EOL_S,(unsigned int)localPort,publicAddress.toString(paddr));
#endif
Mutex::Lock sl(surface_l);
surface.clear();
@ -170,7 +187,7 @@ public:
if (!natPmpSuccess) {
mode = 1;
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: NAT-PMP: request failed, switching to UPnP mode"ZT_EOL_S);
PM_TRACE("PortMapper: NAT-PMP: request failed, switching to UPnP mode" ZT_EOL_S);
#endif
}
}
@ -195,7 +212,7 @@ public:
{
UPNPDev *dev = devlist;
while (dev) {
fprintf(stderr,"PortMapper: found UPnP device at URL '%s': %s"ZT_EOL_S,dev->descURL,dev->st);
PM_TRACE("PortMapper: found UPnP device at URL '%s': %s" ZT_EOL_S,dev->descURL,dev->st);
dev = dev->pNext;
}
}
@ -209,11 +226,11 @@ public:
if ((UPNP_GetValidIGD(devlist,&urls,&data,lanaddr,sizeof(lanaddr)))&&(lanaddr[0])) {
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: UPnP: my LAN IP address: %s"ZT_EOL_S,lanaddr);
PM_TRACE("PortMapper: UPnP: 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_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: UPnP: my external IP address: %s"ZT_EOL_S,externalip);
PM_TRACE("PortMapper: UPnP: my external IP address: %s" ZT_EOL_S,externalip);
#endif
for(int tries=0;tries<60;++tries) {
@ -239,7 +256,7 @@ public:
memset(haveLeaseDuration,0,sizeof(haveLeaseDuration));
if ((UPNP_GetSpecificPortMappingEntry(urls.controlURL,data.first.servicetype,outport,"UDP",(const char *)0,haveIntClient,haveIntPort,haveDesc,haveEnabled,haveLeaseDuration) == UPNPCOMMAND_SUCCESS)&&(uniqueName == haveDesc)) {
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: UPnP: reusing previously reserved external port: %s"ZT_EOL_S,outport);
PM_TRACE("PortMapper: UPnP: reusing previously reserved external port: %s" ZT_EOL_S,outport);
#endif
Mutex::Lock sl(surface_l);
surface.clear();
@ -254,7 +271,7 @@ public:
int mapResult = 0;
if ((mapResult = UPNP_AddPortMapping(urls.controlURL,data.first.servicetype,outport,inport,lanaddr,uniqueName.c_str(),"UDP",(const char *)0,"0")) == UPNPCOMMAND_SUCCESS) {
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: UPnP: reserved external port: %s"ZT_EOL_S,outport);
PM_TRACE("PortMapper: UPnP: reserved external port: %s" ZT_EOL_S,outport);
#endif
Mutex::Lock sl(surface_l);
surface.clear();
@ -264,7 +281,7 @@ public:
break;
} else {
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: UPnP: UPNP_AddPortMapping(%s) failed: %d"ZT_EOL_S,outport,mapResult);
PM_TRACE("PortMapper: UPnP: UPNP_AddPortMapping(%s) failed: %d" ZT_EOL_S,outport,mapResult);
#endif
Thread::sleep(1000);
}
@ -273,13 +290,13 @@ public:
} else {
mode = 0;
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: UPnP: UPNP_GetExternalIPAddress failed, returning to NAT-PMP mode"ZT_EOL_S);
PM_TRACE("PortMapper: UPnP: UPNP_GetExternalIPAddress failed, returning to NAT-PMP mode" ZT_EOL_S);
#endif
}
} else {
mode = 0;
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: UPnP: UPNP_GetValidIGD failed, returning to NAT-PMP mode"ZT_EOL_S);
PM_TRACE("PortMapper: UPnP: UPNP_GetValidIGD failed, returning to NAT-PMP mode" ZT_EOL_S);
#endif
}
@ -288,14 +305,14 @@ public:
} else {
mode = 0;
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: upnpDiscover failed, returning to NAT-PMP mode: %d"ZT_EOL_S,upnpError);
PM_TRACE("PortMapper: upnpDiscover failed, returning to NAT-PMP mode: %d" ZT_EOL_S,upnpError);
#endif
}
}
// ---------------------------------------------------------------------
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"UPNPClient: rescanning in %d ms"ZT_EOL_S,ZT_PORTMAPPER_REFRESH_DELAY);
PM_TRACE("UPNPClient: rescanning in %d ms" ZT_EOL_S,ZT_PORTMAPPER_REFRESH_DELAY);
#endif
Thread::sleep(ZT_PORTMAPPER_REFRESH_DELAY);
}