diff --git a/netcon/Common.c b/netcon/Common.c index beb530c62..59d6648f9 100755 --- a/netcon/Common.c +++ b/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 diff --git a/netcon/Intercept.c b/netcon/Intercept.c index 2a32be17b..bbb1d4c07 100755 --- a/netcon/Intercept.c +++ b/netcon/Intercept.c @@ -43,6 +43,7 @@ char *progname = ""; #include #include #include +#include #include #include #include @@ -50,6 +51,7 @@ char *progname = ""; #include #include #include +#include #include #include @@ -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); diff --git a/netcon/Intercept.h b/netcon/Intercept.h index 9b9d5a976..6f1888a81 100755 --- a/netcon/Intercept.h +++ b/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 diff --git a/netcon/NetconEthernetTap.cpp b/netcon/NetconEthernetTap.cpp index cc72ef919..03274b089 100644 --- a/netcon/NetconEthernetTap.cpp +++ b/netcon/NetconEthernetTap.cpp @@ -188,7 +188,7 @@ void NetconEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType return; } memcpy(q->payload,ðhdr,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; irpcSock == 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; diff --git a/netcon/NetconUtilities.cpp b/netcon/NetconUtilities.cpp index fdfef369f..642d77bab 100644 --- a/netcon/NetconUtilities.cpp +++ b/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; diff --git a/netcon/README.md b/netcon/README.md index 9cc1b1bbd..b0c8ebbe8 100644 --- a/netcon/README.md +++ b/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 + + + + diff --git a/netcon/libintercept.so.1.0 b/netcon/libintercept.so.1.0 index a75d6ac02..356514297 100755 Binary files a/netcon/libintercept.so.1.0 and b/netcon/libintercept.so.1.0 differ diff --git a/netcon/make-intercept.mk b/netcon/make-intercept.mk index a16ff7e7f..fbae717f4 100644 --- a/netcon/make-intercept.mk +++ b/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