diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | ce4a32fe52ef09d8f5ff1dd22c001110902b60a2 (patch) | |
tree | 5ac38a06f3dde268dc7927dc155896926aaf7012 /kdecore/ksocks.cpp | |
download | tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.tar.gz tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdelibs@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kdecore/ksocks.cpp')
-rw-r--r-- | kdecore/ksocks.cpp | 600 |
1 files changed, 600 insertions, 0 deletions
diff --git a/kdecore/ksocks.cpp b/kdecore/ksocks.cpp new file mode 100644 index 000000000..be9331548 --- /dev/null +++ b/kdecore/ksocks.cpp @@ -0,0 +1,600 @@ +/* This file is part of the KDE libraries + Copyright (C) 2001-2003 George Staikos <staikos@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <config.h> + +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif + +#include <qfile.h> +#include <qstring.h> +#include <qmap.h> + +#include <klocale.h> +#include <kdebug.h> +#include "klibloader.h" +#include <kconfig.h> +#include <kapplication.h> + +#include <sys/types.h> +#include <sys/socket.h> + +#include <unistd.h> + +#include "ksocks.h" + +// DO NOT RE-ORDER THESE. +enum SymbolKeys { + S_SOCKSinit = 0, + S_connect = 1, + S_read = 2, + S_write = 3, + S_recvfrom = 4, + S_sendto = 5, + S_recv = 6, + S_send = 7, + S_getsockname = 8, + S_getpeername = 9, + S_accept = 10, + S_select = 11, + S_listen = 12, + S_bind = 13 + }; + + +extern "C" { +// Function pointer table +static int (*F_SOCKSinit) (char *) = 0L; +static int (*F_connect) (int, const struct sockaddr *, ksocklen_t) = 0L; +static signed long int (*F_read) (int, void *, unsigned long int) = 0L; +static signed long int (*F_write) (int, const void *, unsigned long int) = 0L; +static int (*F_recvfrom) (int, void *, unsigned long int, int, struct sockaddr *, + ksocklen_t *) = 0L; +static int (*F_sendto) (int, const void *, unsigned long int, int, + const struct sockaddr *, ksocklen_t) = 0L; +static int (*F_recv) (int, void *, unsigned long int, int) = 0L; +static int (*F_send) (int, const void *, unsigned long int, int) = 0L; +static int (*F_getsockname) (int, struct sockaddr *, ksocklen_t *) = 0L; +static int (*F_getpeername) (int, struct sockaddr *, ksocklen_t *) = 0L; +static int (*F_accept) (int, struct sockaddr *, ksocklen_t *) = 0L; +static int (*F_select) (int, fd_set *, fd_set *, fd_set *, + struct timeval *) = 0L; +static int (*F_listen) (int, int) = 0L; +static int (*F_bind) (int, const struct sockaddr *, ksocklen_t) = 0L; +} + + +class KSocksTable { + public: + KSocksTable(); + virtual ~KSocksTable(); + + // The name of each symbol and it's SOCKS replacement + QMap<SymbolKeys,QString> symbols; + // The name of this library + QString myname; + bool hasWorkingAsyncConnect; +}; + + +KSocksTable::KSocksTable() : myname("Unknown"), hasWorkingAsyncConnect(true) { +} + +KSocksTable::~KSocksTable() { +} + + +/* + * How to add support for a new SOCKS package. + * + * 1) Subclass KSocksTable as is done below and write out all the symbols + * 1.b) Give the class a "myname" + * 2) Make sure that all possible library names are written into the + * _libNames string list. Don't forget that different OSes name shared + * libraries differently. Expect .so, .sl, .a (!) (AIX does this). + * 3) Find a unique symbol in the library that we can use to identify that + * library and write out the test case in the constructor + * 4) Make necessary changes to the KControl module in kdebase/kcontrol/.... + * 5) TEST! + * + */ + +////////////////////////////////////////////////////////////////// +/////// Define each library symbol table here /////// +////////////////////////////////////////////////////////////////// + + +// +// Support for NEC SOCKS client +// + +class KNECSocksTable : public KSocksTable { + public: + KNECSocksTable(); + virtual ~KNECSocksTable(); +}; + + +KNECSocksTable::KNECSocksTable() : KSocksTable() { + myname = i18n("NEC SOCKS client"); + symbols.insert(S_SOCKSinit, "SOCKSinit"); + symbols.insert(S_connect, "connect"); + symbols.insert(S_read, "read"); + symbols.insert(S_write, "write"); + symbols.insert(S_recvfrom, "recvfrom"); + symbols.insert(S_sendto, "sendto"); + symbols.insert(S_recv, "recv"); + symbols.insert(S_send, "send"); + symbols.insert(S_getsockname, "getsockname"); + symbols.insert(S_getpeername, "getpeername"); + symbols.insert(S_accept, "accept"); + symbols.insert(S_select, "select"); + symbols.insert(S_listen, "listen"); + symbols.insert(S_bind, "bind"); +} + +KNECSocksTable::~KNECSocksTable() { +} + + + + +// +// Support for Dante SOCKS client +// + +class KDanteSocksTable : public KSocksTable { + public: + KDanteSocksTable(); + virtual ~KDanteSocksTable(); +}; + +KDanteSocksTable::KDanteSocksTable() : KSocksTable() { + hasWorkingAsyncConnect = false; + myname = i18n("Dante SOCKS client"); + symbols.insert(S_SOCKSinit, "SOCKSinit"); + symbols.insert(S_connect, "Rconnect"); + symbols.insert(S_read, "Rread"); + symbols.insert(S_write, "Rwrite"); + symbols.insert(S_recvfrom, "Rrecvfrom"); + symbols.insert(S_sendto, "Rsendto"); + symbols.insert(S_recv, "Rrecv"); + symbols.insert(S_send, "Rsend"); + symbols.insert(S_getsockname, "Rgetsockname"); + symbols.insert(S_getpeername, "Rgetpeername"); + symbols.insert(S_accept, "Raccept"); + symbols.insert(S_select, "Rselect"); + symbols.insert(S_listen, "Rlisten"); + symbols.insert(S_bind, "Rbind"); +} + + +KDanteSocksTable::~KDanteSocksTable() { +} + + + +////////////////////////////////////////////////////////////////// +/////// End of all symbol table definitions /////// +////////////////////////////////////////////////////////////////// + + +KSocks *KSocks::_me = 0; +#ifdef __CYGWIN__ +bool KSocks::_disabled = true; +#else +bool KSocks::_disabled = false; +#endif +static KStaticDeleter<KSocks> med; + +void KSocks::disable() +{ + if (!_me) + _disabled = true; +} + +KSocks *KSocks::self() { + // Note that we don't use a static deleter here. It makes no sense and tends to cause crashes. + if (!_me) { + if (kapp) { + KConfigGroup cfg(kapp->config(), "Socks"); + _me = new KSocks(&cfg); + } else { + _disabled = true; + _me = new KSocks(0); + } + } + return _me; +} + +void KSocks::setConfig(KConfigBase *config) +{ + // We can change the config from disabled to enabled + // but not the other way around. + if (_me && _disabled) { + delete _me; + _me = 0; + _disabled = false; + } + if (!_me) + _me = new KSocks(config); +} + +bool KSocks::activated() { return (_me != 0L); } + + +KSocks::KSocks(KConfigBase *config) : _socksLib(0L), _st(0L) { + _hasSocks = false; + _useSocks = false; + + if (!config) + return; + + if (!(config->readBoolEntry("SOCKS_enable", false))) { + _disabled = true; + } + + if (_disabled) + return; + + _libPaths << "" + << "/usr/lib" KDELIBSUFF "/" + << "/usr/lib/" + << "/usr/local/lib" KDELIBSUFF "/" + << "/usr/local/lib/" + << "/usr/local/socks5/lib" KDELIBSUFF "/" + << "/usr/local/socks5/lib/" + << "/opt/socks5/lib" KDELIBSUFF "/" + << "/opt/socks5/lib/"; + _libNames << "libsocks.so" // Dante + << "libdsocksd.so.0" // Dante 1.1.14-2 on + // Debian unstable 17-12-2003 + << "libsocks5.so" // ? + << "libsocks5_sh.so"; // NEC + + // Add the custom library paths here + QStringList newlibs = config->readListEntry("SOCKS_lib_path"); + + for (QStringList::Iterator it = newlibs.begin(); + it != newlibs.end(); + ++it) { + QString thisone = *it; + if (thisone[thisone.length()-1] != '/') thisone += "/"; + _libPaths << thisone; + kdDebug(171) << "KSocks added a new library path: " << thisone << endl; + } + + // Load the proper libsocks and KSocksTable + KLibLoader *ll = KLibLoader::self(); + + + int _meth = config->readNumEntry("SOCKS_method", 1); + /**** Current methods + * 1) Autodetect (read: any) 2) NEC + * 3) Dante 4) Custom + */ + + if (_meth == 4) { // try to load^H^H^H^Hguess at a custom library + _socksLib = ll->library(config->readPathEntry("SOCKS_lib").latin1()); + if (_socksLib && _socksLib->symbol("Rconnect")) { // Dante compatible? + _st = new KDanteSocksTable; + _useSocks = true; + _hasSocks = true; + } else if (_socksLib && _socksLib->symbol("connect")) { // NEC compatible? + _st = new KNECSocksTable; + _useSocks = true; + _hasSocks = true; + } else if (_socksLib) { + _socksLib->unload(); + _socksLib = 0L; + } + } else // leave this here "else for {}" + for (QStringList::Iterator pit = _libPaths.begin(); + !_hasSocks && pit != _libPaths.end(); + ++pit) + for (QStringList::Iterator it = _libNames.begin(); + it != _libNames.end(); + ++it) { + _socksLib = ll->library((*pit + *it).latin1()); + if (_socksLib) { + if ((_meth == 1 || _meth == 2) && + _socksLib->symbol("S5LogShowThreadIDS") != 0L) { // NEC SOCKS + kdDebug(171) << "Found NEC SOCKS" << endl; + _st = new KNECSocksTable; + _useSocks = true; + _hasSocks = true; + break; + } else if ((_meth == 1 || _meth == 3) && + _socksLib->symbol("sockaddr2ruleaddress") != 0L) { //Dante + kdDebug(171) << "Found Dante SOCKS" << endl; + _st = new KDanteSocksTable; + _useSocks = true; + _hasSocks = true; + break; + } else { + _socksLib->unload(); + _socksLib = 0L; + } + } + } + + // Load in all the symbols + if (_st) { + for (QMap<SymbolKeys,QString>::Iterator it = _st->symbols.begin(); + it != _st->symbols.end(); + ++it) { + switch(it.key()) { + case S_SOCKSinit: + F_SOCKSinit = (int (*)(char *)) + _socksLib->symbol(it.data().latin1()); + break; + case S_connect: + F_connect = (int (*)(int, const struct sockaddr *, ksocklen_t)) + _socksLib->symbol(it.data().latin1()); + break; + case S_read: + F_read = (signed long int (*)(int, void *, unsigned long int)) + _socksLib->symbol(it.data().latin1()); + break; + case S_write: + F_write = (signed long int (*)(int, const void *, unsigned long int)) + _socksLib->symbol(it.data().latin1()); + break; + case S_recvfrom: + F_recvfrom = (int (*)(int, void *, unsigned long int, int, + struct sockaddr *, ksocklen_t *)) + _socksLib->symbol(it.data().latin1()); + break; + case S_sendto: + F_sendto = (int (*)(int, const void *, unsigned long int, int, + const struct sockaddr *, ksocklen_t)) + _socksLib->symbol(it.data().latin1()); + break; + case S_recv: + F_recv = (int (*)(int, void *, unsigned long int, int)) + _socksLib->symbol(it.data().latin1()); + break; + case S_send: + F_send = (int (*)(int, const void *, unsigned long int, int)) + _socksLib->symbol(it.data().latin1()); + break; + case S_getsockname: + F_getsockname = (int (*)(int, struct sockaddr *, ksocklen_t *)) + _socksLib->symbol(it.data().latin1()); + break; + case S_getpeername: + F_getpeername = (int (*)(int, struct sockaddr *, ksocklen_t *)) + _socksLib->symbol(it.data().latin1()); + break; + case S_accept: + F_accept = (int (*)(int, struct sockaddr *, ksocklen_t *)) + _socksLib->symbol(it.data().latin1()); + break; + case S_select: + F_select = (int (*)(int, fd_set *, fd_set *, fd_set *, struct timeval *)) + _socksLib->symbol(it.data().latin1()); + break; + case S_listen: + F_listen = (int (*)(int, int)) + _socksLib->symbol(it.data().latin1()); + break; + case S_bind: + F_bind = (int (*)(int, const struct sockaddr *, ksocklen_t)) + _socksLib->symbol(it.data().latin1()); + break; + default: + kdDebug(171) << "KSocks got a symbol it doesn't know about!" << endl; + break; + } + } + + // Now we check for the critical stuff. + if (F_SOCKSinit) { + int rc = (*F_SOCKSinit)((char *)"KDE"); + if (rc != 0) + stopSocks(); + else kdDebug(171) << "SOCKS has been activated!" << endl; + } else { + stopSocks(); + } + } +} + + +KSocks::~KSocks() { + stopSocks(); + _me = 0; +} + +void KSocks::die() { + if (_me == this) { + _me = 0; + delete this; + } +} + +void KSocks::stopSocks() { + if (_hasSocks) { + // This library doesn't even provide the basics. + // It's probably broken. Let's abort. + _useSocks = false; + _hasSocks = false; + if (_socksLib) { + _socksLib->unload(); + _socksLib = 0L; + } + delete _st; + _st = 0L; + } +} + + +bool KSocks::usingSocks() { + return _useSocks; +} + + +bool KSocks::hasSocks() { + return _hasSocks; +} + + +void KSocks::disableSocks() { + _useSocks = false; +} + + +void KSocks::enableSocks() { + if (_hasSocks) + _useSocks = true; +} + +bool KSocks::hasWorkingAsyncConnect() +{ + return (_useSocks && _st) ? _st->hasWorkingAsyncConnect : true; +} + + +/* + * REIMPLEMENTED FUNCTIONS FROM LIBC + * + */ + +int KSocks::connect (int sockfd, const sockaddr *serv_addr, + ksocklen_t addrlen) { + if (_useSocks && F_connect) + return (*F_connect)(sockfd, serv_addr, addrlen); + else return ::connect(sockfd, (sockaddr*) serv_addr, (socklen_t)addrlen); +} + + +signed long int KSocks::read (int fd, void *buf, unsigned long int count) { + if (_useSocks && F_read) + return (*F_read)(fd, buf, count); + else return ::read(fd, buf, count); +} + + +signed long int KSocks::write (int fd, const void *buf, unsigned long int count) { + if (_useSocks && F_write) + return (*F_write)(fd, buf, count); + else return ::write(fd, buf, count); +} + + +int KSocks::recvfrom (int s, void *buf, unsigned long int len, int flags, + sockaddr *from, ksocklen_t *fromlen) { + if (_useSocks && F_recvfrom) { + return (*F_recvfrom)(s, buf, len, flags, from, fromlen); + } else { + socklen_t casted_len = (socklen_t) *fromlen; + int rc = ::recvfrom(s, (char*) buf, len, flags, from, &casted_len); + *fromlen = casted_len; + return rc; + } +} + + +int KSocks::sendto (int s, const void *msg, unsigned long int len, int flags, + const sockaddr *to, ksocklen_t tolen) { + if (_useSocks && F_sendto) + return (*F_sendto)(s, msg, len, flags, to, tolen); + else return ::sendto(s, (char*) msg, len, flags, to, (socklen_t)tolen); +} + + +int KSocks::recv (int s, void *buf, unsigned long int len, int flags) { + if (_useSocks && F_recv) + return (*F_recv)(s, buf, len, flags); + else return ::recv(s, (char*) buf, len, flags); +} + + +int KSocks::send (int s, const void *msg, unsigned long int len, int flags) { + if (_useSocks && F_send) + return (*F_send)(s, msg, len, flags); + else return ::send(s, (char*) msg, len, flags); +} + + +int KSocks::getsockname (int s, sockaddr *name, ksocklen_t *namelen) { + if (_useSocks && F_getsockname) { + return (*F_getsockname)(s, name, namelen); + } else { + socklen_t casted_len = *namelen; + int rc = ::getsockname(s, name, &casted_len); + *namelen = casted_len; + return rc; + } +} + + +int KSocks::getpeername (int s, sockaddr *name, ksocklen_t *namelen) { + if (_useSocks && F_getpeername) { + return (*F_getpeername)(s, name, namelen); + } else { + socklen_t casted_len = *namelen; + int rc = ::getpeername(s, name, &casted_len); + *namelen = casted_len; + return rc; + } +} + + +int KSocks::accept (int s, sockaddr *addr, ksocklen_t *addrlen) { + if (_useSocks && F_accept) { + return (*F_accept)(s, addr, addrlen); + } else { + socklen_t casted_len = *addrlen; + int rc = ::accept(s, addr, &casted_len); + *addrlen = casted_len; + return rc; + } +} + + +int KSocks::select (int n, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, struct timeval *timeout) { + if (_useSocks && F_select) + return (*F_select)(n, readfds, writefds, exceptfds, timeout); + else return ::select(n, readfds, writefds, exceptfds, timeout); +} + + +int KSocks::listen (int s, int backlog) { + if (_useSocks && F_listen) + return (*F_listen)(s, backlog); + else return ::listen(s, backlog); +} + + +int KSocks::bind (int sockfd, const sockaddr *my_addr, ksocklen_t addrlen) { + if (_useSocks && F_bind) + return (*F_bind)(sockfd, my_addr, addrlen); + else return ::bind(sockfd, my_addr, (socklen_t)addrlen); +} + +int KSocks::bind (int sockfd, sockaddr *my_addr, ksocklen_t addrlen) { + if (_useSocks && F_bind) + return (*F_bind)(sockfd, my_addr, addrlen); + else return ::bind(sockfd, my_addr, (socklen_t)addrlen); +} + + + |