<commit_before>/*
* Copyright (c) 2013-2021, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/

#include <stdio.h>
#include <string.h>
#include "I2PEndian.h"
#include <fstream>
#include <boost/lexical_cast.hpp>
#include <boost/make_shared.hpp>
#if (BOOST_VERSION >= 105300)
#include <boost/atomic.hpp>
#endif
#include "version.h"
#include "util.h"
#include "Crypto.h"
#include "Base.h"
#include "Timestamp.h"
#include "Log.h"
#include "NetDb.hpp"
#include "RouterContext.h"
#include "RouterInfo.h"

namespace i2p
{
namespace data
{
	RouterInfo::RouterInfo (): m_Buffer (nullptr)
	{
		m_Addresses = boost::make_shared<Addresses>(); // create empty list
	}

	RouterInfo::RouterInfo (const std::string& fullPath):
		m_IsUpdated (false), m_IsUnreachable (false), m_SupportedTransports (0),
		m_ReachableTransports (0), m_Caps (0), m_Version (0)
	{
		m_Addresses = boost::make_shared<Addresses>(); // create empty list
		m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
		ReadFromFile (fullPath);
	}

	RouterInfo::RouterInfo (const uint8_t * buf, int len):
		m_IsUpdated (true), m_IsUnreachable (false), m_SupportedTransports (0),
		m_ReachableTransports (0), m_Caps (0), m_Version (0)
	{
		m_Addresses = boost::make_shared<Addresses>(); // create empty list
		if (len <= MAX_RI_BUFFER_SIZE)
		{
			m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
			memcpy (m_Buffer, buf, len);
			m_BufferLen = len;
			ReadFromBuffer (true);
		}
		else
		{
			LogPrint (eLogError, "RouterInfo: Buffer is too long ", len, ". Ignored");
			m_Buffer = nullptr;
			m_IsUnreachable = true;
		}
	}

	RouterInfo::~RouterInfo ()
	{
		delete[] m_Buffer;
	}

	void RouterInfo::Update (const uint8_t * buf, size_t len)
	{
		if (len > MAX_RI_BUFFER_SIZE)
		{
			LogPrint (eLogError, "RouterInfo: Buffer is too long ", len);
			m_IsUnreachable = true;
			return;
		}
		// verify signature since we have identity already
		int l = len - m_RouterIdentity->GetSignatureLen ();
		if (m_RouterIdentity->Verify (buf, l, buf + l))
		{
			// clean up
			m_IsUpdated = true;
			m_IsUnreachable = false;
			m_SupportedTransports = 0;
			m_ReachableTransports = 0;
			m_Caps = 0;
			// don't clean up m_Addresses, it will be replaced in ReadFromStream
			m_Properties.clear ();
			// copy buffer
			if (!m_Buffer)
				m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
			memcpy (m_Buffer, buf, len);
			m_BufferLen = len;
			// skip identity
			size_t identityLen = m_RouterIdentity->GetFullLen ();
			// read new RI
			std::stringstream str (std::string ((char *)m_Buffer + identityLen, m_BufferLen - identityLen));
			ReadFromStream (str);
			// don't delete buffer until saved to the file
		}
		else
		{
			LogPrint (eLogError, "RouterInfo: Signature verification failed");
			m_IsUnreachable = true;
		}
	}

	void RouterInfo::SetRouterIdentity (std::shared_ptr<const IdentityEx> identity)
	{
		m_RouterIdentity = identity;
		m_Timestamp = i2p::util::GetMillisecondsSinceEpoch ();
	}

	bool RouterInfo::LoadFile (const std::string& fullPath)
	{
		std::ifstream s(fullPath, std::ifstream::binary);
		if (s.is_open ())
		{
			s.seekg (0,std::ios::end);
			m_BufferLen = s.tellg ();
			if (m_BufferLen < 40 || m_BufferLen > MAX_RI_BUFFER_SIZE)
			{
				LogPrint(eLogError, "RouterInfo: File", fullPath, " is malformed");
				return false;
			}
			s.seekg(0, std::ios::beg);
			if (!m_Buffer) m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
			s.read((char *)m_Buffer, m_BufferLen);
		}
		else
		{
			LogPrint (eLogError, "RouterInfo: Can't open file ", fullPath);
			return false;
		}
		return true;
	}

	void RouterInfo::ReadFromFile (const std::string& fullPath)
	{
		if (LoadFile (fullPath))
			ReadFromBuffer (false);
		else
			m_IsUnreachable = true;
	}

	void RouterInfo::ReadFromBuffer (bool verifySignature)
	{
		m_RouterIdentity = std::make_shared<IdentityEx>(m_Buffer, m_BufferLen);
		size_t identityLen = m_RouterIdentity->GetFullLen ();
		if (identityLen >= m_BufferLen)
		{
			LogPrint (eLogError, "RouterInfo: Identity length ", identityLen, " exceeds buffer size ", m_BufferLen);
			m_IsUnreachable = true;
			return;
		}
		if (verifySignature)
		{
			// reject RSA signatures
			if (m_RouterIdentity->IsRSA ())
			{
				LogPrint (eLogError, "RouterInfo: RSA signature type is not allowed");<commit_msg>allocated actual buffer size for RouterInfo<commit_after>/*
* Copyright (c) 2013-2021, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/

#include <stdio.h>
#include <string.h>
#include "I2PEndian.h"
#include <fstream>
#include <boost/lexical_cast.hpp>
#include <boost/make_shared.hpp>
#if (BOOST_VERSION >= 105300)
#include <boost/atomic.hpp>
#endif
#include "version.h"
#include "util.h"
#include "Crypto.h"
#include "Base.h"
#include "Timestamp.h"
#include "Log.h"
#include "NetDb.hpp"
#include "RouterContext.h"
#include "RouterInfo.h"

namespace i2p
{
namespace data
{
	RouterInfo::RouterInfo (): m_Buffer (nullptr)
	{
		m_Addresses = boost::make_shared<Addresses>(); // create empty list
	}

	RouterInfo::RouterInfo (const std::string& fullPath):
		m_Buffer (nullptr), m_IsUpdated (false), m_IsUnreachable (false), 
		m_SupportedTransports (0),m_ReachableTransports (0), m_Caps (0), m_Version (0)
	{
		m_Addresses = boost::make_shared<Addresses>(); // create empty list
		ReadFromFile (fullPath);
	}

	RouterInfo::RouterInfo (const uint8_t * buf, int len):
		m_IsUpdated (true), m_IsUnreachable (false), m_SupportedTransports (0),
		m_ReachableTransports (0), m_Caps (0), m_Version (0)
	{
		m_Addresses = boost::make_shared<Addresses>(); // create empty list
		if (len <= MAX_RI_BUFFER_SIZE)
		{
			m_Buffer = new uint8_t[len];
			memcpy (m_Buffer, buf, len);
			m_BufferLen = len;
			ReadFromBuffer (true);
		}
		else
		{
			LogPrint (eLogError, "RouterInfo: Buffer is too long ", len, ". Ignored");
			m_Buffer = nullptr;
			m_IsUnreachable = true;
		}
	}

	RouterInfo::~RouterInfo ()
	{
		delete[] m_Buffer;
	}

	void RouterInfo::Update (const uint8_t * buf, size_t len)
	{
		if (len > MAX_RI_BUFFER_SIZE)
		{
			LogPrint (eLogError, "RouterInfo: Buffer is too long ", len);
			m_IsUnreachable = true;
			return;
		}
		// verify signature since we have identity already
		int l = len - m_RouterIdentity->GetSignatureLen ();
		if (m_RouterIdentity->Verify (buf, l, buf + l))
		{
			// clean up
			m_IsUpdated = true;
			m_IsUnreachable = false;
			m_SupportedTransports = 0;
			m_ReachableTransports = 0;
			m_Caps = 0;
			// don't clean up m_Addresses, it will be replaced in ReadFromStream
			m_Properties.clear ();
			// copy buffer
			if (m_Buffer && m_BufferLen < len)
			{
				delete[] m_Buffer;
				m_Buffer = nullptr;
			}	
			if (!m_Buffer)
				m_Buffer = new uint8_t[len];
			memcpy (m_Buffer, buf, len);
			m_BufferLen = len;
			// skip identity
			size_t identityLen = m_RouterIdentity->GetFullLen ();
			// read new RI
			std::stringstream str (std::string ((char *)m_Buffer + identityLen, m_BufferLen - identityLen));
			ReadFromStream (str);
			// don't delete buffer until saved to the file
		}
		else
		{
			LogPrint (eLogError, "RouterInfo: Signature verification failed");
			m_IsUnreachable = true;
		}
	}

	void RouterInfo::SetRouterIdentity (std::shared_ptr<const IdentityEx> identity)
	{
		m_RouterIdentity = identity;
		m_Timestamp = i2p::util::GetMillisecondsSinceEpoch ();
	}

	bool RouterInfo::LoadFile (const std::string& fullPath)
	{
		std::ifstream s(fullPath, std::ifstream::binary);
		if (s.is_open ())
		{
			s.seekg (0,std::ios::end);
			m_BufferLen = s.tellg ();
			if (m_BufferLen < 40 || m_BufferLen > MAX_RI_BUFFER_SIZE)
			{
				LogPrint(eLogError, "RouterInfo: File", fullPath, " is malformed");
				return false;
			}
			s.seekg(0, std::ios::beg);
			if (m_Buffer) delete[] m_Buffer;
			m_Buffer = new uint8_t[m_BufferLen];
			s.read((char *)m_Buffer, m_BufferLen);
		}
		else
		{
			LogPrint (eLogError, "RouterInfo: Can't open file ", fullPath);
			return false;
		}
		return true;
	}

	void RouterInfo::ReadFromFile (const std::string& fullPath)
	{
		if (LoadFile (fullPath))
			ReadFromBuffer (false);
		else
			m_IsUnreachable = true;
	}

	void RouterInfo::ReadFromBuffer (bool verifySignature)
	{
		if (!m_Buffer)
		{
			m_IsUnreachable = true;
			return;
		}	
		m_RouterIdentity = std::make_shared<IdentityEx>(m_Buffer, m_BufferLen);
		size_t identityLen = m_RouterIdentity->GetFullLen ();
		if (identityLen >= m_BufferLen)
		{
			LogPrint (eLogError, "RouterInfo: Identity length ", identityLen, " exceeds buffer size ", m_BufferLen);
			m_IsUnreachable = true;
			return;
		}
		if (verifySignature)
		{
			// reject RSA signatures
			if (m_RouterIdentity->IsRSA ())
			{
				LogPrint (eLogError, "RouterInfo: RSA signature type is not allowed");
{'fraction_non_alphanumeric': 0.127196935556557, 'fraction_numerical': 0.009125732311852186, 'mean_word_length': 4.110535405872193, 'pattern_counts': {'":': 0, '<': 30, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5593421', 'n_tokens_mistral': 3575, 'n_tokens_neox': 3174, 'n_words': 779}