Browse Source

Added support for Redis

Joseph Henry 9 years ago
parent
commit
721d58b464

+ 22 - 0
netcon/Common.c

@@ -48,6 +48,28 @@ void dwr(const char *fmt, ...);
 
 extern pthread_mutex_t loglock;
 
+void print_addr(struct sockaddr *addr)
+{
+  char *s = NULL;
+  switch(addr->sa_family) {
+      case AF_INET: {
+          struct sockaddr_in *addr_in = (struct sockaddr_in *)addr;
+          s = malloc(INET_ADDRSTRLEN);
+          inet_ntop(AF_INET, &(addr_in->sin_addr), s, INET_ADDRSTRLEN);
+          break;
+      }
+      case AF_INET6: {
+          struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr;
+          s = malloc(INET6_ADDRSTRLEN);
+          inet_ntop(AF_INET6, &(addr_in6->sin6_addr), s, INET6_ADDRSTRLEN);
+          break;
+      }
+      default:
+          break;
+  }
+  fprintf(stderr, "IP address: %s\n", s);
+  free(s);
+}
 
 
 #ifdef NETCON_SERVICE

+ 123 - 26
netcon/Intercept.c

@@ -43,6 +43,7 @@ char *progname = "";
 #include <sys/time.h>
 #include <pwd.h>
 #include <errno.h>
+#include <linux/errno.h>
 #include <stdarg.h>
 #include <netdb.h>
 #include <string.h>
@@ -50,6 +51,7 @@ char *progname = "";
 #include <sys/syscall.h>
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/poll.h>
 #include <sys/un.h>
 #include <arpa/inet.h>
 
@@ -77,6 +79,8 @@ static int (*realsetsockopt)(SETSOCKOPT_SIG);
 static int (*realgetsockopt)(GETSOCKOPT_SIG);
 static int (*realaccept4)(ACCEPT4_SIG);
 static long (*realsyscall)(SYSCALL_SIG);
+//static int (*realclone)(CLONE_SIG);
+//static int (*realpoll)(POLL_SIG);
 
 /* Exported Function Prototypes */
 void my_init(void);
@@ -91,6 +95,8 @@ int setsockopt(SETSOCKOPT_SIG);
 int getsockopt(GETSOCKOPT_SIG);
 int accept4(ACCEPT4_SIG);
 long syscall(SYSCALL_SIG);
+//int clone(CLONE_SIG);
+//int poll(POLL_SIG);
 
 #ifdef USE_SOCKS_DNS
   int res_init(void);
@@ -111,6 +117,18 @@ ssize_t sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd);
 pthread_mutex_t lock;
 pthread_mutex_t loglock;
 
+void handle_error(char *name, char *info, int err)
+{
+#ifdef ERRORS_ARE_FATAL
+  if(err < 0) {
+    dwr("handle_error(%s)=%d: FATAL: %s\n", name, err, info);
+    //exit(-1);
+  }
+#endif
+#ifdef VERBOSE
+  dwr("%s()=%d\n", name, err);
+#endif
+}
 
 /*------------------------------------------------------------------------------
 ------------------- Intercept<--->Service Comm mechanisms-----------------------
@@ -241,6 +259,7 @@ void load_symbols(void)
   realaccept4 = dlsym(RTLD_NEXT, "accept4");
   //realclone = dlsym(RTLD_NEXT, "clone");
   realsyscall = dlsym(RTLD_NEXT, "syscall");
+  //realsyscall = dlsym(RTLD_NEXT, "poll");
 #ifdef USE_SOCKS_DNS
   realresinit = dlsym(RTLD_NEXT, "res_init");
 #endif
@@ -258,6 +277,7 @@ void load_symbols(void)
   realaccept4 = dlsym(lib), "accept4");
   //realclone = dlsym(lib, "clone");
   realsyscall = dlsym(lib, "syscall");
+  //realsyscall = dlsym(lib, "poll");
 #ifdef USE_SOCKS_DNS
   realresinit = dlsym(lib, "res_init");
 #endif
@@ -292,6 +312,9 @@ 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);
+  //return(realsetsockopt(socket, level, option_name, option_value, option_len));
+
   if(level == IPPROTO_TCP || (level == SOL_SOCKET && option_name == SO_KEEPALIVE)){
     return 0;
   }
@@ -313,9 +336,8 @@ int setsockopt(SETSOCKOPT_SIG)
 
 int getsockopt(GETSOCKOPT_SIG)
 {
-  // make sure we don't touch any standard outputs
+  dwr("setsockopt(%d)\n", sockfd);
   int err = realgetsockopt(sockfd, level, optname, optval, optlen);
-
   // FIXME: this condition will need a little more intelligence later on
   // -- we will need to know if this fd is a local we are spoofing, or a true local
   if(optname == SO_TYPE)
@@ -347,16 +369,19 @@ int socket(SOCKET_SIG)
   int flags = socket_type & ~SOCK_TYPE_MASK;
   if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) {
       errno = EINVAL;
+      handle_error("socket", "", -1);
       return -1;
   }
   socket_type &= SOCK_TYPE_MASK;
   /* Check protocol is in range */
   if (socket_family < 0 || socket_family >= NPROTO){
     errno = EAFNOSUPPORT;
+    handle_error("socket", "", -1);
     return -1;
   }
   if (socket_type < 0 || socket_type >= SOCK_MAX) {
     errno = EINVAL;
+    handle_error("socket", "", -1);
     return -1;
   }
   /* Check that we haven't hit the soft-limit file descriptors allowed */
@@ -375,13 +400,18 @@ int socket(SOCKET_SIG)
   fdret_sock = !is_initialized ? init_service_connection() : fdret_sock;
   if(fdret_sock < 0) {
     dwr("BAD service connection. exiting.\n");
+    handle_error("socket", "", -1);
     exit(-1);
   }
 
   if(socket_family == AF_LOCAL
     || socket_family == AF_NETLINK
     || socket_family == AF_UNIX) {
-    return realsocket(socket_family, socket_type, protocol);
+
+      int err = realsocket(socket_family, socket_type, protocol);
+      dwr("realsocket, err = %d\n", err);
+      handle_error("socket", "", err);
+      return err;
   }
 
   /* Assemble and send RPC */
@@ -395,6 +425,8 @@ int socket(SOCKET_SIG)
   cmd[0] = RPC_SOCKET;
   memcpy(&cmd[1], &rpc_st, sizeof(struct socket_st));
   pthread_mutex_lock(&lock);
+
+  dwr("sending RPC...\n");
   send_command(fdret_sock, cmd);
 
   /* get new fd */
@@ -405,13 +437,14 @@ int socket(SOCKET_SIG)
     /* send our local-fd number back to service so
      it can complete its mapping table entry */
     memset(cmd, '\0', BUF_SZ);
-    cmd[0] = RPC_FD_MAP_COMPLETION;
+    cmd[0] = RPC_MAP;
     memcpy(&cmd[1], &newfd, sizeof(newfd));
 
     //if(newfd > -1) {
       send_command(fdret_sock, cmd);
       pthread_mutex_unlock(&lock);
       errno = ERR_OK; // OK
+      handle_error("socket", "", newfd);
       return newfd;
     //}
     /*
@@ -427,6 +460,7 @@ int socket(SOCKET_SIG)
     dwr("Error while receiving new FD.\n");
     err = get_retval();
     pthread_mutex_unlock(&lock);
+    handle_error("socket", "", -1);
     return err;
   }
 }
@@ -439,26 +473,30 @@ int socket(SOCKET_SIG)
    connect() intercept function */
 int connect(CONNECT_SIG)
 {
-  dwr("connect()*:\n");
+  dwr("connect(%d):\n", __fd);
+  print_addr(__addr);
   struct sockaddr_in *connaddr;
   connaddr = (struct sockaddr_in *) __addr;
 
 #ifdef CHECKS
   /* Check that this is a valid fd */
   if(fcntl(__fd, F_GETFD) < 0) {
-    return -1;
     errno = EBADF;
+    handle_error("connect", "EBADF", -1);
+    return -1;
   }
   /* Check that it is a socket */
   int sock_type;
   socklen_t sock_type_len = sizeof(sock_type);
   if(getsockopt(__fd, SOL_SOCKET, SO_TYPE, (void *) &sock_type, &sock_type_len) < 0) {
     errno = ENOTSOCK;
+    handle_error("connect", "ENOTSOCK", -1);
     return -1;
   }
   /* Check family */
   if (connaddr->sin_family < 0 || connaddr->sin_family >= NPROTO){
     errno = EAFNOSUPPORT;
+    handle_error("connect", "EAFNOSUPPORT", -1);
     return -1;
   }
   /* FIXME: Check that address is in user space, return EFAULT ? */
@@ -467,7 +505,7 @@ int connect(CONNECT_SIG)
   /* make sure we don't touch any standard outputs */
   if(__fd == STDIN_FILENO || __fd == STDOUT_FILENO || __fd == STDERR_FILENO){
     if (realconnect == NULL) {
-      dwr("Unresolved symbol: connect(). Library is exiting.\n");
+      handle_error("connect", "Unresolved symbol [connect]", -1);
       exit(-1);
     }
     return(realconnect(__fd, __addr, __len));
@@ -478,6 +516,8 @@ int connect(CONNECT_SIG)
     || connaddr->sin_family == AF_NETLINK
     || connaddr->sin_family == AF_UNIX)) {
     int err = realconnect(__fd, __addr, __len);
+    perror("connect():");
+    //handle_error("connect", "Cannot connect to local socket", err);
     return err;
   }
 
@@ -502,6 +542,7 @@ int connect(CONNECT_SIG)
   */
   err = get_retval();
   pthread_mutex_unlock(&lock);
+  //handle_error("connect", "", err);
   return err;
 }
 
@@ -525,18 +566,21 @@ int select(SELECT_SIG)
    bind() intercept function */
 int bind(BIND_SIG)
 {
-  dwr("bind()*:\n");
+  dwr("bind(%d):\n", sockfd);
+  print_addr(addr);
 #ifdef CHECKS
   /* Check that this is a valid fd */
   if(fcntl(sockfd, F_GETFD) < 0) {
-    return -1;
     errno = EBADF;
+    handle_error("bind", "EBADF", -1);
+    return -1;
   }
   /* Check that it is a socket */
   int opt = -1;
   socklen_t opt_len;
   if(getsockopt(sockfd, SOL_SOCKET, SO_TYPE, (void *) &opt, &opt_len) < 0) {
     errno = ENOTSOCK;
+    handle_error("bind", "ENOTSOCK", -1);
     return -1;
   }
 #endif
@@ -555,11 +599,11 @@ int bind(BIND_SIG)
     || connaddr->sin_family == AF_NETLINK
     || connaddr->sin_family == AF_UNIX))
   {
-      if(realbind == NULL) {
-        dwr("Unresolved symbol: bind(). Library is exiting.\n");
-        exit(-1);
-      }
-      return(realbind(sockfd, addr, addrlen));
+    if(realbind == NULL) {
+      handle_error("bind", "Unresolved symbol [bind]", -1);
+      exit(-1);
+    }
+    return(realbind(sockfd, addr, addrlen));
   }
   /* Assemble and send RPC */
   char cmd[BUF_SZ];
@@ -575,6 +619,7 @@ int bind(BIND_SIG)
   err = get_retval();
   pthread_mutex_unlock(&lock);
   errno = ERR_OK;
+  handle_error("bind", "", err);
   return err;
 }
 
@@ -587,7 +632,7 @@ int bind(BIND_SIG)
 /* int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags */
 int accept4(ACCEPT4_SIG)
 {
-  dwr("accept4()*:\n");
+  dwr("accept4(%d):\n", sockfd);
 #ifdef CHECKS
   if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) {
     errno = EINVAL;
@@ -601,6 +646,7 @@ int accept4(ACCEPT4_SIG)
     if(flags & SOCK_NONBLOCK)
       fcntl(newfd, F_SETFL, O_NONBLOCK);
   }
+  handle_error("accept4", "", newfd);
   return newfd;
 }
 
@@ -613,23 +659,30 @@ int accept4(ACCEPT4_SIG)
    accept() intercept function */
 int accept(ACCEPT_SIG)
 {
-  dwr("accept()*:\n");
+  dwr("accept(%d):\n", sockfd);
 #ifdef CHECKS
   /* Check that this is a valid fd */
   if(fcntl(sockfd, F_GETFD) < 0) {
     return -1;
     errno = EBADF;
+    dwr("EBADF\n");
+    handle_error("accept", "EBADF", -1);
+    return -1;
   }
   /* Check that it is a socket */
   int opt;
   socklen_t opt_len;
   if(getsockopt(sockfd, SOL_SOCKET, SO_TYPE, (void *) &opt, &opt_len) < 0) {
     errno = ENOTSOCK;
+    dwr("ENOTSOCK\n");
+    handle_error("accept", "ENOTSOCK", -1);
     return -1;
   }
   /* Check that this socket supports accept() */
   if(!(opt && (SOCK_STREAM | SOCK_SEQPACKET))) {
     errno = EOPNOTSUPP;
+    dwr("EOPNOTSUPP\n");
+    handle_error("accept", "EOPNOTSUPP", -1);
     return -1;
   }
   /* Check that we haven't hit the soft-limit file descriptors allowed */
@@ -637,18 +690,24 @@ int accept(ACCEPT_SIG)
   getrlimit(RLIMIT_NOFILE, &rl);
   if(sockfd >= rl.rlim_cur){
     errno = EMFILE;
+    dwr("EMFILE\n");
+    handle_error("accept", "EMFILE", -1);
     return -1;
   }
   /* Check address length */
   if(addrlen < 0) {
     errno = EINVAL;
+    dwr("EINVAL\n");
+    handle_error("accept", "EINVAL", -1);
     return -1;
   }
 #endif
 
   /* redirect calls for standard I/O descriptors to kernel */
-  if(sockfd == STDIN_FILENO || sockfd == STDOUT_FILENO || sockfd == STDERR_FILENO)
+  if(sockfd == STDIN_FILENO || sockfd == STDOUT_FILENO || sockfd == STDERR_FILENO){
+    dwr("realaccept():\n");
     return(realaccept(sockfd, addr, addrlen));
+  }
 
   if(addr)
     addr->sa_family = AF_INET;
@@ -656,15 +715,15 @@ int accept(ACCEPT_SIG)
 
   char cmd[BUF_SZ];
   if(realaccept == NULL) {
-    dwr( "Unresolved symbol: accept()\n");
+    handle_error("accept", "Unresolved symbol [accept]", -1);
     return -1;
   }
-
   //if(opt & O_NONBLOCK)
     //fcntl(sockfd, F_SETFL, O_NONBLOCK);
 
   char rbuf[16], c[1];
   int new_conn_socket;
+
   int n = read(sockfd, c, sizeof(c)); // Read signal byte
   if(n > 0)
   {
@@ -672,28 +731,29 @@ int accept(ACCEPT_SIG)
     if(size > 0) {
       /* Send our local-fd number back to service so it can complete its mapping table */
       memset(cmd, '\0', BUF_SZ);
-      cmd[0] = RPC_FD_MAP_COMPLETION;
+      cmd[0] = RPC_MAP;
       memcpy(&cmd[1], &new_conn_socket, sizeof(new_conn_socket));
       pthread_mutex_lock(&lock);
       int n_write = write(fdret_sock, cmd, BUF_SZ);
       if(n_write < 0) {
-        dwr("Error sending perceived FD to service.\n");
         errno = ECONNABORTED; // FIXME: Closest match, service unreachable
+        handle_error("accept", "ECONNABORTED - Error sending perceived FD to service", -1);
         return -1;
       }
       pthread_mutex_unlock(&lock);
       errno = ERR_OK;
-      dwr("accepting for %d\n", new_conn_socket);
+      dwr("accept()=%d\n", new_conn_socket);
+      handle_error("accept", "", new_conn_socket);
       return new_conn_socket; // OK
     }
     else {
-      dwr("Error receiving new FD from service.\n");
       errno = ECONNABORTED; // FIXME: Closest match, service unreachable
+      handle_error("accept", "ECONNABORTED - Error receiving new FD from service", -1);
       return -1;
     }
   }
-  dwr("Error reading signal byte from service.\n");
   errno = EAGAIN; /* necessary? */
+  handle_error("accept", "EAGAIN - Error reading signal byte from service", -1);
   return -EAGAIN;
 }
 
@@ -706,23 +766,26 @@ int accept(ACCEPT_SIG)
    listen() intercept function */
 int listen(LISTEN_SIG)
 {
-  dwr("listen()*:\n");
+  dwr("listen(%d):\n", sockfd);
   #ifdef CHECKS
   /* Check that this is a valid fd */
   if(fcntl(sockfd, F_GETFD) < 0) {
-    return -1;
     errno = EBADF;
+    handle_error("listen", "EBADF", -1);
+    return -1;
   }
   /* Check that it is a socket */
   int sock_type;
   socklen_t sock_type_len = sizeof(sock_type);
   if(getsockopt(sockfd, SOL_SOCKET, SO_TYPE, (void *) &sock_type, &sock_type_len) < 0) {
     errno = ENOTSOCK;
+    handle_error("listen", "ENOTSOCK", -1);
     return -1;
   }
   /* Check that this socket supports accept() */
   if(!(sock_type && (SOCK_STREAM | SOCK_SEQPACKET))) {
     errno = EOPNOTSUPP;
+    handle_error("listen", "EOPNOTSUPP", -1);
     return -1;
   }
   #endif
@@ -744,15 +807,49 @@ int listen(LISTEN_SIG)
   send_command(fdret_sock, cmd);
   //err = get_retval();
   pthread_mutex_unlock(&lock);
+  handle_error("listen", "", ERR_OK);
   return ERR_OK;
 }
 
+
+
+
+/*------------------------------------------------------------------------------
+-------------------------------------- clone()----------------------------------
+------------------------------------------------------------------------------*/
+
+// int (*fn)(void *), void *child_stack, int flags, void *arg, ...
+/*
+int clone(CLONE_SIG)
+{
+  dwr("clone()\n");
+  return realclone(fn, child_stack, flags, arg);
+}
+*/
+
+
+
+/*------------------------------------------------------------------------------
+-------------------------------------- poll()-----------------------------------
+------------------------------------------------------------------------------*/
+
+// struct pollfd *fds, nfds_t nfds, int timeout
+/*
+int poll(POLL_SIG)
+{
+  dwr("poll()\n");
+  return realpoll(fds, nfds, timeout);
+  //return ERESTART_RESTARTBLOCK;
+}
+*/
+
 /*------------------------------------------------------------------------------
 ------------------------------------ syscall()----------------------------------
 ------------------------------------------------------------------------------*/
 
 long syscall(SYSCALL_SIG)
 {
+  dwr("syscall():\n");
   va_list ap;
   uintptr_t a,b,c,d,e,f;
   va_start(ap, number);

+ 3 - 1
netcon/Intercept.h

@@ -50,7 +50,7 @@
 #define RPC_SHUTDOWN		 				12
 
 /* Administration RPC codes */
-#define RPC_FD_MAP_COMPLETION		20	// Give the service the value we "see" for the new buffer fd
+#define RPC_MAP									20	// Give the service the value we "see" for the new buffer fd
 #define RPC_RETVAL							21	// not RPC per se, but something we should codify
 #define RPC_KILL_INTERCEPT			22  // Tells the service we need to shut down all connections
 
@@ -173,5 +173,7 @@ struct shutdown_st
 #define SETSOCKOPT_SIG int socket, int level, int option_name, const void *option_value, socklen_t option_len
 #define GETSOCKOPT_SIG int sockfd, int level, int optname, void *optval, socklen_t *optlen
 #define SYSCALL_SIG	long number, ...
+#define CLONE_SIG int (*fn)(void *), void *child_stack, int flags, void *arg, ...
+#define POLL_SIG struct pollfd *fds, nfds_t nfds, int timeout
 
 #endif

+ 63 - 30
netcon/NetconEthernetTap.cpp

@@ -188,7 +188,7 @@ void NetconEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType
 			return;
 		}
 		memcpy(q->payload,&ethhdr,sizeof(ethhdr));
-		memcpy(q->payload + sizeof(ethhdr),dataptr,q->len - sizeof(ethhdr));
+		memcpy((char*)q->payload + sizeof(ethhdr),dataptr,q->len - sizeof(ethhdr));
 		dataptr += q->len - sizeof(ethhdr);
 
 		// Remaining pbufs (if any) get rest of data
@@ -266,13 +266,13 @@ TcpConnection *NetconEthernetTap::getConnectionByTheirFD(PhySocket *sock, int fd
  */
 void NetconEthernetTap::closeConnection(TcpConnection *conn)
 {
-	//lwipstack->_tcp_arg(conn->pcb, NULL);
-  //lwipstack->_tcp_sent(conn->pcb, NULL);
-  //lwipstack->_tcp_recv(conn->pcb, NULL);
-  //lwipstack->_tcp_err(conn->pcb, NULL);
-  //lwipstack->_tcp_poll(conn->pcb, NULL, 0);
-	//lwipstack->_tcp_close(conn->pcb);
-	//close(conn->their_fd);
+	fprintf(stderr, "closeConnection(%x, %d)\n", conn->pcb, _phy.getDescriptor(conn->dataSock));
+	lwipstack->_tcp_arg(conn->pcb, NULL);
+  lwipstack->_tcp_sent(conn->pcb, NULL);
+  lwipstack->_tcp_recv(conn->pcb, NULL);
+  lwipstack->_tcp_err(conn->pcb, NULL);
+  lwipstack->_tcp_poll(conn->pcb, NULL, 0);
+	lwipstack->_tcp_close(conn->pcb);
 	if(conn->dataSock) {
 		close(_phy.getDescriptor(conn->dataSock));
 		_phy.close(conn->dataSock,false);
@@ -318,6 +318,7 @@ void NetconEthernetTap::closeAll()
 void NetconEthernetTap::threadMain()
 	throw()
 {
+	//signal(SIGPIPE, SIG_IGN);
 	uint64_t prev_tcp_time = 0;
 	uint64_t prev_status_time = 0;
 	uint64_t prev_etharp_time = 0;
@@ -351,7 +352,7 @@ void NetconEthernetTap::threadMain()
 		uint64_t etharp_remaining = ARP_TMR_INTERVAL;
 		uint64_t status_remaining = STATUS_TMR_INTERVAL;
 
-		if (since_status >= STATUS_TMR_INTERVAL) {
+		if (since_status >= STATUS_TMR_INTERVAL && true == false) {
 			prev_status_time = now;
 			if(rpc_sockets.size() || tcp_connections.size()) {
 				/* Here we will periodically check the list of rpc_sockets for those that
@@ -383,12 +384,13 @@ void NetconEthernetTap::threadMain()
 					// No TCP connections are associated, this is a candidate for removal
 					unsigned char tmpbuf[BUF_SZ];
 					if(read(_phy.getDescriptor(rpc_sockets[i]),&tmpbuf,BUF_SZ) < 0) {
+						fprintf(stderr, "run() ---> RPC close(%d)\n", _phy.getDescriptor(rpc_sockets[i]));
 						closeClient(rpc_sockets[i]);
 					}
 					else {
 							// Handle RPC call, this is rare
 							fprintf(stderr, "run(): RPC read during connection check\n");
-							exit(0);
+							exit(0); // FIXME: This should be addressed - Raise APPLICATION_POLL_FREQ to make it less likely
 							phyOnUnixData(rpc_sockets[i],NULL,&tmpbuf,BUF_SZ);
 					}
 				}
@@ -412,6 +414,14 @@ void NetconEthernetTap::threadMain()
 	dlclose(lwipstack->_libref);
 }
 
+// Unused -- no UDP or TCP from this thread/Phy<>
+void NetconEthernetTap::phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *from,void *data,unsigned long len) {}
+void NetconEthernetTap::phyOnTcpConnect(PhySocket *sock,void **uptr,bool success) {}
+void NetconEthernetTap::phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from) {}
+void NetconEthernetTap::phyOnTcpClose(PhySocket *sock,void **uptr) {}
+void NetconEthernetTap::phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len) {}
+void NetconEthernetTap::phyOnTcpWritable(PhySocket *sock,void **uptr) {}
+
 void NetconEthernetTap::phyOnUnixClose(PhySocket *sock,void **uptr)
 {
 	// FIXME: What do?
@@ -437,14 +447,6 @@ void NetconEthernetTap::phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,
 	}
 }
 
-// Unused -- no UDP or TCP from this thread/Phy<>
-void NetconEthernetTap::phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *from,void *data,unsigned long len) {}
-void NetconEthernetTap::phyOnTcpConnect(PhySocket *sock,void **uptr,bool success) {}
-void NetconEthernetTap::phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from) {}
-void NetconEthernetTap::phyOnTcpClose(PhySocket *sock,void **uptr) {}
-void NetconEthernetTap::phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len) {}
-void NetconEthernetTap::phyOnTcpWritable(PhySocket *sock,void **uptr) {}
-
 /*
  * Add a new PhySocket for the client connection
  */
@@ -478,17 +480,14 @@ void NetconEthernetTap::phyOnUnixData(PhySocket *sock,void **uptr,void *data,uns
 	    memcpy(&bind_rpc, &buf[1], sizeof(struct bind_st));
 	    handle_bind(sock, uptr, &bind_rpc);
 			break;
-	  case RPC_KILL_INTERCEPT:
-			fprintf(stderr, "RPC_KILL_INTERCEPT\n");
-			break;
   	case RPC_CONNECT:
 			fprintf(stderr, "RPC_CONNECT\n");
 	    struct connect_st connect_rpc;
 	    memcpy(&connect_rpc, &buf[1], sizeof(struct connect_st));
 	    handle_connect(sock, uptr, &connect_rpc);
 			break;
-	  case RPC_FD_MAP_COMPLETION:
-			fprintf(stderr, "RPC_FD_MAP_COMPLETION\n");
+	  case RPC_MAP:
+			fprintf(stderr, "RPC_MAP\n");
 	    handle_retval(sock, uptr, buf);
 			break;
 		default:
@@ -596,8 +595,9 @@ err_t NetconEthernetTap::nc_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
 		new_tcp_conn->pcb = newpcb;
 		new_tcp_conn->their_fd = fds[1];
 		tap->tcp_connections.push_back(new_tcp_conn);
-
+		fprintf(stderr, "socketpair = {%d, %d}\n", fds[0], fds[1]);
 		int send_fd = tap->_phy.getDescriptor(conn->rpcSock);
+		fprintf(stderr, "write(%d,...)\n", larg_fd);
 		int n = write(larg_fd, "z", 1); // accept() in library waits for this byte
     if(n > 0) {
 			if(sock_fd_write(send_fd, fds[1]) > 0) {
@@ -854,11 +854,39 @@ err_t NetconEthernetTap::nc_connected(void *arg, struct tcp_pcb *tpcb, err_t err
 void NetconEthernetTap::handle_retval(PhySocket *sock, void **uptr, unsigned char* buf)
 {
 	TcpConnection *conn = (TcpConnection*)*uptr;
-	if(conn->pending) {
-		memcpy(&(conn->perceived_fd), &buf[1], sizeof(int));
-		//fprintf(stderr, "handle_retval(): Mapping [our=%d -> their=%d]\n",
-		//_phy.getDescriptor(conn->dataSock), conn->perceived_fd);
-		conn->pending = false;
+	if(!conn->pending)
+		return;
+
+	// Copy data from buffer to TcpConnection object, update status
+	memcpy(&(conn->perceived_fd), &buf[1], sizeof(int));
+	conn->pending = false;
+
+	fprintf(stderr, "handle_retval(): CONN:%x - Mapping [our=%d -> their=%d]\n",conn,
+	_phy.getDescriptor(conn->dataSock), conn->perceived_fd);
+
+	/* Check for pre-existing connection for this socket ---
+		This block is in response to interesting behaviour from redis-server. A
+		socket is created, setsockopt is called and the socket is set to IPV6 but fails (for now),
+		then it is closed and re-opened and consequently remapped. With two pipes mapped
+		to the same socket, makes it possible that we write to the wrong pipe and fail. So
+		this block merely searches for a possible duplicate mapping and erases it
+	*/
+	for(size_t i=0; i<tcp_connections.size(); i++) {
+		if(tcp_connections[i] == conn)
+			continue;
+		if(tcp_connections[i]->rpcSock == conn->rpcSock) {
+			if(tcp_connections[i]->perceived_fd == conn->perceived_fd) {
+				int n;
+				if((n = send(_phy.getDescriptor(tcp_connections[i]->dataSock), "z", 1, MSG_NOSIGNAL)) < 0) {
+					fprintf(stderr, "handle_retval(): CONN:%x - Socket (%d) already mapped (originally CONN:%x)\n", conn, tcp_connections[i]->perceived_fd, tcp_connections[i]);
+					closeConnection(tcp_connections[i]);
+				}
+				else {
+					fprintf(stderr, "handle_retval(): CONN:%x - This socket is mapped to two different pipes (?). Exiting.\n", conn);
+					exit(0);
+				}
+			}
+		}
 	}
 }
 
@@ -916,6 +944,7 @@ void NetconEthernetTap::handle_bind(PhySocket *sock, void **uptr, struct bind_st
 				d[2] = (ip >> 16) & 0xFF;
 				d[3] = (ip >> 24) & 0xFF;
 				fprintf(stderr, "handle_bind(): error binding to %d.%d.%d.%d : %d\n", d[0],d[1],d[2],d[3], conn_port);
+				fprintf(stderr, "err = %d\n", err);
 				if(err == ERR_USE)
 					send_return_value(conn, -1, EADDRINUSE);
 				if(err == ERR_MEM)
@@ -927,7 +956,7 @@ void NetconEthernetTap::handle_bind(PhySocket *sock, void **uptr, struct bind_st
 				send_return_value(conn, ERR_OK, ERR_OK); // Success
     }
     else {
-			fprintf(stderr, "handle_bind(): PCB not in CLOSED state. Ignoring BIND request.\n");
+			fprintf(stderr, "handle_bind(): PCB (%x) not in CLOSED state. Ignoring BIND request.\n", conn->pcb);
 			send_return_value(conn, -1, EINVAL);
 		}
   }
@@ -1037,6 +1066,9 @@ void NetconEthernetTap::handle_socket(PhySocket *sock, void **uptr, struct socke
 {
 	int rpc_fd = _phy.getDescriptor(sock);
 	struct tcp_pcb *newpcb = lwipstack->tcp_new();
+
+	fprintf(stderr, "handle_socket(): pcb=%x, (state == CLOSED) = %d\n", newpcb, (newpcb->state==CLOSED));
+
   if(newpcb != NULL) {
 		ZT_PHY_SOCKFD_TYPE fds[2];
 		if(socketpair(PF_LOCAL, SOCK_STREAM, 0, fds) < 0) {
@@ -1045,6 +1077,7 @@ void NetconEthernetTap::handle_socket(PhySocket *sock, void **uptr, struct socke
 				return;
 			}
 		}
+		fprintf(stderr, "socketpair = {%d, %d}\n", fds[0], fds[1]);
 		TcpConnection *new_conn = new TcpConnection();
 		new_conn->dataSock = _phy.wrapSocket(fds[0], new_conn);
 		*uptr = new_conn;

+ 0 - 1
netcon/NetconUtilities.cpp

@@ -42,7 +42,6 @@
 namespace ZeroTier
 {
 	// Functions used to pass file descriptors between processes
-
 	ssize_t sock_fd_write(int sock, int fd)
 	{
 		ssize_t size;

+ 14 - 1
netcon/README.md

@@ -15,6 +15,7 @@ vsftpd			[BROKEN as of 20151021] Server sends 500 when 220 is expected
 mysql			[BROKEN as of 20151021]
 postresql		[BROKEN as of 20151021]
 MongoDB			[BROKEN as of 20151021]
+Redis-server		[ WORKS as of 20151027]
 pure-ftpd		[BROKEN as of 20151021] Socket operation on non-socket
 
 To Test:
@@ -27,8 +28,16 @@ To Test:
 	Multithreaded software (e.g. apache in thread mode)
 
 
-20151021 Added Node.js support
 
+20151027 Added Redis-server support
+Notes:
+ - Added extra logic to detect socket re-issuing and consequent service-side double mapping.
+   Redis appears to try to set its initial listen socket to IPV6 only, this currently fails. As 
+   a result, Redis will close the socket and re-open it. The server will now test for closures
+   during mapping and will eliminate any mappings to broken pipes.
+
+
+20151021 Added Node.js support
 Notes:
  - syscall(long number, ...) is now intercepted and re-directs the __NR_accept4 call to our intercepted accept4() function
  - accept() now returns -EAGAIN in the case that we cannot read a signal byte from the descriptor linked to the service. This
@@ -40,3 +49,7 @@ Notes:
    This might be unnecessary or might need a better workaround
  - Careful attention should be given to how arguments are passed in the intercepted syscall() function, this differs for 
    32/64-bit systems
+
+
+
+

BIN
netcon/libintercept.so.1.0


+ 1 - 1
netcon/make-intercept.mk

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