diff options
Diffstat (limited to 'netcon')
-rwxr-xr-x | netcon/Intercept.c | 58 | ||||
-rwxr-xr-x | netcon/Intercept.h | 5 | ||||
-rw-r--r-- | netcon/NetconEthernetTap.cpp | 126 | ||||
-rw-r--r-- | netcon/NetconEthernetTap.hpp | 1 | ||||
-rw-r--r-- | netcon/README.md | 8 | ||||
-rwxr-xr-x | netcon/libintercept.so.1.0 | bin | 55752 -> 56400 bytes |
6 files changed, 125 insertions, 73 deletions
diff --git a/netcon/Intercept.c b/netcon/Intercept.c index bbb1d4c0..3a14e538 100755 --- a/netcon/Intercept.c +++ b/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); diff --git a/netcon/Intercept.h b/netcon/Intercept.h index 6f1888a8..71012be3 100755 --- a/netcon/Intercept.h +++ b/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 diff --git a/netcon/NetconEthernetTap.cpp b/netcon/NetconEthernetTap.cpp index 03274b08..4bb524eb 100644 --- a/netcon/NetconEthernetTap.cpp +++ b/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 diff --git a/netcon/NetconEthernetTap.hpp b/netcon/NetconEthernetTap.hpp index f10761db..159e4042 100644 --- a/netcon/NetconEthernetTap.hpp +++ b/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); diff --git a/netcon/README.md b/netcon/README.md index 510466f2..3e454c33 100644 --- a/netcon/README.md +++ b/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. diff --git a/netcon/libintercept.so.1.0 b/netcon/libintercept.so.1.0 Binary files differindex b5caf725..acac7b3b 100755 --- a/netcon/libintercept.so.1.0 +++ b/netcon/libintercept.so.1.0 |