mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-04-23 17:36:37 +02:00
commit
a518320e3b
23 changed files with 532 additions and 296 deletions
4
.github/workflows/build-windows.yml
vendored
4
.github/workflows/build-windows.yml
vendored
|
@ -29,3 +29,7 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
mkdir -p obj/Win32 obj/libi2pd obj/libi2pd_client obj/daemon
|
mkdir -p obj/Win32 obj/libi2pd obj/libi2pd_client obj/daemon
|
||||||
make USE_UPNP=yes DEBUG=no -j3
|
make USE_UPNP=yes DEBUG=no -j3
|
||||||
|
- name: Upload artifacts
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
path: i2pd.exe
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -66,6 +66,7 @@ mk_obj_dir:
|
||||||
@mkdir -p obj/$(DAEMON_SRC_DIR)
|
@mkdir -p obj/$(DAEMON_SRC_DIR)
|
||||||
|
|
||||||
api: mk_obj_dir $(SHLIB) $(ARLIB)
|
api: mk_obj_dir $(SHLIB) $(ARLIB)
|
||||||
|
client: mk_obj_dir $(SHLIB_CLIENT) $(ARLIB_CLIENT)
|
||||||
api_client: mk_obj_dir $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT)
|
api_client: mk_obj_dir $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT)
|
||||||
|
|
||||||
## NOTE: The NEEDED_CXXFLAGS are here so that CXXFLAGS can be specified at build time
|
## NOTE: The NEEDED_CXXFLAGS are here so that CXXFLAGS can be specified at build time
|
||||||
|
@ -128,6 +129,7 @@ doxygen:
|
||||||
.PHONY: last-dist
|
.PHONY: last-dist
|
||||||
.PHONY: api
|
.PHONY: api
|
||||||
.PHONY: api_client
|
.PHONY: api_client
|
||||||
|
.PHONY: client
|
||||||
.PHONY: mk_obj_dir
|
.PHONY: mk_obj_dir
|
||||||
.PHONY: install
|
.PHONY: install
|
||||||
.PHONY: strip
|
.PHONY: strip
|
||||||
|
|
|
@ -17,7 +17,12 @@ PIDFile=/run/i2pd/i2pd.pid
|
||||||
### Uncomment, if auto restart needed
|
### Uncomment, if auto restart needed
|
||||||
#Restart=on-failure
|
#Restart=on-failure
|
||||||
|
|
||||||
KillSignal=SIGQUIT
|
# Use SIGTERM to stop i2pd immediately.
|
||||||
|
# Some cleanup processes can delay stopping, so we set 30 seconds timeout and then SIGKILL i2pd.
|
||||||
|
KillSignal=SIGTERM
|
||||||
|
TimeoutStopSec=30s
|
||||||
|
SendSIGKILL=yes
|
||||||
|
|
||||||
# If you have the patience waiting 10 min on restarting/stopping it, uncomment this.
|
# If you have the patience waiting 10 min on restarting/stopping it, uncomment this.
|
||||||
# i2pd stops accepting new tunnels and waits ~10 min while old ones do not die.
|
# i2pd stops accepting new tunnels and waits ~10 min while old ones do not die.
|
||||||
#KillSignal=SIGINT
|
#KillSignal=SIGINT
|
||||||
|
|
|
@ -263,6 +263,9 @@ namespace http {
|
||||||
case eRouterErrorOffline:
|
case eRouterErrorOffline:
|
||||||
s << " - Offline";
|
s << " - Offline";
|
||||||
break;
|
break;
|
||||||
|
case eRouterErrorSymmetricNAT:
|
||||||
|
s << " - Symmetric NAT";
|
||||||
|
break;
|
||||||
default: ;
|
default: ;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -706,23 +709,23 @@ namespace http {
|
||||||
std::stringstream tmp_s, tmp_s6; uint16_t cnt = 0, cnt6 = 0;
|
std::stringstream tmp_s, tmp_s6; uint16_t cnt = 0, cnt6 = 0;
|
||||||
for (const auto& it: sessions )
|
for (const auto& it: sessions )
|
||||||
{
|
{
|
||||||
if (it.second && it.second->IsEstablished () && !it.second->GetSocket ().remote_endpoint ().address ().is_v6 ())
|
if (it.second && it.second->IsEstablished () && !it.second->GetRemoteEndpoint ().address ().is_v6 ())
|
||||||
{
|
{
|
||||||
tmp_s << "<div class=\"listitem\">\r\n";
|
tmp_s << "<div class=\"listitem\">\r\n";
|
||||||
if (it.second->IsOutgoing ()) tmp_s << " ⇒ ";
|
if (it.second->IsOutgoing ()) tmp_s << " ⇒ ";
|
||||||
tmp_s << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": "
|
tmp_s << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": "
|
||||||
<< it.second->GetSocket ().remote_endpoint().address ().to_string ();
|
<< it.second->GetRemoteEndpoint ().address ().to_string ();
|
||||||
if (!it.second->IsOutgoing ()) tmp_s << " ⇒ ";
|
if (!it.second->IsOutgoing ()) tmp_s << " ⇒ ";
|
||||||
tmp_s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
tmp_s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
||||||
tmp_s << "</div>\r\n" << std::endl;
|
tmp_s << "</div>\r\n" << std::endl;
|
||||||
cnt++;
|
cnt++;
|
||||||
}
|
}
|
||||||
if (it.second && it.second->IsEstablished () && it.second->GetSocket ().remote_endpoint ().address ().is_v6 ())
|
if (it.second && it.second->IsEstablished () && it.second->GetRemoteEndpoint ().address ().is_v6 ())
|
||||||
{
|
{
|
||||||
tmp_s6 << "<div class=\"listitem\">\r\n";
|
tmp_s6 << "<div class=\"listitem\">\r\n";
|
||||||
if (it.second->IsOutgoing ()) tmp_s6 << " ⇒ ";
|
if (it.second->IsOutgoing ()) tmp_s6 << " ⇒ ";
|
||||||
tmp_s6 << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": "
|
tmp_s6 << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": "
|
||||||
<< "[" << it.second->GetSocket ().remote_endpoint().address ().to_string () << "]";
|
<< "[" << it.second->GetRemoteEndpoint ().address ().to_string () << "]";
|
||||||
if (!it.second->IsOutgoing ()) tmp_s6 << " ⇒ ";
|
if (!it.second->IsOutgoing ()) tmp_s6 << " ⇒ ";
|
||||||
tmp_s6 << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
tmp_s6 << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
||||||
tmp_s6 << "</div>\r\n" << std::endl;
|
tmp_s6 << "</div>\r\n" << std::endl;
|
||||||
|
|
|
@ -81,10 +81,10 @@ namespace transport
|
||||||
void UPnP::Discover ()
|
void UPnP::Discover ()
|
||||||
{
|
{
|
||||||
bool isError;
|
bool isError;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
#if ((MINIUPNPC_API_VERSION >= 8) || defined (UPNPDISCOVER_SUCCESS))
|
#if ((MINIUPNPC_API_VERSION >= 8) || defined (UPNPDISCOVER_SUCCESS))
|
||||||
err = UPNPDISCOVER_SUCCESS;
|
err = UPNPDISCOVER_SUCCESS;
|
||||||
|
|
||||||
#if (MINIUPNPC_API_VERSION >= 14)
|
#if (MINIUPNPC_API_VERSION >= 14)
|
||||||
m_Devlist = upnpDiscover (UPNP_RESPONSE_TIMEOUT, NULL, NULL, 0, 0, 2, &err);
|
m_Devlist = upnpDiscover (UPNP_RESPONSE_TIMEOUT, NULL, NULL, 0, 0, 2, &err);
|
||||||
|
@ -94,8 +94,8 @@ namespace transport
|
||||||
|
|
||||||
isError = err != UPNPDISCOVER_SUCCESS;
|
isError = err != UPNPDISCOVER_SUCCESS;
|
||||||
#else // MINIUPNPC_API_VERSION >= 8
|
#else // MINIUPNPC_API_VERSION >= 8
|
||||||
err = 0;
|
err = 0;
|
||||||
m_Devlist = upnpDiscover (UPNP_RESPONSE_TIMEOUT, NULL, NULL, 0);
|
m_Devlist = upnpDiscover (UPNP_RESPONSE_TIMEOUT, NULL, NULL, 0);
|
||||||
isError = m_Devlist == NULL;
|
isError = m_Devlist == NULL;
|
||||||
#endif // MINIUPNPC_API_VERSION >= 8
|
#endif // MINIUPNPC_API_VERSION >= 8
|
||||||
{
|
{
|
||||||
|
@ -106,15 +106,15 @@ namespace transport
|
||||||
|
|
||||||
if (isError)
|
if (isError)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "UPnP: unable to discover Internet Gateway Devices: error ", err);
|
LogPrint (eLogError, "UPnP: unable to discover Internet Gateway Devices: error ", err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr));
|
err = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr));
|
||||||
m_upnpUrlsInitialized=err!=0;
|
m_upnpUrlsInitialized=err!=0;
|
||||||
if (err == UPNP_IGD_VALID_CONNECTED)
|
if (err == UPNP_IGD_VALID_CONNECTED)
|
||||||
{
|
{
|
||||||
err = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);
|
err = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);
|
||||||
if(err != UPNPCOMMAND_SUCCESS)
|
if(err != UPNPCOMMAND_SUCCESS)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "UPnP: unable to get external address: error ", err);
|
LogPrint (eLogError, "UPnP: unable to get external address: error ", err);
|
||||||
|
@ -125,14 +125,14 @@ namespace transport
|
||||||
LogPrint (eLogError, "UPnP: found Internet Gateway Device ", m_upnpUrls.controlURL);
|
LogPrint (eLogError, "UPnP: found Internet Gateway Device ", m_upnpUrls.controlURL);
|
||||||
if (!m_externalIPAddress[0])
|
if (!m_externalIPAddress[0])
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "UPnP: found Internet Gateway Device doesn't know our external address");
|
LogPrint (eLogError, "UPnP: found Internet Gateway Device doesn't know our external address");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "UPnP: unable to find valid Internet Gateway Device: error ", err);
|
LogPrint (eLogError, "UPnP: unable to find valid Internet Gateway Device: error ", err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ namespace transport
|
||||||
err = CheckMapping (strPort.c_str (), strType.c_str ());
|
err = CheckMapping (strPort.c_str (), strType.c_str ());
|
||||||
if (err != UPNPCOMMAND_SUCCESS) // if mapping not found
|
if (err != UPNPCOMMAND_SUCCESS) // if mapping not found
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "UPnP: possibly port ", strPort, " is not forwarded: return code ", err);
|
LogPrint (eLogDebug, "UPnP: possibly port ", strPort, " is not forwarded: return code ", err);
|
||||||
|
|
||||||
#if ((MINIUPNPC_API_VERSION >= 8) || defined (UPNPDISCOVER_SUCCESS))
|
#if ((MINIUPNPC_API_VERSION >= 8) || defined (UPNPDISCOVER_SUCCESS))
|
||||||
err = UPNP_AddPortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), NULL, NULL);
|
err = UPNP_AddPortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), NULL, NULL);
|
||||||
|
@ -203,7 +203,7 @@ namespace transport
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "UPnP: external forward from ", m_NetworkAddr, ":", strPort, " exists on current Internet Gateway Device");
|
LogPrint (eLogDebug, "UPnP: external forward from ", m_NetworkAddr, ":", strPort, " exists on current Internet Gateway Device");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,14 +220,14 @@ namespace transport
|
||||||
|
|
||||||
void UPnP::CloseMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address)
|
void UPnP::CloseMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address)
|
||||||
{
|
{
|
||||||
if(!m_upnpUrlsInitialized) {
|
if(!m_upnpUrlsInitialized) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::string strType (GetProto (address)), strPort (std::to_string (address->port));
|
std::string strType (GetProto (address)), strPort (std::to_string (address->port));
|
||||||
int err = UPNPCOMMAND_SUCCESS;
|
int err = UPNPCOMMAND_SUCCESS;
|
||||||
|
|
||||||
err = CheckMapping (strPort.c_str (), strType.c_str ());
|
err = CheckMapping (strPort.c_str (), strType.c_str ());
|
||||||
if (err == UPNPCOMMAND_SUCCESS)
|
if (err == UPNPCOMMAND_SUCCESS)
|
||||||
{
|
{
|
||||||
err = UPNP_DeletePortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strType.c_str (), NULL);
|
err = UPNP_DeletePortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strType.c_str (), NULL);
|
||||||
LogPrint (eLogError, "UPnP: DeletePortMapping() returned : ", err);
|
LogPrint (eLogError, "UPnP: DeletePortMapping() returned : ", err);
|
||||||
|
@ -238,11 +238,11 @@ namespace transport
|
||||||
{
|
{
|
||||||
freeUPNPDevlist (m_Devlist);
|
freeUPNPDevlist (m_Devlist);
|
||||||
m_Devlist = 0;
|
m_Devlist = 0;
|
||||||
if(m_upnpUrlsInitialized){
|
if(m_upnpUrlsInitialized){
|
||||||
FreeUPNPUrls (&m_upnpUrls);
|
FreeUPNPUrls (&m_upnpUrls);
|
||||||
m_upnpUrlsInitialized=false;
|
m_upnpUrlsInitialized=false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string UPnP::GetProto (std::shared_ptr<i2p::data::RouterInfo::Address> address)
|
std::string UPnP::GetProto (std::shared_ptr<i2p::data::RouterInfo::Address> address)
|
||||||
{
|
{
|
||||||
|
|
|
@ -50,7 +50,9 @@ namespace config {
|
||||||
("nat", bool_switch()->default_value(true), "Should we assume we are behind NAT? (default: enabled)")
|
("nat", bool_switch()->default_value(true), "Should we assume we are behind NAT? (default: enabled)")
|
||||||
("port", value<uint16_t>()->default_value(0), "Port to listen for incoming connections (default: auto)")
|
("port", value<uint16_t>()->default_value(0), "Port to listen for incoming connections (default: auto)")
|
||||||
("ipv4", bool_switch()->default_value(true), "Enable communication through ipv4 (default: enabled)")
|
("ipv4", bool_switch()->default_value(true), "Enable communication through ipv4 (default: enabled)")
|
||||||
|
("address4", value<std::string>()->default_value(""), "Local address to bind ipv4 transport sockets to")
|
||||||
("ipv6", bool_switch()->default_value(false), "Enable communication through ipv6 (default: disabled)")
|
("ipv6", bool_switch()->default_value(false), "Enable communication through ipv6 (default: disabled)")
|
||||||
|
("address6", value<std::string>()->default_value(""), "Local address to bind ipv6 transport sockets to")
|
||||||
("reservedrange", bool_switch()->default_value(true), "Check remote RI for being in blacklist of reserved IP ranges (default: enabled)")
|
("reservedrange", bool_switch()->default_value(true), "Check remote RI for being in blacklist of reserved IP ranges (default: enabled)")
|
||||||
("netid", value<int>()->default_value(I2PD_NET_ID), "Specify NetID. Main I2P is 2")
|
("netid", value<int>()->default_value(I2PD_NET_ID), "Specify NetID. Main I2P is 2")
|
||||||
("daemon", bool_switch()->default_value(false), "Router will go to background after start (default: disabled)")
|
("daemon", bool_switch()->default_value(false), "Router will go to background after start (default: disabled)")
|
||||||
|
@ -247,7 +249,7 @@ namespace config {
|
||||||
("ntcp2.enabled", value<bool>()->default_value(true), "Enable NTCP2 (default: enabled)")
|
("ntcp2.enabled", value<bool>()->default_value(true), "Enable NTCP2 (default: enabled)")
|
||||||
("ntcp2.published", value<bool>()->default_value(true), "Publish NTCP2 (default: enabled)")
|
("ntcp2.published", value<bool>()->default_value(true), "Publish NTCP2 (default: enabled)")
|
||||||
("ntcp2.port", value<uint16_t>()->default_value(0), "Port to listen for incoming NTCP2 connections (default: auto)")
|
("ntcp2.port", value<uint16_t>()->default_value(0), "Port to listen for incoming NTCP2 connections (default: auto)")
|
||||||
("ntcp2.addressv6", value<std::string>()->default_value("::"), "Address to bind NTCP2 on")
|
("ntcp2.addressv6", value<std::string>()->default_value("::"), "Address to publish NTCP2 with")
|
||||||
("ntcp2.proxy", value<std::string>()->default_value(""), "Proxy URL for NTCP2 transport")
|
("ntcp2.proxy", value<std::string>()->default_value(""), "Proxy URL for NTCP2 transport")
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
@ -353,7 +353,7 @@ namespace crypto
|
||||||
|
|
||||||
bool X25519Keys::Agree (const uint8_t * pub, uint8_t * shared)
|
bool X25519Keys::Agree (const uint8_t * pub, uint8_t * shared)
|
||||||
{
|
{
|
||||||
if (pub[31] & 0x80) return false; // not x25519 key
|
if (!pub || (pub[31] & 0x80)) return false; // not x25519 key
|
||||||
#if OPENSSL_X25519
|
#if OPENSSL_X25519
|
||||||
EVP_PKEY_derive_init (m_Ctx);
|
EVP_PKEY_derive_init (m_Ctx);
|
||||||
auto pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_X25519, NULL, pub, 32);
|
auto pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_X25519, NULL, pub, 32);
|
||||||
|
|
|
@ -333,15 +333,14 @@ namespace transport
|
||||||
if (in_RemoteRouter) // Alice
|
if (in_RemoteRouter) // Alice
|
||||||
{
|
{
|
||||||
m_Establisher->m_RemoteIdentHash = GetRemoteIdentity ()->GetIdentHash ();
|
m_Establisher->m_RemoteIdentHash = GetRemoteIdentity ()->GetIdentHash ();
|
||||||
if (!addr)
|
|
||||||
addr = in_RemoteRouter->GetNTCP2Address (true); // we need a published address
|
|
||||||
if (addr)
|
if (addr)
|
||||||
{
|
{
|
||||||
memcpy (m_Establisher->m_RemoteStaticKey, addr->ntcp2->staticKey, 32);
|
memcpy (m_Establisher->m_RemoteStaticKey, addr->ntcp2->staticKey, 32);
|
||||||
memcpy (m_Establisher->m_IV, addr->ntcp2->iv, 16);
|
memcpy (m_Establisher->m_IV, addr->ntcp2->iv, 16);
|
||||||
|
m_RemoteEndpoint = boost::asio::ip::tcp::endpoint (addr->host, addr->port);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogWarning, "NTCP2: Missing NTCP2 parameters");
|
LogPrint (eLogWarning, "NTCP2: Missing NTCP2 address");
|
||||||
}
|
}
|
||||||
m_NextRouterInfoResendTime = i2p::util::GetSecondsSinceEpoch () + NTCP2_ROUTERINFO_RESEND_INTERVAL +
|
m_NextRouterInfoResendTime = i2p::util::GetSecondsSinceEpoch () + NTCP2_ROUTERINFO_RESEND_INTERVAL +
|
||||||
rand ()%NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD;
|
rand ()%NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD;
|
||||||
|
@ -657,19 +656,13 @@ namespace transport
|
||||||
SendTerminationAndTerminate (eNTCP2Message3Error);
|
SendTerminationAndTerminate (eNTCP2Message3Error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto addr = ri.GetNTCP2Address (false); // any NTCP2 address
|
auto addr = ri.GetNTCP2AddressWithStaticKey (m_Establisher->m_RemoteStaticKey);
|
||||||
if (!addr)
|
if (!addr)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "NTCP2: No NTCP2 address found in SessionConfirmed");
|
LogPrint (eLogError, "NTCP2: No NTCP2 address wth static key found in SessionConfirmed");
|
||||||
Terminate ();
|
Terminate ();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (memcmp (addr->ntcp2->staticKey, m_Establisher->m_RemoteStaticKey, 32))
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "NTCP2: Static key mismatch in SessionConfirmed");
|
|
||||||
SendTerminationAndTerminate (eNTCP2IncorrectSParameter);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
i2p::data::netdb.PostI2NPMsg (CreateI2NPMessage (eI2NPDummyMsg, buf.data () + 3, size)); // TODO: should insert ri and not parse it twice
|
i2p::data::netdb.PostI2NPMsg (CreateI2NPMessage (eI2NPDummyMsg, buf.data () + 3, size)); // TODO: should insert ri and not parse it twice
|
||||||
// TODO: process options
|
// TODO: process options
|
||||||
|
|
||||||
|
@ -1177,7 +1170,9 @@ namespace transport
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_NTCP2Acceptor.reset (new boost::asio::ip::tcp::acceptor (GetService (), boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address->port)));
|
auto ep = m_Address4 ? boost::asio::ip::tcp::endpoint (m_Address4->address(), address->port):
|
||||||
|
boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4(), address->port);
|
||||||
|
m_NTCP2Acceptor.reset (new boost::asio::ip::tcp::acceptor (GetService (), ep));
|
||||||
}
|
}
|
||||||
catch ( std::exception & ex )
|
catch ( std::exception & ex )
|
||||||
{
|
{
|
||||||
|
@ -1274,10 +1269,15 @@ namespace transport
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NTCP2Server::Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr<NTCP2Session> conn)
|
void NTCP2Server::Connect(std::shared_ptr<NTCP2Session> conn)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "NTCP2: Connecting to ", address ,":", port);
|
if (!conn || conn->GetRemoteEndpoint ().address ().is_unspecified ())
|
||||||
GetService ().post([this, address, port, conn]()
|
{
|
||||||
|
LogPrint (eLogError, "NTCP2: Can't connect to unspecified address");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LogPrint (eLogDebug, "NTCP2: Connecting to ", conn->GetRemoteEndpoint ());
|
||||||
|
GetService ().post([this, conn]()
|
||||||
{
|
{
|
||||||
if (this->AddNTCP2Session (conn))
|
if (this->AddNTCP2Session (conn))
|
||||||
{
|
{
|
||||||
|
@ -1290,12 +1290,32 @@ namespace transport
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "NTCP2: Not connected in ", timeout, " seconds");
|
LogPrint (eLogInfo, "NTCP2: Not connected in ", timeout, " seconds");
|
||||||
if (conn->GetRemoteIdentity ())
|
|
||||||
i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true);
|
|
||||||
conn->Terminate ();
|
conn->Terminate ();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn, timer));
|
// bind to local address
|
||||||
|
std::shared_ptr<boost::asio::ip::tcp::endpoint> localAddress;
|
||||||
|
if (conn->GetRemoteEndpoint ().address ().is_v6 ())
|
||||||
|
{
|
||||||
|
if (i2p::util::net::IsYggdrasilAddress (conn->GetRemoteEndpoint ().address ()))
|
||||||
|
localAddress = m_YggdrasilAddress;
|
||||||
|
else
|
||||||
|
localAddress = m_Address6;
|
||||||
|
conn->GetSocket ().open (boost::asio::ip::tcp::v6 ());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
localAddress = m_Address4;
|
||||||
|
conn->GetSocket ().open (boost::asio::ip::tcp::v4 ());
|
||||||
|
}
|
||||||
|
if (localAddress)
|
||||||
|
{
|
||||||
|
boost::system::error_code ec;
|
||||||
|
conn->GetSocket ().bind (*localAddress, ec);
|
||||||
|
if (ec)
|
||||||
|
LogPrint (eLogError, "NTCP2: can't bind to ", localAddress->address ().to_string (), ": ", ec.message ());
|
||||||
|
}
|
||||||
|
conn->GetSocket ().async_connect (conn->GetRemoteEndpoint (), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn, timer));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
conn->Terminate ();
|
conn->Terminate ();
|
||||||
|
@ -1312,7 +1332,7 @@ namespace transport
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "NTCP2: Connected to ", conn->GetSocket ().remote_endpoint ());
|
LogPrint (eLogDebug, "NTCP2: Connected to ", conn->GetRemoteEndpoint ());
|
||||||
conn->ClientLogin ();
|
conn->ClientLogin ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1328,6 +1348,7 @@ namespace transport
|
||||||
LogPrint (eLogDebug, "NTCP2: Connected from ", ep);
|
LogPrint (eLogDebug, "NTCP2: Connected from ", ep);
|
||||||
if (conn)
|
if (conn)
|
||||||
{
|
{
|
||||||
|
conn->SetRemoteEndpoint (ep);
|
||||||
conn->ServerLogin ();
|
conn->ServerLogin ();
|
||||||
m_PendingIncomingSessions.push_back (conn);
|
m_PendingIncomingSessions.push_back (conn);
|
||||||
conn = nullptr;
|
conn = nullptr;
|
||||||
|
@ -1361,6 +1382,7 @@ namespace transport
|
||||||
LogPrint (eLogDebug, "NTCP2: Connected from ", ep);
|
LogPrint (eLogDebug, "NTCP2: Connected from ", ep);
|
||||||
if (conn)
|
if (conn)
|
||||||
{
|
{
|
||||||
|
conn->SetRemoteEndpoint (ep);
|
||||||
conn->ServerLogin ();
|
conn->ServerLogin ();
|
||||||
m_PendingIncomingSessions.push_back (conn);
|
m_PendingIncomingSessions.push_back (conn);
|
||||||
}
|
}
|
||||||
|
@ -1415,13 +1437,18 @@ namespace transport
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NTCP2Server::ConnectWithProxy (const std::string& host, uint16_t port, RemoteAddressType addrtype, std::shared_ptr<NTCP2Session> conn)
|
void NTCP2Server::ConnectWithProxy (std::shared_ptr<NTCP2Session> conn)
|
||||||
{
|
{
|
||||||
if(!m_ProxyEndpoint) return;
|
if(!m_ProxyEndpoint) return;
|
||||||
GetService().post([this, host, port, addrtype, conn]() {
|
if (!conn || conn->GetRemoteEndpoint ().address ().is_unspecified ())
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "NTCP2: Can't connect to unspecified address");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GetService().post([this, conn]()
|
||||||
|
{
|
||||||
if (this->AddNTCP2Session (conn))
|
if (this->AddNTCP2Session (conn))
|
||||||
{
|
{
|
||||||
|
|
||||||
auto timer = std::make_shared<boost::asio::deadline_timer>(GetService());
|
auto timer = std::make_shared<boost::asio::deadline_timer>(GetService());
|
||||||
auto timeout = NTCP2_CONNECT_TIMEOUT * 5;
|
auto timeout = NTCP2_CONNECT_TIMEOUT * 5;
|
||||||
conn->SetTerminationTimeout(timeout * 2);
|
conn->SetTerminationTimeout(timeout * 2);
|
||||||
|
@ -1431,11 +1458,10 @@ namespace transport
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "NTCP2: Not connected in ", timeout, " seconds");
|
LogPrint (eLogInfo, "NTCP2: Not connected in ", timeout, " seconds");
|
||||||
i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true);
|
|
||||||
conn->Terminate ();
|
conn->Terminate ();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
conn->GetSocket ().async_connect (*m_ProxyEndpoint, std::bind (&NTCP2Server::HandleProxyConnect, this, std::placeholders::_1, conn, timer, host, port, addrtype));
|
conn->GetSocket ().async_connect (*m_ProxyEndpoint, std::bind (&NTCP2Server::HandleProxyConnect, this, std::placeholders::_1, conn, timer));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1447,7 +1473,7 @@ namespace transport
|
||||||
m_ProxyPort = port;
|
m_ProxyPort = port;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NTCP2Server::HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer, const std::string & host, uint16_t port, RemoteAddressType addrtype)
|
void NTCP2Server::HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer)
|
||||||
{
|
{
|
||||||
if (ecode)
|
if (ecode)
|
||||||
{
|
{
|
||||||
|
@ -1473,7 +1499,7 @@ namespace transport
|
||||||
});
|
});
|
||||||
auto readbuff = std::make_shared<std::vector<uint8_t> >(2);
|
auto readbuff = std::make_shared<std::vector<uint8_t> >(2);
|
||||||
boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), 2),
|
boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), 2),
|
||||||
[this, readbuff, timer, conn, host, port, addrtype](const boost::system::error_code & ec, std::size_t transferred)
|
[this, readbuff, timer, conn](const boost::system::error_code & ec, std::size_t transferred)
|
||||||
{
|
{
|
||||||
if(ec)
|
if(ec)
|
||||||
{
|
{
|
||||||
|
@ -1486,7 +1512,7 @@ namespace transport
|
||||||
{
|
{
|
||||||
if((*readbuff)[1] == 0x00)
|
if((*readbuff)[1] == 0x00)
|
||||||
{
|
{
|
||||||
AfterSocksHandshake(conn, timer, host, port, addrtype);
|
AfterSocksHandshake(conn, timer);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if ((*readbuff)[1] == 0xff)
|
else if ((*readbuff)[1] == 0xff)
|
||||||
|
@ -1506,13 +1532,14 @@ namespace transport
|
||||||
}
|
}
|
||||||
case eHTTPProxy:
|
case eHTTPProxy:
|
||||||
{
|
{
|
||||||
|
auto& ep = conn->GetRemoteEndpoint ();
|
||||||
i2p::http::HTTPReq req;
|
i2p::http::HTTPReq req;
|
||||||
req.method = "CONNECT";
|
req.method = "CONNECT";
|
||||||
req.version ="HTTP/1.1";
|
req.version ="HTTP/1.1";
|
||||||
if(addrtype == eIP6Address)
|
if(ep.address ().is_v6 ())
|
||||||
req.uri = "[" + host + "]:" + std::to_string(port);
|
req.uri = "[" + ep.address ().to_string() + "]:" + std::to_string(ep.port ());
|
||||||
else
|
else
|
||||||
req.uri = host + ":" + std::to_string(port);
|
req.uri = ep.address ().to_string() + ":" + std::to_string(ep.port ());
|
||||||
|
|
||||||
boost::asio::streambuf writebuff;
|
boost::asio::streambuf writebuff;
|
||||||
std::ostream out(&writebuff);
|
std::ostream out(&writebuff);
|
||||||
|
@ -1566,7 +1593,7 @@ namespace transport
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NTCP2Server::AfterSocksHandshake(std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer, const std::string & host, uint16_t port, RemoteAddressType addrtype)
|
void NTCP2Server::AfterSocksHandshake(std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer)
|
||||||
{
|
{
|
||||||
// build request
|
// build request
|
||||||
size_t sz = 6; // header + port
|
size_t sz = 6; // header + port
|
||||||
|
@ -1576,27 +1603,28 @@ namespace transport
|
||||||
(*buff)[1] = 0x01;
|
(*buff)[1] = 0x01;
|
||||||
(*buff)[2] = 0x00;
|
(*buff)[2] = 0x00;
|
||||||
|
|
||||||
if(addrtype == eIP4Address)
|
auto& ep = conn->GetRemoteEndpoint ();
|
||||||
|
if(ep.address ().is_v4 ())
|
||||||
{
|
{
|
||||||
(*buff)[3] = 0x01;
|
(*buff)[3] = 0x01;
|
||||||
auto addrbytes = boost::asio::ip::address::from_string(host).to_v4().to_bytes();
|
auto addrbytes = ep.address ().to_v4().to_bytes();
|
||||||
sz += 4;
|
sz += 4;
|
||||||
memcpy(buff->data () + 4, addrbytes.data(), 4);
|
memcpy(buff->data () + 4, addrbytes.data(), 4);
|
||||||
}
|
}
|
||||||
else if (addrtype == eIP6Address)
|
else if (ep.address ().is_v6 ())
|
||||||
{
|
{
|
||||||
(*buff)[3] = 0x04;
|
(*buff)[3] = 0x04;
|
||||||
auto addrbytes = boost::asio::ip::address::from_string(host).to_v6().to_bytes();
|
auto addrbytes = ep.address ().to_v6().to_bytes();
|
||||||
sz += 16;
|
sz += 16;
|
||||||
memcpy(buff->data () + 4, addrbytes.data(), 16);
|
memcpy(buff->data () + 4, addrbytes.data(), 16);
|
||||||
}
|
}
|
||||||
else if (addrtype == eHostname)
|
else
|
||||||
{
|
{
|
||||||
// We mustn't really fall here because all connections are made to IP addresses
|
// We mustn't really fall here because all connections are made to IP addresses
|
||||||
LogPrint(eLogError, "NTCP2: Tried to connect to domain name via socks proxy");
|
LogPrint(eLogError, "NTCP2: Tried to connect to unexpected address via proxy");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
htobe16buf(buff->data () + sz - 2, port);
|
htobe16buf(buff->data () + sz - 2, ep.port ());
|
||||||
boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff->data (), sz), boost::asio::transfer_all(),
|
boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff->data (), sz), boost::asio::transfer_all(),
|
||||||
[buff](const boost::system::error_code & ec, std::size_t written)
|
[buff](const boost::system::error_code & ec, std::size_t written)
|
||||||
{
|
{
|
||||||
|
@ -1623,11 +1651,23 @@ namespace transport
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!e)
|
|
||||||
i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true);
|
|
||||||
timer->cancel();
|
timer->cancel();
|
||||||
conn->Terminate();
|
conn->Terminate();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NTCP2Server::SetLocalAddress (const boost::asio::ip::address& localAddress)
|
||||||
|
{
|
||||||
|
auto addr = std::make_shared<boost::asio::ip::tcp::endpoint>(boost::asio::ip::tcp::endpoint(localAddress, 0));
|
||||||
|
if (localAddress.is_v6 ())
|
||||||
|
{
|
||||||
|
if (i2p::util::net::IsYggdrasilAddress (localAddress))
|
||||||
|
m_YggdrasilAddress = addr;
|
||||||
|
else
|
||||||
|
m_Address6 = addr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_Address4 = addr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,6 +134,8 @@ namespace transport
|
||||||
void Close () { m_Socket.close (); }; // for accept
|
void Close () { m_Socket.close (); }; // for accept
|
||||||
|
|
||||||
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
|
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
|
||||||
|
const boost::asio::ip::tcp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
|
||||||
|
void SetRemoteEndpoint (const boost::asio::ip::tcp::endpoint& ep) { m_RemoteEndpoint = ep; };
|
||||||
|
|
||||||
bool IsEstablished () const { return m_IsEstablished; };
|
bool IsEstablished () const { return m_IsEstablished; };
|
||||||
bool IsTerminated () const { return m_IsTerminated; };
|
bool IsTerminated () const { return m_IsTerminated; };
|
||||||
|
@ -189,6 +191,7 @@ namespace transport
|
||||||
|
|
||||||
NTCP2Server& m_Server;
|
NTCP2Server& m_Server;
|
||||||
boost::asio::ip::tcp::socket m_Socket;
|
boost::asio::ip::tcp::socket m_Socket;
|
||||||
|
boost::asio::ip::tcp::endpoint m_RemoteEndpoint;
|
||||||
bool m_IsEstablished, m_IsTerminated;
|
bool m_IsEstablished, m_IsTerminated;
|
||||||
|
|
||||||
std::unique_ptr<NTCP2Establisher> m_Establisher;
|
std::unique_ptr<NTCP2Establisher> m_Establisher;
|
||||||
|
@ -221,13 +224,6 @@ namespace transport
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum RemoteAddressType
|
|
||||||
{
|
|
||||||
eIP4Address,
|
|
||||||
eIP6Address,
|
|
||||||
eHostname
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ProxyType
|
enum ProxyType
|
||||||
{
|
{
|
||||||
eNoProxy,
|
eNoProxy,
|
||||||
|
@ -246,23 +242,23 @@ namespace transport
|
||||||
void RemoveNTCP2Session (std::shared_ptr<NTCP2Session> session);
|
void RemoveNTCP2Session (std::shared_ptr<NTCP2Session> session);
|
||||||
std::shared_ptr<NTCP2Session> FindNTCP2Session (const i2p::data::IdentHash& ident);
|
std::shared_ptr<NTCP2Session> FindNTCP2Session (const i2p::data::IdentHash& ident);
|
||||||
|
|
||||||
void ConnectWithProxy (const std::string& addr, uint16_t port, RemoteAddressType addrtype, std::shared_ptr<NTCP2Session> conn);
|
void ConnectWithProxy (std::shared_ptr<NTCP2Session> conn);
|
||||||
void Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr<NTCP2Session> conn);
|
void Connect(std::shared_ptr<NTCP2Session> conn);
|
||||||
|
|
||||||
void AfterSocksHandshake(std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer, const std::string & host, uint16_t port, RemoteAddressType addrtype);
|
|
||||||
|
|
||||||
|
|
||||||
bool UsingProxy() const { return m_ProxyType != eNoProxy; };
|
bool UsingProxy() const { return m_ProxyType != eNoProxy; };
|
||||||
void UseProxy(ProxyType proxy, const std::string & address, uint16_t port);
|
void UseProxy(ProxyType proxy, const std::string & address, uint16_t port);
|
||||||
|
|
||||||
|
void SetLocalAddress (const boost::asio::ip::address& localAddress);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void HandleAccept (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error);
|
void HandleAccept (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error);
|
||||||
void HandleAcceptV6 (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error);
|
void HandleAcceptV6 (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error);
|
||||||
|
|
||||||
void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer);
|
void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer);
|
||||||
void HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer, const std::string & host, uint16_t port, RemoteAddressType adddrtype);
|
void HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer);
|
||||||
|
void AfterSocksHandshake(std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer);
|
||||||
|
|
||||||
// timer
|
// timer
|
||||||
void ScheduleTermination ();
|
void ScheduleTermination ();
|
||||||
void HandleTerminationTimer (const boost::system::error_code& ecode);
|
void HandleTerminationTimer (const boost::system::error_code& ecode);
|
||||||
|
@ -279,7 +275,8 @@ namespace transport
|
||||||
uint16_t m_ProxyPort;
|
uint16_t m_ProxyPort;
|
||||||
boost::asio::ip::tcp::resolver m_Resolver;
|
boost::asio::ip::tcp::resolver m_Resolver;
|
||||||
std::unique_ptr<boost::asio::ip::tcp::endpoint> m_ProxyEndpoint;
|
std::unique_ptr<boost::asio::ip::tcp::endpoint> m_ProxyEndpoint;
|
||||||
|
std::shared_ptr<boost::asio::ip::tcp::endpoint> m_Address4, m_Address6, m_YggdrasilAddress;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// for HTTP/I2PControl
|
// for HTTP/I2PControl
|
||||||
|
|
|
@ -1150,7 +1150,7 @@ namespace data
|
||||||
return GetRandomRouter (
|
return GetRandomRouter (
|
||||||
[v4only](std::shared_ptr<const RouterInfo> router)->bool
|
[v4only](std::shared_ptr<const RouterInfo> router)->bool
|
||||||
{
|
{
|
||||||
return !router->IsHidden () && router->IsPeerTesting () && router->IsSSU (v4only);
|
return !router->IsHidden () && router->IsPeerTesting (v4only);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ namespace i2p
|
||||||
if (!Load ())
|
if (!Load ())
|
||||||
CreateNewRouter ();
|
CreateNewRouter ();
|
||||||
m_Decryptor = m_Keys.CreateDecryptor (nullptr);
|
m_Decryptor = m_Keys.CreateDecryptor (nullptr);
|
||||||
|
m_TunnelDecryptor = m_Keys.CreateDecryptor (nullptr);
|
||||||
UpdateRouterInfo ();
|
UpdateRouterInfo ();
|
||||||
if (IsECIES ())
|
if (IsECIES ())
|
||||||
{
|
{
|
||||||
|
@ -77,6 +78,12 @@ namespace i2p
|
||||||
std::string ifname; i2p::config::GetOption("ifname", ifname);
|
std::string ifname; i2p::config::GetOption("ifname", ifname);
|
||||||
std::string ifname4; i2p::config::GetOption("ifname4", ifname4);
|
std::string ifname4; i2p::config::GetOption("ifname4", ifname4);
|
||||||
std::string ifname6; i2p::config::GetOption("ifname6", ifname6);
|
std::string ifname6; i2p::config::GetOption("ifname6", ifname6);
|
||||||
|
|
||||||
|
if ((ntcp2 || ygg) && !m_NTCP2Keys)
|
||||||
|
NewNTCP2Keys ();
|
||||||
|
bool ntcp2Published = false;
|
||||||
|
if (ntcp2)
|
||||||
|
i2p::config::GetOption("ntcp2.published", ntcp2Published);
|
||||||
uint8_t caps = 0;
|
uint8_t caps = 0;
|
||||||
if (ipv4)
|
if (ipv4)
|
||||||
{
|
{
|
||||||
|
@ -86,14 +93,20 @@ namespace i2p
|
||||||
else if (!nat && !ifname.empty())
|
else if (!nat && !ifname.empty())
|
||||||
/* bind to interface, we have no NAT so set external address too */
|
/* bind to interface, we have no NAT so set external address too */
|
||||||
host = i2p::util::net::GetInterfaceAddress(ifname, false).to_string(); // v4
|
host = i2p::util::net::GetInterfaceAddress(ifname, false).to_string(); // v4
|
||||||
|
|
||||||
if(ifname4.size())
|
if(ifname4.size())
|
||||||
host = i2p::util::net::GetInterfaceAddress(ifname4, false).to_string();
|
host = i2p::util::net::GetInterfaceAddress(ifname4, false).to_string();
|
||||||
|
|
||||||
|
if (ntcp2)
|
||||||
|
{
|
||||||
|
if (ntcp2Published)
|
||||||
|
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address_v4::from_string (host), port);
|
||||||
|
else // add non-published NTCP2 address
|
||||||
|
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv);
|
||||||
|
}
|
||||||
if (ssu)
|
if (ssu)
|
||||||
{
|
{
|
||||||
routerInfo.AddSSUAddress (host.c_str(), port, nullptr);
|
routerInfo.AddSSUAddress (host.c_str(), port, nullptr);
|
||||||
caps |= i2p::data::RouterInfo::eReachable | i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer; // R, BC
|
caps |= i2p::data::RouterInfo::eReachable; // R
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ipv6)
|
if (ipv6)
|
||||||
|
@ -103,16 +116,35 @@ namespace i2p
|
||||||
i2p::config::GetOption("host", host);
|
i2p::config::GetOption("host", host);
|
||||||
else if (!ifname.empty())
|
else if (!ifname.empty())
|
||||||
host = i2p::util::net::GetInterfaceAddress(ifname, true).to_string(); // v6
|
host = i2p::util::net::GetInterfaceAddress(ifname, true).to_string(); // v6
|
||||||
|
|
||||||
if(ifname6.size())
|
if(ifname6.size())
|
||||||
host = i2p::util::net::GetInterfaceAddress(ifname6, true).to_string();
|
host = i2p::util::net::GetInterfaceAddress(ifname6, true).to_string();
|
||||||
|
|
||||||
|
if (ntcp2)
|
||||||
|
{
|
||||||
|
if (ntcp2Published)
|
||||||
|
{
|
||||||
|
std::string ntcp2Host;
|
||||||
|
if (!i2p::config::IsDefault ("ntcp2.addressv6"))
|
||||||
|
i2p::config::GetOption ("ntcp2.addressv6", ntcp2Host);
|
||||||
|
else
|
||||||
|
ntcp2Host = host;
|
||||||
|
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address_v6::from_string (ntcp2Host), port);
|
||||||
|
}
|
||||||
|
else if (!ipv4) // no other ntcp2 addresses yet
|
||||||
|
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv);
|
||||||
|
}
|
||||||
if (ssu)
|
if (ssu)
|
||||||
{
|
{
|
||||||
routerInfo.AddSSUAddress (host.c_str(), port, nullptr);
|
routerInfo.AddSSUAddress (host.c_str(), port, nullptr);
|
||||||
caps |= i2p::data::RouterInfo::eReachable; // R
|
caps |= i2p::data::RouterInfo::eReachable; // R
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (ygg)
|
||||||
|
{
|
||||||
|
auto yggaddr = i2p::util::net::GetYggdrasilAddress ();
|
||||||
|
if (!yggaddr.is_unspecified ())
|
||||||
|
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, yggaddr, port);
|
||||||
|
}
|
||||||
|
|
||||||
routerInfo.SetCaps (caps); // caps + L
|
routerInfo.SetCaps (caps); // caps + L
|
||||||
routerInfo.SetProperty ("netId", std::to_string (m_NetID));
|
routerInfo.SetProperty ("netId", std::to_string (m_NetID));
|
||||||
|
@ -120,40 +152,6 @@ namespace i2p
|
||||||
routerInfo.CreateBuffer (m_Keys);
|
routerInfo.CreateBuffer (m_Keys);
|
||||||
m_RouterInfo.SetRouterIdentity (GetIdentity ());
|
m_RouterInfo.SetRouterIdentity (GetIdentity ());
|
||||||
m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ());
|
m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ());
|
||||||
|
|
||||||
if (ntcp2) // we don't store iv in the address if non published so we must update it from keys
|
|
||||||
{
|
|
||||||
if (!m_NTCP2Keys) NewNTCP2Keys ();
|
|
||||||
bool published; i2p::config::GetOption("ntcp2.published", published);
|
|
||||||
if (ipv4 || !published) UpdateNTCP2Address (true); // create not published NTCP2 address
|
|
||||||
if (published)
|
|
||||||
{
|
|
||||||
if (ipv4)
|
|
||||||
PublishNTCP2Address (port, true);
|
|
||||||
if (ipv6)
|
|
||||||
{
|
|
||||||
// add NTCP2 ipv6 address
|
|
||||||
std::string host = "::1";
|
|
||||||
if (!i2p::config::IsDefault ("ntcp2.addressv6"))
|
|
||||||
i2p::config::GetOption ("ntcp2.addressv6", host);
|
|
||||||
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address_v6::from_string (host), port);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// enable added NTCP2 addresses
|
|
||||||
if (ipv4) m_RouterInfo.EnableV4 ();
|
|
||||||
if (ipv6) m_RouterInfo.EnableV6 ();
|
|
||||||
}
|
|
||||||
if (ygg)
|
|
||||||
{
|
|
||||||
auto yggaddr = i2p::util::net::GetYggdrasilAddress ();
|
|
||||||
if (!yggaddr.is_unspecified ())
|
|
||||||
{
|
|
||||||
if (!m_NTCP2Keys) NewNTCP2Keys ();
|
|
||||||
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, yggaddr, port);
|
|
||||||
m_RouterInfo.EnableMesh ();
|
|
||||||
UpdateRouterInfo ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::UpdateRouterInfo ()
|
void RouterContext::UpdateRouterInfo ()
|
||||||
|
@ -226,7 +224,7 @@ namespace i2p
|
||||||
if (port == 9150) port = 9151; // Tor browser
|
if (port == 9150) port = 9151; // Tor browser
|
||||||
}
|
}
|
||||||
if (port) address->port = port;
|
if (port) address->port = port;
|
||||||
address->cost = publish ? 3 : 14;
|
address->cost = publish ? i2p::data::COST_NTCP2_PUBLISHED : i2p::data::COST_NTCP2_NON_PUBLISHED;
|
||||||
address->ntcp2->isPublished = publish;
|
address->ntcp2->isPublished = publish;
|
||||||
address->ntcp2->iv = m_NTCP2Keys->iv;
|
address->ntcp2->iv = m_NTCP2Keys->iv;
|
||||||
updated = true;
|
updated = true;
|
||||||
|
@ -427,7 +425,6 @@ namespace i2p
|
||||||
caps &= ~i2p::data::RouterInfo::eReachable;
|
caps &= ~i2p::data::RouterInfo::eReachable;
|
||||||
caps |= i2p::data::RouterInfo::eUnreachable;
|
caps |= i2p::data::RouterInfo::eUnreachable;
|
||||||
caps &= ~i2p::data::RouterInfo::eFloodfill; // can't be floodfill
|
caps &= ~i2p::data::RouterInfo::eFloodfill; // can't be floodfill
|
||||||
caps &= ~i2p::data::RouterInfo::eSSUIntroducer; // can't be introducer
|
|
||||||
m_RouterInfo.SetCaps (caps);
|
m_RouterInfo.SetCaps (caps);
|
||||||
uint16_t port = 0;
|
uint16_t port = 0;
|
||||||
// delete previous introducers
|
// delete previous introducers
|
||||||
|
@ -435,6 +432,8 @@ namespace i2p
|
||||||
for (auto& addr : addresses)
|
for (auto& addr : addresses)
|
||||||
if (addr->ssu)
|
if (addr->ssu)
|
||||||
{
|
{
|
||||||
|
addr->cost = i2p::data::COST_SSU_THROUGH_INTRODUCERS;
|
||||||
|
addr->caps &= ~i2p::data::RouterInfo::eSSUIntroducer; // can't be introducer
|
||||||
addr->ssu->introducers.clear ();
|
addr->ssu->introducers.clear ();
|
||||||
port = addr->port;
|
port = addr->port;
|
||||||
}
|
}
|
||||||
|
@ -452,7 +451,6 @@ namespace i2p
|
||||||
uint8_t caps = m_RouterInfo.GetCaps ();
|
uint8_t caps = m_RouterInfo.GetCaps ();
|
||||||
caps &= ~i2p::data::RouterInfo::eUnreachable;
|
caps &= ~i2p::data::RouterInfo::eUnreachable;
|
||||||
caps |= i2p::data::RouterInfo::eReachable;
|
caps |= i2p::data::RouterInfo::eReachable;
|
||||||
caps |= i2p::data::RouterInfo::eSSUIntroducer;
|
|
||||||
if (m_IsFloodfill)
|
if (m_IsFloodfill)
|
||||||
caps |= i2p::data::RouterInfo::eFloodfill;
|
caps |= i2p::data::RouterInfo::eFloodfill;
|
||||||
m_RouterInfo.SetCaps (caps);
|
m_RouterInfo.SetCaps (caps);
|
||||||
|
@ -462,6 +460,8 @@ namespace i2p
|
||||||
for (auto& addr : addresses)
|
for (auto& addr : addresses)
|
||||||
if (addr->ssu)
|
if (addr->ssu)
|
||||||
{
|
{
|
||||||
|
addr->cost = i2p::data::COST_SSU_DIRECT;
|
||||||
|
addr->caps |= i2p::data::RouterInfo::eSSUIntroducer;
|
||||||
addr->ssu->introducers.clear ();
|
addr->ssu->introducers.clear ();
|
||||||
port = addr->port;
|
port = addr->port;
|
||||||
}
|
}
|
||||||
|
@ -774,7 +774,7 @@ namespace i2p
|
||||||
|
|
||||||
bool RouterContext::DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx)
|
bool RouterContext::DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx)
|
||||||
{
|
{
|
||||||
if (!m_Decryptor) return false;
|
if (!m_TunnelDecryptor) return false;
|
||||||
if (IsECIES ())
|
if (IsECIES ())
|
||||||
{
|
{
|
||||||
if (!m_InitialNoiseState) return false;
|
if (!m_InitialNoiseState) return false;
|
||||||
|
@ -782,7 +782,7 @@ namespace i2p
|
||||||
m_CurrentNoiseState.reset (new i2p::crypto::NoiseSymmetricState (*m_InitialNoiseState));
|
m_CurrentNoiseState.reset (new i2p::crypto::NoiseSymmetricState (*m_InitialNoiseState));
|
||||||
m_CurrentNoiseState->MixHash (encrypted, 32); // h = SHA256(h || sepk)
|
m_CurrentNoiseState->MixHash (encrypted, 32); // h = SHA256(h || sepk)
|
||||||
uint8_t sharedSecret[32];
|
uint8_t sharedSecret[32];
|
||||||
if (!m_Decryptor->Decrypt (encrypted, sharedSecret, ctx, false))
|
if (!m_TunnelDecryptor->Decrypt (encrypted, sharedSecret, ctx, false))
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Router: Incorrect ephemeral public key");
|
LogPrint (eLogWarning, "Router: Incorrect ephemeral public key");
|
||||||
return false;
|
return false;
|
||||||
|
@ -801,7 +801,7 @@ namespace i2p
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return m_Decryptor->Decrypt (encrypted, data, ctx, false);
|
return m_TunnelDecryptor->Decrypt (encrypted, data, ctx, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
i2p::crypto::X25519Keys& RouterContext::GetStaticKeys ()
|
i2p::crypto::X25519Keys& RouterContext::GetStaticKeys ()
|
||||||
|
|
|
@ -39,7 +39,8 @@ namespace i2p
|
||||||
{
|
{
|
||||||
eRouterErrorNone = 0,
|
eRouterErrorNone = 0,
|
||||||
eRouterErrorClockSkew = 1,
|
eRouterErrorClockSkew = 1,
|
||||||
eRouterErrorOffline = 2
|
eRouterErrorOffline = 2,
|
||||||
|
eRouterErrorSymmetricNAT = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
class RouterContext: public i2p::garlic::GarlicDestination
|
class RouterContext: public i2p::garlic::GarlicDestination
|
||||||
|
@ -153,7 +154,7 @@ namespace i2p
|
||||||
|
|
||||||
i2p::data::RouterInfo m_RouterInfo;
|
i2p::data::RouterInfo m_RouterInfo;
|
||||||
i2p::data::PrivateKeys m_Keys;
|
i2p::data::PrivateKeys m_Keys;
|
||||||
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> m_Decryptor;
|
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> m_Decryptor, m_TunnelDecryptor;
|
||||||
uint64_t m_LastUpdateTime; // in seconds
|
uint64_t m_LastUpdateTime; // in seconds
|
||||||
bool m_AcceptsTunnels, m_IsFloodfill;
|
bool m_AcceptsTunnels, m_IsFloodfill;
|
||||||
std::chrono::time_point<std::chrono::steady_clock> m_StartupTime;
|
std::chrono::time_point<std::chrono::steady_clock> m_StartupTime;
|
||||||
|
|
|
@ -186,6 +186,7 @@ namespace data
|
||||||
|
|
||||||
void RouterInfo::ReadFromStream (std::istream& s)
|
void RouterInfo::ReadFromStream (std::istream& s)
|
||||||
{
|
{
|
||||||
|
m_Caps = 0;
|
||||||
s.read ((char *)&m_Timestamp, sizeof (m_Timestamp));
|
s.read ((char *)&m_Timestamp, sizeof (m_Timestamp));
|
||||||
m_Timestamp = be64toh (m_Timestamp);
|
m_Timestamp = be64toh (m_Timestamp);
|
||||||
// read addresses
|
// read addresses
|
||||||
|
@ -215,6 +216,7 @@ namespace data
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
address->transportStyle = eTransportUnknown;
|
address->transportStyle = eTransportUnknown;
|
||||||
|
address->caps = 0;
|
||||||
address->port = 0;
|
address->port = 0;
|
||||||
uint16_t size, r = 0;
|
uint16_t size, r = 0;
|
||||||
s.read ((char *)&size, sizeof (size)); if (!s) return;
|
s.read ((char *)&size, sizeof (size)); if (!s) return;
|
||||||
|
@ -250,7 +252,7 @@ namespace data
|
||||||
LogPrint (eLogWarning, "RouterInfo: Unexpected field 'key' for NTCP");
|
LogPrint (eLogWarning, "RouterInfo: Unexpected field 'key' for NTCP");
|
||||||
}
|
}
|
||||||
else if (!strcmp (key, "caps"))
|
else if (!strcmp (key, "caps"))
|
||||||
ExtractCaps (value);
|
address->caps = ExtractAddressCaps (value);
|
||||||
else if (!strcmp (key, "s")) // ntcp2 static key
|
else if (!strcmp (key, "s")) // ntcp2 static key
|
||||||
{
|
{
|
||||||
Base64ToByteStream (value, strlen (value), address->ntcp2->staticKey, 32);
|
Base64ToByteStream (value, strlen (value), address->ntcp2->staticKey, 32);
|
||||||
|
@ -309,7 +311,15 @@ namespace data
|
||||||
supportedTransports |= eNTCP2V4;
|
supportedTransports |= eNTCP2V4;
|
||||||
}
|
}
|
||||||
else if (!address->ntcp2->isPublished)
|
else if (!address->ntcp2->isPublished)
|
||||||
supportedTransports |= eNTCP2V4; // most likely, since we don't have host
|
{
|
||||||
|
if (address->caps)
|
||||||
|
{
|
||||||
|
if (address->caps | AddressCaps::eV4) supportedTransports |= eNTCP2V4;
|
||||||
|
if (address->caps | AddressCaps::eV6) supportedTransports |= eNTCP2V6;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
supportedTransports |= eNTCP2V4; // most likely, since we don't have host
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (address->transportStyle == eTransportSSU)
|
else if (address->transportStyle == eTransportSSU)
|
||||||
|
@ -319,7 +329,7 @@ namespace data
|
||||||
if (isHost)
|
if (isHost)
|
||||||
supportedTransports |= address->host.is_v4 () ? eSSUV4 : eSSUV6;
|
supportedTransports |= address->host.is_v4 () ? eSSUV4 : eSSUV6;
|
||||||
else
|
else
|
||||||
if (introducers) supportedTransports |= eSSUV4; // in case if host is not presented
|
if (introducers) supportedTransports |= eSSUV4; // in case if host is not presented
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (supportedTransports)
|
if (supportedTransports)
|
||||||
|
@ -430,18 +440,39 @@ namespace data
|
||||||
case CAPS_FLAG_UNREACHABLE:
|
case CAPS_FLAG_UNREACHABLE:
|
||||||
m_Caps |= Caps::eUnreachable;
|
m_Caps |= Caps::eUnreachable;
|
||||||
break;
|
break;
|
||||||
case CAPS_FLAG_SSU_TESTING:
|
|
||||||
m_Caps |= Caps::eSSUTesting;
|
|
||||||
break;
|
|
||||||
case CAPS_FLAG_SSU_INTRODUCER:
|
|
||||||
m_Caps |= Caps::eSSUIntroducer;
|
|
||||||
break;
|
|
||||||
default: ;
|
default: ;
|
||||||
}
|
}
|
||||||
cap++;
|
cap++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t RouterInfo::ExtractAddressCaps (const char * value) const
|
||||||
|
{
|
||||||
|
uint8_t caps = 0;
|
||||||
|
const char * cap = value;
|
||||||
|
while (*cap)
|
||||||
|
{
|
||||||
|
switch (*cap)
|
||||||
|
{
|
||||||
|
case CAPS_FLAG_V4:
|
||||||
|
caps |= AddressCaps::eV4;
|
||||||
|
break;
|
||||||
|
case CAPS_FLAG_V6:
|
||||||
|
caps |= AddressCaps::eV6;
|
||||||
|
break;
|
||||||
|
case CAPS_FLAG_SSU_TESTING:
|
||||||
|
caps |= AddressCaps::eSSUTesting;
|
||||||
|
break;
|
||||||
|
case CAPS_FLAG_SSU_INTRODUCER:
|
||||||
|
caps |= AddressCaps::eSSUIntroducer;
|
||||||
|
break;
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
cap++;
|
||||||
|
}
|
||||||
|
return caps;
|
||||||
|
}
|
||||||
|
|
||||||
void RouterInfo::UpdateCapsProperty ()
|
void RouterInfo::UpdateCapsProperty ()
|
||||||
{
|
{
|
||||||
std::string caps;
|
std::string caps;
|
||||||
|
@ -482,10 +513,26 @@ namespace data
|
||||||
s.write ((const char *)&address.cost, sizeof (address.cost));
|
s.write ((const char *)&address.cost, sizeof (address.cost));
|
||||||
s.write ((const char *)&address.date, sizeof (address.date));
|
s.write ((const char *)&address.date, sizeof (address.date));
|
||||||
std::stringstream properties;
|
std::stringstream properties;
|
||||||
|
bool isPublished = false;
|
||||||
if (address.transportStyle == eTransportNTCP)
|
if (address.transportStyle == eTransportNTCP)
|
||||||
{
|
{
|
||||||
if (address.IsNTCP2 ())
|
if (address.IsNTCP2 ())
|
||||||
|
{
|
||||||
WriteString ("NTCP2", s);
|
WriteString ("NTCP2", s);
|
||||||
|
if (address.IsPublishedNTCP2 ())
|
||||||
|
isPublished = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteString ("caps", properties);
|
||||||
|
properties << '=';
|
||||||
|
std::string caps;
|
||||||
|
if (address.caps & AddressCaps::eV4) caps += CAPS_FLAG_V4;
|
||||||
|
if (address.caps & AddressCaps::eV6) caps += CAPS_FLAG_V6;
|
||||||
|
if (caps.empty ()) caps += CAPS_FLAG_V4;
|
||||||
|
WriteString (caps, properties);
|
||||||
|
properties << ';';
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
continue; // don't write NTCP address
|
continue; // don't write NTCP address
|
||||||
}
|
}
|
||||||
|
@ -496,15 +543,19 @@ namespace data
|
||||||
WriteString ("caps", properties);
|
WriteString ("caps", properties);
|
||||||
properties << '=';
|
properties << '=';
|
||||||
std::string caps;
|
std::string caps;
|
||||||
if (IsPeerTesting ()) caps += CAPS_FLAG_SSU_TESTING;
|
if (address.IsPeerTesting ()) caps += CAPS_FLAG_SSU_TESTING;
|
||||||
if (IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER;
|
if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER;
|
||||||
|
if (IsReachable ())
|
||||||
|
isPublished = true;
|
||||||
|
else
|
||||||
|
caps += CAPS_FLAG_V4;
|
||||||
WriteString (caps, properties);
|
WriteString (caps, properties);
|
||||||
properties << ';';
|
properties << ';';
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
WriteString ("", s);
|
WriteString ("", s);
|
||||||
|
|
||||||
if (!address.IsNTCP2 () || address.IsPublishedNTCP2 ())
|
if (isPublished)
|
||||||
{
|
{
|
||||||
WriteString ("host", properties);
|
WriteString ("host", properties);
|
||||||
properties << '=';
|
properties << '=';
|
||||||
|
@ -514,7 +565,7 @@ namespace data
|
||||||
if (address.transportStyle == eTransportSSU)
|
if (address.transportStyle == eTransportSSU)
|
||||||
{
|
{
|
||||||
// write introducers if any
|
// write introducers if any
|
||||||
if (address.ssu->introducers.size () > 0)
|
if (!address.ssu->introducers.empty())
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (const auto& introducer: address.ssu->introducers)
|
for (const auto& introducer: address.ssu->introducers)
|
||||||
|
@ -593,7 +644,7 @@ namespace data
|
||||||
WriteString (address.ntcp2->iv.ToBase64 (), properties); properties << ';';
|
WriteString (address.ntcp2->iv.ToBase64 (), properties); properties << ';';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!address.IsNTCP2 () || address.IsPublishedNTCP2 ())
|
if (isPublished || address.ssu)
|
||||||
{
|
{
|
||||||
WriteString ("port", properties);
|
WriteString ("port", properties);
|
||||||
properties << '=';
|
properties << '=';
|
||||||
|
@ -721,7 +772,8 @@ namespace data
|
||||||
addr->host = boost::asio::ip::address::from_string (host);
|
addr->host = boost::asio::ip::address::from_string (host);
|
||||||
addr->port = port;
|
addr->port = port;
|
||||||
addr->transportStyle = eTransportSSU;
|
addr->transportStyle = eTransportSSU;
|
||||||
addr->cost = 10; // NTCP should have priority over SSU
|
addr->cost = COST_SSU_DIRECT; // NTCP2 should have priority over SSU
|
||||||
|
addr->caps = i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer; // BC;
|
||||||
addr->date = 0;
|
addr->date = 0;
|
||||||
addr->ssu.reset (new SSUExt ());
|
addr->ssu.reset (new SSUExt ());
|
||||||
addr->ssu->mtu = mtu;
|
addr->ssu->mtu = mtu;
|
||||||
|
@ -744,7 +796,8 @@ namespace data
|
||||||
addr->host = host;
|
addr->host = host;
|
||||||
addr->port = port;
|
addr->port = port;
|
||||||
addr->transportStyle = eTransportNTCP;
|
addr->transportStyle = eTransportNTCP;
|
||||||
addr->cost = port ? 3 : 14; // override from RouterContext::PublishNTCP2Address
|
addr->cost = port ? COST_NTCP2_PUBLISHED : COST_NTCP2_NON_PUBLISHED; // override from RouterContext::PublishNTCP2Address
|
||||||
|
addr->caps = 0;
|
||||||
addr->date = 0;
|
addr->date = 0;
|
||||||
addr->ntcp2.reset (new NTCP2Ext ());
|
addr->ntcp2.reset (new NTCP2Ext ());
|
||||||
if (port) addr->ntcp2->isPublished = true;
|
if (port) addr->ntcp2->isPublished = true;
|
||||||
|
@ -962,12 +1015,13 @@ namespace data
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetNTCP2Address (bool publishedOnly) const
|
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetNTCP2AddressWithStaticKey (const uint8_t * key) const
|
||||||
{
|
{
|
||||||
|
if (!key) return nullptr;
|
||||||
return GetAddress (
|
return GetAddress (
|
||||||
[publishedOnly](std::shared_ptr<const RouterInfo::Address> address)->bool
|
[key](std::shared_ptr<const RouterInfo::Address> address)->bool
|
||||||
{
|
{
|
||||||
return address->IsNTCP2 () && (!publishedOnly || address->IsPublishedNTCP2 ());
|
return address->IsNTCP2 () && !memcmp (address->ntcp2->staticKey, key, 32);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1019,5 +1073,28 @@ namespace data
|
||||||
return IsReachable () && m_Version >= NETDB_MIN_FLOODFILL_VERSION &&
|
return IsReachable () && m_Version >= NETDB_MIN_FLOODFILL_VERSION &&
|
||||||
GetIdentity ()->GetSigningKeyType () != SIGNING_KEY_TYPE_DSA_SHA1;
|
GetIdentity ()->GetSigningKeyType () != SIGNING_KEY_TYPE_DSA_SHA1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RouterInfo::IsPeerTesting (bool v4only) const
|
||||||
|
{
|
||||||
|
auto supportedTransports = m_SupportedTransports & (eSSUV4 | eSSUV6);
|
||||||
|
if (!supportedTransports) return false; // no SSU
|
||||||
|
if (v4only && !(supportedTransports & eSSUV4)) return false; // no SSU v4
|
||||||
|
return GetAddress (
|
||||||
|
[](std::shared_ptr<const RouterInfo::Address> address)->bool
|
||||||
|
{
|
||||||
|
return (address->transportStyle == eTransportSSU) && address->IsPeerTesting ();
|
||||||
|
}) != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RouterInfo::IsIntroducer () const
|
||||||
|
{
|
||||||
|
// TODO: support ipv6
|
||||||
|
if (!(m_SupportedTransports & eSSUV4)) return false;
|
||||||
|
return GetAddress (
|
||||||
|
[](std::shared_ptr<const RouterInfo::Address> address)->bool
|
||||||
|
{
|
||||||
|
return (address->transportStyle == eTransportSSU) && address->IsIntroducer ();
|
||||||
|
}) != nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,9 +44,16 @@ namespace data
|
||||||
const char CAPS_FLAG_EXTRA_BANDWIDTH1 = 'P'; /* 256-2000 KBps */
|
const char CAPS_FLAG_EXTRA_BANDWIDTH1 = 'P'; /* 256-2000 KBps */
|
||||||
const char CAPS_FLAG_EXTRA_BANDWIDTH2 = 'X'; /* > 2000 KBps */
|
const char CAPS_FLAG_EXTRA_BANDWIDTH2 = 'X'; /* > 2000 KBps */
|
||||||
|
|
||||||
|
const char CAPS_FLAG_V4 = '4';
|
||||||
|
const char CAPS_FLAG_V6 = '6';
|
||||||
const char CAPS_FLAG_SSU_TESTING = 'B';
|
const char CAPS_FLAG_SSU_TESTING = 'B';
|
||||||
const char CAPS_FLAG_SSU_INTRODUCER = 'C';
|
const char CAPS_FLAG_SSU_INTRODUCER = 'C';
|
||||||
|
|
||||||
|
const uint8_t COST_NTCP2_PUBLISHED = 3;
|
||||||
|
const uint8_t COST_NTCP2_NON_PUBLISHED = 14;
|
||||||
|
const uint8_t COST_SSU_DIRECT = 9;
|
||||||
|
const uint8_t COST_SSU_THROUGH_INTRODUCERS = 11;
|
||||||
|
|
||||||
const int MAX_RI_BUFFER_SIZE = 2048; // if RouterInfo exceeds 2048 we consider it as malformed, might be changed later
|
const int MAX_RI_BUFFER_SIZE = 2048; // if RouterInfo exceeds 2048 we consider it as malformed, might be changed later
|
||||||
class RouterInfo: public RoutingDestination
|
class RouterInfo: public RoutingDestination
|
||||||
{
|
{
|
||||||
|
@ -67,12 +74,18 @@ namespace data
|
||||||
eHighBandwidth = 0x02,
|
eHighBandwidth = 0x02,
|
||||||
eExtraBandwidth = 0x04,
|
eExtraBandwidth = 0x04,
|
||||||
eReachable = 0x08,
|
eReachable = 0x08,
|
||||||
eSSUTesting = 0x10,
|
eHidden = 0x10,
|
||||||
eSSUIntroducer = 0x20,
|
eUnreachable = 0x20
|
||||||
eHidden = 0x40,
|
|
||||||
eUnreachable = 0x80
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum AddressCaps
|
||||||
|
{
|
||||||
|
eV4 = 0x01,
|
||||||
|
eV6 = 0x02,
|
||||||
|
eSSUTesting = 0x04,
|
||||||
|
eSSUIntroducer = 0x08
|
||||||
|
};
|
||||||
|
|
||||||
enum TransportStyle
|
enum TransportStyle
|
||||||
{
|
{
|
||||||
eTransportUnknown = 0,
|
eTransportUnknown = 0,
|
||||||
|
@ -111,7 +124,7 @@ namespace data
|
||||||
boost::asio::ip::address host;
|
boost::asio::ip::address host;
|
||||||
int port;
|
int port;
|
||||||
uint64_t date;
|
uint64_t date;
|
||||||
uint8_t cost;
|
uint8_t cost, caps;
|
||||||
std::unique_ptr<SSUExt> ssu; // not null for SSU
|
std::unique_ptr<SSUExt> ssu; // not null for SSU
|
||||||
std::unique_ptr<NTCP2Ext> ntcp2; // not null for NTCP2
|
std::unique_ptr<NTCP2Ext> ntcp2; // not null for NTCP2
|
||||||
|
|
||||||
|
@ -134,6 +147,9 @@ namespace data
|
||||||
|
|
||||||
bool IsNTCP2 () const { return (bool)ntcp2; };
|
bool IsNTCP2 () const { return (bool)ntcp2; };
|
||||||
bool IsPublishedNTCP2 () const { return IsNTCP2 () && ntcp2->isPublished; };
|
bool IsPublishedNTCP2 () const { return IsNTCP2 () && ntcp2->isPublished; };
|
||||||
|
|
||||||
|
bool IsIntroducer () const { return caps & eSSUIntroducer; };
|
||||||
|
bool IsPeerTesting () const { return caps & eSSUTesting; };
|
||||||
};
|
};
|
||||||
typedef std::list<std::shared_ptr<Address> > Addresses;
|
typedef std::list<std::shared_ptr<Address> > Addresses;
|
||||||
|
|
||||||
|
@ -150,7 +166,7 @@ namespace data
|
||||||
uint64_t GetTimestamp () const { return m_Timestamp; };
|
uint64_t GetTimestamp () const { return m_Timestamp; };
|
||||||
int GetVersion () const { return m_Version; };
|
int GetVersion () const { return m_Version; };
|
||||||
Addresses& GetAddresses () { return *m_Addresses; }; // should be called for local RI only, otherwise must return shared_ptr
|
Addresses& GetAddresses () { return *m_Addresses; }; // should be called for local RI only, otherwise must return shared_ptr
|
||||||
std::shared_ptr<const Address> GetNTCP2Address (bool publishedOnly) const;
|
std::shared_ptr<const Address> GetNTCP2AddressWithStaticKey (const uint8_t * key) const;
|
||||||
std::shared_ptr<const Address> GetPublishedNTCP2V4Address () const;
|
std::shared_ptr<const Address> GetPublishedNTCP2V4Address () const;
|
||||||
std::shared_ptr<const Address> GetPublishedNTCP2V6Address () const;
|
std::shared_ptr<const Address> GetPublishedNTCP2V6Address () const;
|
||||||
std::shared_ptr<const Address> GetSSUAddress (bool v4only = true) const;
|
std::shared_ptr<const Address> GetSSUAddress (bool v4only = true) const;
|
||||||
|
@ -183,12 +199,12 @@ namespace data
|
||||||
bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; };
|
bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; };
|
||||||
bool HasValidAddresses () const { return m_SupportedTransports; };
|
bool HasValidAddresses () const { return m_SupportedTransports; };
|
||||||
bool UsesIntroducer () const;
|
bool UsesIntroducer () const;
|
||||||
bool IsIntroducer () const { return m_Caps & eSSUIntroducer; };
|
|
||||||
bool IsPeerTesting () const { return m_Caps & eSSUTesting; };
|
|
||||||
bool IsHidden () const { return m_Caps & eHidden; };
|
bool IsHidden () const { return m_Caps & eHidden; };
|
||||||
bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; };
|
bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; };
|
||||||
bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; };
|
bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; };
|
||||||
bool IsEligibleFloodfill () const;
|
bool IsEligibleFloodfill () const;
|
||||||
|
bool IsPeerTesting (bool v4only) const;
|
||||||
|
bool IsIntroducer () const;
|
||||||
|
|
||||||
uint8_t GetCaps () const { return m_Caps; };
|
uint8_t GetCaps () const { return m_Caps; };
|
||||||
void SetCaps (uint8_t caps);
|
void SetCaps (uint8_t caps);
|
||||||
|
@ -232,6 +248,7 @@ namespace data
|
||||||
size_t ReadString (char* str, size_t len, std::istream& s) const;
|
size_t ReadString (char* str, size_t len, std::istream& s) const;
|
||||||
void WriteString (const std::string& str, std::ostream& s) const;
|
void WriteString (const std::string& str, std::ostream& s) const;
|
||||||
void ExtractCaps (const char * value);
|
void ExtractCaps (const char * value);
|
||||||
|
uint8_t ExtractAddressCaps (const char * value) const;
|
||||||
template<typename Filter>
|
template<typename Filter>
|
||||||
std::shared_ptr<const Address> GetAddress (Filter filter) const;
|
std::shared_ptr<const Address> GetAddress (Filter filter) const;
|
||||||
void UpdateCapsProperty ();
|
void UpdateCapsProperty ();
|
||||||
|
|
167
libi2pd/SSU.cpp
167
libi2pd/SSU.cpp
|
@ -22,21 +22,8 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace transport
|
namespace transport
|
||||||
{
|
{
|
||||||
|
|
||||||
SSUServer::SSUServer (const boost::asio::ip::address & addr, int port):
|
|
||||||
m_OnlyV6(true), m_IsRunning(false), m_Thread (nullptr),
|
|
||||||
m_ReceiversThread (nullptr), m_ReceiversThreadV6 (nullptr), m_Work (m_Service),
|
|
||||||
m_ReceiversWork (m_ReceiversService), m_ReceiversWorkV6 (m_ReceiversServiceV6),
|
|
||||||
m_EndpointV6 (addr, port), m_Socket (m_ReceiversService, m_Endpoint),
|
|
||||||
m_SocketV6 (m_ReceiversServiceV6), m_IntroducersUpdateTimer (m_Service),
|
|
||||||
m_PeerTestsCleanupTimer (m_Service), m_TerminationTimer (m_Service),
|
|
||||||
m_TerminationTimerV6 (m_Service)
|
|
||||||
{
|
|
||||||
OpenSocketV6 ();
|
|
||||||
}
|
|
||||||
|
|
||||||
SSUServer::SSUServer (int port):
|
SSUServer::SSUServer (int port):
|
||||||
m_OnlyV6(false), m_IsRunning(false), m_Thread (nullptr),
|
m_IsRunning(false), m_Thread (nullptr),
|
||||||
m_ReceiversThread (nullptr), m_ReceiversThreadV6 (nullptr), m_Work (m_Service),
|
m_ReceiversThread (nullptr), m_ReceiversThreadV6 (nullptr), m_Work (m_Service),
|
||||||
m_ReceiversWork (m_ReceiversService), m_ReceiversWorkV6 (m_ReceiversServiceV6),
|
m_ReceiversWork (m_ReceiversService), m_ReceiversWorkV6 (m_ReceiversServiceV6),
|
||||||
m_Endpoint (boost::asio::ip::udp::v4 (), port), m_EndpointV6 (boost::asio::ip::udp::v6 (), port),
|
m_Endpoint (boost::asio::ip::udp::v4 (), port), m_EndpointV6 (boost::asio::ip::udp::v6 (), port),
|
||||||
|
@ -44,9 +31,6 @@ namespace transport
|
||||||
m_IntroducersUpdateTimer (m_Service), m_PeerTestsCleanupTimer (m_Service),
|
m_IntroducersUpdateTimer (m_Service), m_PeerTestsCleanupTimer (m_Service),
|
||||||
m_TerminationTimer (m_Service), m_TerminationTimerV6 (m_Service)
|
m_TerminationTimer (m_Service), m_TerminationTimerV6 (m_Service)
|
||||||
{
|
{
|
||||||
OpenSocket ();
|
|
||||||
if (context.SupportsV6 ())
|
|
||||||
OpenSocketV6 ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SSUServer::~SSUServer ()
|
SSUServer::~SSUServer ()
|
||||||
|
@ -91,18 +75,18 @@ namespace transport
|
||||||
void SSUServer::Start ()
|
void SSUServer::Start ()
|
||||||
{
|
{
|
||||||
m_IsRunning = true;
|
m_IsRunning = true;
|
||||||
if (!m_OnlyV6)
|
m_Thread = new std::thread (std::bind (&SSUServer::Run, this));
|
||||||
|
if (context.SupportsV4 ())
|
||||||
{
|
{
|
||||||
m_ReceiversThread = new std::thread (std::bind (&SSUServer::RunReceivers, this));
|
OpenSocket ();
|
||||||
m_Thread = new std::thread (std::bind (&SSUServer::Run, this));
|
m_ReceiversThread = new std::thread (std::bind (&SSUServer::RunReceivers, this));
|
||||||
m_ReceiversService.post (std::bind (&SSUServer::Receive, this));
|
m_ReceiversService.post (std::bind (&SSUServer::Receive, this));
|
||||||
ScheduleTermination ();
|
ScheduleTermination ();
|
||||||
}
|
}
|
||||||
if (context.SupportsV6 ())
|
if (context.SupportsV6 ())
|
||||||
{
|
{
|
||||||
|
OpenSocketV6 ();
|
||||||
m_ReceiversThreadV6 = new std::thread (std::bind (&SSUServer::RunReceiversV6, this));
|
m_ReceiversThreadV6 = new std::thread (std::bind (&SSUServer::RunReceiversV6, this));
|
||||||
if (!m_Thread)
|
|
||||||
m_Thread = new std::thread (std::bind (&SSUServer::Run, this));
|
|
||||||
m_ReceiversServiceV6.post (std::bind (&SSUServer::ReceiveV6, this));
|
m_ReceiversServiceV6.post (std::bind (&SSUServer::ReceiveV6, this));
|
||||||
ScheduleTerminationV6 ();
|
ScheduleTerminationV6 ();
|
||||||
}
|
}
|
||||||
|
@ -205,6 +189,14 @@ namespace transport
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SSUServer::SetLocalAddress (const boost::asio::ip::address& localAddress)
|
||||||
|
{
|
||||||
|
if (localAddress.is_v6 ())
|
||||||
|
m_EndpointV6.address (localAddress);
|
||||||
|
else if (localAddress.is_v4 ())
|
||||||
|
m_Endpoint.address (localAddress);
|
||||||
|
}
|
||||||
|
|
||||||
void SSUServer::AddRelay (uint32_t tag, std::shared_ptr<SSUSession> relay)
|
void SSUServer::AddRelay (uint32_t tag, std::shared_ptr<SSUSession> relay)
|
||||||
{
|
{
|
||||||
m_Relays[tag] = relay;
|
m_Relays[tag] = relay;
|
||||||
|
@ -442,21 +434,21 @@ namespace transport
|
||||||
{
|
{
|
||||||
auto address = router->GetSSUAddress (v4only || !context.SupportsV6 ());
|
auto address = router->GetSSUAddress (v4only || !context.SupportsV6 ());
|
||||||
if (address)
|
if (address)
|
||||||
CreateSession (router, address->host, address->port, peerTest);
|
CreateSession (router, address, peerTest);
|
||||||
else
|
else
|
||||||
LogPrint (eLogWarning, "SSU: Router ", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), " doesn't have SSU address");
|
LogPrint (eLogWarning, "SSU: Router ", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), " doesn't have SSU address");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUServer::CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
|
void SSUServer::CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
|
||||||
const boost::asio::ip::address& addr, int port, bool peerTest)
|
std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest)
|
||||||
{
|
{
|
||||||
if (router)
|
if (router && address)
|
||||||
{
|
{
|
||||||
if (router->UsesIntroducer ())
|
if (router->UsesIntroducer ())
|
||||||
m_Service.post (std::bind (&SSUServer::CreateSessionThroughIntroducer, this, router, peerTest)); // always V4 thread
|
m_Service.post (std::bind (&SSUServer::CreateSessionThroughIntroducer, this, router, address, peerTest)); // always V4 thread
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
boost::asio::ip::udp::endpoint remoteEndpoint (addr, port);
|
boost::asio::ip::udp::endpoint remoteEndpoint (address->host, address->port);
|
||||||
m_Service.post (std::bind (&SSUServer::CreateDirectSession, this, router, remoteEndpoint, peerTest));
|
m_Service.post (std::bind (&SSUServer::CreateDirectSession, this, router, remoteEndpoint, peerTest));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -485,13 +477,13 @@ namespace transport
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUServer::CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest)
|
void SSUServer::CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router,
|
||||||
|
std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest)
|
||||||
{
|
{
|
||||||
if (router && router->UsesIntroducer ())
|
if (router && router->UsesIntroducer () && address)
|
||||||
{
|
{
|
||||||
auto address = router->GetSSUAddress (true); // v4 only for now
|
if (!address->host.is_unspecified () && address->port)
|
||||||
if (address)
|
{
|
||||||
{
|
|
||||||
boost::asio::ip::udp::endpoint remoteEndpoint (address->host, address->port);
|
boost::asio::ip::udp::endpoint remoteEndpoint (address->host, address->port);
|
||||||
auto it = m_Sessions.find (remoteEndpoint);
|
auto it = m_Sessions.find (remoteEndpoint);
|
||||||
// check if session is presented already
|
// check if session is presented already
|
||||||
|
@ -502,70 +494,67 @@ namespace transport
|
||||||
session->SendPeerTest ();
|
session->SendPeerTest ();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// create new session
|
}
|
||||||
int numIntroducers = address->ssu->introducers.size ();
|
// create new session
|
||||||
if (numIntroducers > 0)
|
int numIntroducers = address->ssu->introducers.size ();
|
||||||
|
if (numIntroducers > 0)
|
||||||
|
{
|
||||||
|
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
|
std::shared_ptr<SSUSession> introducerSession;
|
||||||
|
const i2p::data::RouterInfo::Introducer * introducer = nullptr;
|
||||||
|
// we might have a session to introducer already
|
||||||
|
for (int i = 0; i < numIntroducers; i++)
|
||||||
{
|
{
|
||||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
auto intr = &(address->ssu->introducers[i]);
|
||||||
std::shared_ptr<SSUSession> introducerSession;
|
if (intr->iExp > 0 && ts > intr->iExp) continue; // skip expired introducer
|
||||||
const i2p::data::RouterInfo::Introducer * introducer = nullptr;
|
boost::asio::ip::udp::endpoint ep (intr->iHost, intr->iPort);
|
||||||
// we might have a session to introducer already
|
if (ep.address ().is_v4 ()) // ipv4 only
|
||||||
for (int i = 0; i < numIntroducers; i++)
|
|
||||||
{
|
{
|
||||||
auto intr = &(address->ssu->introducers[i]);
|
if (!introducer) introducer = intr; // we pick first one for now
|
||||||
if (intr->iExp > 0 && ts > intr->iExp) continue; // skip expired introducer
|
auto it = m_Sessions.find (ep);
|
||||||
boost::asio::ip::udp::endpoint ep (intr->iHost, intr->iPort);
|
if (it != m_Sessions.end ())
|
||||||
if (ep.address ().is_v4 ()) // ipv4 only
|
|
||||||
{
|
{
|
||||||
if (!introducer) introducer = intr; // we pick first one for now
|
introducerSession = it->second;
|
||||||
it = m_Sessions.find (ep);
|
break;
|
||||||
if (it != m_Sessions.end ())
|
|
||||||
{
|
|
||||||
introducerSession = it->second;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!introducer)
|
|
||||||
{
|
|
||||||
LogPrint (eLogWarning, "SSU: Can't connect to unreachable router and no ipv4 non-expired introducers presented");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (introducerSession) // session found
|
|
||||||
LogPrint (eLogWarning, "SSU: Session to introducer already exists");
|
|
||||||
else // create new
|
|
||||||
{
|
|
||||||
LogPrint (eLogDebug, "SSU: Creating new session to introducer ", introducer->iHost);
|
|
||||||
boost::asio::ip::udp::endpoint introducerEndpoint (introducer->iHost, introducer->iPort);
|
|
||||||
introducerSession = std::make_shared<SSUSession> (*this, introducerEndpoint, router);
|
|
||||||
m_Sessions[introducerEndpoint] = introducerSession;
|
|
||||||
}
|
|
||||||
#if BOOST_VERSION >= 104900
|
|
||||||
if (!address->host.is_unspecified () && address->port)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
// create session
|
|
||||||
auto session = std::make_shared<SSUSession> (*this, remoteEndpoint, router, peerTest);
|
|
||||||
m_Sessions[remoteEndpoint] = session;
|
|
||||||
|
|
||||||
// introduce
|
|
||||||
LogPrint (eLogInfo, "SSU: Introduce new session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()),
|
|
||||||
"] through introducer ", introducer->iHost, ":", introducer->iPort);
|
|
||||||
session->WaitForIntroduction ();
|
|
||||||
if (i2p::context.GetRouterInfo ().UsesIntroducer ()) // if we are unreachable
|
|
||||||
{
|
|
||||||
uint8_t buf[1];
|
|
||||||
Send (buf, 0, remoteEndpoint); // send HolePunch
|
|
||||||
}
|
|
||||||
}
|
|
||||||
introducerSession->Introduce (*introducer, router);
|
|
||||||
}
|
}
|
||||||
else
|
if (!introducer)
|
||||||
LogPrint (eLogWarning, "SSU: Can't connect to unreachable router and no introducers present");
|
{
|
||||||
|
LogPrint (eLogWarning, "SSU: Can't connect to unreachable router and no ipv4 non-expired introducers presented");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (introducerSession) // session found
|
||||||
|
LogPrint (eLogWarning, "SSU: Session to introducer already exists");
|
||||||
|
else // create new
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "SSU: Creating new session to introducer ", introducer->iHost);
|
||||||
|
boost::asio::ip::udp::endpoint introducerEndpoint (introducer->iHost, introducer->iPort);
|
||||||
|
introducerSession = std::make_shared<SSUSession> (*this, introducerEndpoint, router);
|
||||||
|
m_Sessions[introducerEndpoint] = introducerSession;
|
||||||
|
}
|
||||||
|
if (!address->host.is_unspecified () && address->port)
|
||||||
|
{
|
||||||
|
// create session
|
||||||
|
boost::asio::ip::udp::endpoint remoteEndpoint (address->host, address->port);
|
||||||
|
auto session = std::make_shared<SSUSession> (*this, remoteEndpoint, router, peerTest);
|
||||||
|
m_Sessions[remoteEndpoint] = session;
|
||||||
|
|
||||||
|
// introduce
|
||||||
|
LogPrint (eLogInfo, "SSU: Introduce new session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()),
|
||||||
|
"] through introducer ", introducer->iHost, ":", introducer->iPort);
|
||||||
|
session->WaitForIntroduction ();
|
||||||
|
if (i2p::context.GetRouterInfo ().UsesIntroducer ()) // if we are unreachable
|
||||||
|
{
|
||||||
|
uint8_t buf[1];
|
||||||
|
Send (buf, 0, remoteEndpoint); // send HolePunch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
introducerSession->Introduce (*introducer, router);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogWarning, "SSU: Router ", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), " doesn't have SSU address");
|
LogPrint (eLogWarning, "SSU: Can't connect to unreachable router and no introducers present");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,13 +48,12 @@ namespace transport
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SSUServer (int port);
|
SSUServer (int port);
|
||||||
SSUServer (const boost::asio::ip::address & addr, int port); // ipv6 only constructor
|
|
||||||
~SSUServer ();
|
~SSUServer ();
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
void CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false, bool v4only = false);
|
void CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false, bool v4only = false);
|
||||||
void CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
|
void CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
|
||||||
const boost::asio::ip::address& addr, int port, bool peerTest = false);
|
std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest = false);
|
||||||
void CreateDirectSession (std::shared_ptr<const i2p::data::RouterInfo> router, boost::asio::ip::udp::endpoint remoteEndpoint, bool peerTest);
|
void CreateDirectSession (std::shared_ptr<const i2p::data::RouterInfo> router, boost::asio::ip::udp::endpoint remoteEndpoint, bool peerTest);
|
||||||
std::shared_ptr<SSUSession> FindSession (std::shared_ptr<const i2p::data::RouterInfo> router) const;
|
std::shared_ptr<SSUSession> FindSession (std::shared_ptr<const i2p::data::RouterInfo> router) const;
|
||||||
std::shared_ptr<SSUSession> FindSession (const boost::asio::ip::udp::endpoint& e) const;
|
std::shared_ptr<SSUSession> FindSession (const boost::asio::ip::udp::endpoint& e) const;
|
||||||
|
@ -64,7 +63,9 @@ namespace transport
|
||||||
void DeleteAllSessions ();
|
void DeleteAllSessions ();
|
||||||
|
|
||||||
boost::asio::io_service& GetService () { return m_Service; };
|
boost::asio::io_service& GetService () { return m_Service; };
|
||||||
const boost::asio::ip::udp::endpoint& GetEndpoint () const { return m_Endpoint; };
|
uint16_t GetPort () const { return m_Endpoint.port (); };
|
||||||
|
void SetLocalAddress (const boost::asio::ip::address& localAddress);
|
||||||
|
|
||||||
void Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to);
|
void Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to);
|
||||||
void AddRelay (uint32_t tag, std::shared_ptr<SSUSession> relay);
|
void AddRelay (uint32_t tag, std::shared_ptr<SSUSession> relay);
|
||||||
void RemoveRelay (uint32_t tag);
|
void RemoveRelay (uint32_t tag);
|
||||||
|
@ -90,7 +91,8 @@ namespace transport
|
||||||
void HandleReceivedPackets (std::vector<SSUPacket *> packets,
|
void HandleReceivedPackets (std::vector<SSUPacket *> packets,
|
||||||
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> >* sessions);
|
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> >* sessions);
|
||||||
|
|
||||||
void CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false);
|
void CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router,
|
||||||
|
std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest = false);
|
||||||
template<typename Filter>
|
template<typename Filter>
|
||||||
std::shared_ptr<SSUSession> GetRandomV4Session (Filter filter);
|
std::shared_ptr<SSUSession> GetRandomV4Session (Filter filter);
|
||||||
template<typename Filter>
|
template<typename Filter>
|
||||||
|
@ -118,7 +120,6 @@ namespace transport
|
||||||
std::shared_ptr<SSUSession> session; // for Bob to Alice
|
std::shared_ptr<SSUSession> session; // for Bob to Alice
|
||||||
};
|
};
|
||||||
|
|
||||||
bool m_OnlyV6;
|
|
||||||
volatile bool m_IsRunning;
|
volatile bool m_IsRunning;
|
||||||
std::thread * m_Thread, * m_ReceiversThread, * m_ReceiversThreadV6;
|
std::thread * m_Thread, * m_ReceiversThread, * m_ReceiversThreadV6;
|
||||||
boost::asio::io_service m_Service, m_ReceiversService, m_ReceiversServiceV6;
|
boost::asio::io_service m_Service, m_ReceiversService, m_ReceiversServiceV6;
|
||||||
|
|
|
@ -321,6 +321,7 @@ namespace transport
|
||||||
void SSUSession::ProcessSessionConfirmed (const uint8_t * buf, size_t len)
|
void SSUSession::ProcessSessionConfirmed (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "SSU: Session confirmed received");
|
LogPrint (eLogDebug, "SSU: Session confirmed received");
|
||||||
|
m_ConnectTimer.cancel ();
|
||||||
auto headerSize = GetSSUHeaderSize (buf);
|
auto headerSize = GetSSUHeaderSize (buf);
|
||||||
if (headerSize >= len)
|
if (headerSize >= len)
|
||||||
{
|
{
|
||||||
|
@ -683,6 +684,8 @@ namespace transport
|
||||||
buf += 2; // our port
|
buf += 2; // our port
|
||||||
LogPrint (eLogInfo, "SSU: Our external address is ", ourIP.to_string (), ":", ourPort);
|
LogPrint (eLogInfo, "SSU: Our external address is ", ourIP.to_string (), ":", ourPort);
|
||||||
i2p::context.UpdateAddress (ourIP);
|
i2p::context.UpdateAddress (ourIP);
|
||||||
|
if (ourPort != m_Server.GetPort ())
|
||||||
|
i2p::context.SetError (eRouterErrorSymmetricNAT);
|
||||||
uint32_t nonce = bufbe32toh (buf);
|
uint32_t nonce = bufbe32toh (buf);
|
||||||
buf += 4; // nonce
|
buf += 4; // nonce
|
||||||
auto it = m_RelayRequests.find (nonce);
|
auto it = m_RelayRequests.find (nonce);
|
||||||
|
|
|
@ -189,7 +189,6 @@ namespace transport
|
||||||
proxytype = NTCP2Server::eHTTPProxy;
|
proxytype = NTCP2Server::eHTTPProxy;
|
||||||
|
|
||||||
m_NTCP2Server->UseProxy(proxytype, proxyurl.host, proxyurl.port);
|
m_NTCP2Server->UseProxy(proxytype, proxyurl.host, proxyurl.port);
|
||||||
m_NTCP2Server->Start();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint(eLogError, "Transports: unsupported NTCP2 proxy URL ", ntcp2proxy);
|
LogPrint(eLogError, "Transports: unsupported NTCP2 proxy URL ", ntcp2proxy);
|
||||||
|
@ -199,40 +198,91 @@ namespace transport
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
m_NTCP2Server = new NTCP2Server ();
|
m_NTCP2Server = new NTCP2Server ();
|
||||||
m_NTCP2Server->Start ();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// create acceptors
|
// create SSU server
|
||||||
auto& addresses = context.GetRouterInfo ().GetAddresses ();
|
int ssuPort = 0;
|
||||||
for (const auto& address : addresses)
|
if (enableSSU)
|
||||||
{
|
{
|
||||||
if (!address) continue;
|
auto& addresses = context.GetRouterInfo ().GetAddresses ();
|
||||||
if (address->transportStyle == RouterInfo::eTransportSSU)
|
for (const auto& address: addresses)
|
||||||
{
|
{
|
||||||
if (m_SSUServer == nullptr && enableSSU)
|
if (!address) continue;
|
||||||
|
if (address->transportStyle == RouterInfo::eTransportSSU)
|
||||||
{
|
{
|
||||||
if (address->host.is_v4())
|
ssuPort = address->port;
|
||||||
m_SSUServer = new SSUServer (address->port);
|
m_SSUServer = new SSUServer (address->port);
|
||||||
else
|
break;
|
||||||
m_SSUServer = new SSUServer (address->host, address->port);
|
|
||||||
LogPrint (eLogInfo, "Transports: Start listening UDP port ", address->port);
|
|
||||||
try {
|
|
||||||
m_SSUServer->Start ();
|
|
||||||
} catch ( std::exception & ex ) {
|
|
||||||
LogPrint(eLogError, "Transports: Failed to bind to UDP port", address->port);
|
|
||||||
delete m_SSUServer;
|
|
||||||
m_SSUServer = nullptr;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
DetectExternalIP ();
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
LogPrint (eLogError, "Transports: SSU server already exists");
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// bind to interfaces
|
||||||
|
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
|
||||||
|
if (ipv4)
|
||||||
|
{
|
||||||
|
std::string address; i2p::config::GetOption("address4", address);
|
||||||
|
if (!address.empty ())
|
||||||
|
{
|
||||||
|
boost::system::error_code ec;
|
||||||
|
auto addr = boost::asio::ip::address::from_string (address, ec);
|
||||||
|
if (!ec)
|
||||||
|
{
|
||||||
|
if (m_NTCP2Server) m_NTCP2Server->SetLocalAddress (addr);
|
||||||
|
if (m_SSUServer) m_SSUServer->SetLocalAddress (addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
|
||||||
|
if (ipv6)
|
||||||
|
{
|
||||||
|
std::string address; i2p::config::GetOption("address6", address);
|
||||||
|
if (!address.empty ())
|
||||||
|
{
|
||||||
|
boost::system::error_code ec;
|
||||||
|
auto addr = boost::asio::ip::address::from_string (address, ec);
|
||||||
|
if (!ec)
|
||||||
|
{
|
||||||
|
if (m_NTCP2Server) m_NTCP2Server->SetLocalAddress (addr);
|
||||||
|
if (m_SSUServer) m_SSUServer->SetLocalAddress (addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg);
|
||||||
|
if (ygg)
|
||||||
|
{
|
||||||
|
std::string address; i2p::config::GetOption("meshnets.yggaddress", address);
|
||||||
|
if (!address.empty ())
|
||||||
|
{
|
||||||
|
boost::system::error_code ec;
|
||||||
|
auto addr = boost::asio::ip::address::from_string (address, ec);
|
||||||
|
if (!ec && m_NTCP2Server && i2p::util::net::IsYggdrasilAddress (addr))
|
||||||
|
m_NTCP2Server->SetLocalAddress (addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// start servers
|
||||||
|
if (m_NTCP2Server) m_NTCP2Server->Start ();
|
||||||
|
if (m_SSUServer)
|
||||||
|
{
|
||||||
|
LogPrint (eLogInfo, "Transports: Start listening UDP port ", ssuPort);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_SSUServer->Start ();
|
||||||
|
}
|
||||||
|
catch (std::exception& ex )
|
||||||
|
{
|
||||||
|
LogPrint(eLogError, "Transports: Failed to bind to UDP port", ssuPort);
|
||||||
|
m_SSUServer->Stop ();
|
||||||
|
delete m_SSUServer;
|
||||||
|
m_SSUServer = nullptr;
|
||||||
|
}
|
||||||
|
if (m_SSUServer) DetectExternalIP ();
|
||||||
|
}
|
||||||
|
|
||||||
m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT));
|
m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT));
|
||||||
m_PeerCleanupTimer->async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1));
|
m_PeerCleanupTimer->async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1));
|
||||||
|
|
||||||
|
@ -351,7 +401,7 @@ namespace transport
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto r = netdb.FindRouter (ident);
|
auto r = netdb.FindRouter (ident);
|
||||||
if (!r || !r->IsCompatible (i2p::context.GetRouterInfo ())) return;
|
if (!r || r->IsUnreachable () || !r->IsCompatible (i2p::context.GetRouterInfo ())) return;
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||||
it = m_Peers.insert (std::pair<i2p::data::IdentHash, Peer>(ident, { 0, r, {},
|
it = m_Peers.insert (std::pair<i2p::data::IdentHash, Peer>(ident, { 0, r, {},
|
||||||
|
@ -418,19 +468,10 @@ namespace transport
|
||||||
if (address)
|
if (address)
|
||||||
{
|
{
|
||||||
auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router, address);
|
auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router, address);
|
||||||
|
if( m_NTCP2Server->UsingProxy())
|
||||||
if(m_NTCP2Server->UsingProxy())
|
m_NTCP2Server->ConnectWithProxy(s);
|
||||||
{
|
|
||||||
NTCP2Server::RemoteAddressType remote = NTCP2Server::eIP4Address;
|
|
||||||
std::string addr = address->host.to_string();
|
|
||||||
|
|
||||||
if(address->host.is_v6())
|
|
||||||
remote = NTCP2Server::eIP6Address;
|
|
||||||
|
|
||||||
m_NTCP2Server->ConnectWithProxy(addr, address->port, remote, s);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
m_NTCP2Server->Connect (address->host, address->port, s);
|
m_NTCP2Server->Connect (s);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -464,7 +505,7 @@ namespace transport
|
||||||
}
|
}
|
||||||
if (address)
|
if (address)
|
||||||
{
|
{
|
||||||
m_SSUServer->CreateSession (peer.router, address->host, address->port);
|
m_SSUServer->CreateSession (peer.router, address);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -480,7 +521,7 @@ namespace transport
|
||||||
if (address)
|
if (address)
|
||||||
{
|
{
|
||||||
auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router, address);
|
auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router, address);
|
||||||
m_NTCP2Server->Connect (address->host, address->port, s);
|
m_NTCP2Server->Connect (s);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -645,6 +645,22 @@ namespace client
|
||||||
localDestination->RequestDestinationWithEncryptedLeaseSet (addr->blindedPublicKey, requstCallback);
|
localDestination->RequestDestinationWithEncryptedLeaseSet (addr->blindedPublicKey, requstCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BOBCommandSession::LookupLocalCommandHandler (const char * operand, size_t len)
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "BOB: lookup local ", operand);
|
||||||
|
auto addr = context.GetAddressBook ().GetAddress (operand);
|
||||||
|
if (!addr)
|
||||||
|
{
|
||||||
|
SendReplyError ("Address Not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto ls = i2p::data::netdb.FindLeaseSet (addr->identHash);
|
||||||
|
if (ls)
|
||||||
|
SendReplyOK (ls->GetIdentity ()->ToBase64 ().c_str ());
|
||||||
|
else
|
||||||
|
SendReplyError ("Local LeaseSet Not found");
|
||||||
|
}
|
||||||
|
|
||||||
void BOBCommandSession::ClearCommandHandler (const char * operand, size_t len)
|
void BOBCommandSession::ClearCommandHandler (const char * operand, size_t len)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "BOB: clear");
|
LogPrint (eLogDebug, "BOB: clear");
|
||||||
|
@ -770,6 +786,7 @@ namespace client
|
||||||
m_CommandHandlers[BOB_COMMAND_INPORT] = &BOBCommandSession::InportCommandHandler;
|
m_CommandHandlers[BOB_COMMAND_INPORT] = &BOBCommandSession::InportCommandHandler;
|
||||||
m_CommandHandlers[BOB_COMMAND_QUIET] = &BOBCommandSession::QuietCommandHandler;
|
m_CommandHandlers[BOB_COMMAND_QUIET] = &BOBCommandSession::QuietCommandHandler;
|
||||||
m_CommandHandlers[BOB_COMMAND_LOOKUP] = &BOBCommandSession::LookupCommandHandler;
|
m_CommandHandlers[BOB_COMMAND_LOOKUP] = &BOBCommandSession::LookupCommandHandler;
|
||||||
|
m_CommandHandlers[BOB_COMMAND_LOOKUP_LOCAL] = &BOBCommandSession::LookupLocalCommandHandler;
|
||||||
m_CommandHandlers[BOB_COMMAND_CLEAR] = &BOBCommandSession::ClearCommandHandler;
|
m_CommandHandlers[BOB_COMMAND_CLEAR] = &BOBCommandSession::ClearCommandHandler;
|
||||||
m_CommandHandlers[BOB_COMMAND_LIST] = &BOBCommandSession::ListCommandHandler;
|
m_CommandHandlers[BOB_COMMAND_LIST] = &BOBCommandSession::ListCommandHandler;
|
||||||
m_CommandHandlers[BOB_COMMAND_OPTION] = &BOBCommandSession::OptionCommandHandler;
|
m_CommandHandlers[BOB_COMMAND_OPTION] = &BOBCommandSession::OptionCommandHandler;
|
||||||
|
|
|
@ -42,6 +42,7 @@ namespace client
|
||||||
const char BOB_COMMAND_INPORT[] = "inport";
|
const char BOB_COMMAND_INPORT[] = "inport";
|
||||||
const char BOB_COMMAND_QUIET[] = "quiet";
|
const char BOB_COMMAND_QUIET[] = "quiet";
|
||||||
const char BOB_COMMAND_LOOKUP[] = "lookup";
|
const char BOB_COMMAND_LOOKUP[] = "lookup";
|
||||||
|
const char BOB_COMMAND_LOOKUP_LOCAL[] = "lookuplocal";
|
||||||
const char BOB_COMMAND_CLEAR[] = "clear";
|
const char BOB_COMMAND_CLEAR[] = "clear";
|
||||||
const char BOB_COMMAND_LIST[] = "list";
|
const char BOB_COMMAND_LIST[] = "list";
|
||||||
const char BOB_COMMAND_OPTION[] = "option";
|
const char BOB_COMMAND_OPTION[] = "option";
|
||||||
|
@ -206,6 +207,7 @@ namespace client
|
||||||
void InportCommandHandler (const char * operand, size_t len);
|
void InportCommandHandler (const char * operand, size_t len);
|
||||||
void QuietCommandHandler (const char * operand, size_t len);
|
void QuietCommandHandler (const char * operand, size_t len);
|
||||||
void LookupCommandHandler (const char * operand, size_t len);
|
void LookupCommandHandler (const char * operand, size_t len);
|
||||||
|
void LookupLocalCommandHandler (const char * operand, size_t len);
|
||||||
void ClearCommandHandler (const char * operand, size_t len);
|
void ClearCommandHandler (const char * operand, size_t len);
|
||||||
void ListCommandHandler (const char * operand, size_t len);
|
void ListCommandHandler (const char * operand, size_t len);
|
||||||
void OptionCommandHandler (const char * operand, size_t len);
|
void OptionCommandHandler (const char * operand, size_t len);
|
||||||
|
|
|
@ -691,7 +691,7 @@ namespace client
|
||||||
i2p::data::SigningKeyType sigType = section.second.get (I2P_SERVER_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519);
|
i2p::data::SigningKeyType sigType = section.second.get (I2P_SERVER_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519);
|
||||||
i2p::data::CryptoKeyType cryptoType = section.second.get (I2P_CLIENT_TUNNEL_CRYPTO_TYPE, i2p::data::CRYPTO_KEY_TYPE_ELGAMAL);
|
i2p::data::CryptoKeyType cryptoType = section.second.get (I2P_CLIENT_TUNNEL_CRYPTO_TYPE, i2p::data::CRYPTO_KEY_TYPE_ELGAMAL);
|
||||||
|
|
||||||
std::string address = section.second.get<std::string> (I2P_SERVER_TUNNEL_ADDRESS, "127.0.0.1");
|
std::string address = section.second.get<std::string> (I2P_SERVER_TUNNEL_ADDRESS, "");
|
||||||
bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true);
|
bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true);
|
||||||
|
|
||||||
// I2CP
|
// I2CP
|
||||||
|
@ -718,6 +718,7 @@ namespace client
|
||||||
{
|
{
|
||||||
// udp server tunnel
|
// udp server tunnel
|
||||||
// TODO: hostnames
|
// TODO: hostnames
|
||||||
|
if (address.empty ()) address = "127.0.0.1";
|
||||||
auto localAddress = boost::asio::ip::address::from_string(address);
|
auto localAddress = boost::asio::ip::address::from_string(address);
|
||||||
boost::asio::ip::udp::endpoint endpoint(boost::asio::ip::address::from_string(host), port);
|
boost::asio::ip::udp::endpoint endpoint(boost::asio::ip::address::from_string(host), port);
|
||||||
auto serverTunnel = std::make_shared<I2PUDPServerTunnel>(name, localDestination, localAddress, endpoint, port, gzip);
|
auto serverTunnel = std::make_shared<I2PUDPServerTunnel>(name, localDestination, localAddress, endpoint, port, gzip);
|
||||||
|
@ -750,12 +751,13 @@ namespace client
|
||||||
else // regular server tunnel by default
|
else // regular server tunnel by default
|
||||||
serverTunnel = std::make_shared<I2PServerTunnel> (name, host, port, localDestination, inPort, gzip);
|
serverTunnel = std::make_shared<I2PServerTunnel> (name, host, port, localDestination, inPort, gzip);
|
||||||
|
|
||||||
|
if (!address.empty ())
|
||||||
|
serverTunnel->SetLocalAddress (address);
|
||||||
if(!isUniqueLocal)
|
if(!isUniqueLocal)
|
||||||
{
|
{
|
||||||
LogPrint(eLogInfo, "Clients: disabling loopback address mapping");
|
LogPrint(eLogInfo, "Clients: disabling loopback address mapping");
|
||||||
serverTunnel->SetUniqueLocal(isUniqueLocal);
|
serverTunnel->SetUniqueLocal(isUniqueLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (accessList.length () > 0)
|
if (accessList.length () > 0)
|
||||||
{
|
{
|
||||||
std::set<i2p::data::IdentHash> idents;
|
std::set<i2p::data::IdentHash> idents;
|
||||||
|
|
|
@ -107,6 +107,22 @@ namespace client
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void I2PTunnelConnection::Connect (const boost::asio::ip::address& localAddress)
|
||||||
|
{
|
||||||
|
if (m_Socket)
|
||||||
|
{
|
||||||
|
if (m_RemoteEndpoint.address().is_v6 ())
|
||||||
|
m_Socket->open (boost::asio::ip::tcp::v6 ());
|
||||||
|
else
|
||||||
|
m_Socket->open (boost::asio::ip::tcp::v4 ());
|
||||||
|
boost::system::error_code ec;
|
||||||
|
m_Socket->bind (boost::asio::ip::tcp::endpoint (localAddress, 0), ec);
|
||||||
|
if (ec)
|
||||||
|
LogPrint (eLogError, "I2PTunnel: can't bind to ", localAddress.to_string (), ": ", ec.message ());
|
||||||
|
}
|
||||||
|
Connect (false);
|
||||||
|
}
|
||||||
|
|
||||||
void I2PTunnelConnection::Terminate ()
|
void I2PTunnelConnection::Terminate ()
|
||||||
{
|
{
|
||||||
if (Kill()) return;
|
if (Kill()) return;
|
||||||
|
@ -600,6 +616,16 @@ namespace client
|
||||||
m_IsAccessList = true;
|
m_IsAccessList = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void I2PServerTunnel::SetLocalAddress (const std::string& localAddress)
|
||||||
|
{
|
||||||
|
boost::system::error_code ec;
|
||||||
|
auto addr = boost::asio::ip::address::from_string(localAddress, ec);
|
||||||
|
if (!ec)
|
||||||
|
m_LocalAddress.reset (new boost::asio::ip::address (addr));
|
||||||
|
else
|
||||||
|
LogPrint (eLogError, "I2PTunnel: can't set local address ", localAddress);
|
||||||
|
}
|
||||||
|
|
||||||
void I2PServerTunnel::Accept ()
|
void I2PServerTunnel::Accept ()
|
||||||
{
|
{
|
||||||
if (m_PortDestination)
|
if (m_PortDestination)
|
||||||
|
@ -631,7 +657,10 @@ namespace client
|
||||||
// new connection
|
// new connection
|
||||||
auto conn = CreateI2PConnection (stream);
|
auto conn = CreateI2PConnection (stream);
|
||||||
AddHandler (conn);
|
AddHandler (conn);
|
||||||
conn->Connect (m_IsUniqueLocal);
|
if (m_LocalAddress)
|
||||||
|
conn->Connect (*m_LocalAddress);
|
||||||
|
else
|
||||||
|
conn->Connect (m_IsUniqueLocal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,8 @@ namespace client
|
||||||
~I2PTunnelConnection ();
|
~I2PTunnelConnection ();
|
||||||
void I2PConnect (const uint8_t * msg = nullptr, size_t len = 0);
|
void I2PConnect (const uint8_t * msg = nullptr, size_t len = 0);
|
||||||
void Connect (bool isUniqueLocal = true);
|
void Connect (bool isUniqueLocal = true);
|
||||||
|
void Connect (const boost::asio::ip::address& localAddress);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void Terminate ();
|
void Terminate ();
|
||||||
|
@ -314,6 +315,8 @@ namespace client
|
||||||
void SetUniqueLocal (bool isUniqueLocal) { m_IsUniqueLocal = isUniqueLocal; }
|
void SetUniqueLocal (bool isUniqueLocal) { m_IsUniqueLocal = isUniqueLocal; }
|
||||||
bool IsUniqueLocal () const { return m_IsUniqueLocal; }
|
bool IsUniqueLocal () const { return m_IsUniqueLocal; }
|
||||||
|
|
||||||
|
void SetLocalAddress (const std::string& localAddress);
|
||||||
|
|
||||||
const std::string& GetAddress() const { return m_Address; }
|
const std::string& GetAddress() const { return m_Address; }
|
||||||
int GetPort () const { return m_Port; };
|
int GetPort () const { return m_Port; };
|
||||||
uint16_t GetLocalPort () const { return m_PortDestination->GetLocalPort (); };
|
uint16_t GetLocalPort () const { return m_PortDestination->GetLocalPort (); };
|
||||||
|
@ -339,6 +342,7 @@ namespace client
|
||||||
std::shared_ptr<i2p::stream::StreamingDestination> m_PortDestination;
|
std::shared_ptr<i2p::stream::StreamingDestination> m_PortDestination;
|
||||||
std::set<i2p::data::IdentHash> m_AccessList;
|
std::set<i2p::data::IdentHash> m_AccessList;
|
||||||
bool m_IsAccessList;
|
bool m_IsAccessList;
|
||||||
|
std::unique_ptr<boost::asio::ip::address> m_LocalAddress;
|
||||||
};
|
};
|
||||||
|
|
||||||
class I2PServerTunnelHTTP: public I2PServerTunnel
|
class I2PServerTunnelHTTP: public I2PServerTunnel
|
||||||
|
|
Loading…
Add table
Reference in a new issue