diff --git a/libretroshare/src/pqi/pqissllistener.cc b/libretroshare/src/pqi/pqissllistener.cc index 67c5b032c..ed2ca8e4a 100644 --- a/libretroshare/src/pqi/pqissllistener.cc +++ b/libretroshare/src/pqi/pqissllistener.cc @@ -83,7 +83,8 @@ int pqissllistenbase::tick() status(); // check listen port. acceptconnection(); - return continueaccepts(); + continueaccepts(); + return finaliseAccepts(); } int pqissllistenbase::status() @@ -440,22 +441,7 @@ int pqissllistenbase::continueSSL(SSL *ssl, struct sockaddr_in remote_addr, bool /* we have failed -> get certificate if possible */ Extract_Failed_SSL_Certificate(ssl, &remote_addr); - // other wise delete ssl connection. - // kill connection.... - // so it will be removed from cache. - SSL_shutdown(ssl); - - // close socket??? -/************************** WINDOWS/UNIX SPECIFIC PART ******************/ -#ifndef WINDOWS_SYS // ie UNIX - shutdown(fd, SHUT_RDWR); - close(fd); -#else //WINDOWS_SYS - closesocket(fd); -#endif -/************************** WINDOWS/UNIX SPECIFIC PART ******************/ - // free connection. - SSL_free(ssl); + closeConnection(fd, ssl); std::ostringstream out; out << "Read Error on the SSL Socket"; @@ -477,6 +463,22 @@ int pqissllistenbase::continueSSL(SSL *ssl, struct sockaddr_in remote_addr, bool pqioutput(PQL_WARNING, pqissllistenzone, "pqissllistenbase::completeConnection() Failed!"); + closeConnection(fd, ssl); + + std::ostringstream out; + out << "Shutting it down!" << std::endl; + pqioutput(PQL_WARNING, pqissllistenzone, out.str()); + + // failure -1, pending 0, sucess 1. + return -1; +} + + +int pqissllistenbase::closeConnection(int fd, SSL *ssl) +{ + /* else we shut it down! */ + pqioutput(PQL_WARNING, pqissllistenzone, "pqissllistenbase::closeConnection() Shutting it Down!"); + // delete ssl connection. SSL_shutdown(ssl); @@ -491,16 +493,11 @@ int pqissllistenbase::continueSSL(SSL *ssl, struct sockaddr_in remote_addr, bool /************************** WINDOWS/UNIX SPECIFIC PART ******************/ // free connection. SSL_free(ssl); - - std::ostringstream out; - out << "Shutting it down!" << std::endl; - pqioutput(PQL_WARNING, pqissllistenzone, out.str()); - - // failure -1, pending 0, sucess 1. - return -1; } + + int pqissllistenbase::Extract_Failed_SSL_Certificate(SSL *ssl, struct sockaddr_in *inaddr) { pqioutput(PQL_DEBUG_BASIC, pqissllistenzone, @@ -563,6 +560,124 @@ int pqissllistenbase::continueaccepts() return 1; } +#define ACCEPT_WAIT_TIME 30 + +int pqissllistenbase::finaliseAccepts() +{ + + // for each of the incoming sockets.... call continue. + std::list::iterator it; + + time_t now = time(NULL); + for(it = accepted_ssl.begin(); it != accepted_ssl.end();) + { + pqioutput(PQL_DEBUG_BASIC, pqissllistenzone, + "pqissllistenbase::finalisedAccepts() Continuing SSL Accept"); + + /* check that the socket is still active - how? */ + int active = isSSLActive(it->mFd, it->mSSL); + if (active > 0) + { + pqioutput(PQL_WARNING, pqissllistenzone, + "pqissllistenbase::finaliseAccepts() SSL Connection Ok => finaliseConnection"); + + if (0 > finaliseConnection(it->mFd, it->mSSL, it->mPeerId, it->mAddr)) + { + closeConnection(it->mFd, it->mSSL); + } + it = accepted_ssl.erase(it); + } + else if (active < 0) + { + pqioutput(PQL_WARNING, pqissllistenzone, + "pqissllistenbase::finaliseAccepts() SSL Connection Dead => closeConnection"); + + closeConnection(it->mFd, it->mSSL); + it = accepted_ssl.erase(it); + } + else if (now - it->mAcceptTS > ACCEPT_WAIT_TIME) + { + pqioutput(PQL_WARNING, pqissllistenzone, + "pqissllistenbase::finaliseAccepts() SSL Connection Timed Out => closeConnection"); + closeConnection(it->mFd, it->mSSL); + it = accepted_ssl.erase(it); + } + else + { + pqioutput(PQL_DEBUG_BASIC, pqissllistenzone, + "pqissllistenbase::finaliseAccepts() SSL Connection Status Unknown"); + it++; + } + } + return 1; +} + +int pqissllistenbase::isSSLActive(int fd, SSL *ssl) +{ + + /* can we just get error? */ + int bufsize = 8; /* just a little look */ + uint8_t buf[bufsize]; + int err = SSL_peek(ssl, buf, bufsize); + if (err <= 0) + { + int ssl_err = SSL_get_error(ssl, err); + int err_err = ERR_get_error(); + + { + std::ostringstream out; + out << "pqissllistenbase::isSSLActive() "; + out << "Issues with SSL_Accept(" << err << ")!" << std::endl; + printSSLError(ssl, err, ssl_err, err_err, out); + pqioutput(PQL_DEBUG_BASIC, pqissllistenzone, out.str()); + } + + if (ssl_err == SSL_ERROR_ZERO_RETURN) + { + std::ostringstream out; + out << "pqissllistenbase::isSSLActive() SSL_ERROR_ZERO_RETURN "; + out << " Connection state unknown"; + out << std::endl; + + pqioutput(PQL_DEBUG_BASIC, pqissllistenzone, out.str()); + + // zero means still continuing.... + return 0; + } + if ((ssl_err == SSL_ERROR_WANT_READ) || + (ssl_err == SSL_ERROR_WANT_WRITE)) + { + std::ostringstream out; + out << "pqissllistenbase::isSSLActive() SSL_ERROR_WANT_READ || SSL_ERROR_WANT_WRITE "; + out << " Connection state unknown"; + out << std::endl; + + pqioutput(PQL_DEBUG_BASIC, pqissllistenzone, out.str()); + + // zero means still continuing.... + return 0; + } + else + { + std::ostringstream out; + out << "pqissllistenbase::isSSLActive() "; + out << "Issues with SSL Peek(" << err << ") Likely the Connection was killed by Peer" << std::endl; + printSSLError(ssl, err, ssl_err, err_err, out); + pqioutput(PQL_ALERT, pqissllistenzone, out.str()); + + return -1; + } + } + + std::ostringstream out; + out << "pqissllistenbase::isSSLActive() Successful Peer -> Connection Okay"; + pqioutput(PQL_WARNING, pqissllistenzone, out.str()); + + return 1; +} + + + /************************ PQI SSL LISTENER **************************** * @@ -747,17 +862,65 @@ int pqissllistener::completeConnection(int fd, SSL *ssl, struct sockaddr_in &rem return -1; } - pqissl *pqis = it -> second; + // Cleanup cert. + X509_free(peercert); - // dont remove from the list of certificates. - // want to allow a new connection to replace a faulty one! - // listenaddr.erase(it); + // Pushback into Accepted List. + AcceptedSSL as; + as.mFd = fd; + as.mSSL = ssl; + as.mPeerId = newPeerId; + as.mAddr = remote_addr; + as.mAcceptTS = time(NULL); - // timestamp - // done in sslroot... npc -> lr_timestamp = time(NULL); + accepted_ssl.push_back(as); + + std::ostringstream out; + + out << "pqissllistener::completeConnection() Successful Connection with: " << newPeerId; + out << " for Connection:" << rs_inet_ntoa(remote_addr.sin_addr) << " Adding to WAIT-ACCEPT Queue"; + out << std::endl; + pqioutput(PQL_WARNING, pqissllistenzone, out.str()); + + return 1; +} + + + + + +int pqissllistener::finaliseConnection(int fd, SSL *ssl, std::string peerId, struct sockaddr_in &remote_addr) +{ + bool found = false; + std::map::iterator it; + + std::ostringstream out; + + out << "pqissllistener::finaliseConnection()" << std::endl; + out << "checking: " << peerId << std::endl; + // check if cert is in the list..... + + it = listenaddr.find(peerId); + if (it == listenaddr.end()) + { + out << "No Matching Peer"; + out << " for Connection:" << rs_inet_ntoa(remote_addr.sin_addr); + out << std::endl; + out << "pqissllistener => Shutting Down!" << std::endl; + pqioutput(PQL_WARNING, pqissllistenzone, out.str()); + return -1; + } + + out << "Found Matching Peer"; + out << " for Connection:" << rs_inet_ntoa(remote_addr.sin_addr); + out << std::endl; + out << "pqissllistener => Passing to pqissl module!" << std::endl; + pqioutput(PQL_WARNING, pqissllistenzone, out.str()); + + // hand off ssl conection. + pqissl *pqis = it -> second; + pqis -> accept(ssl, fd, remote_addr); - // hand off ssl conection. - pqis -> accept(ssl, fd, remote_addr); return 1; } diff --git a/libretroshare/src/pqi/pqissllistener.h b/libretroshare/src/pqi/pqissllistener.h index 211ceb28c..577c7a674 100644 --- a/libretroshare/src/pqi/pqissllistener.h +++ b/libretroshare/src/pqi/pqissllistener.h @@ -47,6 +47,21 @@ class pqissl; class p3PeerMgr; +class AcceptedSSL +{ + public: + + int mFd; + SSL *mSSL; + std::string mPeerId; + + struct sockaddr_in mAddr; + time_t mAcceptTS; +}; + + + + class pqissllistenbase: public pqilistener { public: @@ -68,14 +83,18 @@ virtual int resetlisten(); int acceptconnection(); int continueaccepts(); -int continueSSL(SSL *ssl, struct sockaddr_in remote_addr, bool); +int finaliseAccepts(); +int continueSSL(SSL *ssl, struct sockaddr_in remote_addr, bool); +int closeConnection(int fd, SSL *ssl); +int isSSLActive(int fd, SSL *ssl); virtual int completeConnection(int sockfd, SSL *in_connection, struct sockaddr_in &raddr) = 0; - +virtual int finaliseConnection(int fd, SSL *ssl, std::string peerId, struct sockaddr_in &raddr) = 0; protected: struct sockaddr_in laddr; + std::list accepted_ssl; private: @@ -108,6 +127,7 @@ int removeListenPort(std::string id); virtual int status(); virtual int completeConnection(int sockfd, SSL *in_connection, struct sockaddr_in &raddr); +virtual int finaliseConnection(int fd, SSL *ssl, std::string peerId, struct sockaddr_in &raddr); private: