From 6353d9b060ac6731f92d974b5462aea963a9313b Mon Sep 17 00:00:00 2001 From: Joseph Henry Date: Wed, 17 Aug 2016 12:41:59 -0700 Subject: [PATCH] Improved proxy server controls --- src/SDK.h | 2 +- src/SDK_EthernetTap.cpp | 9 +--- src/SDK_EthernetTap.hpp | 27 +++++----- src/SDK_Proxy.cpp | 111 ++++++++++++++++++++++++++++------------ src/SDK_Service.cpp | 77 +++++++++++++++++++--------- 5 files changed, 145 insertions(+), 81 deletions(-) diff --git a/src/SDK.h b/src/SDK.h index b17e2a7..9ea4df0 100644 --- a/src/SDK.h +++ b/src/SDK.h @@ -85,7 +85,7 @@ extern char *debug_logfile; // NOTE: Each platform specific exposed API will be implemented in terms of zts_* // SOCKS5 Proxy Controls -int zts_start_proxy_server(const char *nwid, struct sockaddr_storage *addr); +int zts_start_proxy_server(const char *homepath, const char * nwid, struct sockaddr_storage * addr); int zts_stop_proxy_server(const char *nwid); int zts_get_proxy_server_address(const char * nwid, struct sockaddr_storage *addr); // ZT Service Controls diff --git a/src/SDK_EthernetTap.cpp b/src/SDK_EthernetTap.cpp index 1b25c08..a49a5fc 100644 --- a/src/SDK_EthernetTap.cpp +++ b/src/SDK_EthernetTap.cpp @@ -129,16 +129,10 @@ NetconEthernetTap::NetconEthernetTap( _enabled(true), _run(true) { + sockstate = -1; char sockPath[4096],lwipPath[4096]; Utils::snprintf(sockPath,sizeof(sockPath),"%s%snc_%.16llx",homePath,ZT_PATH_SEPARATOR_S,_nwid,ZT_PATH_SEPARATOR_S,(unsigned long long)nwid); _dev = sockPath; // in SDK mode, set device to be just the network ID - - // Start SOCKS5 Proxy server - // For use when traditional syscall hooking isn't available (ex. some APIs on iOS and Android) - #if defined(USE_SOCKS_PROXY) - StartProxy(sockPath, _homePath.c_str(), _nwid); - #endif - Utils::snprintf(lwipPath,sizeof(lwipPath),"%s%sliblwip.so",homePath,ZT_PATH_SEPARATOR_S); lwipstack = new LWIPStack(lwipPath); @@ -1383,7 +1377,6 @@ void NetconEthernetTap::handleWrite(Connection *conn) if(buf_remaining) memmove(&conn->txbuf, (conn->txbuf+udp_trans_len), buf_remaining); conn->txsz -= udp_trans_len; - int max = conn->type == SOCK_STREAM ? DEFAULT_TCP_TX_BUF_SZ : DEFAULT_UDP_TX_BUF_SZ; #if DEBUG_LEVEL >= MSG_TRANSFER struct sockaddr_in * addr_in2 = (struct sockaddr_in *)conn->peer_addr; diff --git a/src/SDK_EthernetTap.hpp b/src/SDK_EthernetTap.hpp index 06aad04..95ff448 100644 --- a/src/SDK_EthernetTap.hpp +++ b/src/SDK_EthernetTap.hpp @@ -151,11 +151,21 @@ namespace ZeroTier { throw(); LWIPStack *lwipstack; - uint64_t _nwid; - void (*_handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); - void *_arg; + uint64_t _nwid; + void (*_handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); + void *_arg; - int proxyListenPort; + // --- Proxy + struct sockaddr_storage proxyServerAddress; + int sockstate; // Use as flag to determine whether proxy has been started, TODO: Rename + int proxyListenSocket; + PhySocket *proxyListenPhySocket; + int startProxyServer(const char *homepath, uint64_t nwid, struct sockaddr_storage *addr); + int stopProxyServer(); + int getProxyServerAddress(struct sockaddr_storage *addr); + int getProxyServerPort(); + void phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,bool readable,bool writable); + // --- end Proxy private: // LWIP callbacks @@ -462,15 +472,6 @@ namespace ZeroTier { */ void closeConnection(PhySocket *sock); - // --- Proxy - int sockstate; - int proxyListenSocket; - PhySocket *proxyListenPhySocket; - void StartProxy(const char *sockpath, const char *homepath, uint64_t nwid); - void phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,bool readable,bool writable); - - // --- end Proxy - ip_addr_t convert_ip(struct sockaddr_in * addr) { ip_addr_t conn_addr; diff --git a/src/SDK_Proxy.cpp b/src/SDK_Proxy.cpp index 6c03928..ad609cd 100644 --- a/src/SDK_Proxy.cpp +++ b/src/SDK_Proxy.cpp @@ -64,42 +64,85 @@ void dwr(int level, const char *fmt, ... ); namespace ZeroTier { - void NetconEthernetTap::StartProxy(const char *sockpath, const char *homepath, uint64_t nwid) - { - dwr(MSG_ERROR, "StartProxy()\n"); - // Look for a port file for this network's proxy server instance - char portFile[4096]; - Utils::snprintf(portFile,sizeof(portFile),"%s/networks.d/%.16llx.port",homepath,nwid); - std::string portStr; - printf("Proxy(): Reading port from: %s\n", portFile); - if(ZeroTier::OSUtils::fileExists(portFile,true)) - { - if(ZeroTier::OSUtils::readFile(portFile, portStr)) { - proxyListenPort = atoi(portStr.c_str()); - } - } - else - { - unsigned int randp = 0; - Utils::getSecureRandom(&randp,sizeof(randp)); - proxyListenPort = 1000 + (randp % 1000); - dwr(MSG_DEBUG, "Proxy(): No port specified in networks.d/%.16llx.port, randomly picking port\n", nwid); - std::stringstream ss; - ss << proxyListenPort; - portStr = ss.str(); - if(!ZeroTier::OSUtils::writeFile(portFile, portStr)) { - dwr(MSG_ERROR, "unable to write proxy port file: %s\n", portFile); - } + int NetconEthernetTap::getProxyServerAddress(struct sockaddr_storage *addr) { + if(sockstate >= 0) { + addr = &proxyServerAddress; + return 0; } + return -1; + } - struct sockaddr_in in4; - memset(&in4,0,sizeof(in4)); - in4.sin_family = AF_INET; - in4.sin_addr.s_addr = Utils::hton((uint32_t)0x00000000); // right now we just listen for TCP @0.0.0.0 - in4.sin_port = Utils::hton((uint16_t)proxyListenPort); - proxyListenPhySocket = _phy.tcpListen((const struct sockaddr*)&in4,(void *)this); - sockstate = SOCKS_OPEN; - dwr(MSG_DEBUG, "SOCKS5 proxy server address for <%.16llx> is: <0.0.0.0:%d> (sock=%p)\n", nwid, proxyListenPort, (void*)&proxyListenPhySocket); + int NetconEthernetTap::getProxyServerPort() { + struct sockaddr_in *in4; + in4 = (struct sockaddr_in *)&proxyServerAddress; + return in4->sin_port; + } + + int NetconEthernetTap::stopProxyServer() + { + dwr(MSG_DEBUG, "stopProxyServer()"); + if(proxyListenPhySocket) { + _phy.close(proxyListenPhySocket); + return 0; + } + dwr(MSG_ERROR, "stopProxyServer(): Invalid proxyListenPhySocket"); + return -1; + } + + int NetconEthernetTap::startProxyServer(const char *homepath, uint64_t nwid, struct sockaddr_storage *addr) + { + // Address of proxy server is determined in the following order: + // - Provided address in param: addr + // - If no address, assume 127.0.0.1: + // - If no port assignment file, 127.0.0.1:RANDOM_PORT + + dwr(MSG_DEBUG, "startProxyServer()\n"); + int portno = -1; + if(addr) { + dwr(MSG_DEBUG, "startProxyServer(): Using provided address"); + // This address pointer may come from a different memory space and might be de-allocated, so we keep a copy + memcpy(&proxyServerAddress, addr, sizeof(struct sockaddr_storage)); + struct sockaddr_in *in4 = (struct sockaddr_in *)&addr; + proxyListenPhySocket = _phy.tcpListen((const struct sockaddr*)&in4,(void *)this); + sockstate = SOCKS_OPEN; + dwr(MSG_DEBUG, "SOCKS5 proxy server address for <%.16llx> is: <%s> (sock=%p)\n", nwid, inet_ntoa(in4->sin_addr), /*ntohs(in4->sin_port), */(void*)&proxyListenPhySocket); + return 0; + } + else { + dwr(MSG_DEBUG, "startProxyServer(): No address provided. Checking port file."); + // Look for a port file for this network's proxy server instance + char portFile[4096]; + Utils::snprintf(portFile,sizeof(portFile),"%s/networks.d/%.16llx.port",homepath,nwid); + std::string portStr; + printf("Proxy(): Reading port from: %s\n", portFile); + if(ZeroTier::OSUtils::fileExists(portFile,true)) + { + if(ZeroTier::OSUtils::readFile(portFile, portStr)) { + portno = atoi(portStr.c_str()); + } + } + else { + unsigned int randp = 0; + Utils::getSecureRandom(&randp,sizeof(randp)); + portno = 1000 + (randp % 1000); + dwr(MSG_DEBUG, "Proxy(): No port specified in networks.d/%.16llx.port, randomly picking port\n", nwid); + std::stringstream ss; + ss << portno; + portStr = ss.str(); + if(!ZeroTier::OSUtils::writeFile(portFile, portStr)) { + dwr(MSG_ERROR, "unable to write proxy port file: %s\n", portFile); + } + } + struct sockaddr_in in4; + memset(&in4,0,sizeof(in4)); + in4.sin_family = AF_INET; + in4.sin_addr.s_addr = Utils::hton((uint32_t)0x00000000); // right now we just listen for TCP @0.0.0.0 + in4.sin_port = Utils::hton((uint16_t)portno); + proxyListenPhySocket = _phy.tcpListen((const struct sockaddr*)&in4,(void *)this); + sockstate = SOCKS_OPEN; + //dwr(MSG_DEBUG, "SOCKS5 proxy server address for <%.16llx> is: <%s:%d> (sock=%p)\n", nwid, , portno, (void*)&proxyListenPhySocket); + } + return 0; } void ExtractAddress(int addr_type, unsigned char *buf, struct sockaddr_in * addr) diff --git a/src/SDK_Service.cpp b/src/SDK_Service.cpp index e797e14..1b446f7 100644 --- a/src/SDK_Service.cpp +++ b/src/SDK_Service.cpp @@ -94,10 +94,49 @@ void dwr(int level, const char *fmt, ... ); #endif +int zts_start_proxy_server(const char *homepath, const char * nwid, struct sockaddr_storage * addr) { + LOGV("zts_start_proxy_server\n"); + + dwr(MSG_DEBUG, "zts_start_proxy_server()"); + uint64_t nwid_int = strtoull(nwid, NULL, 16); + ZeroTier::NetconEthernetTap * tap = zt1Service->getTaps()[nwid_int]; + if(tap) { + if(tap->startProxyServer(homepath, nwid_int, addr) < 0) { + dwr(MSG_ERROR, "zts_start_proxy_server(%s): Problem while starting server.", nwid); + return -1; + } + } + dwr(MSG_ERROR, "zts_start_proxy_server(%s): Invalid tap. Possibly incorrect NWID", nwid); + return 0; +} +int zts_stop_proxy_server(const char *nwid) { + dwr(MSG_DEBUG, "zts_stop_proxy_server()"); + uint64_t nwid_int = strtoull(nwid, NULL, 16); + ZeroTier::NetconEthernetTap * tap = zt1Service->getTaps()[nwid_int]; + if(tap) { + if(tap->stopProxyServer() < 0) { + dwr(MSG_ERROR, "zts_stop_proxy_server(%s): Problem while stopping server.", nwid); + return -1; + } + } + dwr(MSG_ERROR, "zts_stop_proxy_server(%s): Invalid tap. Possibly incorrect NWID", nwid); + return 0; +} +int zts_get_proxy_server_address(const char * nwid, struct sockaddr_storage * addr) { + uint64_t nwid_int = strtoull(nwid, NULL, 16); + ZeroTier::NetconEthernetTap * tap = zt1Service->getTaps()[nwid_int]; + if(tap) { + tap->getProxyServerAddress(addr); + return 0; + } + return -1; +} + // Basic ZT service controls +// Will also spin up a SOCKS5 proxy server if USE_SOCKS_PROXY is set void zts_join_network(const char * nwid) { + LOGV("zts_join_network\n"); std::string confFile = zt1Service->givenHomePath() + "/networks.d/" + nwid + ".conf"; - dwr(MSG_ERROR, "writing conf file = %s\n", confFile.c_str()); if(!ZeroTier::OSUtils::mkdir(netDir)) { dwr(MSG_ERROR, "unable to create %s\n", netDir.c_str()); } @@ -106,6 +145,15 @@ void zts_join_network(const char * nwid) { } // Provide the API with the RPC information zt_init_rpc(homeDir.c_str(), nwid); + + // SOCKS5 Proxy server + // Default is 127.0.0.1:RANDOM_PORT + LOGV("-----USE_SOCKS_PROXY ?\n"); + #if defined(USE_SOCKS_PROXY) + LOGV("-----USE_SOCKS_PROXY!\\n"); + + zts_start_proxy_server(homeDir.c_str(), nwid, NULL); // NULL addr for default + #endif } void zts_leave_network(const char * nwid) { zt1Service->leave(nwid); } bool zts_is_running() { return zt1Service->isRunning(); } @@ -145,22 +193,6 @@ bool zts_is_relayed() { return false; } -int zts_start_proxy_server(const char * nwid, struct sockaddr_storage * addr) { - //uint64_t nwid_int = strtoull(nwid, NULL, 16); - //return zt1Service->getTaps()[nwid_int]->proxyListenPort; - return 0; -} -int zts_stop_proxy_server(const char * nwid) { - //uint64_t nwid_int = strtoull(nwid, NULL, 16); - //return zt1Service->getTaps()[nwid_int]->proxyListenPort; - return 0; -} -int zts_get_proxy_server_address(const char * nwid, struct sockaddr_storage * addr) { - //uint64_t nwid_int = strtoull(nwid, NULL, 16); - //zt1Service->getTaps()[nwid_int]->proxyListenPort; - return 0; -} - // Android JNI wrapper // JNI naming convention: Java_PACKAGENAME_CLASSNAME_METHODNAME #if defined(__ANDROID__) @@ -284,6 +316,9 @@ int zts_get_proxy_server_address(const char * nwid, struct sockaddr_storage * ad * Starts a new service instance */ #if defined(__ANDROID__) + /* NOTE: Since on Android devices the sdcard is formatted as fat32, we can't use just any + location to set up the RPC unix domain socket. Rather we must use the application's specific + data directory given by getApplicationContext().getFilesDir() */ JNIEXPORT int JNICALL Java_ZeroTier_SDK_zt_1start_1service(JNIEnv *env, jobject thisObj, jstring path) { if(path) homeDir = env->GetStringUTFChars(path, NULL); @@ -314,14 +349,6 @@ int zts_get_proxy_server_address(const char * nwid, struct sockaddr_storage * ad #endif #endif - #if defined(__ANDROID__) - /* NOTE: Since on Android devices the sdcard is formatted as fat32, we can't use this - location to set up the RPC unix domain socket. Rather we must use the application's - specific data directory given by getApplicationContext().getFilesDir() */ - //rpcDir = homeDir; // Take given homeDir as rpcDir - //homeDir = "/sdcard/zerotier"; // Use fat32-formatted sdcard for writing network conf & supporting files - #endif - #if defined(__APPLE__) && !defined(__IOS__) homeDir = givenHomeDir; localHomeDir = givenHomeDir; // Used for RPC and *can* differ from homeDir on some platforms