diff --git a/ext/lwipopts.h b/ext/lwipopts.h index 7105346..fdcd4ed 100644 --- a/ext/lwipopts.h +++ b/ext/lwipopts.h @@ -44,6 +44,9 @@ */ #include "lwip/debug.h" +//#define LWIP_DEBUG 1 +//#define LWIP_DBG_TYPES_ON LWIP_DBG_TRACE + #define LWIP_CHKSUM_ALGORITHM 2 #undef TCP_MSS @@ -472,4 +475,4 @@ happening sooner than they should. */ #define PPP_SUPPORT 0 -#endif /* __LWIPOPTS_H__ */ \ No newline at end of file +#endif /* __LWIPOPTS_H__ */ diff --git a/integrations/android/example_app/app/src/main/java/ZeroTier/SDK.java b/integrations/android/example_app/app/src/main/java/ZeroTier/SDK.java index 4443b15..197a5a9 100644 --- a/integrations/android/example_app/app/src/main/java/ZeroTier/SDK.java +++ b/integrations/android/example_app/app/src/main/java/ZeroTier/SDK.java @@ -30,8 +30,10 @@ import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.ArrayList; +import java.util.zip.ZipError; import android.os.ParcelFileDescriptor; +import android.util.Log; import android.util.Pair; public class SDK { @@ -49,70 +51,178 @@ public class SDK { // ZeroTier service controls public native void zt_start_service(String homeDir); - public native void zt_join_network(String nwid); - public native void zt_leave_network(String nwid); - public native ArrayList zt_get_addresses(String nwid); - public native boolean zt_running(); + public void start_service(String homeDir) { + zt_start_service(homeDir); + } + + public native void zt_join_network(String nwid); + public void join_network(String nwid) { + zt_join_network(nwid); + } + + public native void zt_leave_network(String nwid); + public void leave_network(String nwid) { + zt_leave_network(nwid); + } + + public native ArrayList zt_get_addresses(String nwid); + public ArrayList get_addresses(String nwid) { + return zt_get_addresses(nwid); + } + + public native int zt_get_proxy_port(String nwid); + public int get_proxy_port(String nwid) { + return zt_get_proxy_port(nwid); + } + + public native boolean zt_running(); + public boolean running() { + return zt_running(); + } + + + // ------------------------------------------------------------------------------ + // ----------------------------------- socket() --------------------------------- + // ------------------------------------------------------------------------------ - // Direct-call API - // --- These calls skip the intercept and interface directly via the RPC mechanism public native int zt_socket(int family, int type, int protocol); + public int socket(int family, int type, int protocol) { + return zt_socket(family, type, protocol); + } + + + // ------------------------------------------------------------------------------ + // ----------------------------------- connect() -------------------------------- + // ------------------------------------------------------------------------------ + public native int zt_connect(int fd, String addr, int port); + + public int connect(int sock, ZTAddress zaddr, String nwid) { + return connect(sock, zaddr.Address(), zaddr.Port(), nwid); + } + + public int connect(int sock, String addr, int port, String nwid) + { + int err = -1; + ArrayList addresses = new ArrayList(); + while (err < 0) { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + } + addresses = zt_get_addresses(nwid); + if (addresses.size() > 0) { + if(!addresses.get(0).startsWith("-1.-1.-1.-1/-1")) { + err = zt_connect(sock, addr, port); + } + } + } + return err; + } + + // ------------------------------------------------------------------------------ + // ------------------------------------ bind() ---------------------------------- + // ------------------------------------------------------------------------------ + public native int zt_bind(int fd, String addr, int port); + + public int bind(int sock, ZTAddress zaddr, String nwid) { + return bind(sock, zaddr.Address(), zaddr.Port(), nwid); + } + public int bind(int sock, String addr, int port, String nwid) { + int err = -1; + ArrayList addresses = new ArrayList(); + while (err < 0) { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + } + addresses = zt_get_addresses(nwid); + if (addresses.size() > 0) { + if(!addresses.get(0).startsWith("-1.-1.-1.-1/-1")) { + err = zt_bind(sock, addr, port); + } + } + } + return err; + } + + + // ------------------------------------------------------------------------------ + // ---------------------------------- accept4() --------------------------------- + // ------------------------------------------------------------------------------ + public native int zt_accept4(int fd, String addr, int port); + public int accept4(int fd, String addr, int port) { + return zt_accept4(fd,addr,port); + } + + + // ------------------------------------------------------------------------------ + // ---------------------------------- accept() ---------------------------------- + // ------------------------------------------------------------------------------ + public native int zt_accept(int fd, ZeroTier.ZTAddress addr); + public int accept(int fd, ZeroTier.ZTAddress addr) { + return zt_accept(fd, addr); + } + + // ------------------------------------------------------------------------------ + // ----------------------------------- listen() --------------------------------- + // ------------------------------------------------------------------------------ + public native int zt_listen(int fd, int backlog); + public int listen(int fd, int backlog) { + return zt_listen(fd,backlog); + } + + // ------------------------------------------------------------------------------ + // ----------------------------------- close() ---------------------------------- + // ------------------------------------------------------------------------------ + + public native int zt_close(int fd); + public int close(int fd) { + return close(fd); + } + + + // ------------------------------------------------------------------------------ + // ------------------------------------ read() ---------------------------------- + // ------------------------------------------------------------------------------ + + public native int zt_read(int fd, byte[] buf, int len); + public int read(int fd, byte[] buf, int len) { + return zt_read(fd, buf, len); + } + + // ------------------------------------------------------------------------------ + // ----------------------------------- write() ---------------------------------- + // ------------------------------------------------------------------------------ + + public native int zt_write(int fd, byte[] buf, int len); + public int write(int fd, byte[] buf, int len) { + return zt_write(fd, buf, len); + } + + // ------------------------------------------------------------------------------ + // ----------------------------------- sendto() --------------------------------- + // ------------------------------------------------------------------------------ + + public native int zt_sendto(int fd, byte[] buf, int len, int flags, ZeroTier.ZTAddress addr); + public int sendto(int fd, byte[] buf, int len, int flags, ZeroTier.ZTAddress addr){ + return zt_sendto(fd,buf,len,flags,addr); + } + + // ------------------------------------------------------------------------------ + // ---------------------------------- recvfrom() -------------------------------- + // ------------------------------------------------------------------------------ + + public native int zt_recvfrom(int fd, byte[] buf, int len, int flags, ZeroTier.ZTAddress addr); + public int recvfrom(int fd, byte[] buf, int len, int flags, ZeroTier.ZTAddress addr){ + return zt_recvfrom(fd,buf,len,flags,addr); + } + //public static native int zt_getsockopt(int fd, int type, int protocol); //public static native int zt_setsockopt(int fd, int type, int protocol); //public static native int zt_getsockname(int fd, int type, int protocol); - public native int zt_close(int fd); - public native int zt_read(int fd, byte[] buf, int len); - public native int zt_write(int fd, byte[] buf, int len); - - // --- Below is experimental - - // Converts a numerical fd to a FileDescriptor - public static native FileDescriptor zt_getFileDescriptor(int fd); - - // Returns a pair of I/O streams for the given fd - public static Pair zt_getFileStreams(int fd) - { - FileDescriptor fileDesc = zt_getFileDescriptor(fd); - FileOutputStream fos = new FileOutputStream(fileDesc); - FileInputStream fis = new FileInputStream(fileDesc); - return new Pair(fis, fos); - } - - // Example Usage: - // Get corresponding new I/O streams - /* - Pair streamPair; - streamPair = SDK.zt_getFileStreams(sock); - FileInputStream fis = streamPair.first; - FileOutputStream fos = streamPair.second; - */ - - /* - // Wrapper for TX - public static void zt_write(FileOutputStream fos, byte[] buf, int len) - { - try { - fos.write(buf, 0, len); - } - catch (java.io.IOException e) { - e.printStackTrace(); - } - } - - // Wrapper for RX - public static void zt_read(FileInputStream fis, byte[] buf, int len) - { - try { - fis.read(buf, 0, len); - } - catch (java.io.IOException e) { - e.printStackTrace(); - } - } - */ } \ No newline at end of file diff --git a/integrations/android/example_app/app/src/main/java/ZeroTier/ZTAddress.java b/integrations/android/example_app/app/src/main/java/ZeroTier/ZTAddress.java index 3c34d0b..65b4c57 100644 --- a/integrations/android/example_app/app/src/main/java/ZeroTier/ZTAddress.java +++ b/integrations/android/example_app/app/src/main/java/ZeroTier/ZTAddress.java @@ -1,16 +1,65 @@ package ZeroTier; +import java.math.BigInteger; +import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.UnknownHostException; public class ZTAddress { - public String addr; + static public byte[] toIPByteArray(long addr){ + return new byte[]{(byte)addr,(byte)(addr>>>8),(byte)(addr>>>16),(byte)(addr>>>24)}; + } + + int pack(byte[] bytes) { + int val = 0; + for (int i = 0; i < bytes.length; i++) { + val <<= 8; + val |= bytes[i] & 0xff; + } + return val; + } + public int port; + public int Port() { + return port; + } + + public long _rawAddr; + public String Address() + { + try { + return InetAddress.getByAddress(toIPByteArray(_rawAddr)).getHostAddress(); + } catch (UnknownHostException e) { + //should never happen + return null; + } + } + + public String toString() { + return Address() + ":" + Port(); + } + + public ZTAddress() + { + + } + + public ZTAddress(String _addr, int _port) + { + port = _port; + _rawAddr = pack(_addr.getBytes()); + } + + public void ZTAddress(InetSocketAddress ins) + { + + } public InetSocketAddress ToInetSocketAddress() throws IllegalArgumentException { InetSocketAddress sock_addr = null; try { - sock_addr = new InetSocketAddress(addr, port); + sock_addr = new InetSocketAddress(Address(), port); } catch (IllegalArgumentException e) { e.printStackTrace(); } diff --git a/integrations/android/example_app/app/src/main/java/com/example/joseph/example_app/MainActivity.java b/integrations/android/example_app/app/src/main/java/com/example/joseph/example_app/MainActivity.java index 4f6cdcb..038ca9a 100644 --- a/integrations/android/example_app/app/src/main/java/com/example/joseph/example_app/MainActivity.java +++ b/integrations/android/example_app/app/src/main/java/com/example/joseph/example_app/MainActivity.java @@ -4,9 +4,18 @@ import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import java.net.InetSocketAddress; import android.util.*; + +import java.nio.charset.Charset; import java.util.ArrayList; +import java.util.Arrays; + +// For SOCKS5 Proxy example +import java.net.Proxy; +import java.net.Socket; +import java.net.SocketAddress; import ZeroTier.SDK; +import ZeroTier.ZTAddress; public class MainActivity extends AppCompatActivity { @@ -15,39 +24,32 @@ public class MainActivity extends AppCompatActivity { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); + String nwid = "8056c2e21c000001"; // Set up service final SDK zt = new SDK(); final String homeDir = getApplicationContext().getFilesDir() + "/zerotier"; new Thread(new Runnable() { public void run() { // Calls to JNI code - zt.zt_start_service(homeDir); + zt.start_service(homeDir); } }).start(); - while(!zt.zt_running()) { } - zt.zt_join_network("XXXXXXXXXXXXXXXX"); - - // Create ZeroTier socket - int sock = zt.zt_socket(SDK.AF_INET, SDK.SOCK_STREAM, 0); + while(!zt.running()) { } // client/server mode toggle - int mode = 1, err = -1; + int mode = 4, err = -1; // Establish outgoing connection if(mode==0) { - while(err < 0) { + zt.join_network(nwid); + int sock = zt.socket(SDK.AF_INET, SDK.SOCK_STREAM, 0); - try { - Thread.sleep(1000); - } - catch(java.lang.InterruptedException e) { } - err = zt.zt_connect(sock, "10.9.9.100", 7004); - Log.d("TEST", "err = " + err + "\n"); - } + err = zt.connect(sock, "10.9.9.100", 7004, nwid); + Log.d("TEST", "err = " + err + "\n"); // TX - zt.zt_write(sock, "Welcome to the machine".getBytes(), 16); + zt.write(sock, "Welcome to the machine".getBytes(), 16); // Test section for(int i=0; i<1000; i++) @@ -58,52 +60,151 @@ public class MainActivity extends AppCompatActivity { catch(java.lang.InterruptedException e) { } String msg = "Welcome to the machine!"; - int written = zt.zt_write(sock, msg.getBytes(), msg.length()); + int written = zt.write(sock, msg.getBytes(), msg.length()); Log.d("TEST", "TX[" + i + "] = " + written); // RX byte[] buffer = new byte[1024]; - zt.zt_read(sock, buffer, buffer.length); + zt.read(sock, buffer, buffer.length); String bufStr = new String(buffer); Log.d("TEST", "RX[" + i + "] = " + bufStr); } - } // Listen to incoming connections if(mode==1) { - ArrayList addresses = new ArrayList(); - while(err < 0) { - try { - Thread.sleep(1000); - } - catch(java.lang.InterruptedException e) { } - addresses = zt.zt_get_addresses("XXXXXXXXXXXXXXXX"); + zt.join_network(nwid); + int sock = zt.socket(SDK.AF_INET, SDK.SOCK_STREAM, 0); - if(addresses.size() > 0) { - for(int i=0; i addresses = new ArrayList(); + addresses = zt.get_addresses(nwid); + for(int i=0; i__udp_remove(conn->UDP_pcb); } if(conn->TCP_pcb && conn->TCP_pcb->state != CLOSED) { - dwr(MSG_DEBUG,"closeConnection(conn=%p,sock=%p): PCB->state = %d\n", + dwr(MSG_DEBUG_EXTRA,"closeConnection(conn=%p,sock=%p): PCB->state = %d\n", (void*)&conn, (void*)&sock, conn->TCP_pcb->state); if(conn->TCP_pcb->state == SYN_SENT /*|| conn->TCP_pcb->state == CLOSE_WAIT*/) { - dwr(MSG_DEBUG,"closeConnection(sock=%p): invalid PCB state for this operation. ignoring.\n", + dwr(MSG_DEBUG_EXTRA,"closeConnection(sock=%p): invalid PCB state for this operation. ignoring.\n", (void*)&sock); return; } - dwr(MSG_DEBUG, "__tcp_close(...)\n"); + dwr(MSG_DEBUG_EXTRA, "__tcp_close(...)\n"); if(lwipstack->__tcp_close(conn->TCP_pcb) == ERR_OK) { // Unregister callbacks for this PCB lwipstack->__tcp_arg(conn->TCP_pcb, NULL); @@ -413,7 +413,7 @@ void NetconEthernetTap::closeConnection(PhySocket *sock) lwipstack->__tcp_poll(conn->TCP_pcb, NULL, 1); } else { - dwr(MSG_ERROR,"closeConnection(sock=%p): error while calling tcp_close()\n", (void*)&sock); + dwr(MSG_DEBUG_EXTRA,"closeConnection(sock=%p): error while calling tcp_close()\n", (void*)&sock); } } for(size_t i=0;i<_Connections.size();++i) { @@ -430,7 +430,7 @@ void NetconEthernetTap::closeConnection(PhySocket *sock) } void NetconEthernetTap::phyOnUnixClose(PhySocket *sock,void **uptr) { - dwr(MSG_DEBUG, "phyOnUnixClose(sock=%p):\n", (void*)&sock); + dwr(MSG_DEBUG_EXTRA, "phyOnUnixClose(sock=%p):\n", (void*)&sock); Mutex::Lock _l(_tcpconns_m); closeConnection(sock); } @@ -454,12 +454,13 @@ void NetconEthernetTap::processReceivedData(PhySocket *sock,void **uptr,bool lwi if(conn->type==SOCK_DGRAM){ conn->unread_udp_packet = false; _phy.setNotifyWritable(conn->sock, false); + dwr(MSG_TRANSFER,"UDP RX <--- :: {TX: ------, RX: ------, sock=%x} :: %d bytes\n", conn->sock, n); } //dwr(MSG_DEBUG, "phyOnUnixWritable(): tid = %d\n", pthread_mach_thread_np(pthread_self())); if(conn->type==SOCK_STREAM) { // Only acknolwedge receipt of TCP packets lwipstack->__tcp_recved(conn->TCP_pcb, n); float max = conn->type == SOCK_STREAM ? (float)DEFAULT_TCP_TX_BUF_SZ : (float)DEFAULT_UDP_TX_BUF_SZ; - dwr(MSG_TRANSFER," RX <--- :: {TX: %.3f%%, RX: %.3f%%, sock=%x} :: %d bytes\n", + dwr(MSG_TRANSFER,"TCP RX <--- :: {TX: %.3f%%, RX: %.3f%%, sock=%x} :: %d bytes\n", (float)conn->txsz / max, (float)conn->rxsz / max, conn->sock, n); } } else { @@ -486,7 +487,7 @@ void NetconEthernetTap::phyOnUnixWritable(PhySocket *sock,void **uptr,bool lwip_ void NetconEthernetTap::phyOnUnixData(PhySocket *sock, void **uptr, void *data, ssize_t len) { - dwr(MSG_DEBUG, "phyOnUnixData(%p), len = %d\n", (void*)&sock, len); + dwr(MSG_DEBUG_EXTRA, "phyOnUnixData(%p), len = %d\n", (void*)&sock, len); uint64_t CANARY_num; pid_t pid, tid; ssize_t wlen = len; @@ -642,13 +643,13 @@ void NetconEthernetTap::phyOnUnixData(PhySocket *sock, void **uptr, void *data, } int NetconEthernetTap::sendReturnValue(PhySocket *sock, int retval, int _errno = 0){ - dwr(MSG_DEBUG," sendReturnValue(sock=%p)\n", (void*)&sock); + dwr(MSG_DEBUG_EXTRA," sendReturnValue(sock=%p)\n", (void*)&sock); return sendReturnValue(_phy.getDescriptor(sock), retval, _errno); } int NetconEthernetTap::sendReturnValue(int fd, int retval, int _errno = 0) { //#if !defined(USE_SOCKS_PROXY) - dwr(MSG_DEBUG," sendReturnValue(): fd = %d, retval = %d, errno = %d\n", fd, retval, _errno); + dwr(MSG_DEBUG_EXTRA," sendReturnValue(): fd = %d, retval = %d, errno = %d\n", fd, retval, _errno); int sz = sizeof(char) + sizeof(retval) + sizeof(errno); char retmsg[sz]; memset(&retmsg, 0, sizeof(retmsg)); @@ -717,7 +718,8 @@ err_t NetconEthernetTap::nc_accept(void *arg, struct tcp_pcb *newPCB, err_t err) tap->lwipstack->__tcp_sent(newPCB, nc_sent); tap->lwipstack->__tcp_poll(newPCB, nc_poll, 1); if(conn->TCP_pcb->state == LISTEN) { - dwr(MSG_DEBUG," nc_accept(): can't call tcp_accept() on LISTEN socket (pcb = %x)\n", conn->TCP_pcb); + // FIX: This error likely doesn't have user significance and is a candidate for removal + // dwr(MSG_DEBUG," nc_accept(): can't call tcp_accept() on LISTEN socket (pcb = %x)\n", conn->TCP_pcb); return ERR_OK; } tcp_accepted(conn->TCP_pcb); // Let lwIP know that it can queue additional incoming connections @@ -739,6 +741,12 @@ void NetconEthernetTap::nc_udp_recved(void * arg, struct udp_pcb * upcb, struct if(p) { l->conn->rxsz = 0; memset(l->conn->rxbuf, 0, DEFAULT_UDP_RX_BUF_SZ); + // Add address info beginning of data buffer + u32_t raw_addr = ip4_addr_get_u32(addr); + memcpy(l->conn->rxbuf + (l->conn->rxsz), &raw_addr, sizeof(u32_t)); // addr + l->conn->rxsz += sizeof(u32_t); + memcpy(l->conn->rxbuf + (l->conn->rxsz), &port, sizeof(u16_t)); // port + l->conn->rxsz += sizeof(u16_t); } while(p != NULL) { if(p->len <= 0) @@ -750,7 +758,8 @@ void NetconEthernetTap::nc_udp_recved(void * arg, struct udp_pcb * upcb, struct tot += len; } if(tot) { - dwr(MSG_DEBUG, " nc_udp_recved(): tot = %d, rxsz = %d\n", tot, l->conn->rxsz); + dwr(MSG_DEBUG, " nc_udp_recved(): data_len = %d, rxsz = %d, addr_info_len = %d\n", + tot, l->conn->rxsz, sizeof(u32_t) + sizeof(u16_t)); l->conn->unread_udp_packet = true; l->tap->phyOnUnixWritable(l->conn->sock, NULL, true); l->tap->_phy.setNotifyWritable(l->conn->sock, true); @@ -1005,8 +1014,11 @@ void NetconEthernetTap::handleListen(PhySocket *sock, PhySocket *rpcSock, void * Mutex::Lock _l(_tcpconns_m); Connection *conn = getConnection(sock); - if(conn->type==SOCK_DGRAM) + if(conn->type==SOCK_DGRAM) { + // FIX: Added sendReturnValue() call to fix listen() return bug on Android + sendReturnValue(rpcSock, ERR_OK, ERR_OK); return; + } if(!conn) { dwr(MSG_ERROR," handleListen(): unable to locate Connection.\n"); sendReturnValue(rpcSock, -1, EBADF); @@ -1200,9 +1212,16 @@ void NetconEthernetTap::handleConnect(PhySocket *sock, PhySocket *rpcSock, Conne Mutex::Lock _l(_tcpconns_m); struct sockaddr_in *rawAddr = (struct sockaddr_in *) &connect_rpc->__addr; int port = lwipstack->__lwip_ntohs(rawAddr->sin_port); - ip_addr_t connAddr = convert_ip(rawAddr); - int err = 0; - + ip_addr_t connAddr = convert_ip(rawAddr); + int err = 0, ip = rawAddr->sin_addr.s_addr; + + unsigned char d[4]; + d[0] = ip & 0xFF; + d[1] = (ip >> 8) & 0xFF; + d[2] = (ip >> 16) & 0xFF; + d[3] = (ip >> 24) & 0xFF; + dwr(MSG_DEBUG," handleConnect(): %d.%d.%d.%d: %d\n", d[0],d[1],d[2],d[3], port); + if(conn->type == SOCK_DGRAM) { // Generates no network traffic if((err = lwipstack->__udp_connect(conn->UDP_pcb,&connAddr,port)) < 0) @@ -1217,15 +1236,7 @@ void NetconEthernetTap::handleConnect(PhySocket *sock, PhySocket *rpcSock, Conne lwipstack->__tcp_err(conn->TCP_pcb, nc_err); lwipstack->__tcp_poll(conn->TCP_pcb, nc_poll, APPLICATION_POLL_FREQ); lwipstack->__tcp_arg(conn->TCP_pcb, new Larg(this, conn)); - - int ip = rawAddr->sin_addr.s_addr; - unsigned char d[4]; - d[0] = ip & 0xFF; - d[1] = (ip >> 8) & 0xFF; - d[2] = (ip >> 16) & 0xFF; - d[3] = (ip >> 24) & 0xFF; - - dwr(MSG_DEBUG," handleConnect(): %d.%d.%d.%d: %d\n", d[0],d[1],d[2],d[3], port); + dwr(MSG_DEBUG," handleConnect(): pcb->state = %x\n", conn->TCP_pcb->state); if(conn->TCP_pcb->state != CLOSED) { dwr(MSG_DEBUG," handleConnect(): PCB != CLOSED, cannot connect using this PCB\n"); @@ -1316,13 +1327,13 @@ void NetconEthernetTap::handleWrite(Connection *conn) } else if(err != ERR_OK) { dwr(MSG_DEBUG, " handleWrite(): Error sending packet - %d\n", err); } else { + // Success int buf_remaining = (conn->txsz)-udp_trans_len; 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; - dwr(MSG_TRANSFER," TX ---> :: {TX: %.3f%%, RX: %.3f%%, sock=%x} :: %d bytes\n", - (float)conn->txsz / (float)max, (float)conn->rxsz / max, conn->sock, udp_trans_len); + dwr(MSG_TRANSFER,"UDP TX ---> :: {TX: ------, RX: ------, sock=%x} :: %d bytes\n", conn->sock, udp_trans_len); } lwipstack->__pbuf_free(pb); return; @@ -1370,7 +1381,7 @@ void NetconEthernetTap::handleWrite(Connection *conn) memmove(&conn->txbuf, (conn->txbuf+r), sz); conn->txsz -= r; int max = conn->type == SOCK_STREAM ? DEFAULT_TCP_TX_BUF_SZ : DEFAULT_UDP_TX_BUF_SZ; - dwr(MSG_TRANSFER," TX ---> :: {TX: %.3f%%, RX: %.3f%%, sock=%p} :: %d bytes\n", + dwr(MSG_TRANSFER,"TCP TX ---> :: {TX: %.3f%%, RX: %.3f%%, sock=%p} :: %d bytes\n", (float)conn->txsz / (float)max, (float)conn->rxsz / max, (void*)&conn->sock, r); return; } diff --git a/src/SDK_EthernetTap.hpp b/src/SDK_EthernetTap.hpp index d2cccf7..01f3e0b 100644 --- a/src/SDK_EthernetTap.hpp +++ b/src/SDK_EthernetTap.hpp @@ -154,6 +154,8 @@ namespace ZeroTier { void (*_handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); void *_arg; + int proxyListenPort; + private: // LWIP callbacks // NOTE: these are called from within LWIP, meaning that lwipstack->_lock is ALREADY @@ -454,20 +456,14 @@ namespace ZeroTier { */ void closeConnection(PhySocket *sock); - // --- Proxy stubs - int proxyListenPort; - - //std::map proxySockStates; - + // --- 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 stubs + // --- end Proxy ip_addr_t convert_ip(struct sockaddr_in * addr) { diff --git a/src/SDK_Proxy.cpp b/src/SDK_Proxy.cpp index f7268eb..6c03928 100644 --- a/src/SDK_Proxy.cpp +++ b/src/SDK_Proxy.cpp @@ -105,7 +105,7 @@ namespace ZeroTier void ExtractAddress(int addr_type, unsigned char *buf, struct sockaddr_in * addr) { // TODO: Generalize extraction logic - if(addr_type == 3) + if(addr_type == 144) { // Extract address from buffer int domain_len = buf[IDX_DST_ADDR]; // (L):D @@ -216,8 +216,10 @@ namespace ZeroTier // CONNECT request if(cmd == 1) { + dwr(MSG_DEBUG, "CONNECT request\n"); // Ipv4 - if(addr_type == 1) + /* + if(addr_type == 144) { //printf("IPv4\n"); int raw_addr; @@ -235,20 +237,22 @@ namespace ZeroTier struct sockaddr_in addr; addr.sin_addr.s_addr = IPADDR_ANY; addr.sin_family = AF_INET; - addr.sin_port = Utils::hton(proxyListenPort); + addr.sin_port = Utils::hton(8080); int fd = socket(AF_INET, SOCK_STREAM, 0); + dwr(MSG_DEBUG, "fd = %d\n", fd); if(fd < 0) perror("socket"); int err = connect(fd, (struct sockaddr*)&addr, sizeof(addr)); + dwr(MSG_DEBUG, "connect_err = %d\n", err); if(err < 0) perror("connect"); } - + */ // Fully-qualified domain name - if(addr_type == 3) + if(addr_type == 144) { int domain_len = buf[IDX_DST_ADDR]; // (L):D struct sockaddr_in addr; diff --git a/src/SDK_ServiceSetup.cpp b/src/SDK_ServiceSetup.cpp index cb3de6d..ac6a145 100644 --- a/src/SDK_ServiceSetup.cpp +++ b/src/SDK_ServiceSetup.cpp @@ -112,8 +112,20 @@ void zts_leave_network(const char * nwid) { zt1Service->leave(nwid); } bool zts_is_running() { return zt1Service->isRunning(); } void zts_terminate() { zt1Service->terminate(); } -std::vector zt_get_addresses(std::string nwid) +// FIXME: Re-implemented to make it play nicer with the C-linkage required for Xcode integrations +// Now only returns first assigned address per network. Shouldn't normally be a problem +void zts_get_addresses(const char * nwid, char *addrstr) { + uint64_t nwid_int = strtoull(nwid, NULL, 16); + ZeroTier::NetconEthernetTap * tap = zt1Service->getTaps()[nwid_int]; + if(tap && tap->_ips.size()){ + std::string addr = tap->_ips[0].toString(); + memcpy(addrstr, addr.c_str(), addr.length()); + } + else { + memcpy(addrstr, "-1.-1.-1.-1/-1", 14); + } + /* uint64_t nwid_int = strtoull(nwid.c_str(), NULL, 16); ZeroTier::NetconEthernetTap * tap = zt1Service->getTaps()[nwid_int]; std::vector ip_strings; @@ -124,6 +136,18 @@ std::vector zt_get_addresses(std::string nwid) return ip_strings; } return ip_strings; + */ +} + +bool zts_is_relayed() { + // TODO + // zt1Service->getNode()->peers() + return false; +} + +int zts_get_proxy_port(const char * nwid) { + uint64_t nwid_int = strtoull(nwid, NULL, 16); + return zt1Service->getTaps()[nwid_int]->proxyListenPort; } @@ -153,12 +177,23 @@ std::vector zt_get_addresses(std::string nwid) if(zt1Service) zts_terminate(); } + // FIXME: Re-implemented to make it play nicer with the C-linkage required for Xcode integrations + // Now only returns first assigned address per network. Shouldn't normally be a problem JNIEXPORT jobject JNICALL Java_ZeroTier_SDK_zt_1get_1addresses(JNIEnv *env, jobject thisObj, jstring nwid) { const char *nwid_str = env->GetStringUTFChars(nwid, NULL); - std::vector address_strings = zt_get_addresses(nwid_str); + char address_string[32]; + memset(address_string, 0, 32); + zts_get_addresses(nwid_str, address_string); + jclass clazz = (*env).FindClass("java/util/ArrayList"); + jobject addresses = (*env).NewObject(clazz, (*env).GetMethodID(clazz, "", "()V")); + jstring _str = (*env).NewStringUTF(address_string); + env->CallBooleanMethod(addresses, env->GetMethodID(clazz, "add", "(Ljava/lang/Object;)Z"), _str); + return addresses; + /* + const char *nwid_str = env->GetStringUTFChars(nwid, NULL); + std::vector address_strings = zts_get_addresses(nwid_str); jclass clazz = (*env).FindClass("java/util/ArrayList"); jobject addresses = (*env).NewObject(clazz, (*env).GetMethodID(clazz, "", "()V")); - if(address_strings.size()) { for (int n=0;n zt_get_addresses(std::string nwid) env->CallBooleanMethod(addresses, env->GetMethodID(clazz, "add", "(Ljava/lang/Object;)Z"), _str); } return addresses; + */ } + JNIEXPORT jboolean JNICALL Java_ZeroTier_SDK_zt_1is_1relayed() { + return zts_is_relayed(); + } + JNIEXPORT int JNICALL Java_ZeroTier_SDK_zt_1get_1proxy_1port(JNIEnv *env, jobject thisObj, jstring nwid) { + const char *nwid_str = env->GetStringUTFChars(nwid, NULL); + return zts_get_proxy_port(nwid_str); + } #endif diff --git a/src/SDK_ServiceSetup.hpp b/src/SDK_ServiceSetup.hpp index ee3a309..c0bd1f9 100644 --- a/src/SDK_ServiceSetup.hpp +++ b/src/SDK_ServiceSetup.hpp @@ -33,7 +33,7 @@ extern "C" { #include #endif -#include +//#include #ifndef ONE_SERVICE_SETUP_HPP #define ONE_SERVICE_SETUP_HPP @@ -50,6 +50,8 @@ extern "C" { JNIEXPORT void JNICALL Java_ZeroTier_SDK_zt_1leave_1network(JNIEnv *env, jobject thisObj, jstring nwid); JNIEXPORT jboolean JNICALL Java_ZeroTier_SDK_zt_1running(JNIEnv *env, jobject thisObj); JNIEXPORT jobject JNICALL Java_ZeroTier_SDK_zt_1get_1addresses(JNIEnv *env, jobject thisObj, jstring nwid); + JNIEXPORT jboolean JNICALL Java_ZeroTier_SDK_zt_1is_1relayed(); + JNIEXPORT int JNICALL Java_ZeroTier_SDK_zt_1get_1proxy_1port(JNIEnv *env, jobject thisObj, jstring nwid); #else void init_service(int key, const char * path); void init_service_and_rpc(int key, const char * path, const char * nwid); @@ -67,7 +69,10 @@ void zts_join_network(const char * nwid); void zts_leave_network(const char * nwid); bool zts_is_running(); void zts_terminate(); -std::vector zt_get_addresses(std::string nwid); +void zts_get_addresses(const char * nwid, char * addrstr); +//std::vector zts_get_addresses(std::string nwid); +bool zts_is_relayed(); +int zts_get_proxy_port(const char * nwid); #endif diff --git a/src/SDK_Signatures.h b/src/SDK_Signatures.h index da97006..7f6d951 100644 --- a/src/SDK_Signatures.h +++ b/src/SDK_Signatures.h @@ -36,7 +36,7 @@ #define SENDMSG_SIG int socket, const struct msghdr *message, int flags #define SENDTO_SIG int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addr_len #define RECV_SIG int socket, void *buffer, size_t length, int flags -#define RECVFROM_SIG int socket, void * buffer, size_t length, int flags, struct sockaddr * __restrict address, socklen_t * __restrict address_len +#define RECVFROM_SIG int socket, void * buffer, size_t length, int flags, struct sockaddr_in * __restrict address, socklen_t * __restrict address_len #define RECVMSG_SIG int socket, struct msghdr *message,int flags #define SEND_SIG int socket, const void *buffer, size_t length, int flags diff --git a/src/SDK_Sockets.c b/src/SDK_Sockets.c index 93d2d40..abd06fc 100644 --- a/src/SDK_Sockets.c +++ b/src/SDK_Sockets.c @@ -127,14 +127,41 @@ int (*realclose)(CLOSE_SIG); // int sockfd, const void *buf, size_t len, int flags, // const struct sockaddr *addr, socklen_t addr_len -#if !defined(__ANDROID__) +#if defined(__ANDROID__) + // TODO: Check result of each JNI call + // UDP TX + JNIEXPORT jint JNICALL Java_ZeroTier_SDK_zt_1sendto( + JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len, jint flags, jobject ztaddr) + { + struct sockaddr_in addr; + jclass cls = (*env)->GetObjectClass(env, ztaddr); + jfieldID f = (*env)->GetFieldID(env, cls, "port", "I"); + addr.sin_port = htons((*env)->GetIntField(env, ztaddr, f)); + f = (*env)->GetFieldID(env, cls, "_rawAddr", "J"); + addr.sin_addr.s_addr = (*env)->GetLongField(env, ztaddr, f); + addr.sin_family = AF_INET; + LOGV("zt_sendto(): fd = %d\naddr = %s\nport=%d", fd, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + + // TODO: Optimize this + jbyte *body = (*env)->GetByteArrayElements(env, buf, 0); + char * bufp = (char *)malloc(sizeof(char)*len); + memcpy(bufp, body, len); + (*env)->ReleaseByteArrayElements(env, buf, body, 0); + + // "connect" and send buffer contents + int sent_bytes = zts_sendto(fd, body, len, flags, (struct sockaddr *)&addr, sizeof(addr)); + return sent_bytes; + } +#endif + +//#if !defined(__ANDROID__) #ifdef DYNAMIC_LIB ssize_t zt_sendto(SENDTO_SIG) // Exposed as API #else ssize_t zts_sendto(SENDTO_SIG) // Used as internal implementation #endif { - dwr(MSG_DEBUG, "zt_sendto()\n"); + LOGV("zt_sendto()\n"); if(len > ZT_UDP_DEFAULT_PAYLOAD_MTU) { errno = EMSGSIZE; // Msg is too large return -1; @@ -162,14 +189,14 @@ int (*realclose)(CLOSE_SIG); // TODO: More efficient solution // This connect call is used to get the address info to the stack for sending the packet int err; - if((err = connect(sockfd, addr, addr_len)) < 0) { - dwr(MSG_DEBUG, "sendto(): unknown problem passing address info to stack\n"); + if((err = zts_connect(sockfd, addr, addr_len)) < 0) { + LOGV("sendto(): unknown problem passing address info to stack\n"); errno = EISCONN; // double-check this is correct return -1; } - return send(sockfd, buf, len, flags); + return write(sockfd, buf, len); } -#endif +//#endif // ------------------------------------------------------------------------------ // ----------------------------------- sendmsg() -------------------------------- @@ -216,7 +243,28 @@ int (*realclose)(CLOSE_SIG); // int socket, void *restrict buffer, size_t length, int flags, struct sockaddr // *restrict address, socklen_t *restrict address_len -#if !defined(__ANDROID__) +#if defined(__ANDROID__) + // UDP RX + JNIEXPORT jint JNICALL Java_ZeroTier_SDK_zt_1recvfrom( + JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len, jint flags, jobject ztaddr) + { + struct sockaddr_in addr; + dwr(MSG_DEBUG, "zt_recvfrom(): fd = %d\n", fd); + jbyte *body = (*env)->GetByteArrayElements(env, buf, 0); + int recvd_bytes = zts_recvfrom(fd, body, len, flags, &addr, sizeof(addr)); + (*env)->ReleaseByteArrayElements(env, buf, body, 0); + // Update fields of Java ZTAddress object + jfieldID fid; + jclass cls = (*env)->GetObjectClass(env, ztaddr); + fid = (*env)->GetFieldID(env, cls, "port", "I"); + (*env)->SetIntField(env, ztaddr, fid, addr.sin_port); + fid = (*env)->GetFieldID(env, cls,"_rawAddr", "J"); + (*env)->SetLongField(env, ztaddr, fid,addr.sin_addr.s_addr); + return recvd_bytes; + } +#endif + +//#if !defined(__ANDROID__) #ifdef DYNAMIC_LIB ssize_t zt_recvfrom(RECVFROM_SIG) #else @@ -233,14 +281,24 @@ int (*realclose)(CLOSE_SIG); realgetsockopt(socket, SOL_SOCKET, SO_TYPE, (void *) &sock_type, &type_len); */ //if(sock_type == SOCK_DGRAM && address != NULL && address_len != NULL) { - zts_getsockname(socket, address, address_len); + //zts_getsockname(socket, address, address_len); //} + // TODO: Explore more efficient means of adjusting buffer + unsigned short port; + unsigned int addr; err = read(socket, buffer, length); + int addr_info_len = sizeof(addr) + sizeof(port); + memcpy(&addr, buffer, sizeof(addr)); + memcpy(&port, buffer + sizeof(addr), sizeof(port)); + memmove(buffer, (buffer + addr_info_len), err - addr_info_len); + address->sin_addr.s_addr = addr; + address->sin_port = port; + // zts_getsockname(socket, address, address_len); if(err < 0) perror("read:\n"); - return err; + return err < 0 ? err : err - addr_info_len; // Adjust reported buffer size to exclude address info } -#endif +//#endif // ------------------------------------------------------------------------------ // ----------------------------------- recvmsg() -------------------------------- @@ -311,7 +369,7 @@ int (*realclose)(CLOSE_SIG); // ------------------------------------------------------------------------------ #if defined(__ANDROID__) - // TX + // TCP TX JNIEXPORT jint JNICALL Java_ZeroTier_SDK_zt_1write(JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len) { jbyte *body = (*env)->GetByteArrayElements(env, buf, 0); @@ -319,14 +377,14 @@ int (*realclose)(CLOSE_SIG); (*env)->ReleaseByteArrayElements(env, buf, body, 0); return written_bytes; } - // RX + // TCP RX JNIEXPORT jint JNICALL Java_ZeroTier_SDK_zt_1read(JNIEnv *env, jobject thisObj, jint fd, jarray buf, jint len) { jbyte *body = (*env)->GetByteArrayElements(env, buf, 0); int read_bytes = read(fd, body, len); (*env)->ReleaseByteArrayElements(env, buf, body, 0); return read_bytes; - } + } #endif // ------------------------------------------------------------------------------ @@ -657,20 +715,36 @@ int (*realclose)(CLOSE_SIG); struct getsockname_st rpc_st; rpc_st.sockfd = sockfd; memcpy(&rpc_st.addrlen, &addrlen, sizeof(socklen_t)); + LOGV("A\n"); int rpcfd = rpc_send_command(api_netpath, RPC_GETSOCKNAME, sockfd, &rpc_st, sizeof(struct getsockname_st)); + LOGV("b\n"); + /* read address info from service */ char addrbuf[sizeof(struct sockaddr_storage)]; + LOGV("c\n"); + memset(&addrbuf, 0, sizeof(struct sockaddr_storage)); + LOGV("d\n"); + if(rpcfd > -1) if(read(rpcfd, &addrbuf, sizeof(struct sockaddr_storage)) > 0) close(rpcfd); + LOGV("e\n"); + struct sockaddr_storage sock_storage; memcpy(&sock_storage, addrbuf, sizeof(struct sockaddr_storage)); + LOGV("Afn"); + *addrlen = sizeof(struct sockaddr_in); + memcpy(addr, &sock_storage, (*addrlen > sizeof(sock_storage)) ? sizeof(sock_storage) : *addrlen); + LOGV("g\n"); + addr->sa_family = AF_INET; + LOGV("h-\n"); + return 0; }