diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp
index 2a083dea..d236ca3d 100644
--- a/daemon/HTTPServer.cpp
+++ b/daemon/HTTPServer.cpp
@@ -222,7 +222,7 @@ namespace http {
s << "" << tr("ERROR") << ": " << string << "
\r\n";
}
- static void ShowNetworkStatus (std::stringstream& s, RouterStatus status)
+ static void ShowNetworkStatus (std::stringstream& s, RouterStatus status, RouterError error)
{
switch (status)
{
@@ -235,7 +235,7 @@ namespace http {
case eRouterStatusError:
{
s << tr("Error");
- switch (i2p::context.GetError ())
+ switch (error)
{
case eRouterErrorClockSkew:
s << " - " << tr("Clock skew");
@@ -260,12 +260,12 @@ namespace http {
ShowUptime(s, i2p::context.GetUptime ());
s << "
\r\n";
s << "" << tr("Network status") << ": ";
- ShowNetworkStatus (s, i2p::context.GetStatus ());
+ ShowNetworkStatus (s, i2p::context.GetStatus (), i2p::context.GetError ());
s << "
\r\n";
if (i2p::context.SupportsV6 ())
{
s << "" << tr("Network status v6") << ": ";
- ShowNetworkStatus (s, i2p::context.GetStatusV6 ());
+ ShowNetworkStatus (s, i2p::context.GetStatusV6 (), i2p::context.GetErrorV6 ());
s << "
\r\n";
}
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp
index 636d47ce..2095a465 100644
--- a/libi2pd/RouterContext.cpp
+++ b/libi2pd/RouterContext.cpp
@@ -29,7 +29,7 @@ namespace i2p
RouterContext::RouterContext ():
m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false),
m_ShareRatio (100), m_Status (eRouterStatusUnknown), m_StatusV6 (eRouterStatusUnknown),
- m_Error (eRouterErrorNone), m_NetID (I2PD_NET_ID)
+ m_Error (eRouterErrorNone), m_ErrorV6 (eRouterErrorNone), m_NetID (I2PD_NET_ID)
{
}
@@ -263,6 +263,7 @@ namespace i2p
if (status != m_StatusV6)
{
m_StatusV6 = status;
+ m_ErrorV6 = eRouterErrorNone;
switch (m_StatusV6)
{
case eRouterStatusOK:
diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h
index 4946b7ca..9e02b5d5 100644
--- a/libi2pd/RouterContext.h
+++ b/libi2pd/RouterContext.h
@@ -109,6 +109,8 @@ namespace garlic
RouterStatus GetStatusV6 () const { return m_StatusV6; };
void SetStatusV6 (RouterStatus status);
void SetStatusV6SSU2 (RouterStatus status);
+ RouterError GetErrorV6 () const { return m_ErrorV6; };
+ void SetErrorV6 (RouterError error) { m_StatusV6 = eRouterStatusError; m_ErrorV6 = error; };
int GetNetID () const { return m_NetID; };
void SetNetID (int netID) { m_NetID = netID; };
bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data);
@@ -197,7 +199,7 @@ namespace garlic
uint64_t m_BandwidthLimit; // allowed bandwidth
int m_ShareRatio;
RouterStatus m_Status, m_StatusV6;
- RouterError m_Error;
+ RouterError m_Error, m_ErrorV6;
int m_NetID;
std::mutex m_GarlicMutex;
std::unique_ptr m_NTCP2Keys;
diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp
index 551dd148..e551010a 100644
--- a/libi2pd/SSU2.cpp
+++ b/libi2pd/SSU2.cpp
@@ -155,6 +155,14 @@ namespace transport
}
return false;
}
+
+ uint16_t SSU2Server::GetPort (bool v4) const
+ {
+ boost::system::error_code ec;
+ boost::asio::ip::udp::endpoint ep = v4 ? m_SocketV4.local_endpoint (ec) : m_SocketV6.local_endpoint (ec);
+ if (ec) return 0;
+ return ep.port ();
+ }
boost::asio::ip::udp::socket& SSU2Server::OpenSocket (const boost::asio::ip::udp::endpoint& localEndpoint)
{
diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h
index 010c2c00..00e944e4 100644
--- a/libi2pd/SSU2.h
+++ b/libi2pd/SSU2.h
@@ -55,6 +55,7 @@ namespace transport
boost::asio::io_service& GetService () { return GetIOService (); };
void SetLocalAddress (const boost::asio::ip::address& localAddress);
bool IsSupported (const boost::asio::ip::address& addr) const;
+ uint16_t GetPort (bool v4) const;
void AddSession (std::shared_ptr session);
void RemoveSession (uint64_t connID);
diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp
index 475d7cef..e463e6fc 100644
--- a/libi2pd/SSU2Session.cpp
+++ b/libi2pd/SSU2Session.cpp
@@ -1370,16 +1370,9 @@ namespace transport
HandleAck (buf + offset, size);
break;
case eSSU2BlkAddress:
- {
- boost::asio::ip::udp::endpoint ep;
- if (ExtractEndpoint (buf + offset, size, ep))
- {
- LogPrint (eLogInfo, "SSU2: Our external address is ", ep);
- if (!i2p::util::net::IsInReservedRange (ep.address ()))
- i2p::context.UpdateAddress (ep.address ());
- }
- break;
- }
+ LogPrint (eLogDebug, "SSU2: Address");
+ HandleAddress (buf + offset, size);
+ break;
case eSSU2BlkIntroKey:
break;
case eSSU2BlkRelayTagRequest:
@@ -1482,6 +1475,47 @@ namespace transport
}
}
+ void SSU2Session::HandleAddress (const uint8_t * buf, size_t len)
+ {
+ boost::asio::ip::udp::endpoint ep;
+ if (ExtractEndpoint (buf, len, ep))
+ {
+ LogPrint (eLogInfo, "SSU2: Our external address is ", ep);
+ if (!i2p::util::net::IsInReservedRange (ep.address ()))
+ {
+ i2p::context.UpdateAddress (ep.address ());
+ // check our port
+ bool isV4 = ep.address ().is_v4 ();
+ if (ep.port () != m_Server.GetPort (isV4))
+ {
+ if (isV4)
+ {
+ if (i2p::context.GetStatus () == eRouterStatusTesting)
+ i2p::context.SetError (eRouterErrorSymmetricNAT);
+ }
+ else
+ {
+ if (i2p::context.GetStatusV6 () == eRouterStatusTesting)
+ i2p::context.SetErrorV6 (eRouterErrorSymmetricNAT);
+ }
+ }
+ else
+ {
+ if (isV4)
+ {
+ if (i2p::context.GetStatus () == eRouterStatusError && i2p::context.GetError () == eRouterErrorSymmetricNAT)
+ i2p::context.SetStatus (eRouterStatusTesting);
+ }
+ else
+ {
+ if (i2p::context.GetStatusV6 () == eRouterStatusError && i2p::context.GetErrorV6 () == eRouterErrorSymmetricNAT)
+ i2p::context.SetStatusV6 (eRouterStatusTesting);
+ }
+ }
+ }
+ }
+ }
+
void SSU2Session::HandleFirstFragment (const uint8_t * buf, size_t len)
{
uint32_t msgID; memcpy (&msgID, buf + 1, 4);
diff --git a/libi2pd/SSU2Session.h b/libi2pd/SSU2Session.h
index 3971358c..eae593c2 100644
--- a/libi2pd/SSU2Session.h
+++ b/libi2pd/SSU2Session.h
@@ -278,6 +278,7 @@ namespace transport
void HandlePayload (const uint8_t * buf, size_t len);
void HandleAck (const uint8_t * buf, size_t len);
void HandleAckRange (uint32_t firstPacketNum, uint32_t lastPacketNum, uint64_t ts);
+ void HandleAddress (const uint8_t * buf, size_t len);
bool ExtractEndpoint (const uint8_t * buf, size_t size, boost::asio::ip::udp::endpoint& ep);
size_t CreateEndpoint (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep);
std::shared_ptr FindLocalAddress () const;