Browse Source

Merge pull request #1421 from nonlinear-chaos-order-etc/openssl

Fixes three upnp issues, probably including: probably fixed #1419
pull/1432/head
orignal 5 years ago committed by GitHub
parent
commit
2497c3d187
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 143
      daemon/UPnP.cpp
  2. 59
      daemon/UPnP.h
  3. 4
      qt/i2pd_qt/i2pd_qt.pro

143
daemon/UPnP.cpp

@ -79,43 +79,59 @@ namespace transport
void UPnP::Discover () void UPnP::Discover ()
{ {
#if MINIUPNPC_API_VERSION >= 14 bool isError;
int nerror = 0; int err;
m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, 2, &nerror);
#elif ( MINIUPNPC_API_VERSION >= 8 || defined(UPNPDISCOVER_SUCCESS) ) #if ((MINIUPNPC_API_VERSION >= 8) || defined (UPNPDISCOVER_SUCCESS))
int nerror = 0; err = UPNPDISCOVER_SUCCESS;
m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, &nerror);
#if (MINIUPNPC_API_VERSION >= 14)
m_Devlist = upnpDiscover (UPNP_RESPONSE_TIMEOUT, NULL, NULL, 0, 0, 2, &err);
#else #else
m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0); m_Devlist = upnpDiscover (UPNP_RESPONSE_TIMEOUT, NULL, NULL, 0, 0, &err);
#endif #endif
isError = err != UPNPDISCOVER_SUCCESS;
#else // MINIUPNPC_API_VERSION >= 8
err = 0;
m_Devlist = upnpDiscover (UPNP_RESPONSE_TIMEOUT, NULL, NULL, 0);
isError = m_Devlist == NULL;
#endif // MINIUPNPC_API_VERSION >= 8
{ {
// notify satrting thread // notify starting thread
std::unique_lock<std::mutex> l(m_StartedMutex); std::unique_lock<std::mutex> l(m_StartedMutex);
m_Started.notify_all (); m_Started.notify_all ();
} }
int r; if (isError)
r = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr)); {
if (r == 1) LogPrint (eLogError, "UPnP: unable to discover Internet Gateway Devices: error ", err);
return;
}
err = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr));
m_upnpUrlsInitialized=err!=0;
if (err == UPNP_IGD_VALID_CONNECTED)
{ {
r = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress); err = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);
if(r != UPNPCOMMAND_SUCCESS) if(err != UPNPCOMMAND_SUCCESS)
{ {
LogPrint (eLogError, "UPnP: UPNP_GetExternalIPAddress() returned ", r); LogPrint (eLogError, "UPnP: unable to get external address: error ", err);
return; return;
} }
else else
{ {
LogPrint (eLogError, "UPnP: found Internet Gateway Device ", m_upnpUrls.controlURL);
if (!m_externalIPAddress[0]) if (!m_externalIPAddress[0])
{ {
LogPrint (eLogError, "UPnP: GetExternalIPAddress() failed."); LogPrint (eLogError, "UPnP: found Internet Gateway Device doesn't know our external address");
return; return;
} }
} }
} }
else else
{ {
LogPrint (eLogError, "UPnP: GetValidIGD() failed."); LogPrint (eLogError, "UPnP: unable to find valid Internet Gateway Device: error ", err);
return; return;
} }
@ -126,6 +142,20 @@ namespace transport
PortMapping (); PortMapping ();
} }
int UPnP::CheckMapping (const char* port, const char* type)
{
int err = UPNPCOMMAND_SUCCESS;
#if (MINIUPNPC_API_VERSION >= 10)
err = UPNP_GetSpecificPortMappingEntry(m_upnpUrls.controlURL, m_upnpData.first.servicetype, port, type, NULL, NULL, NULL, NULL, NULL, NULL);
#elif ((MINIUPNPC_API_VERSION >= 8) || defined (UPNPDISCOVER_SUCCESS))
err = UPNP_GetSpecificPortMappingEntry(m_upnpUrls.controlURL, m_upnpData.first.servicetype, port, type, NULL, NULL, NULL, NULL, NULL);
#else
err = UPNP_GetSpecificPortMappingEntry(m_upnpUrls.controlURL, m_upnpData.first.servicetype, port, type, NULL, NULL);
#endif
return err;
}
void UPnP::PortMapping () void UPnP::PortMapping ()
{ {
const auto& a = context.GetRouterInfo().GetAddresses(); const auto& a = context.GetRouterInfo().GetAddresses();
@ -134,72 +164,95 @@ namespace transport
if (!address->host.is_v6 () && address->port) if (!address->host.is_v6 () && address->port)
TryPortMapping (address); TryPortMapping (address);
} }
m_Timer.expires_from_now (boost::posix_time::minutes(20)); // every 20 minutes m_Timer.expires_from_now (boost::posix_time::minutes(20)); // every 20 minutes
m_Timer.async_wait ([this](const boost::system::error_code& ecode) m_Timer.async_wait ([this](const boost::system::error_code& ecode)
{ {
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
PortMapping (); PortMapping ();
}); });
}
void UPnP::CloseMapping ()
{
const auto& a = context.GetRouterInfo().GetAddresses();
for (const auto& address : a)
{
if (!address->host.is_v6 () && address->port)
CloseMapping (address);
}
} }
void UPnP::TryPortMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address) void UPnP::TryPortMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address)
{ {
std::string strType (GetProto (address)), strPort (std::to_string (address->port)); std::string strType (GetProto (address)), strPort (std::to_string (address->port));
int r;
std::string strDesc; i2p::config::GetOption("upnp.name", strDesc); std::string strDesc; i2p::config::GetOption("upnp.name", strDesc);
#ifdef UPNPDISCOVER_SUCCESS int err = UPNPCOMMAND_SUCCESS;
r = UPNP_AddPortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0, "0");
// check for existing mapping
err = CheckMapping (strPort.c_str (), strType.c_str ());
if (err != UPNPCOMMAND_SUCCESS) // if mapping not found
{
LogPrint (eLogDebug, "UPnP: possibly port ", strPort, " is not forwarded: return code ", err);
#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);
#else #else
r = UPNP_AddPortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0); 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);
#endif #endif
if (r!=UPNPCOMMAND_SUCCESS) if (err != UPNPCOMMAND_SUCCESS)
{ {
LogPrint (eLogError, "UPnP: AddPortMapping (", m_NetworkAddr, ":", strPort, ") failed with code ", r); LogPrint (eLogError, "UPnP: port forwarding to ", m_NetworkAddr, ":", strPort, " failed: return code ", err);
return; return;
}
else
{
LogPrint (eLogInfo, "UPnP: port successfully forwarded (", m_externalIPAddress ,":", strPort, " type ", strType, " -> ", m_NetworkAddr ,":", strPort ,")");
return;
}
} }
else else
{ {
LogPrint (eLogDebug, "UPnP: Port Mapping successful. (", m_NetworkAddr ,":", strPort, " type ", strType, " -> ", m_externalIPAddress ,":", strPort ,")"); LogPrint (eLogDebug, "UPnP: external forward from ", m_NetworkAddr, ":", strPort, " exists on current Internet Gateway Device");
return; return;
} }
} }
void UPnP::CloseMapping ()
{
const auto& a = context.GetRouterInfo().GetAddresses();
for (const auto& address : a)
{
if (!address->host.is_v6 () && address->port)
CloseMapping (address);
}
}
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) {
return;
}
std::string strType (GetProto (address)), strPort (std::to_string (address->port)); std::string strType (GetProto (address)), strPort (std::to_string (address->port));
int r = 0; int err = UPNPCOMMAND_SUCCESS;
r = UPNP_DeletePortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strType.c_str (), 0);
LogPrint (eLogError, "UPnP: DeletePortMapping() returned : ", r); err = CheckMapping (strPort.c_str (), strType.c_str ());
if (err == UPNPCOMMAND_SUCCESS)
{
err = UPNP_DeletePortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strType.c_str (), NULL);
LogPrint (eLogError, "UPnP: DeletePortMapping() returned : ", err);
}
} }
void UPnP::Close () void UPnP::Close ()
{ {
freeUPNPDevlist (m_Devlist); freeUPNPDevlist (m_Devlist);
m_Devlist = 0; m_Devlist = 0;
FreeUPNPUrls (&m_upnpUrls); if(m_upnpUrlsInitialized){
} FreeUPNPUrls (&m_upnpUrls);
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)
{ {
switch (address->transportStyle) switch (address->transportStyle)
{ {
case i2p::data::RouterInfo::eTransportNTCP: case i2p::data::RouterInfo::eTransportNTCP:
return "TCP"; return "TCP";
break; break;
case i2p::data::RouterInfo::eTransportSSU: case i2p::data::RouterInfo::eTransportSSU:
default: default:
return "UDP"; return "UDP";
} }
} }
} }

59
daemon/UPnP.h

@ -19,20 +19,31 @@ namespace i2p
{ {
namespace transport namespace transport
{ {
const int UPNP_RESPONSE_TIMEOUT = 2000; // in milliseconds
enum
{
UPNP_IGD_NONE = 0,
UPNP_IGD_VALID_CONNECTED = 1,
UPNP_IGD_VALID_NOT_CONNECTED = 2,
UPNP_IGD_INVALID = 3
};
class UPnP class UPnP
{ {
public: public:
UPnP (); UPnP ();
~UPnP (); ~UPnP ();
void Close (); void Close ();
void Start (); void Start ();
void Stop (); void Stop ();
private: private:
void Discover (); void Discover ();
int CheckMapping (const char* port, const char* type);
void PortMapping (); void PortMapping ();
void TryPortMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address); void TryPortMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address);
void CloseMapping (); void CloseMapping ();
@ -41,23 +52,22 @@ namespace transport
void Run (); void Run ();
std::string GetProto (std::shared_ptr<i2p::data::RouterInfo::Address> address); std::string GetProto (std::shared_ptr<i2p::data::RouterInfo::Address> address);
private: private:
bool m_IsRunning; bool m_IsRunning;
std::unique_ptr<std::thread> m_Thread; std::unique_ptr<std::thread> m_Thread;
std::condition_variable m_Started; std::condition_variable m_Started;
std::mutex m_StartedMutex; std::mutex m_StartedMutex;
boost::asio::io_service m_Service; boost::asio::io_service m_Service;
boost::asio::deadline_timer m_Timer; boost::asio::deadline_timer m_Timer;
struct UPNPUrls m_upnpUrls; bool m_upnpUrlsInitialized=false;
struct IGDdatas m_upnpData; struct UPNPUrls m_upnpUrls;
struct IGDdatas m_upnpData;
// For miniupnpc
char * m_MulticastIf = 0; // For miniupnpc
char * m_Minissdpdpath = 0; struct UPNPDev * m_Devlist = 0;
struct UPNPDev * m_Devlist = 0; char m_NetworkAddr[64];
char m_NetworkAddr[64]; char m_externalIPAddress[40];
char m_externalIPAddress[40];
}; };
} }
} }
@ -65,14 +75,15 @@ namespace transport
#else // USE_UPNP #else // USE_UPNP
namespace i2p { namespace i2p {
namespace transport { namespace transport {
/* class stub */ /* class stub */
class UPnP { class UPnP {
public: public:
UPnP () {};
~UPnP () {}; UPnP () {};
void Start () { LogPrint(eLogWarning, "UPnP: this module was disabled at compile-time"); } ~UPnP () {};
void Stop () {}; void Start () { LogPrint(eLogWarning, "UPnP: this module was disabled at compile-time"); }
}; void Stop () {};
};
} }
} }
#endif // USE_UPNP #endif // USE_UPNP

4
qt/i2pd_qt/i2pd_qt.pro

@ -6,9 +6,7 @@ TARGET = i2pd_qt
TEMPLATE = app TEMPLATE = app
QMAKE_CXXFLAGS *= -std=c++11 -Wno-unused-parameter -Wno-maybe-uninitialized QMAKE_CXXFLAGS *= -std=c++11 -Wno-unused-parameter -Wno-maybe-uninitialized
# For now, disable UPnP which currently crashes in UPnP::Stop() -- https://github.com/PurpleI2P/i2pd/issues/1387 DEFINES += USE_UPNP
#DEFINES += USE_UPNP
DEFINES -= USE_UPNP
CONFIG(debug, debug|release) { CONFIG(debug, debug|release) {
message(Debug build) message(Debug build)

Loading…
Cancel
Save