mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2024-12-19 21:17:52 +00:00
Added support for Redis
This commit is contained in:
parent
8cfee8a38c
commit
721d58b464
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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; 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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
Binary file not shown.
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user