diff options
-rw-r--r-- | make-linux.mk | 2 | ||||
-rwxr-xr-x | netcon/Intercept.c | 7 | ||||
-rwxr-xr-x | netcon/Intercept.h | 3 | ||||
-rw-r--r-- | netcon/NetconEthernetTap.cpp | 278 | ||||
-rw-r--r-- | netcon/NetconEthernetTap.hpp | 8 | ||||
-rw-r--r-- | netcon/NetconService.hpp | 3 | ||||
-rw-r--r-- | netcon/NetconUtilities.cpp | 40 | ||||
-rw-r--r-- | netcon/NetconUtilities.hpp | 5 | ||||
-rwxr-xr-x | netcon/libintercept.so.1.0 | bin | 56400 -> 56400 bytes | |||
-rw-r--r-- | osdep/Phy.hpp | 8 |
10 files changed, 254 insertions, 100 deletions
diff --git a/make-linux.mk b/make-linux.mk index 2f60597c..af8d3967 100644 --- a/make-linux.mk +++ b/make-linux.mk @@ -85,7 +85,7 @@ else CFLAGS+=-Wall -fPIE -fvisibility=hidden -pthread $(INCLUDES) -DNDEBUG $(DEFS) CXXFLAGS?=-O3 -fstack-protector CXXFLAGS+=-Wall -Wreorder -fPIE -fvisibility=hidden -fno-rtti -pthread $(INCLUDES) -DNDEBUG $(DEFS) - LDFLAGS=-ldl -pie -Wl,-z,relro,-z,now + LDFLAGS=-ldl -lcurses -pie -Wl,-z,relro,-z,now STRIP=strip --strip-all endif diff --git a/netcon/Intercept.c b/netcon/Intercept.c index 3a14e538..27e57c76 100755 --- a/netcon/Intercept.c +++ b/netcon/Intercept.c @@ -202,7 +202,6 @@ int is_mapped_to_service(int sockfd) return get_retval(); } - /*------------------------------------------------------------------------------ ---------- Unix-domain socket lazy initializer (for fd-transfers)-------------- ------------------------------------------------------------------------------*/ @@ -439,10 +438,10 @@ int socket(SOCKET_SIG) memset(cmd, '\0', BUF_SZ); cmd[0] = RPC_SOCKET; - memcpy(&cmd[1], &rpc_st, sizeof(struct socket_st)); + dwr("pid = %d\n", thispid); + memcpy(&cmd[1], &thispid, sizeof(pid_t)); + memcpy(&cmd[1]+sizeof(pid_t), &rpc_st, sizeof(struct socket_st)); pthread_mutex_lock(&lock); - - dwr("sending RPC...\n"); send_command(fdret_sock, cmd); /* get new fd */ diff --git a/netcon/Intercept.h b/netcon/Intercept.h index 71012be3..86fb0049 100755 --- a/netcon/Intercept.h +++ b/netcon/Intercept.h @@ -31,7 +31,7 @@ #include <sys/socket.h> -#define BUF_SZ 32 +#define BUF_SZ 128 #define ERR_OK 0 /* Userland RPC codes */ @@ -54,6 +54,7 @@ #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 +#define RPC_I_AM 24 // Tells the service the PID for the current client /* Connection statuses */ #define UNSTARTED 0 diff --git a/netcon/NetconEthernetTap.cpp b/netcon/NetconEthernetTap.cpp index a50eb30e..dd49a186 100644 --- a/netcon/NetconEthernetTap.cpp +++ b/netcon/NetconEthernetTap.cpp @@ -49,9 +49,11 @@ #include "Intercept.h" #include "NetconUtilities.hpp" +#include <curses.h> + #define APPLICATION_POLL_FREQ 20 #define ZT_LWIP_TCP_TIMER_INTERVAL 10 -#define STATUS_TMR_INTERVAL 2000 // How often we check connection statuses +#define STATUS_TMR_INTERVAL 100 // How often we check connection statuses namespace ZeroTier { @@ -85,6 +87,7 @@ NetconEthernetTap::NetconEthernetTap( lwipstack->lwip_init(); _unixListenSocket = _phy.unixListen(sockPath,(void *)this); + dwr(" NetconEthernetTap(): RPC listening on: %d\n", _phy.getDescriptor(_unixListenSocket)); if (!_unixListenSocket) throw std::runtime_error(std::string("unable to bind to ")+sockPath); _thread = Thread::start(this); @@ -184,7 +187,7 @@ void NetconEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType // First pbuf gets ethernet header at start q = p; if (q->len < sizeof(ethhdr)) { - fprintf(stderr,"_put(): Dropped packet: first pbuf smaller than ethernet header\n"); + dwr("_put(): Dropped packet: first pbuf smaller than ethernet header\n"); return; } memcpy(q->payload,ðhdr,sizeof(ethhdr)); @@ -197,14 +200,14 @@ void NetconEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType dataptr += q->len; } } else { - fprintf(stderr, "_put(): Dropped packet: no pbufs available\n"); + dwr("_put(): Dropped packet: no pbufs available\n"); return; } { Mutex::Lock _l2(lwipstack->_lock); if(interface.input(p, &interface) != ERR_OK) { - fprintf(stderr, "_put(): Error while RXing packet (netif->input)\n"); + dwr("_put(): Error while RXing packet (netif->input)\n"); } } } @@ -243,22 +246,84 @@ void NetconEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,s _multicastGroups.swap(newGroups); } -TcpConnection *NetconEthernetTap::getConnectionByPCB(struct tcp_pcb *pcb) +TcpConnection *NetconEthernetTap::getConnectionByTheirFD(PhySocket *sock, int fd) { for(size_t i=0; i<tcp_connections.size(); i++) { - if(tcp_connections[i]->pcb == pcb) + if(tcp_connections[i]->perceived_fd == fd && tcp_connections[i]->rpcSock == sock) return tcp_connections[i]; } return NULL; } -TcpConnection *NetconEthernetTap::getConnectionByTheirFD(PhySocket *sock, int fd) +/* + * Dumps service state in 80x25 when debug mode is off + */ +void NetconEthernetTap::compact_dump() { - for(size_t i=0; i<tcp_connections.size(); i++) { - if(tcp_connections[i]->perceived_fd == fd && tcp_connections[i]->rpcSock == sock) - return tcp_connections[i]; + /* + //clearscreen(); + refresh(); + clear(); + gotoxy(0,0); + fprintf(stderr, "ZeroTier - Network Containers Service [State Dump]\n\r"); + fprintf(stderr, " RPC Sockets = %d\n\r", rpc_sockets.size()); + fprintf(stderr, " TCP Connections = %d\n\r", tcp_connections.size()); + */ +} + +/* + * Dumps service state + */ +void NetconEthernetTap::dump() +{ + clearscreen(); + gotoxy(0,0); + fprintf(stderr, "\n\n---\n\ndie(): BEGIN SERVICE STATE DUMP\n"); + fprintf(stderr, "*** IF YOU SEE THIS, EMAIL THE DUMP TEXT TO joseph.henry@zerotier.com ***\n"); + fprintf(stderr, " tcp_conns = %d, rpc_socks = %d\n", tcp_connections.size(), rpc_sockets.size()); + + // TODO: Add logic to detect bad mapping conditions + for(size_t i=0; i<rpc_sockets.size(); i++) { + for(size_t j=0; j<rpc_sockets.size(); j++) { + if(j != i && rpc_sockets[i] == rpc_sockets[j]) { + fprintf(stderr, "Duplicate PhySockets found! (0x%x)\n", rpc_sockets[i]); + } + } } - return NULL; + + // Dump the state of the service mapping + for(size_t i=0; i<rpc_sockets.size(); i++) { + int rpc_fd = _phy.getDescriptor(rpc_sockets[i]); + char buf[80]; + int pid = pidmap[rpc_sockets[i]]; + get_path_from_pid(buf, pid); + + fprintf(stderr, "\nClient(addr=0x%x, rpc=%d, pid=%d) %s\n", rpc_sockets[i], rpc_fd, pid, buf); + for(size_t j=0; j<tcp_connections.size(); j++) { + get_path_from_pid(buf, tcp_connections[j]->pid); + if(tcp_connections[j]->rpcSock==rpc_sockets[i]){ + fprintf(stderr, " |\n"); + fprintf(stderr, " | Connection(0x%x):\n", tcp_connections[j]); + fprintf(stderr, " | path\t\t\t= %s\n", buf); + fprintf(stderr, " | perceived_fd\t\t= %d\t(fd)\n", tcp_connections[j]->perceived_fd); + fprintf(stderr, " | their_fd\t\t= %d\t(fd)\n", tcp_connections[j]->their_fd); + fprintf(stderr, " | dataSock(0x%x)\t= %d\t(fd)\n", tcp_connections[j]->dataSock, _phy.getDescriptor(tcp_connections[j]->dataSock)); + fprintf(stderr, " | rpcSock(0x%x)\t= %d\t(fd)\n", tcp_connections[j]->rpcSock, _phy.getDescriptor(tcp_connections[j]->rpcSock)); + fprintf(stderr, " | pending\t\t= %d\n", tcp_connections[j]->pending); + fprintf(stderr, " | listening\t\t= %d\n", tcp_connections[j]->listening); + fprintf(stderr, " \\------pcb(0x%x)->state\t= %d\n", tcp_connections[j]->pcb, tcp_connections[j]->pcb->state); + } + } + } + fprintf(stderr, "\n\ndie(): END SERVICE STATE DUMP\n\n---\n\n"); +} + +/* + * Dumps service state and then exits + */ +void NetconEthernetTap::die(int exret) { + dump(); + exit(exret); } /* @@ -266,7 +331,7 @@ TcpConnection *NetconEthernetTap::getConnectionByTheirFD(PhySocket *sock, int fd */ void NetconEthernetTap::closeConnection(TcpConnection *conn) { - fprintf(stderr, "closeConnection(%x, %d)\n", conn->pcb, _phy.getDescriptor(conn->dataSock)); + fprintf(stderr, " closeConnection(%x, %d)\n", conn->pcb, _phy.getDescriptor(conn->dataSock)); //lwipstack->_tcp_sent(conn->pcb, NULL); //lwipstack->_tcp_recv(conn->pcb, NULL); @@ -319,6 +384,7 @@ void NetconEthernetTap::closeAll() void NetconEthernetTap::threadMain() throw() { + //initscr(); //signal(SIGPIPE, SIG_IGN); uint64_t prev_tcp_time = 0; uint64_t prev_status_time = 0; @@ -345,7 +411,6 @@ void NetconEthernetTap::threadMain() // Main timer loop while (_run) { uint64_t now = OSUtils::now(); - uint64_t since_tcp = now - prev_tcp_time; uint64_t since_etharp = now - prev_etharp_time; uint64_t since_status = now - prev_status_time; @@ -353,9 +418,13 @@ void NetconEthernetTap::threadMain() uint64_t etharp_remaining = ARP_TMR_INTERVAL; uint64_t status_remaining = STATUS_TMR_INTERVAL; + // Connection prunning if (since_status >= STATUS_TMR_INTERVAL) { + //compact_dump(); prev_status_time = now; if(rpc_sockets.size() || tcp_connections.size()) { + + //dump(); /* Here we will periodically check the list of rpc_sockets for those that do not currently have any data connection associated with them. If they are unused, then we will try to read from them, if they fail, we can safely assume @@ -368,14 +437,14 @@ void NetconEthernetTap::threadMain() } else { // Here we should handle the case there there is incoming data (?) - fprintf(stderr, "Listening socketpair closed. Removing RPC connection (%d)\n", + dwr(" tap_thread(): Listening socketpair closed. Removing RPC connection (%d)\n", _phy.getDescriptor(tcp_connections[i]->dataSock)); closeConnection(tcp_connections[i]); } } } } - fprintf(stderr, "tcp_conns = %d, rpc_socks = %d\n", tcp_connections.size(), rpc_sockets.size()); + dwr(" tap_thread(): tcp_conns = %d, rpc_socks = %d\n", tcp_connections.size(), rpc_sockets.size()); for(size_t i=0, associated = 0; i<rpc_sockets.size(); i++, associated = 0) { for(size_t j=0; j<tcp_connections.size(); j++) { if (tcp_connections[j]->rpcSock == rpc_sockets[i]) @@ -383,20 +452,26 @@ void NetconEthernetTap::threadMain() } if(!associated){ // No TCP connections are associated, this is a candidate for removal + int fd = _phy.getDescriptor(rpc_sockets[i]); + fcntl(fd, F_SETFL, O_NONBLOCK); 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])); + int n; + if((n = read(fd,&tmpbuf,BUF_SZ)) < 0) { + dwr(" tap_thread(): RPC close(%d)\n", _phy.getDescriptor(rpc_sockets[i])); closeClient(rpc_sockets[i]); } - else { + // < 0 is failure + // 0 nothing to read, RPC still active + // > 0 RPC data read, handle it + else if (n > 0) { // Handle RPC call, this is rare - fprintf(stderr, "run(): RPC read during connection check\n"); - exit(0); // FIXME: This should be addressed - Raise APPLICATION_POLL_FREQ to make it less likely - phyOnUnixData(rpc_sockets[i],NULL,&tmpbuf,BUF_SZ); + dwr(" tap_thread(): RPC read during connection check (%d bytes)\n", n); + phyOnUnixData(rpc_sockets[i],_phy.getuptr(rpc_sockets[i]),&tmpbuf,BUF_SZ); } } } } + // Main TCP/ETHARP timer section if (since_tcp >= ZT_LWIP_TCP_TIMER_INTERVAL) { prev_tcp_time = now; lwipstack->tcp_tmr(); @@ -444,7 +519,7 @@ void NetconEthernetTap::phyOnFileDescriptorActivity(PhySocket *sock,void **uptr, } } else { - fprintf(stderr, "phyOnFileDescriptorActivity(): PhySocket not readable\n"); + dwr("phyOnFileDescriptorActivity(): PhySocket not readable\n"); } } @@ -452,6 +527,11 @@ void NetconEthernetTap::phyOnFileDescriptorActivity(PhySocket *sock,void **uptr, * Add a new PhySocket for the client connection */ void NetconEthernetTap::phyOnUnixAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN) { + if(find(rpc_sockets.begin(), rpc_sockets.end(), sockN) != rpc_sockets.end()){ + dwr("SockN (0x%x) already exists!\n", sockN); + return; + } + dwr("phyOnUnixAccept(): push_back( 0x%x )\n", sockN); rpc_sockets.push_back(sockN); } @@ -464,42 +544,63 @@ void NetconEthernetTap::phyOnUnixData(PhySocket *sock,void **uptr,void *data,uns switch(buf[0]) { case RPC_SOCKET: - fprintf(stderr, "RPC_SOCKET\n"); + dwr("RPC_SOCKET\n"); struct socket_st socket_rpc; - memcpy(&socket_rpc, &buf[1], sizeof(struct socket_st)); - handle_socket(sock, uptr, &socket_rpc); + pid_t pid; + memcpy(&pid, &buf[1], sizeof(pid_t)); // PID for client RPC tracking (only for debug) + memcpy(&socket_rpc, &buf[64], sizeof(struct socket_st)); + if(handle_socket(sock, uptr, &socket_rpc) >= 0) { + fprintf(stderr, "pidmap[...] = %d\n", pid); + pidmap[sock] = pid; + } break; case RPC_LISTEN: - fprintf(stderr, "RPC_LISTEN\n"); + dwr("RPC_LISTEN\n"); struct listen_st listen_rpc; memcpy(&listen_rpc, &buf[1], sizeof(struct listen_st)); handle_listen(sock, uptr, &listen_rpc); break; case RPC_BIND: - fprintf(stderr, "RPC_BIND\n"); + dwr("RPC_BIND\n"); struct bind_st bind_rpc; memcpy(&bind_rpc, &buf[1], sizeof(struct bind_st)); handle_bind(sock, uptr, &bind_rpc); break; case RPC_CONNECT: - fprintf(stderr, "RPC_CONNECT\n"); + dwr("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_MAP: - fprintf(stderr, "RPC_MAP\n"); + dwr("RPC_MAP\n"); handle_retval(sock, uptr, buf); break; case RPC_MAP_REQ: - fprintf(stderr, "RPC_MAP_REQ\n"); + dwr("RPC_MAP_REQ\n"); handle_map_request(sock, uptr, buf); break; + case RPC_I_AM: + dwr("RPC_I_AM\n"); + handle_i_am(sock, uptr, buf); + break; default: break; } } + +void NetconEthernetTap::handle_i_am(PhySocket *sock, void **uptr, unsigned char* buf) +{ + TcpConnection *conn = (TcpConnection*)*uptr; + if(!conn) + return; + int pid; + memcpy(&pid, &buf[1], sizeof(pid)); + dwr(" pid = %d\n", pid); + conn->pid = pid; +} + /* * Send a 'retval' and 'errno' to the client for an RPC over connection->rpcSock */ @@ -510,7 +611,7 @@ int NetconEthernetTap::send_return_value(TcpConnection *conn, int retval, int _e if(n > 0) conn->pending = false; else { - fprintf(stderr, "Unable to send return value to the intercept. Closing connection\n"); + dwr("Unable to send return value to the intercept. Closing connection\n"); closeConnection(conn); } return n; @@ -579,7 +680,7 @@ int NetconEthernetTap::send_return_value(int fd, int retval, int _errno = 0) */ err_t NetconEthernetTap::nc_accept(void *arg, struct tcp_pcb *newpcb, err_t err) { - fprintf(stderr, "nc_accept()\n"); + dwr("nc_accept()\n"); Larg *l = (Larg*)arg; TcpConnection *conn = l->conn; NetconEthernetTap *tap = l->tap; @@ -590,7 +691,7 @@ err_t NetconEthernetTap::nc_accept(void *arg, struct tcp_pcb *newpcb, err_t err) if(socketpair(PF_LOCAL, SOCK_STREAM, 0, fds) < 0) { if(errno < 0) { l->tap->send_return_value(conn, -1, errno); - fprintf(stderr, "nc_accept(): unable to create socketpair\n"); + dwr("nc_accept(): unable to create socketpair\n"); return ERR_MEM; } } @@ -600,12 +701,12 @@ 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]); + dwr("socketpair = {%d, %d}\n", fds[0], fds[1]); int n, send_fd = tap->_phy.getDescriptor(conn->rpcSock); - fprintf(stderr, "write(%d,...)\n", listening_fd); + dwr("write(%d,...)\n", listening_fd); //int n = write(listening_fd, "z", 1); // accept() in library waits for this byte if((n = send(listening_fd, "z", 1, MSG_NOSIGNAL)) < 0) { - fprintf(stderr, " nc_accept(): Error: [send(listening_fd,...) = MSG_NOSIGNAL].\n"); + dwr(" nc_accept(): Error: [send(listening_fd,...) = MSG_NOSIGNAL].\n"); return -1; } else if(n > 0) { @@ -614,11 +715,11 @@ err_t NetconEthernetTap::nc_accept(void *arg, struct tcp_pcb *newpcb, err_t err) new_tcp_conn->pending = true; } else { - fprintf(stderr, "nc_accept(%d): unable to send fd to client\n", listening_fd); + dwr("nc_accept(%d): unable to send fd to client\n", listening_fd); } } else { - fprintf(stderr, "nc_accept(%d): error writing signal byte (send_fd = %d, perceived_fd = %d)\n", listening_fd, send_fd, fds[1]); + dwr("nc_accept(%d): error writing signal byte (send_fd = %d, perceived_fd = %d)\n", listening_fd, send_fd, fds[1]); return -1; } tap->lwipstack->_tcp_arg(newpcb, new Larg(tap, new_tcp_conn)); @@ -630,7 +731,7 @@ err_t NetconEthernetTap::nc_accept(void *arg, struct tcp_pcb *newpcb, err_t err) return ERR_OK; } else { - fprintf(stderr, "nc_accept(%d): can't locate Connection object for PCB.\n", listening_fd); + dwr("nc_accept(%d): can't locate Connection object for PCB.\n", listening_fd); } return -1; } @@ -655,16 +756,16 @@ err_t NetconEthernetTap::nc_recved(void *arg, struct tcp_pcb *tpcb, struct pbuf struct pbuf* q = p; if(!l->conn) { - fprintf(stderr, "nc_recved(): no connection object\n"); + dwr("nc_recved(): no connection object\n"); return ERR_OK; // ? } if(p == NULL) { if(l->conn) { - fprintf(stderr, "nc_recved(): closing connection\n"); + dwr("nc_recved(): closing connection\n"); l->tap->closeConnection(l->conn); } else { - fprintf(stderr, "nc_recved(): can't locate connection via (arg)\n"); + dwr("nc_recved(): can't locate connection via (arg)\n"); } return err; } @@ -674,12 +775,12 @@ err_t NetconEthernetTap::nc_recved(void *arg, struct tcp_pcb *tpcb, struct pbuf break; // ? if((n = l->tap->_phy.streamSend(l->conn->dataSock,p->payload, p->len)) > 0) { if(n < p->len) { - fprintf(stderr, "nc_recved(): unable to write entire pbuf to buffer\n"); + dwr("nc_recved(): unable to write entire pbuf to buffer\n"); } l->tap->lwipstack->_tcp_recved(tpcb, n); // TODO: would it be more efficient to call this once at the end? } else { - fprintf(stderr, "nc_recved(): No data written to intercept buffer\n"); + dwr("nc_recved(): No data written to intercept buffer\n"); } p = p->next; } @@ -700,52 +801,50 @@ err_t NetconEthernetTap::nc_recved(void *arg, struct tcp_pcb *tpcb, struct pbuf void NetconEthernetTap::nc_err(void *arg, err_t err) { Larg *l = (Larg*)arg; - //fprintf(stderr, "larg = %x, nc_err() = %d\n", l, err); - if(!l->conn) - fprintf(stderr, "nc_err(): Connection is NULL!\n"); + dwr("nc_err(): Connection is NULL!\n"); if(l->conn) { switch(err) { case ERR_MEM: - fprintf(stderr, "nc_err(): ERR_MEM->ENOMEM\n"); + dwr("nc_err(): ERR_MEM->ENOMEM\n"); l->tap->send_return_value(l->conn, -1, ENOMEM); break; case ERR_BUF: - fprintf(stderr, "nc_err(): ERR_BUF->ENOBUFS\n"); + dwr("nc_err(): ERR_BUF->ENOBUFS\n"); l->tap->send_return_value(l->conn, -1, ENOBUFS); break; case ERR_TIMEOUT: - fprintf(stderr, "nc_err(): ERR_TIMEOUT->ETIMEDOUT\n"); + dwr("nc_err(): ERR_TIMEOUT->ETIMEDOUT\n"); l->tap->send_return_value(l->conn, -1, ETIMEDOUT); break; case ERR_RTE: - fprintf(stderr, "nc_err(): ERR_RTE->ENETUNREACH\n"); + dwr("nc_err(): ERR_RTE->ENETUNREACH\n"); l->tap->send_return_value(l->conn, -1, ENETUNREACH); break; case ERR_INPROGRESS: - fprintf(stderr, "nc_err(): ERR_INPROGRESS->EINPROGRESS\n"); + dwr("nc_err(): ERR_INPROGRESS->EINPROGRESS\n"); l->tap->send_return_value(l->conn, -1, EINPROGRESS); break; case ERR_VAL: - fprintf(stderr, "nc_err(): ERR_VAL->EINVAL\n"); + dwr("nc_err(): ERR_VAL->EINVAL\n"); l->tap->send_return_value(l->conn, -1, EINVAL); break; case ERR_WOULDBLOCK: - fprintf(stderr, "nc_err(): ERR_WOULDBLOCK->EWOULDBLOCK\n"); + dwr("nc_err(): ERR_WOULDBLOCK->EWOULDBLOCK\n"); l->tap->send_return_value(l->conn, -1, EWOULDBLOCK); break; case ERR_USE: - fprintf(stderr, "nc_err(): ERR_USE->EADDRINUSE\n"); + dwr("nc_err(): ERR_USE->EADDRINUSE\n"); l->tap->send_return_value(l->conn, -1, EADDRINUSE); break; case ERR_ISCONN: - fprintf(stderr, "nc_err(): ERR_ISCONN->EISCONN\n"); + dwr("nc_err(): ERR_ISCONN->EISCONN\n"); l->tap->send_return_value(l->conn, -1, EISCONN); break; case ERR_ABRT: - fprintf(stderr, "nc_err(): ERR_ABRT->ECONNREFUSED\n"); + dwr("nc_err(): ERR_ABRT->ECONNREFUSED\n"); l->tap->send_return_value(l->conn, -1, ECONNREFUSED); break; @@ -769,11 +868,11 @@ void NetconEthernetTap::nc_err(void *arg, err_t err) default: break; } - fprintf(stderr, "nc_err(): closing connection\n"); + dwr("nc_err(): closing connection\n"); l->tap->closeConnection(l->conn); } else { - fprintf(stderr, "nc_err(): can't locate connection object for PCB\n"); + dwr("nc_err(): can't locate connection object for PCB\n"); } } @@ -788,11 +887,6 @@ void NetconEthernetTap::nc_err(void *arg, err_t err) err_t NetconEthernetTap::nc_poll(void* arg, struct tcp_pcb *tpcb) { //Larg *l = (Larg*)arg; - - - - - /* Larg *l = (Larg*)arg; TcpConnection *conn = l->conn; @@ -821,7 +915,7 @@ err_t NetconEthernetTap::nc_sent(void* arg, struct tcp_pcb *tpcb, u16_t len) //fprintf(stderr, " nc_sent()\n"); Larg *l = (Larg*)arg; if(len) { - fprintf(stderr, " nc_sent(): ACKING len = %d, setting read-notify = true, (sndbuf = %d)\n", len, l->conn->pcb->snd_buf); + //fprintf(stderr, " nc_sent(): ACKING len = %d, setting read-notify = true, (sndbuf = %d)\n", len, l->conn->pcb->snd_buf); l->tap->_phy.setNotifyReadable(l->conn->dataSock, true); l->tap->_phy.whack(); } @@ -840,7 +934,7 @@ err_t NetconEthernetTap::nc_sent(void* arg, struct tcp_pcb *tpcb, u16_t len) */ err_t NetconEthernetTap::nc_connected(void *arg, struct tcp_pcb *tpcb, err_t err) { - fprintf(stderr, "nc_connected()\n"); + dwr("nc_connected()\n"); Larg *l = (Larg*)arg; l->tap->send_return_value(l->conn, ERR_OK); return ERR_OK; @@ -864,13 +958,13 @@ void NetconEthernetTap::handle_map_request(PhySocket *sock, void **uptr, unsigne 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, + dwr(" 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); + dwr(" handle_map_request(their=%d): NOT MAPPED\n", req_fd); } /** @@ -891,7 +985,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, + dwr(" 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 --- @@ -908,12 +1002,12 @@ 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]); + dwr(" 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); + dwr(" handle_retval(): CONN:%x - This socket is mapped to two different pipes (?). Exiting.\n", conn); + die(0); // FIXME: Print service mapping state and exit } } } @@ -973,8 +1067,8 @@ 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, " handle_bind(): err = %d\n", err); + dwr(" handle_bind(): error binding to %d.%d.%d.%d : %d\n", d[0],d[1],d[2],d[3], conn_port); + dwr(" handle_bind(): err = %d\n", err); if(err == ERR_USE) send_return_value(conn, -1, EADDRINUSE); @@ -987,12 +1081,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); + dwr(" 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"); + dwr(" handle_bind(): can't locate connection for PCB\n"); send_return_value(conn, -1, EBADF); } } @@ -1018,17 +1112,17 @@ 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); + dwr(" handle_listen(their=%d):\n", listen_rpc->sockfd); TcpConnection *conn = getConnectionByTheirFD(sock, listen_rpc->sockfd); if(!conn){ - fprintf(stderr, " handle_listen(): unable to locate connection object\n"); + dwr(" 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); + dwr(" 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"); + dwr(" handle_listen(): PCB is already in listening state.\n"); return; } struct tcp_pcb* listening_pcb; @@ -1092,22 +1186,22 @@ void NetconEthernetTap::handle_listen(PhySocket *sock, void **uptr, struct liste [?] EPROTONOSUPPORT - The protocol type or the specified protocol is not supported within this domain. */ -void NetconEthernetTap::handle_socket(PhySocket *sock, void **uptr, struct socket_st* socket_rpc) +int NetconEthernetTap::handle_socket(PhySocket *sock, void **uptr, struct socket_st* socket_rpc) { int rpc_fd = _phy.getDescriptor(sock); struct tcp_pcb *newpcb = lwipstack->tcp_new(); - fprintf(stderr, " handle_socket(): pcb=%x\n", newpcb); + dwr(" handle_socket(): pcb=%x\n", newpcb); if(newpcb != NULL) { ZT_PHY_SOCKFD_TYPE fds[2]; if(socketpair(PF_LOCAL, SOCK_STREAM, 0, fds) < 0) { if(errno < 0) { send_return_value(rpc_fd, -1, errno); - return; + return -1; } } - fprintf(stderr, " handle_socket(): socketpair = {%d, %d}\n", fds[0], fds[1]); + dwr(" 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; @@ -1119,11 +1213,13 @@ void NetconEthernetTap::handle_socket(PhySocket *sock, void **uptr, struct socke close(fds[1]); // close other end of socketpair // Once the client tells us what its fd is on the other end, we can then complete the mapping new_conn->pending = true; + return 0; } 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"); + dwr(" handle_socket(): Memory not available for new PCB\n"); send_return_value(rpc_fd, -1, ENOMEM); + return -1; } } @@ -1224,14 +1320,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"); + dwr(" 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, " handle_connect(): could not locate PCB based on their fd\n"); + dwr(" handle_connect(): could not locate PCB based on their fd\n"); send_return_value(conn, -1, EBADF); } } @@ -1243,12 +1339,12 @@ void NetconEthernetTap::handle_write(TcpConnection *conn) int r; if(!conn) { - fprintf(stderr, " handle_write(): could not locate connection for this fd\n"); + dwr(" 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"); + dwr(" 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 @@ -1275,7 +1371,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); + dwr(" handle_write(): error while writing to PCB, (err = %d)\n", err); return; } else { @@ -1288,7 +1384,7 @@ void NetconEthernetTap::handle_write(TcpConnection *conn) } } else { - fprintf(stderr, " handle_write(): LWIP stack full\n"); + dwr(" handle_write(): LWIP stack full\n"); return; } } diff --git a/netcon/NetconEthernetTap.hpp b/netcon/NetconEthernetTap.hpp index 159e4042..930807a5 100644 --- a/netcon/NetconEthernetTap.hpp +++ b/netcon/NetconEthernetTap.hpp @@ -107,8 +107,9 @@ private: 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_i_am(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); + int handle_socket(PhySocket *sock, void **uptr, struct socket_st* socket_rpc); void handle_connect(PhySocket *sock, void **uptr, struct connect_st* connect_rpc); void handle_write(TcpConnection *conn); @@ -141,16 +142,19 @@ private: // Client helpers TcpConnection *getConnectionByTheirFD(PhySocket *sock, int fd); - TcpConnection *getConnectionByPCB(struct tcp_pcb *pcb); void closeConnection(TcpConnection *conn); void closeAll(); void closeClient(PhySocket *sock); + void compact_dump(); + void dump(); + void die(int exret); Phy<NetconEthernetTap *> _phy; PhySocket *_unixListenSocket; std::vector<TcpConnection*> tcp_connections; std::vector<PhySocket*> rpc_sockets; + std::map<PhySocket*, pid_t> pidmap; netif interface; diff --git a/netcon/NetconService.hpp b/netcon/NetconService.hpp index 8f192823..fc6bd46c 100644 --- a/netcon/NetconService.hpp +++ b/netcon/NetconService.hpp @@ -56,7 +56,8 @@ namespace ZeroTier { int their_fd; bool pending; bool listening; - + int pid; + PhySocket *rpcSock; PhySocket *dataSock; struct tcp_pcb *pcb; diff --git a/netcon/NetconUtilities.cpp b/netcon/NetconUtilities.cpp index 642d77ba..45332512 100644 --- a/netcon/NetconUtilities.cpp +++ b/netcon/NetconUtilities.cpp @@ -30,6 +30,7 @@ #include <stdlib.h> #include <unistd.h> #include <stdio.h> +#include <stdarg.h> #include <sys/socket.h> #include "lwip/ip.h" @@ -41,6 +42,45 @@ namespace ZeroTier { + void dwr(char *fmt, ... ) + { +//#ifdef ZT_DEBUG + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + fflush(stderr); + va_end(ap); +//#endif + } + + void clearscreen() + { + fprintf(stderr, "\033[2J"); + } + + //void reset_cursor() + void gotoxy(int x,int y) { + fprintf(stderr, "%c[%d;%df",0x1B,y,x); + } + + // Gets the process/path name associated with a pid + void get_path_from_pid(char* dest, int pid) + { + char ppath[80]; + sprintf(ppath, "/proc/%d/exe", pid); + if (readlink (ppath, dest, 80) != -1){ + } + } + + // Gets the process/path name associated with a fd + void get_path_from_fd(char* dest, int pid, int fd) + { + char ppfd[80]; + sprintf(ppfd, "/proc/%d/fd/%d", pid, fd); + if (readlink (ppfd, dest, 80) != -1){ + } + } + // Functions used to pass file descriptors between processes ssize_t sock_fd_write(int sock, int fd) { diff --git a/netcon/NetconUtilities.hpp b/netcon/NetconUtilities.hpp index ac6042e6..93824705 100644 --- a/netcon/NetconUtilities.hpp +++ b/netcon/NetconUtilities.hpp @@ -31,6 +31,11 @@ namespace ZeroTier { + void dwr(char *str, ... ); + void clearscreen(); + void gotoxy(int x,int y); + void get_path_from_pid(char* dest, int pid); + void get_path_from_fd(char* dest, int pid, int fd); ip_addr_t ip_addr_sin(register struct sockaddr_in *sin); ssize_t sock_fd_write(int sock, int fd); ssize_t sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd); diff --git a/netcon/libintercept.so.1.0 b/netcon/libintercept.so.1.0 Binary files differindex acac7b3b..46a1f024 100755 --- a/netcon/libintercept.so.1.0 +++ b/netcon/libintercept.so.1.0 diff --git a/osdep/Phy.hpp b/osdep/Phy.hpp index df20bb40..c7b2a340 100644 --- a/osdep/Phy.hpp +++ b/osdep/Phy.hpp @@ -238,6 +238,14 @@ public: */ static inline ZT_PHY_SOCKFD_TYPE getDescriptor(PhySocket *s) throw() { return reinterpret_cast<PhySocketImpl *>(s)->sock; } + + /** + * @param s Socket object + * @return Pointer to user object + */ + static inline void** getuptr(PhySocket *s) throw() { return &(reinterpret_cast<PhySocketImpl *>(s)->uptr); } + + /** * Cause poll() to stop waiting immediately * |