void EstablishmentManager::processConfirmed(EstablishmentStatePtr const &state)
        {
            I2P_LOG_SCOPED_TAG(m_log, "RouterHash", state->getTheirIdentity().getHash());

            if(!state->verifyConfirmationSignature()) {
                I2P_LOG(m_log, warning) << "confirmation signature verification failed";
                state->setState(EstablishmentState::State::FAILURE);
                post(state);

                return;
            } else
                I2P_LOG(m_log, debug) << "confirmation signature verification succeeded";

            Endpoint ep = state->getTheirEndpoint();
            PeerState ps(ep, state->getTheirIdentity().getHash());
            ps.setCurrentSessionKey(state->getSessionKey());
            ps.setCurrentMacKey(state->getMacKey());

            std::lock_guard<std::mutex> lock(m_context.peers.getMutex());
            m_context.peers.addPeer(std::move(ps));

            delState(ep);

            m_context.ios.post(boost::bind(boost::ref(m_context.establishedSignal), state->getTheirIdentity().getHash(), (state->getDirection() == EstablishmentState::Direction::INBOUND)));
        }
Beispiel #2
0
		void SearchManager::connectionFailure(RouterHash const rh)
		{
			std::lock_guard<std::mutex> lock(m_searchesMutex);

			if(m_searches.get<1>().count(rh)) {
				I2P_LOG_SCOPED_RH(m_log, rh);

				SearchStateByCurrent::iterator itr = m_searches.get<1>().find(rh);
				const SearchState& ss = *itr;

				m_searches.get<1>().modify(itr, InsertTried(rh));

				RouterHash front;
				if(ss.alternates.size()) {
					front = ss.alternates.front();
					while(!m_ctx.getDatabase().routerExists(front)) {
						I2P_LOG(m_log, debug) << "could not try alternate " << front << " because it doesn't exist";

						m_searches.get<1>().modify(itr, PopAlternates());

						if(ss.alternates.size())
							front = ss.alternates.front();
						else {
							I2P_LOG(m_log, debug) << "no more alternates left, search failed";

							cancel(ss.goal);

							return;
						}
					}

					while(ss.tried.count(front)) {
						m_searches.get<1>().modify(itr, PopAlternates());

						if(ss.alternates.size())
							front = ss.alternates.front();
						else {
							I2P_LOG(m_log, debug) << "no more alternates left, search failed";

							cancel(ss.goal);

							return;
						}
					}

					I2P_LOG(m_log, debug) << "connecting to alternate " << front;

					m_searches.get<1>().modify(itr, ModifyState(front, rh));

					m_ctx.getOutMsgDisp().getTransport()->connect(m_ctx.getDatabase().getRouterInfo(front));
				} else {
					I2P_LOG(m_log, debug) << "connection failed and there are no more alternates, search failed";

					cancel(ss.goal);

					return;
				}
			}
		}
Beispiel #3
0
		void SearchManager::searchReply(RouterHash const from, std::array<unsigned char, 32> const query, std::list<RouterHash> const hashes)
		{
			I2P_LOG_SCOPED_RH(m_log, from);
			I2P_LOG(m_log, debug) << "received search reply";

			std::lock_guard<std::mutex> lock(m_searchesMutex);

			if(m_searches.get<0>().count(query)) {
				I2P_LOG(m_log, debug) << "found RouterHash in pending search table";

				SearchStateByGoal::iterator itr = m_searches.get<0>().find(query);
				const SearchState& ss = *itr;

				if(ss.state == SearchState::LOOKUP_SENT) {
					m_searches.get<0>().modify(itr, InsertTried(from));

					for(auto h: hashes) {
						if(!ss.tried.count(h))
							m_searches.get<0>().modify(itr, PushAlternates(h));
					}

					RouterHash front;
					if(ss.alternates.size()) {
						front = ss.alternates.front();
						while(ss.tried.count(front)) {
							m_searches.get<0>().modify(itr, PopAlternates());

							if(ss.alternates.size())
								front = ss.alternates.front();
							else {
								I2P_LOG(m_log, debug) << "no more alternates left, search failed";

								cancel(ss.goal);

								return;
							}
						}

						if(!m_ctx.getDatabase().routerExists(front)) {
							I2P_LOG(m_log, debug) << "received unknown peer hash " << front << ", asking for its RouterInfo";

							m_searches.get<0>().modify(itr, ModifyState(front));

							I2NP::MessagePtr dbl(new I2NP::DatabaseLookup(front, m_ctx.getIdentity().getHash(), 0, ss.excluded));
							m_ctx.getOutMsgDisp().sendMessage(from, dbl);
						} else {
							I2P_LOG(m_log, debug) << "received known peer hash " << front << ", connecting";

							m_searches.get<0>().modify(itr, ModifyState(front, from));

							m_ctx.getOutMsgDisp().getTransport()->connect(m_ctx.getDatabase().getRouterInfo(front));
						}
					}
				}
			}
		}
        void EstablishmentManager::processCreated(EstablishmentStatePtr const &state)
        {
            state->calculateDHSecret();

            if(!state->verifyCreationSignature()) {
                I2P_LOG(m_log, warning) << "creation signature verification failed";
                state->setState(EstablishmentState::State::FAILURE);
                return;
            }

            const ByteArray& dhSecret = state->getDHSecret();
            SessionKey newKey(toSessionKey(dhSecret)), newMacKey;

            state->setSessionKey(newKey);

            copy(dhSecret.begin() + 32, dhSecret.begin() + 32 + 32, newMacKey.begin());
            state->setMacKey(newMacKey);

            Endpoint ep = state->getTheirEndpoint();
            PeerState ps(ep, state->getTheirIdentity().getHash());
            ps.setCurrentSessionKey(state->getSessionKey());
            ps.setCurrentMacKey(state->getMacKey());

            std::lock_guard<std::mutex> lock(m_context.peers.getMutex());
            m_context.peers.addPeer(std::move(ps));

            PacketPtr p = PacketBuilder::buildSessionConfirmed(state);
            p->encrypt(state->getSessionKey(), state->getMacKey());

            m_context.sendPacket(p);

            state->setState(EstablishmentState::State::CONFIRMED_SENT);
            post(state);
        }
Beispiel #5
0
		void DeliveryStatus::handleMessage(RouterHash const from, I2NP::MessagePtr const msg)
		{
			I2P_LOG_SCOPED_RH(m_log, from);
			I2P_LOG(m_log, debug) << "received DeliveryStatus message, replying with DatabaseStore message";

			Mapping am;
			am.setValue("caps", "BC");
			am.setValue("host", m_ctx.getDatabase().getConfigValue("ssu_external_ip"));
			am.setValue("key", m_ctx.getIdentity().getHashEncoded());
			am.setValue("port", m_ctx.getDatabase().getConfigValue("ssu_external_port"));
			RouterAddress a(5, Date(0), "SSU", am);

			Mapping rm;
			rm.setValue("coreVersion", "0.9.6");
			rm.setValue("netId", "2");
			rm.setValue("router.version", "0.9.6");
			rm.setValue("stat_uptime", "90m");
			rm.setValue("caps", "MR");
			RouterInfo myInfo(m_ctx.getIdentity(), Date(), rm);
			myInfo.addAddress(a);
			myInfo.sign(m_ctx.getSigningKey());

			Botan::Pipe gzPipe(new Botan::Zlib_Compression);
			gzPipe.start_msg();
			gzPipe.write(myInfo.serialize());
			gzPipe.end_msg();

			unsigned int size = gzPipe.remaining();
			ByteArray gzInfoBytes(size);
			gzPipe.read(gzInfoBytes.data(), size);

			auto mydsm = std::make_shared<I2NP::DatabaseStore>(myInfo.getIdentity().getHash(), I2NP::DatabaseStore::DataType::ROUTER_INFO, 0, gzInfoBytes);
			m_ctx.getOutMsgDisp().sendMessage(from, mydsm);
		}
Beispiel #6
0
        void DatabaseStore::handleMessage(RouterHash const from, I2NP::MessagePtr const msg)
        {
            try {
                std::shared_ptr<I2NP::DatabaseStore> dsm = std::dynamic_pointer_cast<I2NP::DatabaseStore>(msg);

                I2P_LOG_SCOPED_TAG(m_log, "RouterHash", from);
                I2P_LOG(m_log, debug) << "received DatabaseStore message";

                Botan::Pipe ungzPipe(new Gzip_Decompression);

                switch(dsm->getDataType()) {
                    case I2NP::DatabaseStore::DataType::ROUTER_INFO:
                        {
                            ungzPipe.start_msg();
                            ungzPipe.write(dsm->getData());
                            ungzPipe.end_msg();

                            unsigned int size = ungzPipe.remaining();
                            ByteArray inflatedData(size);
                            ungzPipe.read(inflatedData.data(), size);

                            auto begin = inflatedData.cbegin();
                            RouterInfo ri(begin, inflatedData.cend());

                            if(ri.verifySignature()) {
                                m_ctx.getDatabase()->setRouterInfo(ri);
                                I2P_LOG(m_log, debug) << "added RouterInfo to DB";

                                m_ctx.getSignals().invokeDatabaseStore(from, ri.getIdentity().getHash(), true);
                            } else {
                                I2P_LOG(m_log, error) << "RouterInfo verification failed";
                            }
                        }

                        break;

                    case I2NP::DatabaseStore::DataType::LEASE_SET:
                        I2P_LOG(m_log, debug) << "this is a LeaseSet";

                        // signal here
                        break;
                }
            } catch(Botan::Decoding_Error &e) {
                I2P_LOG(m_log, error) << "problem decompressing data: " << e.what();
            }
        }
        void VariableTunnelBuildReply::handleMessage(RouterHash const from, I2NP::MessagePtr const msg)
        {
            std::shared_ptr<I2NP::VariableTunnelBuildReply> vtbr = std::dynamic_pointer_cast<I2NP::VariableTunnelBuildReply>(msg);

            I2P_LOG_SCOPED_TAG(m_log, "RouterHash", from);
            I2P_LOG(m_log, debug) << "received VariableTunnelBuildReply message";

            m_ctx.getSignals().invokeTunnelRecordsReceived(vtbr->getMsgId(), vtbr->getRecords());
        }
Beispiel #8
0
        void TunnelData::handleMessage(RouterHash const from, I2NP::MessagePtr const msg)
        {
            std::shared_ptr<I2NP::TunnelData> td = std::dynamic_pointer_cast<I2NP::TunnelData>(msg);

            I2P_LOG_SCOPED_TAG(m_log, "RouterHash", from);
            I2P_LOG(m_log, debug) << "received TunnelData message";

            m_ctx.getSignals().invokeTunnelData(from, td->getTunnelId(), td->getData());
        }
        void DatabaseSearchReply::handleMessage(RouterHash const from, I2NP::MessagePtr const msg)
        {
            std::shared_ptr<I2NP::DatabaseSearchReply> dsr = std::dynamic_pointer_cast<I2NP::DatabaseSearchReply>(msg);

            I2P_LOG_SCOPED_TAG(m_log, "RouterHash", from);
            I2P_LOG(m_log, debug) << "received DatabaseSearchReply message";

            m_ctx.getSignals().invokeSearchReply(from, dsr->getKey(), dsr->getHashes());
        }
Beispiel #10
0
		void SearchManager::timeout(const boost::system::error_code& e, KademliaKey const k)
		{
			if(!e) {
				I2P_LOG(m_log, debug) << "timeout for " << Base64::encode(ByteArray(k.cbegin(), k.cend()));

				std::lock_guard<std::mutex> lock(m_searchesMutex);
				cancel(k);
			}
		}
        void EstablishmentManager::timeoutCallback(const boost::system::error_code& e, EstablishmentStatePtr es)
        {
            if(!e) {
                I2P_LOG_SCOPED_TAG(m_log, "Endpoint", es->getTheirEndpoint());
                I2P_LOG(m_log, debug) << "establishment timed out";

                es->setState(EstablishmentState::State::FAILURE);
                post(es);
            }
        }
Beispiel #12
0
    void PeerManager::callback(const boost::system::error_code &e)
    {
        try {
            uint32_t minPeers = std::stoi(m_ctx.getDatabase()->getConfigValue("min_peers"));
            uint32_t numPeers = m_ctx.getOutMsgDisp().getTransport()->numPeers();

            I2P_LOG(m_log, debug) << "current number of peers: " << numPeers;
            I2P_LOG(m_log, debug) << boost::log::add_value("peers", (uint32_t) numPeers);
            int32_t gap = minPeers - numPeers;
            for(int32_t i = 0; i < gap; i++)
                m_ctx.getOutMsgDisp().getTransport()->connect(m_ctx.getProfileManager().getPeer());

        } catch(std::exception &e) {
                I2P_LOG(m_log, error) << "exception in PeerManager: " << e.what();
        }
        if ( ! m_graceful ) {
            m_timer.expires_at(m_timer.expires_at() + boost::posix_time::time_duration(0, 0, 10));
            m_timer.async_wait(boost::bind(&PeerManager::callback, this, boost::asio::placeholders::error));
        }
    }
Beispiel #13
0
		void SearchManager::databaseStore(RouterHash const from, std::array<unsigned char, 32> const k, bool isRouterInfo)
		{
			I2P_LOG_SCOPED_RH(m_log, from);
			I2P_LOG(m_log, debug) << "received DatabaseStore";

			std::lock_guard<std::mutex> lock(m_searchesMutex);

			if(m_searches.get<0>().count(k)) {
				I2P_LOG(m_log, debug) << "received DatabaseStore for our goal, terminating search";

				SearchStateByGoal::iterator itr = m_searches.get<0>().find(k);
				const SearchState& ss = *itr;

				if(isRouterInfo)
					m_ios.post(boost::bind(boost::ref(m_successSignal), ss.goal, m_ctx.getDatabase().getRouterInfo(k).getIdentity().getHash()));

				m_searches.get<0>().erase(itr);
				m_timers.erase(k);

				return;
			}

			if(isRouterInfo) {
				if(m_searches.get<1>().count(from)) {
					I2P_LOG(m_log, debug) << "found Routerhash in pending search table";

					SearchStateByCurrent::iterator itr = m_searches.get<1>().find(from);
					const SearchState& ss = *itr;

					if(ss.next == k) {
						I2P_LOG(m_log, debug) << "stored hash is one we're waiting for, connecting";

						m_searches.get<1>().modify(itr, ModifyState(k, from));

						m_ctx.getOutMsgDisp().getTransport()->connect(m_ctx.getDatabase().getRouterInfo(k));
					}
				}
			}
		}
Beispiel #14
0
		void SearchManager::connected(RouterHash const rh)
		{
			I2P_LOG_SCOPED_RH(m_log, rh);
			I2P_LOG(m_log, debug) << "connection established";

			std::lock_guard<std::mutex> lock(m_searchesMutex);

			if(m_searches.get<1>().count(rh)) {
				I2P_LOG(m_log, debug) << "found RouterHash in pending search table";

				SearchStateByCurrent::iterator itr = m_searches.get<1>().find(rh);
				const SearchState& ss = *itr;

				if(ss.state == SearchState::CONNECTING) {
					I2P_LOG(m_log, debug) << "found good SearchState, sending DatabaseLookup";

					m_searches.get<1>().modify(itr, ModifyState(SearchState::LOOKUP_SENT));

					I2NP::MessagePtr dbl(new I2NP::DatabaseLookup(ss.goal, m_ctx.getIdentity().getHash(), 0, ss.excluded));
					m_ctx.getOutMsgDisp().getTransport()->send(rh, dbl->toBytes());
				}
			}
		}
        void EstablishmentManager::stateChanged(EstablishmentStatePtr es)
        {
            const Endpoint &ep = es->getTheirEndpoint();
            I2P_LOG_SCOPED_TAG(m_log, "Endpoint", ep);

            switch(es->getState())
            {
                case EstablishmentState::State::REQUEST_SENT:
                    I2P_LOG(m_log, debug) << "sent session request";
                    break;

                case EstablishmentState::State::REQUEST_RECEIVED:
                    I2P_LOG(m_log, debug) << "received session request";
                    processRequest(es);
                    break;

                case EstablishmentState::State::CREATED_SENT:
                    I2P_LOG(m_log, debug) << "sent session created";
                    break;

                case EstablishmentState::State::CREATED_RECEIVED:
                    I2P_LOG(m_log, debug) << "received session created";
                    processCreated(es);
                    break;

                case EstablishmentState::State::CONFIRMED_SENT:
                    {
                        const RouterHash &rh = es->getTheirIdentity().getHash();
                        I2P_LOG_SCOPED_TAG(m_log, "RouterHash", rh);
                        I2P_LOG(m_log, debug) << "sent session confirmed";
                        m_context.ios.post(boost::bind(boost::ref(m_context.establishedSignal), rh, (es->getDirection() == EstablishmentState::Direction::INBOUND)));
                        delState(ep);
                    }
                    break;

                case EstablishmentState::State::CONFIRMED_RECEIVED:
                    I2P_LOG(m_log, debug) << "received session confirmed";
                    processConfirmed(es);
                    break;

                case EstablishmentState::State::UNKNOWN:
                case EstablishmentState::State::FAILURE:
                    I2P_LOG(m_log, info) << "establishment failed";
                    if(es->getDirection() == EstablishmentState::Direction::OUTBOUND)
                        m_context.ios.post(boost::bind(boost::ref(m_context.failureSignal), es->getTheirIdentity().getHash()));

                    delState(ep);
                    break;
            }
        }
Beispiel #16
0
		void SearchManager::createSearch(KademliaKey const &k, RouterHash const &start)
		{
			std::lock_guard<std::mutex> lock(m_searchesMutex);

			if(m_searches.get<0>().count(k)) return;

			SearchState ss;
			ss.goal = k;
			ss.current = start;

			m_searches.insert(ss);

			m_timers[k] = std::make_shared<boost::asio::deadline_timer>(m_ios, boost::posix_time::time_duration(0, 2, 0));
			m_timers[k]->async_wait(boost::bind(&SearchManager::timeout, this, boost::asio::placeholders::error, k));

			I2P_LOG(m_log, debug) << "created SearchState for " << Base64::encode(ByteArray(k.cbegin(), k.cend())) << " starting with " << start;

			m_ctx.getOutMsgDisp().getTransport()->connect(m_ctx.getDatabase().getRouterInfo(start));
		}
Beispiel #17
0
    void Router::start()
    {
        I2P_LOG(m_impl->log, info) << "local router hash: " << m_impl->ctx.getIdentity()->getHash();

        m_impl->serviceThread = std::thread([&](){
            while(1) {
                try {
                    m_impl->ios.run();
                    break;
                } catch(std::exception &e) {
                    // TODO Backtrace
                    I2P_LOG(m_impl->log, error) << "exception in service thread: " << e.what();
                }
            }
        });

        /* Peer conected */
        m_impl->ctx.getSignals().registerPeerConnected(boost::bind(
            &PeerManager::connected, boost::ref(m_impl->ctx.getPeerManager()), _1
        ));
        m_impl->ctx.getSignals().registerPeerConnected(boost::bind(
            &OutboundMessageDispatcher::connected,
            boost::ref(m_impl->ctx.getOutMsgDisp()), _1
        ));
        m_impl->ctx.getSignals().registerPeerConnected(boost::bind(
            &DHT::SearchManager::connected,
            boost::ref(m_impl->ctx.getDHT()->getSearchManager()), _1
        ));

        /* Connection failure */
        m_impl->ctx.getSignals().registerConnectionFailure(boost::bind(
            &DHT::SearchManager::connectionFailure,
            boost::ref(m_impl->ctx.getDHT()->getSearchManager()), _1
        ));
        m_impl->ctx.getSignals().registerConnectionFailure(boost::bind(
            &PeerManager::failure, boost::ref(m_impl->ctx.getPeerManager()), _1
        ));

        m_impl->ctx.getSignals().registerSearchReply(boost::bind(
            &DHT::SearchManager::searchReply,
            boost::ref(m_impl->ctx.getDHT()->getSearchManager()), _1, _2, _3
        ));
        m_impl->ctx.getSignals().registerDatabaseStore(boost::bind(
            &DHT::SearchManager::databaseStore,
            boost::ref(m_impl->ctx.getDHT()->getSearchManager()), _1, _2, _3
        ));

        /* Everything related to tunnels */
        m_impl->ctx.getSignals().registerTunnelRecordsReceived(boost::bind(
            &Tunnel::Manager::receiveRecords,
            boost::ref(m_impl->ctx.getTunnelManager()), _1, _2
        ));
        m_impl->ctx.getSignals().registerTunnelGatewayData(boost::bind(
            &Tunnel::Manager::receiveGatewayData,
            boost::ref(m_impl->ctx.getTunnelManager()), _1, _2, _3
        ));
        m_impl->ctx.getSignals().registerTunnelData(boost::bind(
            &Tunnel::Manager::receiveData,
            boost::ref(m_impl->ctx.getTunnelManager()), _1, _2, _3
        ));

        /* Everything related to the DHT */
        m_impl->ctx.getDHT()->getSearchManager().registerSuccess(boost::bind(
            &OutboundMessageDispatcher::dhtSuccess,
            boost::ref(m_impl->ctx.getOutMsgDisp()), _1, _2
        ));
        m_impl->ctx.getDHT()->getSearchManager().registerFailure(
            boost::bind(&OutboundMessageDispatcher::dhtFailure,
            boost::ref(m_impl->ctx.getOutMsgDisp()), _1
        ));

        m_impl->ctx.getPeerManager().begin();
        //m_impl->ctx.getTunnelManager().begin();
    }
Beispiel #18
0
 void PeerManager::begin()
 {
     I2P_LOG(m_log,info) << "PeerManager beginning";
     m_timer.async_wait(boost::bind(&PeerManager::callback, this, boost::asio::placeholders::error));
 }