diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 36e26785..a7bd693f 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -54,7 +54,7 @@ namespace http { " body { font: 100%/1.5em sans-serif; margin: 0; padding: 1.5em; background: #FAFAFA; color: #103456; }\r\n" " a, .slide label { text-decoration: none; color: #894C84; }\r\n" " a:hover, .slide label:hover { color: #FAFAFA; background: #894C84; }\r\n" - " a.button { -webkit-appearance: button; -moz-appearance: button; appearance: button; text-decoration: none; color: initial;}\r\n" + " a.button { -webkit-appearance: button; -moz-appearance: button; appearance: button; text-decoration: none; color: initial; width: 1.5em;}\r\n" " .header { font-size: 2.5em; text-align: center; margin: 1.5em 0; color: #894C84; }\r\n" " .wrapper { margin: 0 auto; padding: 1em; max-width: 60em; }\r\n" " .left { float: left; position: absolute; }\r\n" @@ -64,12 +64,13 @@ namespace http { " .tunnel.failed { color: #D33F3F; }\r\n" " .tunnel.building { color: #434343; }\r\n" " caption { font-size: 1.5em; text-align: center; color: #894C84; }\r\n" - " table { width: 100%; border-collapse: collapse; text-align: center; }\r\n" - " .slide p, .slide [type='checkbox'] { display: none; }\r\n" - " .slide [type='checkbox']:checked ~ p { display: block; margin-top: 0; padding: 0; }\r\n" + " table { display: table; border-collapse: collapse; text-align: center; }\r\n" + " table.extaddr { text-align: left; }\r\n table.services { width: 100%; }" + " .streamdest { width: 120px; max-width: 240px; overflow: hidden; text-overflow: ellipsis;}\r\n" + " .slide div.content, .slide [type='checkbox'] { display: none; }\r\n" + " .slide [type='checkbox']:checked ~ div.content { display: block; margin-top: 0; padding: 0; }\r\n" " .disabled:after { color: #D33F3F; content: \"Disabled\" }\r\n" " .enabled:after { color: #56B734; content: \"Enabled\" }\r\n" - " .streamdest { width: 120px; max-width: 240px; overflow: hidden; text-overflow: ellipsis;}\r\n" "\r\n"; const char HTTP_PAGE_TUNNELS[] = "tunnels"; @@ -181,8 +182,10 @@ namespace http { "
\r\n" " Main page
\r\n
\r\n" " Router commands
\r\n" - " Local destinations
\r\n" - " LeaseSets
\r\n" + " Local destinations
\r\n"; + if (i2p::context.IsFloodfill ()) + s << " LeaseSets
\r\n"; + s << " Tunnels
\r\n" " Transit tunnels
\r\n" " Transports
\r\n" @@ -234,11 +237,8 @@ namespace http { } s << "
\r\n"; #if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY)) - if (auto remains = Daemon.gracefulShutdownInterval) { - s << "Stopping in: "; - s << remains << " seconds"; - s << "
\r\n"; - } + if (auto remains = Daemon.gracefulShutdownInterval) + s << "Stopping in: " << remains << " seconds
\r\n"; #endif auto family = i2p::context.GetFamily (); if (family.length () > 0) @@ -256,45 +256,50 @@ namespace http { s << "Data path: " << i2p::fs::GetDataDir() << "
\r\n"; s << "
"; if((outputFormat==OutputFormatEnum::forWebConsole)||!includeHiddenContent) { - s << "\r\n\r\n

\r\n"; + s << "\r\n\r\n

\r\n"; } if(includeHiddenContent) { s << "Router Ident: " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "
\r\n"; - s << "Router Family: " << i2p::context.GetRouterInfo().GetProperty("family") << "
\r\n"; + if (!i2p::context.GetRouterInfo().GetProperty("family").empty()) + s << "Router Family: " << i2p::context.GetRouterInfo().GetProperty("family") << "
\r\n"; s << "Router Caps: " << i2p::context.GetRouterInfo().GetProperty("caps") << "
\r\n"; - s << "Our external address:" << "
\r\n" ; + s << "Our external address:" << "
\r\n\r\n"; for (const auto& address : i2p::context.GetRouterInfo().GetAddresses()) { + s << "\r\n"; if (address->IsNTCP2 () && !address->IsPublishedNTCP2 ()) { - s << "NTCP2"; + s << "\r\n\r\n"; continue; } switch (address->transportStyle) { case i2p::data::RouterInfo::eTransportNTCP: { - s << "NTCP"; + s << "\r\n"; break; } case i2p::data::RouterInfo::eTransportSSU: + { + s << "\r\n"; + break; + } default: - s << "Unknown  "; + s << "\r\n"; } - s << address->host.to_string() << ":" << address->port << "
\r\n"; + s << "\r\n\r\n"; } + s << "
NTCP2"; if (address->host.is_v6 ()) s << "v6"; - s << "   supported
\r\n"; + s << "
supported
NTCP"; if (address->IsPublishedNTCP2 ()) s << "2"; if (address->host.is_v6 ()) s << "v6"; - s << "  "; + s << "SSU"; if (address->host.is_v6 ()) - s << "SSUv6     "; - else - s << "SSU     "; - break; + s << "v6"; + s << "Unknown" << address->host.to_string() << ":" << address->port << "
\r\n"; } - s << "

\r\n
\r\n"; + s << "\r\n
\r\n
\r\n"; if(outputFormat==OutputFormatEnum::forQtUi) { s << "
"; } @@ -310,15 +315,15 @@ namespace http { s << "Transit Tunnels: " << std::to_string(transitTunnelCount) << "
\r\n
\r\n"; if(outputFormat==OutputFormatEnum::forWebConsole) { - s << "\r\n"; - s << "\r\n"; - s << "\r\n"; - s << "\r\n"; - s << "\r\n"; - s << "\r\n"; bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol); - s << "\r\n"; - s << "
Services
ServiceState
" << "HTTP Proxy" << "
" << "SOCKS Proxy" << "
" << "BOB" << "
" << "SAM" << "
" << "I2CP" << "
" << "I2PControl" << "
\r\n"; + s << "\r\n"; + s << "\r\n"; + s << "\r\n"; + s << "\r\n"; + s << "\r\n"; + s << "\r\n"; + s << "\r\n"; + s << "
Services
" << "HTTP Proxy" << "
" << "SOCKS Proxy" << "
" << "BOB" << "
" << "SAM" << "
" << "I2CP" << "
" << "I2PControl" << "
\r\n"; } } @@ -358,19 +363,20 @@ namespace http { if (dest->IsEncryptedLeaseSet ()) { i2p::data::BlindedPublicKey blinded (dest->GetIdentity (), dest->IsPerClientAuth ()); - s << "
\r\n\r\n

\r\n"; + s << "

\r\n\r\n
\r\n"; s << blinded.ToB33 () << ".b32.i2p
\r\n"; - s << "

\r\n
\r\n"; + s << "
\r\n
\r\n"; } if(dest->GetNumRemoteLeaseSets()) { - s << "
\r\n\r\n

\r\n"; + s << "

\r\n\r\n
\r\n"; for(auto& it: dest->GetLeaseSets ()) - s << it.first.ToBase32 () << " " << (int)it.second->GetStoreType () << "
\r\n"; - s << "

\r\n\r\n"; + s << "\r\n"; + s << "
AddressTypeEncType
" << it.first.ToBase32 () << "" << (int)it.second->GetStoreType () << "" << (int)it.second->GetEncryptionType () <<"
\r\n
\r\n
\r\n
\r\n"; } else - s << "LeaseSets: 0
\r\n"; + s << "LeaseSets: 0
\r\n
\r\n"; auto pool = dest->GetTunnelPool (); if (pool) { @@ -395,10 +401,11 @@ namespace http { if (!dest->GetSessions ().empty ()) { std::stringstream tmp_s; uint32_t out_tags = 0; for (const auto& it: dest->GetSessions ()) { - tmp_s << i2p::client::context.GetAddressBook ().ToAddress(it.first) << " " << it.second->GetNumOutgoingTags () << "
\r\n"; + tmp_s << "" << i2p::client::context.GetAddressBook ().ToAddress(it.first) << "" << it.second->GetNumOutgoingTags () << "\r\n"; out_tags = out_tags + it.second->GetNumOutgoingTags (); } - s << "
\r\n\r\n

\r\n" << tmp_s.str () << "

\r\n
\r\n"; + s << "
\r\n\r\n" + << "
\r\n\r\n" << tmp_s.str () << "
DestinationAmount
\r\n
\r\n
\r\n"; } else s << "Outgoing: 0
\r\n"; s << "
\r\n"; @@ -473,46 +480,57 @@ namespace http { void ShowLeasesSets(std::stringstream& s) { - s << "LeaseSets:
\r\n
\r\n"; - int counter = 1; - // for each lease set - i2p::data::netdb.VisitLeaseSets( - [&s, &counter](const i2p::data::IdentHash dest, std::shared_ptr leaseSet) - { - // create copy of lease set so we extract leases - auto storeType = leaseSet->GetStoreType (); - std::unique_ptr ls; - if (storeType == i2p::data::NETDB_STORE_TYPE_LEASESET) - ls.reset (new i2p::data::LeaseSet (leaseSet->GetBuffer(), leaseSet->GetBufferLen())); - else - ls.reset (new i2p::data::LeaseSet2 (storeType, leaseSet->GetBuffer(), leaseSet->GetBufferLen())); - if (!ls) return; - s << "
\r\n"; - if (!ls->IsValid()) - s << "
!! Invalid !!
\r\n"; - s << "
\r\n"; - s << "\r\n

\r\n"; - s << "Store type: " << (int)storeType << "
\r\n"; - s << "Expires: " << ConvertTime(ls->GetExpirationTime()) << "
\r\n"; - if (storeType == i2p::data::NETDB_STORE_TYPE_LEASESET || storeType == i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2) - { - // leases information is available - auto leases = ls->GetNonExpiredLeases(); - s << "Non Expired Leases: " << leases.size() << "
\r\n"; - for ( auto & l : leases ) + if (i2p::data::netdb.GetNumLeaseSets ()) + { + s << "LeaseSets:
\r\n
\r\n"; + int counter = 1; + // for each lease set + i2p::data::netdb.VisitLeaseSets( + [&s, &counter](const i2p::data::IdentHash dest, std::shared_ptr leaseSet) + { + // create copy of lease set so we extract leases + auto storeType = leaseSet->GetStoreType (); + std::unique_ptr ls; + if (storeType == i2p::data::NETDB_STORE_TYPE_LEASESET) + ls.reset (new i2p::data::LeaseSet (leaseSet->GetBuffer(), leaseSet->GetBufferLen())); + else + ls.reset (new i2p::data::LeaseSet2 (storeType, leaseSet->GetBuffer(), leaseSet->GetBufferLen())); + if (!ls) return; + s << "

\r\n"; + if (!ls->IsValid()) + s << "
!! Invalid !!
\r\n"; + s << "
\r\n"; + s << "\r\n
\r\n"; + s << "Store type: " << (int)storeType << "
\r\n"; + s << "Expires: " << ConvertTime(ls->GetExpirationTime()) << "
\r\n"; + if (storeType == i2p::data::NETDB_STORE_TYPE_LEASESET || storeType == i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2) { - s << "Gateway: " << l->tunnelGateway.ToBase64() << "
\r\n"; - s << "TunnelID: " << l->tunnelID << "
\r\n"; - s << "EndDate: " << ConvertTime(l->endDate) << "
\r\n"; + // leases information is available + auto leases = ls->GetNonExpiredLeases(); + s << "Non Expired Leases: " << leases.size() << "
\r\n"; + for ( auto & l : leases ) + { + s << "Gateway: " << l->tunnelGateway.ToBase64() << "
\r\n"; + s << "TunnelID: " << l->tunnelID << "
\r\n"; + s << "EndDate: " << ConvertTime(l->endDate) << "
\r\n"; + } } - } - s << "

\r\n
\r\n
\r\n"; - } - ); - // end for each lease set + s << "
\r\n
\r\n
\r\n"; + } + ); + // end for each lease set + } + else if (!i2p::context.IsFloodfill ()) + { + s << "LeaseSets: not floodfill.
\r\n"; + } + else + { + s << "LeaseSets: 0
\r\n"; + } } void ShowTunnels (std::stringstream& s) @@ -574,16 +592,23 @@ namespace http { void ShowTransitTunnels (std::stringstream& s) { - s << "Transit tunnels:
\r\n
\r\n"; - for (const auto& it: i2p::tunnel::tunnels.GetTransitTunnels ()) + if(i2p::tunnel::tunnels.CountTransitTunnels()) { - if (std::dynamic_pointer_cast(it)) - s << it->GetTunnelID () << " ⇒ "; - else if (std::dynamic_pointer_cast(it)) - s << " ⇒ " << it->GetTunnelID (); - else - s << " ⇒ " << it->GetTunnelID () << " ⇒ "; - s << " " << it->GetNumTransmittedBytes () << "
\r\n"; + s << "Transit tunnels:
\r\n
\r\n"; + for (const auto& it: i2p::tunnel::tunnels.GetTransitTunnels ()) + { + if (std::dynamic_pointer_cast(it)) + s << it->GetTunnelID () << " ⇒ "; + else if (std::dynamic_pointer_cast(it)) + s << " ⇒ " << it->GetTunnelID (); + else + s << " ⇒ " << it->GetTunnelID () << " ⇒ "; + s << " " << it->GetNumTransmittedBytes () << "
\r\n"; + } + } + else + { + s << "Transit tunnels: no transit tunnels currently built.
\r\n"; } } @@ -617,13 +642,15 @@ namespace http { } if (!tmp_s.str ().empty ()) { - s << "
\r\n\r\n

"; - s << tmp_s.str () << "

\r\n
\r\n"; + s << "
\r\n\r\n
" + << tmp_s.str () << "
\r\n
\r\n"; } if (!tmp_s6.str ().empty ()) { - s << "
\r\n\r\n

"; - s << tmp_s6.str () << "

\r\n
\r\n"; + s << "
\r\n\r\n
" + << tmp_s6.str () << "
\r\n
\r\n"; } } @@ -650,7 +677,7 @@ namespace http { auto sessions = ssuServer->GetSessions (); if (!sessions.empty ()) { - s << "
\r\n\r\n

"; + s << "

\r\n\r\n
"; for (const auto& it: sessions) { auto endpoint = it.second->GetRemoteEndpoint (); @@ -662,12 +689,12 @@ namespace http { s << " [itag:" << it.second->GetRelayTag () << "]"; s << "
\r\n" << std::endl; } - s << "

\r\n
\r\n"; + s << "
\r\n
\r\n"; } auto sessions6 = ssuServer->GetSessionsV6 (); if (!sessions6.empty ()) { - s << "
\r\n\r\n

"; + s << "

\r\n\r\n
"; for (const auto& it: sessions6) { auto endpoint = it.second->GetRemoteEndpoint (); @@ -679,7 +706,7 @@ namespace http { s << " [itag:" << it.second->GetRelayTag () << "]"; s << "
\r\n" << std::endl; } - s << "

\r\n
\r\n"; + s << "
\r\n
\r\n"; } } } @@ -688,17 +715,24 @@ namespace http { { std::string webroot; i2p::config::GetOption("http.webroot", webroot); auto sam = i2p::client::context.GetSAMBridge (); - if (!sam) { + if (!sam) + { ShowError(s, "SAM disabled"); return; } - s << "SAM Sessions:
\r\n
\r\n"; - for (auto& it: sam->GetSessions ()) + + if(sam->GetSessions ().size ()) { - auto& name = it.second->localDestination->GetNickname (); - s << ""; - s << name << " (" << it.first << ")
\r\n" << std::endl; + s << "SAM Sessions:
\r\n
\r\n"; + for (auto& it: sam->GetSessions ()) + { + auto& name = it.second->localDestination->GetNickname (); + s << ""; + s << name << " (" << it.first << ")
\r\n" << std::endl; + } } + else + s << "SAM Sessions: no sessions currently running.
\r\n"; } static void ShowSAMSession (std::stringstream& s, const std::string& id)