Browse Source

Added support for MongoDB (server side)

Joseph Henry 9 years ago
parent
commit
c8f27da294
6 changed files with 125 additions and 73 deletions
  1. 38 20
      netcon/Intercept.c
  2. 3 2
      netcon/Intercept.h
  3. 76 50
      netcon/NetconEthernetTap.cpp
  4. 1 0
      netcon/NetconEthernetTap.hpp
  5. 7 1
      netcon/README.md
  6. BIN
      netcon/libintercept.so.1.0

+ 38 - 20
netcon/Intercept.c

@@ -170,6 +170,7 @@ void send_command(int rpc_fd, char *cmd)
  */
 int get_retval()
 {
+  dwr("get_retval()\n");
   if(fdret_sock >= 0) {
     int retval;
     int sz = sizeof(char) + sizeof(retval) + sizeof(errno);
@@ -186,6 +187,21 @@ int get_retval()
   return -1;
 }
 
+/* Check whether the socket is mapped to the service or not. We
+need to know if this is a regular AF_LOCAL socket or an end of a socketpair
+that the service uses. We don't want to keep state in the intercept, so
+we simply ask the service via an RPC */
+int is_mapped_to_service(int sockfd)
+{
+  dwr("is_mapped_to_service()\n");
+  char cmd[BUF_SZ];
+  memset(cmd, '\0', BUF_SZ);
+  cmd[0] = RPC_MAP_REQ;
+  memcpy(&cmd[1], &sockfd, sizeof(sockfd));
+  send_command(fdret_sock, cmd);
+  return get_retval();
+}
+
 
 /*------------------------------------------------------------------------------
 ----------  Unix-domain socket lazy initializer (for fd-transfers)--------------
@@ -194,6 +210,7 @@ int get_retval()
 /* Sets up the connection pipes and sockets to the service */
 int init_service_connection()
 {
+  dwr("init_service_connection()\n");
   if(!is_initialized) {
     struct sockaddr_un addr;
     int tfd = -1, attempts = 0, conn_err = -1;
@@ -309,6 +326,7 @@ void set_up_intercept()
 /*------------------------------------------------------------------------------
 --------------------------------- setsockopt() ---------------------------------
 ------------------------------------------------------------------------------*/
+
 /* int socket, int level, int option_name, const void *option_value, socklen_t option_len */
 int setsockopt(SETSOCKOPT_SIG)
 {
@@ -332,8 +350,8 @@ int setsockopt(SETSOCKOPT_SIG)
 /*------------------------------------------------------------------------------
 --------------------------------- getsockopt() ---------------------------------
 ------------------------------------------------------------------------------*/
-/* int sockfd, int level, int optname, void *optval, socklen_t *optlen */
 
+/* int sockfd, int level, int optname, void *optval, socklen_t *optlen */
 int getsockopt(GETSOCKOPT_SIG)
 {
   dwr("setsockopt(%d)\n", sockfd);
@@ -359,7 +377,6 @@ int getsockopt(GETSOCKOPT_SIG)
 
 /* int socket_family, int socket_type, int protocol
    socket() intercept function */
-
 int socket(SOCKET_SIG)
 {
   dwr("socket()*:\n");
@@ -407,7 +424,6 @@ int socket(SOCKET_SIG)
   if(socket_family == AF_LOCAL
     || socket_family == AF_NETLINK
     || socket_family == AF_UNIX) {
-
       int err = realsocket(socket_family, socket_type, protocol);
       dwr("realsocket, err = %d\n", err);
       handle_error("socket", "", err);
@@ -554,7 +570,7 @@ int connect(CONNECT_SIG)
 fd_set *exceptfds, struct timeval *timeout */
 int select(SELECT_SIG)
 {
-  //dwr("select()*:\n");
+  //dwr("select():\n");
   return realselect(n, readfds, writefds, exceptfds, timeout);
 }
 
@@ -592,19 +608,16 @@ int bind(BIND_SIG)
 
   /* If local, just use normal syscall */
   struct sockaddr_in *connaddr;
-  connaddr = (struct sockaddr_in *) addr;
+  connaddr = (struct sockaddr_in *)addr;
 
-  if (addr != NULL && (connaddr->sin_family == AF_LOCAL
-    || connaddr->sin_family == PF_NETLINK
+  if(connaddr->sin_family == AF_LOCAL
     || connaddr->sin_family == AF_NETLINK
-    || connaddr->sin_family == AF_UNIX))
-  {
-    if(realbind == NULL) {
-      handle_error("bind", "Unresolved symbol [bind]", -1);
-      exit(-1);
-    }
-    return(realbind(sockfd, addr, addrlen));
+    || connaddr->sin_family == AF_UNIX) {
+      int err = realbind(sockfd, addr, addrlen);
+      dwr("realbind, err = %d\n", err);
+      return err;
   }
+
   /* Assemble and send RPC */
   char cmd[BUF_SZ];
   struct bind_st rpc_st;
@@ -767,6 +780,9 @@ int accept(ACCEPT_SIG)
 int listen(LISTEN_SIG)
 {
   dwr("listen(%d):\n", sockfd);
+  int sock_type;
+  socklen_t sock_type_len = sizeof(sock_type);
+
   #ifdef CHECKS
   /* Check that this is a valid fd */
   if(fcntl(sockfd, F_GETFD) < 0) {
@@ -775,8 +791,6 @@ int listen(LISTEN_SIG)
     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);
@@ -794,6 +808,13 @@ int listen(LISTEN_SIG)
   if(sockfd == STDIN_FILENO || sockfd == STDOUT_FILENO || sockfd == STDERR_FILENO)
     return(reallisten(sockfd, backlog));
 
+  if(!is_mapped_to_service(sockfd)) {
+    // We now know this socket is not one of our socketpairs
+    int err = reallisten(sockfd, backlog);
+    dwr("reallisten()=%d\n", err);
+    return err;
+  }
+
   /* Assemble and send RPC */
   char cmd[BUF_SZ];
   memset(cmd, '\0', BUF_SZ);
@@ -811,9 +832,6 @@ int listen(LISTEN_SIG)
   return ERR_OK;
 }
 
-
-
-
 /*------------------------------------------------------------------------------
 -------------------------------------- clone()----------------------------------
 ------------------------------------------------------------------------------*/
@@ -849,7 +867,7 @@ int poll(POLL_SIG)
 
 long syscall(SYSCALL_SIG)
 {
-  dwr("syscall():\n");
+  //dwr("syscall(%u, ...):\n", number);
   va_list ap;
   uintptr_t a,b,c,d,e,f;
   va_start(ap, number);

+ 3 - 2
netcon/Intercept.h

@@ -51,8 +51,9 @@
 
 /* Administration RPC codes */
 #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
+#define RPC_MAP_REQ							21  // A call to determine whether an fd is mapped to the service
+#define RPC_RETVAL							22	// not RPC per se, but something we should codify
+#define RPC_KILL_INTERCEPT			23  // Tells the service we need to shut down all connections
 
 /* Connection statuses */
 #define UNSTARTED								0

+ 76 - 50
netcon/NetconEthernetTap.cpp

@@ -490,6 +490,10 @@ void NetconEthernetTap::phyOnUnixData(PhySocket *sock,void **uptr,void *data,uns
 			fprintf(stderr, "RPC_MAP\n");
 	    handle_retval(sock, uptr, buf);
 			break;
+		case RPC_MAP_REQ:
+			fprintf(stderr, "RPC_MAP_REQ\n");
+			handle_map_request(sock, uptr, buf);
+			break;
 		default:
 			break;
 	}
@@ -843,6 +847,29 @@ err_t NetconEthernetTap::nc_connected(void *arg, struct tcp_pcb *tpcb, err_t err
 ----------------------------- RPC Handler functions ----------------------------
 ------------------------------------------------------------------------------*/
 
+/*
+	Responds to a request from the [intercept] to determine whether a local socket is
+	mapped to this service. In other words, how do the intercept's overridden calls
+	tell the difference between regular AF_LOCAL sockets and one of our socketpairs
+	that is used to communicate over the network?
+*/
+void NetconEthernetTap::handle_map_request(PhySocket *sock, void **uptr, unsigned char* buf)
+{
+	TcpConnection *conn = (TcpConnection*)*uptr;
+	int req_fd;
+	memcpy(&req_fd, &buf[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
+			fprintf(stderr, " handle_map_request(their=%d): MAPPED (to %d)\n", req_fd,
+				_phy.getDescriptor(tcp_connections[i]->dataSock));
+			return;
+		}
+	}
+	send_return_value(conn, 0, ERR_OK); // False
+	fprintf(stderr, " handle_map_request(their=%d): NOT MAPPED\n", req_fd);
+}
+
 /**
  * Handles a return value (client's perceived fd) and completes a mapping
  * so that we know what connection an RPC call should be associated with.
@@ -861,7 +888,7 @@ void NetconEthernetTap::handle_retval(PhySocket *sock, void **uptr, unsigned cha
 	memcpy(&(conn->perceived_fd), &buf[1], sizeof(int));
 	conn->pending = false;
 
-	fprintf(stderr, "handle_retval(): CONN:%x - Mapping [our=%d -> their=%d]\n",conn,
+	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 ---
@@ -878,11 +905,11 @@ void NetconEthernetTap::handle_retval(PhySocket *sock, void **uptr, unsigned cha
 			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]);
+					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);
+					fprintf(stderr, " handle_retval(): CONN:%x - This socket is mapped to two different pipes (?). Exiting.\n", conn);
 					exit(0);
 				}
 			}
@@ -943,8 +970,9 @@ void NetconEthernetTap::handle_bind(PhySocket *sock, void **uptr, struct bind_st
 				d[1] = (ip >>  8) & 0xFF;
 				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);
+				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, " handle_bind(): err = %d\n", err);
+
 				if(err == ERR_USE)
 					send_return_value(conn, -1, EADDRINUSE);
 				if(err == ERR_MEM)
@@ -956,12 +984,12 @@ 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 (%x) not in CLOSED state. Ignoring BIND request.\n", conn->pcb);
+			fprintf(stderr, " handle_bind(): PCB (%x) not in CLOSED state. Ignoring BIND request.\n", conn->pcb);
 			send_return_value(conn, -1, EINVAL);
 		}
   }
   else {
-		fprintf(stderr, "handle_bind(): can't locate connection for PCB\n");
+		fprintf(stderr, " handle_bind(): can't locate connection for PCB\n");
 		send_return_value(conn, -1, EBADF);
 	}
 }
@@ -987,48 +1015,47 @@ void NetconEthernetTap::handle_bind(PhySocket *sock, void **uptr, struct bind_st
  */
 void NetconEthernetTap::handle_listen(PhySocket *sock, void **uptr, struct listen_st *listen_rpc)
 {
+	fprintf(stderr, " handle_listen(their=%d):\n", listen_rpc->sockfd);
 	TcpConnection *conn = getConnectionByTheirFD(sock, listen_rpc->sockfd);
-  if(conn) {
-    if(conn->pcb->state == LISTEN) {
-      fprintf(stderr, "handle_listen(): PCB is already in listening state.\n");
-      return;
-    }
-		struct tcp_pcb* listening_pcb;
+	if(!conn){
+		fprintf(stderr, " handle_listen(): unable to locate connection object\n");
+		// ? send_return_value(conn, -1, EBADF);
+		return;
+	}
+	fprintf(stderr, " handle_listen(our=%d -> their=%d)\n", _phy.getDescriptor(conn->dataSock), conn->perceived_fd);
+
+  if(conn->pcb->state == LISTEN) {
+    fprintf(stderr, " handle_listen(): PCB is already in listening state.\n");
+    return;
+  }
+	struct tcp_pcb* listening_pcb;
 
 #ifdef TCP_LISTEN_BACKLOG
-			listening_pcb = lwipstack->tcp_listen_with_backlog(conn->pcb, listen_rpc->backlog);
+		listening_pcb = lwipstack->tcp_listen_with_backlog(conn->pcb, listen_rpc->backlog);
 #else
-			listening_pcb = lwipstack->tcp_listen(conn->pcb);
+		listening_pcb = lwipstack->tcp_listen(conn->pcb);
 #endif
 
-    if(listening_pcb != NULL) {
-      conn->pcb = listening_pcb;
-      lwipstack->tcp_accept(listening_pcb, nc_accept);
-			lwipstack->tcp_arg(listening_pcb, new Larg(this, conn));
-			/* we need to wait for the client to send us the fd allocated on their end
-			for this listening socket */
-			fcntl(_phy.getDescriptor(conn->dataSock), F_SETFL, O_NONBLOCK);
-			conn->listening = true;
-			conn->pending = true;
-			send_return_value(conn, ERR_OK, ERR_OK);
-    }
-    else {
-			/*
-			fprintf(stderr, "handle_listen(): unable to allocate memory for new listening PCB\n");
-			 // FIXME: This does not have an equivalent errno value
-			 // lwip will reclaim space with a tcp_listen call since a PCB in a LISTEN
-			 // state takes up less space. If something goes wrong during the creation of a
-			 // new listening socket we should return an error that implies we can't use this
-			 // socket, even if the reason isn't describing what really happened internally.
-			 // See: http://lwip.wikia.com/wiki/Raw/TCP
-			send_return_value(conn, -1, EBADF);
-    	*/
-		}
+  if(listening_pcb != NULL) {
+    conn->pcb = listening_pcb;
+    lwipstack->tcp_accept(listening_pcb, nc_accept);
+		lwipstack->tcp_arg(listening_pcb, new Larg(this, conn));
+		/* we need to wait for the client to send us the fd allocated on their end
+		for this listening socket */
+		fcntl(_phy.getDescriptor(conn->dataSock), F_SETFL, O_NONBLOCK);
+		conn->listening = true;
+		conn->pending = true;
+		send_return_value(conn, ERR_OK, ERR_OK);
   }
   else {
 		/*
-		// We can't find a connection mapped to the socket fd provided
-    fprintf(stderr, "handle_listen(): can't locate connection for PCB\n");
+		fprintf(stderr, "handle_listen(): unable to allocate memory for new listening PCB\n");
+		 // FIXME: This does not have an equivalent errno value
+		 // lwip will reclaim space with a tcp_listen call since a PCB in a LISTEN
+		 // state takes up less space. If something goes wrong during the creation of a
+		 // new listening socket we should return an error that implies we can't use this
+		 // socket, even if the reason isn't describing what really happened internally.
+		 // See: http://lwip.wikia.com/wiki/Raw/TCP
 		send_return_value(conn, -1, EBADF);
   	*/
 	}
@@ -1067,7 +1094,7 @@ 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));
+	fprintf(stderr, " handle_socket(): pcb=%x\n", newpcb);
 
   if(newpcb != NULL) {
 		ZT_PHY_SOCKFD_TYPE fds[2];
@@ -1077,7 +1104,7 @@ void NetconEthernetTap::handle_socket(PhySocket *sock, void **uptr, struct socke
 				return;
 			}
 		}
-		fprintf(stderr, "socketpair = {%d, %d}\n", fds[0], fds[1]);
+		fprintf(stderr, " handle_socket(): 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;
@@ -1092,7 +1119,7 @@ void NetconEthernetTap::handle_socket(PhySocket *sock, void **uptr, struct socke
   }
   else {
 		sock_fd_write(rpc_fd, -1); // Send a bad fd, to signal error
-    fprintf(stderr, "handle_socket(): Memory not available for new PCB\n");
+    fprintf(stderr, " handle_socket(): Memory not available for new PCB\n");
 		send_return_value(rpc_fd, -1, ENOMEM);
   }
 }
@@ -1194,14 +1221,14 @@ void NetconEthernetTap::handle_connect(PhySocket *sock, void **uptr, struct conn
 			//   that's it!
 			// - Most instances of a retval for a connect() should happen
 			//   in the nc_connect() and nc_err() callbacks!
-			fprintf(stderr, "handle_connect(): unable to connect\n");
+			fprintf(stderr, " handle_connect(): unable to connect\n");
 			send_return_value(conn, -1, EAGAIN);
 		}
 		// Everything seems to be ok, but we don't have enough info to retval
 		conn->pending=true;
 	}
 	else {
-		fprintf(stderr, "could not locate PCB based on their fd\n");
+		fprintf(stderr, " handle_connect(): could not locate PCB based on their fd\n");
 		send_return_value(conn, -1, EBADF);
 	}
 }
@@ -1213,12 +1240,12 @@ void NetconEthernetTap::handle_write(TcpConnection *conn)
 	int r;
 
 	if(!conn) {
-		fprintf(stderr, "handle_write(): could not locate connection for this fd\n");
+		fprintf(stderr, " handle_write(): could not locate connection for this fd\n");
 		return;
 	}
 	if(conn->idx < max) {
 		if(!conn->pcb) {
-			fprintf(stderr, "handle_write(): conn->pcb == NULL. Failed to write.\n");
+			fprintf(stderr, " handle_write(): conn->pcb == NULL. Failed to write.\n");
 			return;
 		}
 		int sndbuf = conn->pcb->snd_buf; // How much we are currently allowed to write to the connection
@@ -1245,7 +1272,7 @@ void NetconEthernetTap::handle_write(TcpConnection *conn)
 					int err = lwipstack->_tcp_write(conn->pcb, &conn->buf, r, TCP_WRITE_FLAG_COPY);
 					lwipstack->_tcp_output(conn->pcb);
 					if(err != ERR_OK) {
-						fprintf(stderr, "handle_write(): error while writing to PCB, (err = %d)\n", err);
+						fprintf(stderr, " handle_write(): error while writing to PCB, (err = %d)\n", err);
 						return;
 					}
 					else {
@@ -1258,7 +1285,7 @@ void NetconEthernetTap::handle_write(TcpConnection *conn)
 					}
 				}
 				else {
-					fprintf(stderr, "handle_write(): LWIP stack full\n");
+					fprintf(stderr, " handle_write(): LWIP stack full\n");
 					return;
 				}
 			}
@@ -1266,7 +1293,6 @@ void NetconEthernetTap::handle_write(TcpConnection *conn)
 	}
 }
 
-
 } // namespace ZeroTier
 
 #endif // ZT_ENABLE_NETCON

+ 1 - 0
netcon/NetconEthernetTap.hpp

@@ -106,6 +106,7 @@ private:
 	// RPC handlers (from NetconIntercept)
 	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_socket(PhySocket *sock, void **uptr, struct socket_st* socket_rpc);
 	void handle_connect(PhySocket *sock, void **uptr, struct connect_st* connect_rpc);

+ 7 - 1
netcon/README.md

@@ -108,7 +108,7 @@ Network Containers have been tested with the following:
 	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]
+	MongoDB			[ WORKS as of 20151021] Only basic connection tested, no DB operations yet
 	Redis-server		[ WORKS as of 20151027]
 	pure-ftpd		[BROKEN as of 20151021] Socket operation on non-socket
 
@@ -125,6 +125,12 @@ To Test:
 
 ### Extended Version Notes
 
+20151028 Added MongoDB support:
+
+	- Added logic (RPC_MAP_REQ) to check whether a given AF_LOCAL socket is mapped to anything
+	inside the service instance. 
+
+
 20151027 Added Redis-server support:
 
 	- Added extra logic to detect socket re-issuing and consequent service-side double mapping.

BIN
netcon/libintercept.so.1.0