Browse Source

Updated RPC handling

Joseph Henry 9 years ago
parent
commit
e5fad005a9

BIN
docker-test/httpd_demo/lib/libintercept.so.1.0


BIN
docker-test/throughput/libintercept.so.1.0


BIN
docker-test/throughput/liblwip.so


BIN
docker-test/throughput/zerotier-cli


BIN
docker-test/throughput/zerotier-one


+ 0 - 0
docker-test/throughput/Dockerfile → docker-test/throughput_httpd_2.4.16/Dockerfile


+ 0 - 0
docker-test/throughput/build.sh → docker-test/throughput_httpd_2.4.16/build.sh


+ 0 - 0
docker-test/throughput/entrypoint.sh → docker-test/throughput_httpd_2.4.16/entrypoint.sh


+ 0 - 0
docker-test/throughput/generate_file.sh → docker-test/throughput_httpd_2.4.16/generate_file.sh


+ 0 - 0
docker-test/throughput/intercept → docker-test/throughput_httpd_2.4.16/intercept


+ 40 - 0
docker-test/throughput_httpd_2.4.17/Dockerfile

@@ -0,0 +1,40 @@
+# ZT Netcon Throughput test
+FROM fedora:23
+MAINTAINER https://www.zerotier.com/
+
+# Install apps
+RUN yum -y update
+RUN yum -y install httpd-2.4.17-3.fc23
+RUN yum -y install nano
+RUN yum -y install strace
+RUN yum clean all
+
+EXPOSE 9993/udp 9992/udp 9991/udp 9990/udp
+
+# Install sys-call intercept library
+ADD intercept /
+ADD libintercept.so.1.0 /
+RUN cp libintercept.so.1.0 lib/libintercept.so.1.0
+RUN cp libintercept.so.1.0 /lib/libintercept.so.1.0
+RUN ln -sf /lib/libintercept.so.1.0 /lib/libintercept
+RUN /usr/bin/install -c intercept /usr/bin
+
+# Add ZT files
+RUN mkdir -p /var/lib/zerotier-one/networks.d
+RUN touch /var/lib/zerotier-one/networks.d/e5cd7a9e1c5311ab.conf
+ADD zerotier-one /
+ADD zerotier-cli /
+
+# Install test-setup scripts
+ADD generate_file.sh /generate_file.sh
+RUN chmod -v +x /generate_file.sh
+ADD entrypoint.sh /entrypoint.sh
+RUN chmod -v +x /entrypoint.sh
+
+# Install LWIP library used by service
+ADD liblwip.so /
+RUN mkdir -p ext/bin/lwip
+RUN cp liblwip.so ext/bin/lwip/liblwip.so
+
+# Start ZeroTier-One
+CMD ["./entrypoint.sh"]

+ 17 - 0
docker-test/throughput_httpd_2.4.17/build.sh

@@ -0,0 +1,17 @@
+cd ../../
+make clean
+make
+cd netcon
+make -f make-intercept.mk lib
+rm *.o
+rm liblwip.so
+make -f make-liblwip.mk
+
+cd ../docker-test/throughput_httpd_2.4.17
+
+cp ../../zerotier-one zerotier-one
+cp ../../zerotier-cli zerotier-cli
+
+cp ../../netcon/liblwip.so liblwip.so
+cp ../../netcon/libintercept.so.1.0 libintercept.so.1.0
+

+ 14 - 0
docker-test/throughput_httpd_2.4.17/entrypoint.sh

@@ -0,0 +1,14 @@
+#!/bin/bash
+
+export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/
+
+echo '***'
+echo '*** ZeroTier Network Containers Test Image'
+echo '*** https://www.zerotier.com/'
+echo '***'
+
+./zerotier-one &
+./zerotier-cli join e5cd7a9e1c5311ab
+./zerotier-cli listnetworks
+
+

+ 1 - 0
docker-test/throughput_httpd_2.4.17/generate_file.sh

@@ -0,0 +1 @@
+dd if=/dev/urandom of=/var/www/html/big  bs=100M  count=1

+ 54 - 0
docker-test/throughput_httpd_2.4.17/intercept

@@ -0,0 +1,54 @@
+#!/bin/sh
+# usage:
+# /usr/bin/intercept program <args>
+
+if [ $# = 0 ] ; then
+   echo "$0: insufficient arguments"
+   exit
+fi
+
+case "$1" in
+	on)
+		if [ -z "$LD_PRELOAD" ]
+			then
+				export LD_PRELOAD="/lib/libintercept.so.1.0"
+			else
+				echo $LD_PRELOAD | grep -q "/lib/libintercept\.so.1.0" || \
+				export LD_PRELOAD="/lib/libintercept.so $LD_PRELOAD"
+		fi
+	;;
+	off)
+		export LD_PRELOAD=`echo -n $LD_PRELOAD | sed 's/\/lib\/libintercept.so.1.0 \?//'`
+		if [ -z "$LD_PRELOAD" ]
+			then
+				unset LD_PRELOAD
+		fi
+	;;
+	show|sh)
+		echo "LD_PRELOAD=\"$LD_PRELOAD\""
+	;;
+	-h|-?)
+      echo ""
+   ;;
+	*)
+		if [ -z "$LD_PRELOAD" ]
+		then
+			export LD_PRELOAD="/lib/libintercept.so.1.0"
+		else
+			echo $LD_PRELOAD | grep -q "/lib/libintercept\.so.1.0" || \
+			export LD_PRELOAD="/lib/libintercept.so.1.0 $LD_PRELOAD"
+		fi
+
+		if [ $# = 0 ]
+		then
+			${SHELL:-/bin/sh}
+		fi
+
+		if [ $# -gt 0 ]
+		then
+			exec "$@"
+		fi
+	;;
+esac
+
+#EOF

+ 4 - 0
make-linux.mk

@@ -112,6 +112,10 @@ installer: one FORCE
 
 clean:
 	rm -rf *.o
+	find docker-test/ -name "*.1.0" -type f -delete
+	find docker-test/ -name "*.so" -type f -delete
+	find docker-test/ -name "zerotier-one" -type f -delete
+	find docker-test/ -name "zerotier-cli" -type f -delete
 	rm -rf netcon/*.o netcon/*.so netcon/*.1.0
 	rm -rf node/*.o controller/*.o osdep/*.o service/*.o ext/http-parser/*.o ext/lz4/*.o ext/json-parser/*.o zerotier-one zerotier-idtool zerotier-cli zerotier-selftest build-* ZeroTierOneInstaller-* *.deb *.rpm
 

+ 127 - 19
netcon/Intercept.c

@@ -79,14 +79,16 @@ static int (*realsetsockopt)(SETSOCKOPT_SIG);
 static int (*realgetsockopt)(GETSOCKOPT_SIG);
 static int (*realaccept4)(ACCEPT4_SIG);
 static long (*realsyscall)(SYSCALL_SIG);
+static int (*realclose)(CLOSE_SIG);
 //static int (*realclone)(CLONE_SIG);
 //static int (*realpoll)(POLL_SIG);
+static int (*realdup2)(DUP2_SIG);
+static int (*realdup3)(DUP3_SIG);
 
 /* Exported Function Prototypes */
 void my_init(void);
 int connect(CONNECT_SIG);
 int select(SELECT_SIG);
-int close(CLOSE_SIG);
 int bind(BIND_SIG);
 int accept(ACCEPT_SIG);
 int listen(LISTEN_SIG);
@@ -95,8 +97,12 @@ int setsockopt(SETSOCKOPT_SIG);
 int getsockopt(GETSOCKOPT_SIG);
 int accept4(ACCEPT4_SIG);
 long syscall(SYSCALL_SIG);
+int close(CLOSE_SIG);
 //int clone(CLONE_SIG);
 //int poll(POLL_SIG);
+int dup2(DUP2_SIG);
+int dup3(DUP3_SIG);
+
 
 #ifdef USE_SOCKS_DNS
   int res_init(void);
@@ -110,6 +116,7 @@ void set_up_intercept();
 int checkpid();
 
 #define SERVICE_CONNECT_ATTEMPTS  30
+#define RPC_FD                    1023
 
 ssize_t sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd);
 
@@ -126,10 +133,12 @@ void handle_error(char *name, char *info, int err)
   }
 #endif
 #ifdef VERBOSE
-  //dwr("%s()=%d\n", name, err);
+  dwr("%s()=%d\n", name, err);
 #endif
 }
 
+static unsigned long rpc_count = 0;
+
 /*------------------------------------------------------------------------------
 ------------------- Intercept<--->Service Comm mechanisms-----------------------
 ------------------------------------------------------------------------------*/
@@ -158,7 +167,45 @@ int checkpid() {
  */
 int send_command(int rpc_fd, char *cmd)
 {
-  int n_write = write(rpc_fd, cmd, BUF_SZ);
+#ifdef DEBUG
+/*
+  dwr(" - IDX_PID = %d\n", IDX_PID);  
+  dwr(" - IDX_TID = %d\n", IDX_TID);      
+  dwr(" - IDX_COUNT = %d\n", IDX_COUNT);   
+  dwr(" - IDX_TIME = %d\n", IDX_TIME);    
+  dwr(" - IDX_PAYLOAD = %d\n", IDX_PAYLOAD);    
+*/
+/*
+  #define IDX_PID       0
+  #define IDX_TID       sizeof(pid_t)
+  #define IDX_COUNT     IDX_TID + sizeof(pid_t)
+  #define IDX_TIME      IDX_COUNT + sizeof(int)
+  #define IDX_CMD       IDX_TIME + 20 // 20 being the length of the timestamp string
+  #define IDX_PAYLOAD   IDX_TIME + sizeof(char) 
+*/
+
+  // [pid_t] [pid_t] [rpc_count] [int] [...]
+  char metabuf[BUF_SZ]; // portion of buffer which contains RPC meta-data for debugging
+  memset(metabuf, '\0', BUF_SZ);
+  pid_t pid = syscall(SYS_getpid);
+  pid_t tid = syscall(SYS_gettid);
+  int payload_idx = sizeof(pid_t)*2 + sizeof(rpc_count);
+  rpc_count++;
+  char timestring[20];
+  time_t timestamp;
+  timestamp = time(NULL);
+  strftime(timestring, sizeof(timestring), "%H:%M:%S", localtime(&timestamp));
+
+  memcpy(&metabuf[IDX_PID],     &pid,         sizeof(pid_t)      ); // pid
+  memcpy(&metabuf[IDX_TID],     &tid,         sizeof(pid_t)      ); // tid
+  memcpy(&metabuf[IDX_COUNT],   &rpc_count,   sizeof(rpc_count)  ); // rpc_count
+  memcpy(&metabuf[IDX_TIME],    &timestring,   20                ); // timestamp
+#endif
+  // copy payload into final command buffer
+  int copied = BUF_SZ-IDX_PAYLOAD;
+  memcpy(&metabuf[IDX_PAYLOAD], cmd, 200);
+  //dwr(" RX: (pid=%d, tid=%d, rpc_count=%d, timestamp=%s, cmd=%d\n", pid, tid, rpc_count, timestring, cmd[0]);
+  int n_write = write(rpc_fd, &metabuf, BUF_SZ);
   if(n_write < 0){
     dwr("Error writing command to service (CMD = %d)\n", cmd[0]);
     errno = 0;
@@ -200,9 +247,12 @@ int is_mapped_to_service(int sockfd)
   memset(cmd, '\0', BUF_SZ);
   cmd[0] = RPC_MAP_REQ;
   memcpy(&cmd[1], &sockfd, sizeof(sockfd));
+  pthread_mutex_lock(&lock);
   if(send_command(fdret_sock, cmd) < 0)
     return -1;
-  return get_retval();
+  int err = get_retval();
+  pthread_mutex_unlock(&lock);
+  return err;
 }
 
 /*------------------------------------------------------------------------------
@@ -233,7 +283,10 @@ int init_service_connection()
       else {
         dwr("AF_UNIX connection established: %d\n", tfd);
         is_initialized = 1;
-        return tfd;
+        int newtfd = realdup2(tfd, 1023);
+        dwr("dup'd to rpc_fd = %d\n", newtfd);
+        close(tfd);
+        return newtfd;
       }
       attempts++;
     }
@@ -277,8 +330,11 @@ void load_symbols(void)
   realgetsockopt = dlsym(RTLD_NEXT, "getsockopt");
   realaccept4 = dlsym(RTLD_NEXT, "accept4");
   //realclone = dlsym(RTLD_NEXT, "clone");
+  realclose = dlsym(RTLD_NEXT, "close");
   realsyscall = dlsym(RTLD_NEXT, "syscall");
   //realsyscall = dlsym(RTLD_NEXT, "poll");
+  realdup2 = dlsym(RTLD_NEXT, "dup2");
+  realdup3 = dlsym(RTLD_NEXT, "dup3");
 #ifdef USE_SOCKS_DNS
   realresinit = dlsym(RTLD_NEXT, "res_init");
 #endif
@@ -295,8 +351,11 @@ void load_symbols(void)
   realgetsockopt = dlsym(lib, "getsockopt");
   realaccept4 = dlsym(lib), "accept4");
   //realclone = dlsym(lib, "clone");
+  realclose = dlsym(lib, "close");
   realsyscall = dlsym(lib, "syscall");
   //realsyscall = dlsym(lib, "poll");
+  realdup2 = dlsym(RTLD_NEXT, "dup2");
+  realdup3 = dlsym(RTLD_NEXT, "dup3");
 #ifdef USE_SOCKS_DNS
   realresinit = dlsym(lib, "res_init");
 #endif
@@ -332,7 +391,7 @@ void set_up_intercept()
 /* int socket, int level, int option_name, const void *option_value, socklen_t option_len */
 int setsockopt(SETSOCKOPT_SIG)
 {
-  dwr("setsockopt(%d)\n", socket);
+  dwr("\n\nsetsockopt(%d)\n", socket);
   /*
   if(is_mapped_to_service(socket) < 0) { // First, check if the service manages this
     return realsetsockopt(socket, level, option_name, option_value, option_len);
@@ -363,7 +422,7 @@ int setsockopt(SETSOCKOPT_SIG)
 /* int sockfd, int level, int optname, void *optval, socklen_t *optlen */
 int getsockopt(GETSOCKOPT_SIG)
 {
-  dwr("getsockopt(%d)\n", sockfd);
+  dwr("\n\ngetsockopt(%d)\n", sockfd);
   /*
   if(is_mapped_to_service(sockfd) < 0) { // First, check if the service manages this
     return realgetsockopt(sockfd, level, optname, optval, optlen);
@@ -393,7 +452,7 @@ int getsockopt(GETSOCKOPT_SIG)
    socket() intercept function */
 int socket(SOCKET_SIG)
 {
-  dwr("socket()*:\n");
+  dwr("\n\nsocket()*:\n");
   int err;
 #ifdef CHECKS
   /* Check that type makes sense */
@@ -426,7 +485,6 @@ int socket(SOCKET_SIG)
   */
   /* FIXME: detect ENFILE condition */
 #endif
-
   char cmd[BUF_SZ];
   fdret_sock = !is_initialized ? init_service_connection() : fdret_sock;
   if(fdret_sock < 0) {
@@ -434,7 +492,6 @@ int socket(SOCKET_SIG)
     handle_error("socket4", "", -1);
     exit(-1);
   }
-
   if(socket_family == AF_LOCAL
     || socket_family == AF_NETLINK
     || socket_family == AF_UNIX) {
@@ -443,18 +500,15 @@ int socket(SOCKET_SIG)
       handle_error("socket5", "", err);
       return err;
   }
-
   /* Assemble and send RPC */
   struct socket_st rpc_st;
   rpc_st.socket_family = socket_family;
   rpc_st.socket_type = socket_type;
   rpc_st.protocol = protocol;
   rpc_st.__tid = syscall(SYS_gettid);
-
   memset(cmd, '\0', BUF_SZ);
   cmd[0] = RPC_SOCKET;
   dwr("pid = %d\n", thispid);
-  memcpy(&cmd[1], &thispid, sizeof(pid_t));
   memcpy(&cmd[1]+sizeof(pid_t), &rpc_st, sizeof(struct socket_st));
   pthread_mutex_lock(&lock);
   send_command(fdret_sock, cmd);
@@ -462,9 +516,11 @@ int socket(SOCKET_SIG)
   /* get new fd */
   char rbuf[16];
   ssize_t sz = sock_fd_read(fdret_sock, rbuf, sizeof(rbuf), &newfd);
+  int tmp = newfd;
   dwr("read %d bytes (%s)\n", sz, &rbuf);
   if(sz > 0)
   {
+    dwr("sending fd = %d to Service over (%d)\n", newfd, fdret_sock);
     /* send our local-fd number back to service so
      it can complete its mapping table entry */
     memset(cmd, '\0', BUF_SZ);
@@ -504,7 +560,7 @@ int socket(SOCKET_SIG)
    connect() intercept function */
 int connect(CONNECT_SIG)
 {
-  dwr("connect(%d):\n", __fd);
+  dwr("\n\nconnect(%d):\n", __fd);
   print_addr(__addr);
   struct sockaddr_in *connaddr;
   connaddr = (struct sockaddr_in *) __addr;
@@ -597,7 +653,7 @@ int select(SELECT_SIG)
    bind() intercept function */
 int bind(BIND_SIG)
 {
-  dwr("bind(%d):\n", sockfd);
+  dwr("\n\nbind(%d):\n", sockfd);
   print_addr(addr);
 #ifdef CHECKS
   /* Check that this is a valid fd */
@@ -660,7 +716,7 @@ int bind(BIND_SIG)
 /* int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags */
 int accept4(ACCEPT4_SIG)
 {
-  dwr("accept4(%d):\n", sockfd);
+  dwr("\n\naccept4(%d):\n", sockfd);
 #ifdef CHECKS
   if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) {
     errno = EINVAL;
@@ -687,7 +743,7 @@ int accept4(ACCEPT4_SIG)
    accept() intercept function */
 int accept(ACCEPT_SIG)
 {
-  dwr("accept(%d):\n", sockfd);
+  dwr("\n\naccept(%d):\n", sockfd);
 #ifdef CHECKS
   /* Check that this is a valid fd */
   if(fcntl(sockfd, F_GETFD) < 0) {
@@ -794,7 +850,7 @@ int accept(ACCEPT_SIG)
    listen() intercept function */
 int listen(LISTEN_SIG)
 {
-  dwr("listen(%d):\n", sockfd);
+  dwr("\n\nlisten(%d):\n", sockfd);
   int sock_type;
   socklen_t sock_type_len = sizeof(sock_type);
 
@@ -861,7 +917,6 @@ int clone(CLONE_SIG)
 */
 
 
-
 /*------------------------------------------------------------------------------
 -------------------------------------- poll()-----------------------------------
 ------------------------------------------------------------------------------*/
@@ -876,6 +931,59 @@ int poll(POLL_SIG)
 }
 */
 
+/*------------------------------------------------------------------------------
+-------------------------------------- close()-----------------------------------
+------------------------------------------------------------------------------*/
+
+// int fd
+int close(CLOSE_SIG)
+{
+  dwr("close(%d)\n", fd);
+  if(fd == fdret_sock)
+    return 0; // FIXME: Ignore request to shut down our rpc fd, this is *almost always* safe
+  if(fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO){
+    return realclose(fd);
+  }
+}
+
+/*------------------------------------------------------------------------------
+-------------------------------------- dup2()-----------------------------------
+------------------------------------------------------------------------------*/
+
+// int oldfd, int newfd
+int dup2(DUP2_SIG)
+{
+  dwr("dup2(%d, %d)\n", oldfd, newfd);
+    if(oldfd == fdret_sock) {
+    dwr("client application attempted to dup2 RPC socket (%d). This is not allowed.\n", oldfd);
+    errno = EBADF;
+    return -1;
+  }
+  if(oldfd != STDIN_FILENO && oldfd != STDOUT_FILENO && oldfd != STDERR_FILENO) {
+    return realdup2(oldfd, newfd);
+  }
+}
+
+/*------------------------------------------------------------------------------
+-------------------------------------- dup3()-----------------------------------
+------------------------------------------------------------------------------*/
+
+// int oldfd, int newfd, int flags
+int dup3(DUP3_SIG)
+{
+  dwr("dup3(%d, %d, %d)\n", oldfd, newfd, flags);
+#ifdef DEBUG
+  // Only do this check if we want to debug the intercept, otherwise, dont mess with 
+  // the client application's logging methods
+  if(newfd == STDIN_FILENO || newfd == STDOUT_FILENO || newfd == STDERR_FILENO)
+    return newfd; // FIXME: This is to prevent httpd from dup'ing over our stderr 
+                  //and preventing us from debugging
+  else
+#endif
+    return realdup3(oldfd, newfd, flags);
+}
+
+
 /*------------------------------------------------------------------------------
 ------------------------------------ syscall()----------------------------------
 ------------------------------------------------------------------------------*/

+ 10 - 1
netcon/Intercept.h

@@ -31,7 +31,13 @@
 
 #include <sys/socket.h>
 
-#define BUF_SZ                  128
+#define IDX_PID				0
+#define IDX_TID				sizeof(pid_t)
+#define IDX_COUNT			IDX_TID + sizeof(pid_t)
+#define IDX_TIME			IDX_COUNT + sizeof(int)
+#define IDX_PAYLOAD			IDX_TIME + 20 // 20 being the length of the timestamp string
+
+#define BUF_SZ                  256
 #define ERR_OK                  0
 
 /* Userland RPC codes */
@@ -177,4 +183,7 @@ struct shutdown_st
 #define CLONE_SIG int (*fn)(void *), void *child_stack, int flags, void *arg, ...
 #define POLL_SIG struct pollfd *fds, nfds_t nfds, int timeout
 
+#define DUP2_SIG int oldfd, int newfd
+#define DUP3_SIG int oldfd, int newfd, int flags
+
 #endif

+ 53 - 18
netcon/NetconEthernetTap.cpp

@@ -567,22 +567,39 @@ void NetconEthernetTap::phyOnUnixAccept(PhySocket *sockL,PhySocket *sockN,void *
 	rpc_sockets.push_back(sockN);
 }
 
+void unload_rpc(void *data, pid_t &pid, pid_t &tid, int &rpc_count, char (timestamp[20]), char &cmd, void* &payload);
+
 /*
  * Processes incoming data on a client-specific RPC connection
  */
 void NetconEthernetTap::phyOnUnixData(PhySocket *sock,void **uptr,void *data,unsigned long len)
 {
+	pid_t pid, tid;
+	int rpc_count;
+	char timestamp[20];
+	char cmd;
+	void *payload;
+	unload_rpc(data, pid, tid, rpc_count, timestamp, cmd, payload);
+	dwr("\n\nRX: (pid=%d, tid=%d, rpc_count=%d, timestamp=%s, cmd=%d\n", pid, tid, rpc_count, timestamp, cmd);
 	unsigned char *buf = (unsigned char*)data;
-	switch(buf[0])
+
+	switch(cmd)
 	{
 		case RPC_SOCKET:
 			dwr(2, "RPC_SOCKET\n");
-	    struct socket_st socket_rpc;
-			pid_t pid;
-			memcpy(&pid, &buf[1], sizeof(pid_t)); // PID for client RPC tracking (only for debug)
-	    memcpy(&socket_rpc, &buf[sizeof(pid_t)], sizeof(struct socket_st));
+			struct socket_st socket_rpc;
+			memcpy(&socket_rpc, &buf[IDX_PAYLOAD+1], sizeof(struct socket_st));
+
+		    if(rpc_count==rpc_counter) {
+		    	dwr("Detected repeat RPC.\n");
+		    	//return;
+		    }
+		    else {
+		    	rpc_counter = rpc_count;
+		    }
+
 			TcpConnection * new_conn;
-			if(new_conn = handle_socket(sock, uptr, &socket_rpc)) {
+			if((new_conn = handle_socket(sock, uptr, &socket_rpc))) {
 				pidmap[sock] = pid;
 				new_conn->pid = pid;
 			}
@@ -590,24 +607,30 @@ void NetconEthernetTap::phyOnUnixData(PhySocket *sock,void **uptr,void *data,uns
 	  case RPC_LISTEN:
 			dwr(2, "RPC_LISTEN\n");
 	    struct listen_st listen_rpc;
-	    memcpy(&listen_rpc, &buf[1], sizeof(struct listen_st));
+	    memcpy(&listen_rpc,  &buf[IDX_PAYLOAD+1], sizeof(struct listen_st));
 	    handle_listen(sock, uptr, &listen_rpc);
 			break;
 	  case RPC_BIND:
 			dwr(2, "RPC_BIND\n");
 	    struct bind_st bind_rpc;
-	    memcpy(&bind_rpc, &buf[1], sizeof(struct bind_st));
+	    memcpy(&bind_rpc,  &buf[IDX_PAYLOAD+1], sizeof(struct bind_st));
 	    handle_bind(sock, uptr, &bind_rpc);
 			break;
   	case RPC_CONNECT:
 			dwr(2, "RPC_CONNECT\n");
 	    struct connect_st connect_rpc;
-	    memcpy(&connect_rpc, &buf[1], sizeof(struct connect_st));
+	    memcpy(&connect_rpc,  &buf[IDX_PAYLOAD+1], sizeof(struct connect_st));
 	    handle_connect(sock, uptr, &connect_rpc);
 			break;
 	  case RPC_MAP:
-			dwr(2, "RPC_MAP\n");
-	    handle_retval(sock, uptr, buf);
+			dwr(2, "RPC_MAP (len = %d)\n", len);
+
+			int newfd;
+			//memcpy(&pid,  &buf[IDX_PAYLOAD+1], sizeof(pid_t)); // PID for client RPC tracking (only for debug)
+	    	memcpy(&newfd, &buf[IDX_PAYLOAD+1], sizeof(int));
+	    	//dwr("newfd = %d\n", newfd);
+
+	    	handle_retval(sock, uptr, rpc_count, newfd);
 			break;
 		case RPC_MAP_REQ:
 			dwr(2, "RPC_MAP_REQ\n");
@@ -616,6 +639,7 @@ void NetconEthernetTap::phyOnUnixData(PhySocket *sock,void **uptr,void *data,uns
 		default:
 			break;
 	}
+	//memset(data, '\0', 256);
 }
 
 /*
@@ -973,7 +997,7 @@ void NetconEthernetTap::handle_map_request(PhySocket *sock, void **uptr, unsigne
 	dwr(4, " handle_map_request()\n");
 	TcpConnection *conn = (TcpConnection*)*uptr;
 	int req_fd;
-	memcpy(&req_fd, &buf[1], sizeof(req_fd));
+	memcpy(&req_fd, &buf[IDX_PAYLOAD+1], sizeof(req_fd));
 	for(size_t i=0; i<tcp_connections.size(); i++) {
 		if(tcp_connections[i]->rpcSock == conn->rpcSock && tcp_connections[i]->perceived_fd == req_fd){
 			send_return_value(conn, 1, ERR_OK); // True
@@ -994,16 +1018,26 @@ void NetconEthernetTap::handle_map_request(PhySocket *sock, void **uptr, unsigne
  * @param structure containing the data and parameters for this client's RPC
  *
  */
-void NetconEthernetTap::handle_retval(PhySocket *sock, void **uptr, unsigned char* buf)
+void NetconEthernetTap::handle_retval(PhySocket *sock, void **uptr, int rpc_count, int newfd)
 {
 	dwr(4, " handle_retval()\n");
 	TcpConnection *conn = (TcpConnection*)*uptr;
 	if(!conn->pending)
 		return;
 
-	// Copy data from buffer to TcpConnection object, update status
-	memcpy(&(conn->perceived_fd), &buf[1], sizeof(int));
 	conn->pending = false;
+    conn->perceived_fd = newfd;
+
+    if(rpc_count==rpc_counter) {
+    	dwr("Detected repeat RPC.\n");
+    	//return;
+    }
+    else {
+    	rpc_counter = rpc_count;
+    	//dwr("pid = %d\n", rpc_count);
+    	//dwr("rpc_counter = %d\n", rpc_counter);
+    	
+    }
 
 	dwr(4, " handle_retval(): CONN:%x - Mapping [our=%d -> their=%d]\n",conn,
 	_phy.getDescriptor(conn->dataSock), conn->perceived_fd);
@@ -1027,7 +1061,7 @@ void NetconEthernetTap::handle_retval(PhySocket *sock, void **uptr, unsigned cha
 				}
 				else {
 					dwr(" handle_retval(): CONN:%x - This socket is mapped to two different pipes (?). Exiting.\n", conn);
-					die(0); // FIXME: Print service mapping state and exit
+					//die(0); // FIXME: Print service mapping state and exit
 				}
 			}
 		}
@@ -1070,7 +1104,7 @@ void NetconEthernetTap::handle_retval(PhySocket *sock, void **uptr, unsigned cha
  */
 void NetconEthernetTap::handle_bind(PhySocket *sock, void **uptr, struct bind_st *bind_rpc)
 {
-	dwr(3, " handle_bind()\n");
+	
   struct sockaddr_in *connaddr;
   connaddr = (struct sockaddr_in *) &bind_rpc->addr;
   int conn_port = lwipstack->ntohs(connaddr->sin_port);
@@ -1078,6 +1112,8 @@ void NetconEthernetTap::handle_bind(PhySocket *sock, void **uptr, struct bind_st
 	conn_addr.addr = *((u32_t *)_ips[0].rawIpData());
 	TcpConnection *conn = getConnectionByTheirFD(sock, bind_rpc->sockfd);
 
+  dwr(3, " handle_bind(%d)\n", bind_rpc->sockfd);
+
   if(conn) {
     if(conn->pcb->state == CLOSED){
       int err = lwipstack->tcp_bind(conn->pcb, &conn_addr, conn_port);
@@ -1229,7 +1265,6 @@ TcpConnection * NetconEthernetTap::handle_socket(PhySocket *sock, void **uptr, s
 	  new_conn->their_fd = fds[1];
 		tcp_connections.push_back(new_conn);
     int n = sock_fd_write(_phy.getDescriptor(sock), fds[1]);
-		dwr("wrote %d bytes\n", n);
 		close(fds[1]); // close other end of socketpair
 		// Once the client tells us what its fd is on the other end, we can then complete the mapping
     new_conn->pending = true;

+ 2 - 1
netcon/NetconEthernetTap.hpp

@@ -107,7 +107,7 @@ private:
 	void handle_bind(PhySocket *sock, void **uptr, struct bind_st *bind_rpc);
 	void handle_listen(PhySocket *sock, void **uptr, struct listen_st *listen_rpc);
 	void handle_map_request(PhySocket *sock, void **uptr, unsigned char* buf);
-	void handle_retval(PhySocket *sock, void **uptr, unsigned char* buf);
+	void handle_retval(PhySocket *sock, void **uptr, int rpc_count, int newfd);
 	TcpConnection * handle_socket(PhySocket *sock, void **uptr, struct socket_st* socket_rpc);
 	void handle_connect(PhySocket *sock, void **uptr, struct connect_st* connect_rpc);
 	void handle_write(TcpConnection *conn);
@@ -154,6 +154,7 @@ private:
 	std::vector<TcpConnection*> tcp_connections;
 	std::vector<PhySocket*> rpc_sockets;
 	std::map<PhySocket*, pid_t> pidmap;
+	pid_t rpc_counter = -1;
 
 	netif interface;
 

+ 22 - 1
netcon/NetconUtilities.cpp

@@ -37,6 +37,8 @@
 #include "lwip/ip_addr.h"
 #include "lwip/ip_frag.h"
 
+#include "Intercept.h"
+
 #ifndef _NETCON_UTILITIES_CPP
 #define _NETCON_UTILITIES_CPP
 
@@ -64,8 +66,27 @@ namespace ZeroTier
 		va_end(ap);
 	}
 
-	void clearscreen()
+	void unload_rpc(void *data, pid_t &pid, pid_t &tid, int &rpc_count, char (timestamp[20]), char &cmd, void* &payload)
 	{
+		unsigned char *buf = (unsigned char*)data;
+
+/*
+		dwr(" - IDX_PID = %d\n", IDX_PID);	
+		dwr(" - IDX_TID = %d\n", IDX_TID);			
+		dwr(" - IDX_COUNT = %d\n", IDX_COUNT);		
+		dwr(" - IDX_TIME = %d\n", IDX_TIME);		
+		dwr(" - IDX_PAYLOAD = %d\n", IDX_PAYLOAD);		
+*/
+		memcpy(&pid, 		&buf[IDX_PID], 		sizeof(pid_t));
+		memcpy(&tid, 		&buf[IDX_TID], 		sizeof(pid_t));
+		memcpy(&rpc_count, 	&buf[IDX_COUNT], 	sizeof(int));
+		memcpy(timestamp, 	&buf[IDX_TIME], 	20);
+		memcpy(&cmd, 		&buf[IDX_PAYLOAD], 	sizeof(char));
+		payload = buf+IDX_PAYLOAD+1;
+		//dwr("RX: (pid=%d, tid=%d, rpc_count=%d, timestamp=%s, cmd=%d\n", pid, tid, rpc_count, timestamp, cmd);
+	}
+
+	void clearscreen(){
 		fprintf(stderr, "\033[2J");
 	}
 

+ 1 - 1
netcon/make-intercept.mk

@@ -27,7 +27,7 @@
 
 SHCC=gcc
 
-intercept_CFLAGS = -c -fPIC -g -O2 -Wall -std=c99 -DERRORS_ARE_FATAL -DVERBOSE -DCHECKS -D_GNU_SOURCE -DNETCON_INTERCEPT
+intercept_CFLAGS = -c -fPIC -g -O2 -Wall -std=c99 -DERRORS_ARE_FATAL -DDEBUG -DVERBOSE -DCHECKS -D_GNU_SOURCE -DNETCON_INTERCEPT
 LIB_NAME = intercept
 SHLIB_EXT=dylib
 SHLIB_MAJOR = 1