File indexing completed on 2025-01-05 04:37:21

0001 /*
0002     SPDX-FileCopyrightText: 2005 Joris Guisson <joris.guisson@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 #include "authenticate.h"
0007 #include "peerconnector.h"
0008 #include <mse/encryptedpacketsocket.h>
0009 #include <net/socks.h>
0010 #include <peer/accessmanager.h>
0011 #include <util/log.h>
0012 #include <utp/utpsocket.h>
0013 
0014 namespace bt
0015 {
0016 Authenticate::Authenticate(const net::Address &addr, TransportProtocol proto, const SHA1Hash &info_hash, const PeerID &peer_id, PeerConnector::WPtr pcon)
0017     : info_hash(info_hash)
0018     , our_peer_id(peer_id)
0019     , addr(addr)
0020     , pcon(pcon)
0021     , socks(nullptr)
0022 {
0023     finished = succes = false;
0024     if (proto == TCP)
0025         sock = mse::EncryptedPacketSocket::Ptr(new mse::EncryptedPacketSocket(addr.ipVersion()));
0026     else
0027         sock = mse::EncryptedPacketSocket::Ptr(new mse::EncryptedPacketSocket(new utp::UTPSocket()));
0028 
0029     Out(SYS_CON | LOG_NOTICE) << "Initiating connection to " << addr.toString() << " via (" << (proto == TCP ? "TCP" : "UTP") << ")" << endl;
0030     if (net::Socks::enabled()) {
0031         socks = new net::Socks(sock, addr);
0032         switch (socks->setup()) {
0033         case net::Socks::FAILED:
0034             Out(SYS_CON | LOG_NOTICE) << "Failed to connect to " << addr.toString() << " via socks server " << endl;
0035             // Don't call onFinish here, will lead to problems
0036             // Instead change the interval of timeout timer, to force a failure
0037             timer.setInterval(1);
0038             break;
0039         case net::Socks::CONNECTED:
0040             delete socks;
0041             socks = nullptr;
0042             connected();
0043             break;
0044         default:
0045             break;
0046         }
0047     } else {
0048         if (sock->connectTo(addr)) {
0049             connected();
0050         } else if (sock->connecting()) {
0051             // do nothing the monitor will notify us when we are connected
0052         } else {
0053             // Don't call onFinish here, will lead to problems
0054             // Instead change the interval of timeout timer, to force a failure
0055             timer.setInterval(1);
0056         }
0057     }
0058 }
0059 
0060 Authenticate::~Authenticate()
0061 {
0062     delete socks;
0063 }
0064 
0065 void Authenticate::onReadyWrite()
0066 {
0067     if (!sock)
0068         return;
0069 
0070     if (socks) {
0071         switch (socks->onReadyToWrite()) {
0072         case net::Socks::FAILED:
0073             Out(SYS_CON | LOG_NOTICE) << "Failed to connect to socks server " << endl;
0074             onFinish(false);
0075             break;
0076         case net::Socks::CONNECTED:
0077             delete socks;
0078             socks = nullptr;
0079             connected();
0080             break;
0081         default:
0082             break;
0083         }
0084     } else if (sock->connectSuccesFull()) {
0085         connected();
0086     } else {
0087         onFinish(false);
0088     }
0089 }
0090 
0091 void Authenticate::onReadyRead()
0092 {
0093     if (!sock)
0094         return;
0095 
0096     if (!socks) {
0097         AuthenticateBase::onReadyRead();
0098     } else {
0099         switch (socks->onReadyToRead()) {
0100         case net::Socks::FAILED:
0101             Out(SYS_CON | LOG_NOTICE) << "Failed to connect to host via socks server " << endl;
0102             onFinish(false);
0103             break;
0104         case net::Socks::CONNECTED:
0105             // connection established, so get rid of socks shit
0106             delete socks;
0107             socks = nullptr;
0108             connected();
0109             if (sock->bytesAvailable() > 0)
0110                 AuthenticateBase::onReadyRead();
0111             break;
0112         default:
0113             break;
0114         }
0115     }
0116 }
0117 
0118 void Authenticate::connected()
0119 {
0120     sendHandshake(info_hash, our_peer_id);
0121 }
0122 
0123 void Authenticate::onFinish(bool succes)
0124 {
0125     Out(SYS_CON | LOG_NOTICE) << "Authentication to " << addr.toString() << " : " << (succes ? "ok" : "failure") << endl;
0126     finished = true;
0127     this->succes = succes;
0128 
0129     if (!succes)
0130         sock.clear();
0131 
0132     timer.stop();
0133     PeerConnector::Ptr pc = pcon.toStrongRef();
0134     if (pc)
0135         pc->authenticationFinished(this, succes);
0136 }
0137 
0138 void Authenticate::handshakeReceived(bool full)
0139 {
0140     const Uint8 *hs = handshake;
0141     if (!AccessManager::instance().allowed(addr)) {
0142         Out(SYS_CON | LOG_DEBUG) << "The IP address " << addr.toString() << " is blocked " << endl;
0143         onFinish(false);
0144         return;
0145     }
0146 
0147     SHA1Hash rh(hs + 28);
0148     if (rh != info_hash) {
0149         Out(SYS_CON | LOG_DEBUG) << "Wrong info_hash : " << rh.toString() << endl;
0150         onFinish(false);
0151         return;
0152     }
0153 
0154     if (full) {
0155         char tmp[21];
0156         tmp[20] = '\0';
0157         memcpy(tmp, hs + 48, 20);
0158         peer_id = PeerID(tmp);
0159 
0160         if (our_peer_id == peer_id) {
0161             Out(SYS_CON | LOG_DEBUG) << "Lets not connect to our selves " << endl;
0162             onFinish(false);
0163             return;
0164         }
0165 
0166         // only finish when the handshake was fully received
0167         onFinish(true);
0168     }
0169 }
0170 
0171 void Authenticate::stop()
0172 {
0173     if (finished)
0174         return;
0175 
0176     onFinish(false);
0177 }
0178 
0179 }
0180 
0181 #include "moc_authenticate.cpp"