Browse Source

Merge pull request #920 from PurpleI2P/openssl

2.15.0
pull/1036/head
orignal 7 years ago committed by GitHub
parent
commit
c21c1f5225
  1. 14
      ChangeLog
  2. 9
      README.md
  3. 24
      Win32/Win32Service.cpp
  4. 2
      Win32/installer.iss
  5. 2
      android/AndroidManifest.xml
  6. 2
      appveyor.yml
  7. 13
      contrib/certificates/family/gostcoin.crt
  8. 4
      contrib/debian/i2pd.service
  9. 2
      contrib/docker/Dockerfile
  10. 2
      contrib/docker/entrypoint.sh
  11. 2
      contrib/i2pd.conf
  12. 13
      contrib/rpm/i2pd.spec
  13. 57
      daemon/HTTPServer.cpp
  14. 6
      debian/changelog
  15. 2099
      docs/Doxyfile
  16. 49
      libi2pd/Config.cpp
  17. 2
      libi2pd/Destination.cpp
  18. 6
      libi2pd/Destination.h
  19. 4
      libi2pd/HTTP.cpp
  20. 12
      libi2pd/HTTP.h
  21. 25
      libi2pd/Identity.cpp
  22. 6
      libi2pd/Identity.h
  23. 4
      libi2pd/NetDb.cpp
  24. 8
      libi2pd/SSU.cpp
  25. 3
      libi2pd/Tag.h
  26. 11
      libi2pd/Transports.cpp
  27. 2
      libi2pd/Transports.h
  28. 2
      libi2pd/Tunnel.h
  29. 4
      libi2pd/version.h
  30. 19
      libi2pd_client/AddressBook.cpp
  31. 102
      libi2pd_client/ClientContext.cpp
  32. 3
      libi2pd_client/ClientContext.h
  33. 3
      libi2pd_client/HTTPProxy.cpp
  34. 32
      libi2pd_client/I2PService.cpp
  35. 23
      libi2pd_client/I2PService.h
  36. 2
      libi2pd_client/SAM.cpp
  37. 4
      libi2pd_client/SOCKS.cpp
  38. 5
      libi2pd_client/SOCKS.h
  39. 1
      qt/i2pd_qt/ClientTunnelPane.h
  40. 1
      qt/i2pd_qt/DaemonQT.cpp
  41. 1
      qt/i2pd_qt/ServerTunnelPane.h
  42. 11
      qt/i2pd_qt/SignatureTypeComboboxFactory.h
  43. 3
      qt/i2pd_qt/TunnelConfig.h
  44. 1
      qt/i2pd_qt/TunnelPane.h
  45. 2
      qt/i2pd_qt/android/AndroidManifest.xml
  46. 19
      qt/i2pd_qt/mainwindow.cpp
  47. 27
      qt/i2pd_qt/mainwindow.h
  48. 50
      qt/i2pd_qt/mainwindow.ui

14
ChangeLog

@ -1,6 +1,20 @@ @@ -1,6 +1,20 @@
# for this file format description,
# see https://github.com/olivierlacan/keep-a-changelog
## [2.15.0] - 2017-08-17
### Added
- QT GUI
- Ability to add and remove I2P tunnels without restart
- Ability to disable SOCKS outproxy option
### Changed
- Strip-out Accept-* hedaers in HTTP proxy
- Don't run peer test if nat=false
- Separate output of NTCP and SSU sessions in Transports tab
### Fixed
- Handle lines with comments in hosts.txt file for address book
- Run router with empty netdb for testnet
- Skip expired introducers by iexp
## [2.14.0] - 2017-06-01
### Added
- Transit traffic bandwidth limitation

9
README.md

@ -43,6 +43,15 @@ The easiest way to install i2pd is by using @@ -43,6 +43,15 @@ The easiest way to install i2pd is by using
See [documentation](https://i2pd.readthedocs.io/en/latest/) for how to build
i2pd from source on your OS.
Build instructions:
* [unix](https://i2pd.readthedocs.io/en/latest/devs/building/unix/)
* [windows](https://i2pd.readthedocs.io/en/latest/devs/building/windows/)
* [iOS](https://i2pd.readthedocs.io/en/latest/devs/building/ios/)
* [android](https://i2pd.readthedocs.io/en/latest/devs/building/android/)
**Supported systems:**
* GNU/Linux x86/x64 - [![Build Status](https://travis-ci.org/PurpleI2P/i2pd.svg?branch=openssl)](https://travis-ci.org/PurpleI2P/i2pd)

24
Win32/Win32Service.cpp

@ -70,7 +70,6 @@ void WINAPI I2PService::ServiceCtrlHandler(DWORD dwCtrl) @@ -70,7 +70,6 @@ void WINAPI I2PService::ServiceCtrlHandler(DWORD dwCtrl)
}
}
I2PService::I2PService(PSTR pszServiceName,
BOOL fCanStop,
BOOL fCanShutdown,
@ -147,8 +146,7 @@ void I2PService::Start(DWORD dwArgc, PSTR *pszArgv) @@ -147,8 +146,7 @@ void I2PService::Start(DWORD dwArgc, PSTR *pszArgv)
void I2PService::OnStart(DWORD dwArgc, PSTR *pszArgv)
{
LogPrint(eLogInfo, "Win32Service in OnStart",
EVENTLOG_INFORMATION_TYPE);
LogPrint(eLogInfo, "Win32Service in OnStart", EVENTLOG_INFORMATION_TYPE);
Daemon.start();
@ -270,12 +268,10 @@ void I2PService::Continue() @@ -270,12 +268,10 @@ void I2PService::Continue()
}
}
void I2PService::OnContinue()
{
}
void I2PService::Shutdown()
{
try
@ -294,19 +290,16 @@ void I2PService::Shutdown() @@ -294,19 +290,16 @@ void I2PService::Shutdown()
}
}
void I2PService::OnShutdown()
{
}
void I2PService::SetServiceStatus(DWORD dwCurrentState,
DWORD dwWin32ExitCode,
DWORD dwWaitHint)
{
static DWORD dwCheckPoint = 1;
m_status.dwCurrentState = dwCurrentState;
m_status.dwWin32ExitCode = dwWin32ExitCode;
m_status.dwWaitHint = dwWaitHint;
@ -335,12 +328,7 @@ void FreeHandles(SC_HANDLE schSCManager, SC_HANDLE schService) @@ -335,12 +328,7 @@ void FreeHandles(SC_HANDLE schSCManager, SC_HANDLE schService)
}
}
void InstallService(PSTR pszServiceName,
PSTR pszDisplayName,
DWORD dwStartType,
PSTR pszDependencies,
PSTR pszAccount,
PSTR pszPassword)
void InstallService(PSTR pszServiceName, PSTR pszDisplayName, DWORD dwStartType, PSTR pszDependencies, PSTR pszAccount, PSTR pszPassword)
{
printf("Try to install Win32Service (%s).\n", pszServiceName);
@ -354,10 +342,10 @@ void InstallService(PSTR pszServiceName, @@ -354,10 +342,10 @@ void InstallService(PSTR pszServiceName,
FreeHandles(schSCManager, schService);
return;
}
strncat(szPath, " --daemon", MAX_PATH);
// Open the local default service control manager database
schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT |
SC_MANAGER_CREATE_SERVICE);
schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE);
if (schSCManager == NULL)
{
printf("OpenSCManager failed w/err 0x%08lx\n", GetLastError());
@ -381,6 +369,7 @@ void InstallService(PSTR pszServiceName, @@ -381,6 +369,7 @@ void InstallService(PSTR pszServiceName,
pszAccount, // Service running account
pszPassword // Password of the account
);
if (schService == NULL)
{
printf("CreateService failed w/err 0x%08lx\n", GetLastError());
@ -412,8 +401,7 @@ void UninstallService(PSTR pszServiceName) @@ -412,8 +401,7 @@ void UninstallService(PSTR pszServiceName)
}
// Open the service with delete, stop, and query status permissions
schService = OpenService(schSCManager, pszServiceName, SERVICE_STOP |
SERVICE_QUERY_STATUS | DELETE);
schService = OpenService(schSCManager, pszServiceName, SERVICE_STOP | SERVICE_QUERY_STATUS | DELETE);
if (schService == NULL)
{
printf("OpenService failed w/err 0x%08lx\n", GetLastError());

2
Win32/installer.iss

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
#define I2Pd_AppName "i2pd"
#define I2Pd_ver "2.14.0"
#define I2Pd_ver "2.15.0"
#define I2Pd_Publisher "PurpleI2P"
[Setup]

2
android/AndroidManifest.xml

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.purplei2p.i2pd"
android:versionCode="1"
android:versionName="2.14.0"
android:versionName="2.15.0"
android:installLocation="auto">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="25"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

2
appveyor.yml

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
version: 2.14.{build}
version: 2.15.{build}
pull_requests:
do_not_increment_build_number: true
branches:

13
contrib/certificates/family/gostcoin.crt

@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE-----
MIIB6jCCAY+gAwIBAgIJAPeWi4iUKLBJMAoGCCqGSM49BAMCMHoxCzAJBgNVBAYT
AlhYMQswCQYDVQQIDAJYWDELMAkGA1UEBwwCWFgxHjAcBgNVBAoMFUkyUCBBbm9u
eW1vdXMgTmV0d29yazEPMA0GA1UECwwGZmFtaWx5MSAwHgYDVQQDDBdnb3N0Y29p
bi5mYW1pbHkuaTJwLm5ldDAeFw0xNzA4MDExMzQ4MzdaFw0yNzA3MzAxMzQ4Mzda
MHoxCzAJBgNVBAYTAlhYMQswCQYDVQQIDAJYWDELMAkGA1UEBwwCWFgxHjAcBgNV
BAoMFUkyUCBBbm9ueW1vdXMgTmV0d29yazEPMA0GA1UECwwGZmFtaWx5MSAwHgYD
VQQDDBdnb3N0Y29pbi5mYW1pbHkuaTJwLm5ldDBZMBMGByqGSM49AgEGCCqGSM49
AwEHA0IABC+9iIYumUNnsqKbnTluHimV8OdGvo7yeGxuqhfNNB2b3jvbFJ81scgH
dsZtMQmUxgKM5nH+NQJMoCxHhSlRy2QwCgYIKoZIzj0EAwIDSQAwRgIhANNh7mOp
nBBPRh2a/ipG1VYS0d+mNjSrpz8xWcG3CXPLAiEAjM5MTfv9sOJ74PeZVhFZ02w4
vhgyZCeLJ57f123Lm1A=
-----END CERTIFICATE-----

4
contrib/debian/i2pd.service vendored

@ -5,7 +5,9 @@ After=network.target @@ -5,7 +5,9 @@ After=network.target
[Service]
User=i2pd
Group=i2pd
Type=forking
RuntimeDirectory=i2pd
RuntimeDirectoryMode=0700
Type=simple
ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --pidfile=/var/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
ExecReload=/bin/kill -HUP $MAINPID
PIDFile=/var/run/i2pd/i2pd.pid

2
contrib/docker/Dockerfile

@ -12,7 +12,7 @@ ENV REPO_URL=${REPO_URL} @@ -12,7 +12,7 @@ ENV REPO_URL=${REPO_URL}
ENV I2PD_HOME="/home/i2pd"
ENV DATA_DIR="${I2PD_HOME}/data"
RUN mkdir -p "$I2PD_HOME" \
RUN mkdir -p "$I2PD_HOME" "$DATA_DIR" \
&& adduser -S -h "$I2PD_HOME" i2pd \
&& chown -R i2pd:nobody "$I2PD_HOME"

2
contrib/docker/entrypoint.sh

@ -7,8 +7,6 @@ DEFAULT_ARGS=" --datadir=$DATA_DIR --reseed.verify=true --upnp.enabled=false --h @@ -7,8 +7,6 @@ DEFAULT_ARGS=" --datadir=$DATA_DIR --reseed.verify=true --upnp.enabled=false --h
if [ "$1" = "--help" ]; then
set -- $COMMAND --help
else
# Create datadir
mkdir -p "$DATA_DIR"
ln -s /i2pd_certificates "$DATA_DIR"/certificates
set -- $COMMAND $DEFAULT_ARGS $@
fi

2
contrib/i2pd.conf

@ -136,6 +136,8 @@ port = 4447 @@ -136,6 +136,8 @@ port = 4447
# keys = socks-proxy-keys.dat
## Socks outproxy. Example below is set to use Tor for all connections except i2p
## Uncomment and set to 'true' to enable using of SOCKS outproxy
# outproxy.enabled = false
## Address and port of outproxy
# outproxy = 127.0.0.1
# outproxyport = 9050

13
contrib/rpm/i2pd.spec

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
%define build_timestamp %(date +"%Y%m%d")
Name: i2pd
Version: 2.14.0
Version: 2.15.0
Release: %{build_timestamp}git%{?dist}
Summary: I2P router written in C++
@ -103,6 +103,17 @@ getent passwd i2pd >/dev/null || \ @@ -103,6 +103,17 @@ getent passwd i2pd >/dev/null || \
%changelog
* Thu Aug 17 2017 orignal <i2porignal@yandex.ru> - 2.15.0
- Added QT GUI
- Added ability add and remove I2P tunnels without restart
- Added ability to disable SOCKS outproxy option
- Changed strip-out Accept-* hedaers in HTTP proxy
- Changed peer test if nat=false
- Changed separate output of NTCP and SSU sessions in Transports tab
- Fixed handle lines with comments in hosts.txt file for address book
- Fixed run router with empty netdb for testnet
- Fixed skip expired introducers by iexp
* Thu Jun 01 2017 orignal <i2porignal@yandex.ru> - 2.14.0
- Added transit traffic bandwidth limitation
- Added NTCP connections through HTTP and SOCKS proxies

57
daemon/HTTPServer.cpp

@ -496,18 +496,42 @@ namespace http { @@ -496,18 +496,42 @@ namespace http {
if (ntcpServer)
{
auto sessions = ntcpServer->GetNTCPSessions ();
s << "<b>NTCP</b> ( " << (int) sessions.size() << " )<br>\r\n";
if (!sessions.empty ())
{
std::stringstream tmp_s, tmp_s6; uint16_t cnt = 0, cnt6 = 0;
for (const auto& it: sessions )
{
if (it.second && it.second->IsEstablished ())
if (it.second && it.second->IsEstablished () && !it.second->GetSocket ().remote_endpoint ().address ().is_v6 ())
{
// incoming connection doesn't have remote RI
if (it.second->IsOutgoing ()) s << " &#8658; ";
s << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": "
if (it.second->IsOutgoing ()) tmp_s << " &#8658; ";
tmp_s << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": "
<< it.second->GetSocket ().remote_endpoint().address ().to_string ();
if (!it.second->IsOutgoing ()) s << " &#8658; ";
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
s << "<br>\r\n" << std::endl;
if (!it.second->IsOutgoing ()) tmp_s << " &#8658; ";
tmp_s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
tmp_s << "<br>\r\n" << std::endl;
cnt++;
}
if (it.second && it.second->IsEstablished () && it.second->GetSocket ().remote_endpoint ().address ().is_v6 ())
{
if (it.second->IsOutgoing ()) tmp_s6 << " &#8658; ";
tmp_s6 << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": "
<< "[" << it.second->GetSocket ().remote_endpoint().address ().to_string () << "]";
if (!it.second->IsOutgoing ()) tmp_s6 << " &#8658; ";
tmp_s6 << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
tmp_s6 << "<br>\r\n" << std::endl;
cnt6++;
}
}
if (!tmp_s.str ().empty ())
{
s << "<b>NTCP</b> ( " << cnt << " )<br>\r\n";
s << tmp_s.str () << "<br>\r\n";
}
if (!tmp_s6.str ().empty ())
{
s << "<b>NTCP6</b> ( " << cnt6 << " )<br>\r\n";
s << tmp_s6.str () << "<br>\r\n";
}
}
}
@ -515,7 +539,9 @@ namespace http { @@ -515,7 +539,9 @@ namespace http {
if (ssuServer)
{
auto sessions = ssuServer->GetSessions ();
s << "<br>\r\n<b>SSU</b> ( " << (int) sessions.size() << " )<br>\r\n";
if (!sessions.empty ())
{
s << "<b>SSU</b> ( " << (int) sessions.size() << " )<br>\r\n";
for (const auto& it: sessions)
{
auto endpoint = it.second->GetRemoteEndpoint ();
@ -527,16 +553,25 @@ namespace http { @@ -527,16 +553,25 @@ namespace http {
s << " [itag:" << it.second->GetRelayTag () << "]";
s << "<br>\r\n" << std::endl;
}
s << "<br>\r\n<b>SSU6</b><br>\r\n";
for (const auto& it: ssuServer->GetSessionsV6 ())
s << "<br>\r\n";
}
auto sessions6 = ssuServer->GetSessionsV6 ();
if (!sessions6.empty ())
{
s << "<b>SSU6</b> ( " << (int) sessions6.size() << " )<br>\r\n";
for (const auto& it: sessions6)
{
auto endpoint = it.second->GetRemoteEndpoint ();
if (it.second->IsOutgoing ()) s << " &#8658; ";
s << endpoint.address ().to_string () << ":" << endpoint.port ();
s << "[" << endpoint.address ().to_string () << "]:" << endpoint.port ();
if (!it.second->IsOutgoing ()) s << " &#8658; ";
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
if (it.second->GetRelayTag ())
s << " [itag:" << it.second->GetRelayTag () << "]";
s << "<br>\r\n" << std::endl;
}
s << "<br>\r\n";
}
}
}

6
debian/changelog vendored

@ -1,3 +1,9 @@ @@ -1,3 +1,9 @@
i2pd (2.15.0-1) unstable; urgency=low
* updated to version 2.15.0/0.9.31
-- orignal <orignal@i2pmail.org> Thu, 17 Aug 2017 18:00:00 +0000
i2pd (2.14.0-1) unstable; urgency=low
* updated to version 2.14.0/0.9.30

2099
docs/Doxyfile

File diff suppressed because it is too large Load Diff

49
libi2pd/Config.cpp

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2016, The PurpleI2P Project
* Copyright (c) 2013-2017, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@ -27,8 +27,8 @@ namespace config { @@ -27,8 +27,8 @@ namespace config {
options_description m_OptionsDesc;
variables_map m_Options;
void Init() {
void Init()
{
options_description general("General options");
general.add_options()
("help", "Show this message")
@ -44,9 +44,9 @@ namespace config { @@ -44,9 +44,9 @@ namespace config {
("ifname", value<std::string>()->default_value(""), "Network interface to bind to")
("ifname4", value<std::string>()->default_value(""), "Network interface to bind to for ipv4")
("ifname6", value<std::string>()->default_value(""), "Network interface to bind to for ipv6")
("nat", value<bool>()->zero_tokens()->default_value(true), "Should we assume we are behind NAT?")
("nat", value<bool>()->default_value(true), "Should we assume we are behind NAT?")
("port", value<uint16_t>()->default_value(0), "Port to listen for incoming connections (default: auto)")
("ipv4", value<bool>()->zero_tokens()->default_value(true), "Enable communication through ipv4")
("ipv4", value<bool>()->default_value(true), "Enable communication through ipv4")
("ipv6", value<bool>()->zero_tokens()->default_value(false), "Enable communication through ipv6")
("netid", value<int>()->default_value(I2PD_NET_ID), "Specify NetID. Main I2P is 2")
("daemon", value<bool>()->zero_tokens()->default_value(false), "Router will go to background after start")
@ -55,9 +55,9 @@ namespace config { @@ -55,9 +55,9 @@ namespace config {
("floodfill", value<bool>()->zero_tokens()->default_value(false), "Router will be floodfill")
("bandwidth", value<std::string>()->default_value(""), "Bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)")
("share", value<int>()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100")
("ntcp", value<bool>()->zero_tokens()->default_value(true), "Enable NTCP transport")
("ssu", value<bool>()->zero_tokens()->default_value(true), "Enable SSU transport")
("ntcpproxy", value<std::string>()->default_value(""), "proxy url for ntcp transport")
("ntcp", value<bool>()->default_value(true), "Enable NTCP transport")
("ssu", value<bool>()->default_value(true), "Enable SSU transport")
("ntcpproxy", value<std::string>()->default_value(""), "Proxy URL for NTCP transport")
#ifdef _WIN32
("svcctl", value<std::string>()->default_value(""), "Windows service management ('install' or 'remove')")
("insomnia", value<bool>()->zero_tokens()->default_value(false), "Prevent system from sleeping")
@ -112,6 +112,7 @@ namespace config { @@ -112,6 +112,7 @@ namespace config {
("socksproxy.outbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy outbound tunnels quantity")
("socksproxy.latency.min", value<std::string>()->default_value("0"), "SOCKS proxy min latency for tunnels")
("socksproxy.latency.max", value<std::string>()->default_value("0"), "SOCKS proxy max latency for tunnels")
("socksproxy.outproxy.enabled", value<bool>()->default_value(false), "Enable or disable SOCKS outproxy")
("socksproxy.outproxy", value<std::string>()->default_value("127.0.0.1"), "Upstream outproxy address for SOCKS Proxy")
("socksproxy.outproxyport", value<uint16_t>()->default_value(9050), "Upstream outproxy port for SOCKS Proxy")
;
@ -179,8 +180,8 @@ namespace config { @@ -179,8 +180,8 @@ namespace config {
"https://reseed.i2p-projekt.de/,"
"https://i2p.mooo.com/netDb/,"
"https://netdb.i2p2.no/,"
// "https://us.reseed.i2p2.no:444/," // mamoth's shit
// "https://uk.reseed.i2p2.no:444/," // mamoth's shit
// "https://us.reseed.i2p2.no:444/," // mamoth's shit
// "https://uk.reseed.i2p2.no:444/," // mamoth's shit
"https://i2p-0.manas.ca:8443/,"
"https://download.xxlspeed.com/,"
"https://reseed-ru.lngserv.ru/,"
@ -197,28 +198,30 @@ namespace config { @@ -197,28 +198,30 @@ namespace config {
("addressbook.defaulturl", value<std::string>()->default_value(
"http://joajgazyztfssty4w2on5oaqksz6tqoxbduy553y34mf4byv6gpq.b32.i2p/export/alive-hosts.txt"
), "AddressBook subscription URL for initial setup")
("addressbook.subscriptions", value<std::string>()->default_value(""),
"AddressBook subscriptions URLs, separated by comma");
("addressbook.subscriptions", value<std::string>()->default_value(""), "AddressBook subscriptions URLs, separated by comma");
options_description trust("Trust options");
trust.add_options()
("trust.enabled", value<bool>()->default_value(false), "Enable explicit trust options")
("trust.family", value<std::string>()->default_value(""), "Router Familiy to trust for first hops")
("trust.routers", value<std::string>()->default_value(""), "Only Connect to these routers")
("trust.hidden", value<bool>()->default_value(false), "Should we hide our router from other routers?");
("trust.hidden", value<bool>()->default_value(false), "Should we hide our router from other routers?")
;
options_description websocket("Websocket Options");
websocket.add_options()
("websockets.enabled", value<bool>()->default_value(false), "enable websocket server")
("websockets.address", value<std::string>()->default_value("127.0.0.1"), "address to bind websocket server on")
("websockets.port", value<uint16_t>()->default_value(7666), "port to bind websocket server on");
("websockets.enabled", value<bool>()->default_value(false), "Enable websocket server")
("websockets.address", value<std::string>()->default_value("127.0.0.1"), "Address to bind websocket server on")
("websockets.port", value<uint16_t>()->default_value(7666), "Port to bind websocket server on")
;
options_description exploratory("Exploratory Options");
exploratory.add_options()
("exploratory.inbound.length", value<int>()->default_value(2), "Exploratory inbound tunnel length")
("exploratory.outbound.length", value<int>()->default_value(2), "Exploratory outbound tunnel length")
("exploratory.inbound.quantity", value<int>()->default_value(3), "Exploratory inbound tunnels quantity")
("exploratory.outbound.quantity", value<int>()->default_value(3), "Exploratory outbound tunnels quantity");
("exploratory.outbound.quantity", value<int>()->default_value(3), "Exploratory outbound tunnels quantity")
;
m_OptionsDesc
.add(general)
@ -266,7 +269,8 @@ namespace config { @@ -266,7 +269,8 @@ namespace config {
}
}
void ParseConfig(const std::string& path) {
void ParseConfig(const std::string& path)
{
if (path == "") return;
std::ifstream config(path, std::ios::in);
@ -288,11 +292,13 @@ namespace config { @@ -288,11 +292,13 @@ namespace config {
};
}
void Finalize() {
void Finalize()
{
notify(m_Options);
}
bool IsDefault(const char *name) {
bool IsDefault(const char *name)
{
if (!m_Options.count(name))
throw "try to check non-existent option";
@ -301,7 +307,8 @@ namespace config { @@ -301,7 +307,8 @@ namespace config {
return false;
}
bool GetOptionAsAny(const char *name, boost::any& value) {
bool GetOptionAsAny(const char *name, boost::any& value)
{
if (!m_Options.count(name))
return false;
value = m_Options[name];

2
libi2pd/Destination.cpp

@ -694,7 +694,7 @@ namespace client @@ -694,7 +694,7 @@ namespace client
ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map<std::string, std::string> * params):
LeaseSetDestination (isPublic, params),
m_Keys (keys), m_DatagramDestination (nullptr),
m_Keys (keys), m_DatagramDestination (nullptr), m_RefCounter (0),
m_ReadyChecker(GetService())
{
if (isPublic)

6
libi2pd/Destination.h

@ -181,6 +181,11 @@ namespace client @@ -181,6 +181,11 @@ namespace client
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); };
// ref counter
int Acquire () { return ++m_RefCounter; };
int Release () { return --m_RefCounter; };
int GetRefCounter () const { return m_RefCounter; };
// streaming
std::shared_ptr<i2p::stream::StreamingDestination> CreateStreamingDestination (int port, bool gzip = true); // additional
std::shared_ptr<i2p::stream::StreamingDestination> GetStreamingDestination (int port = 0) const;
@ -224,6 +229,7 @@ namespace client @@ -224,6 +229,7 @@ namespace client
std::shared_ptr<i2p::stream::StreamingDestination> m_StreamingDestination; // default
std::map<uint16_t, std::shared_ptr<i2p::stream::StreamingDestination> > m_StreamingDestinationsByPorts;
i2p::datagram::DatagramDestination * m_DatagramDestination;
int m_RefCounter; // how many clients(tunnels) use this destination
boost::asio::deadline_timer m_ReadyChecker;

4
libi2pd/HTTP.cpp

@ -293,11 +293,11 @@ namespace http { @@ -293,11 +293,11 @@ namespace http {
}
}
void HTTPReq::RemoveHeader (const std::string& name)
void HTTPReq::RemoveHeader (const std::string& name, const std::string& exempt)
{
for (auto it = headers.begin (); it != headers.end ();)
{
if (!it->first.compare(0, name.length (), name))
if (!it->first.compare(0, name.length (), name) && it->first != exempt)
it = headers.erase (it);
else
it++;

12
libi2pd/HTTP.h

@ -16,14 +16,17 @@ @@ -16,14 +16,17 @@
#include <string>
#include <vector>
namespace i2p {
namespace http {
namespace i2p
{
namespace http
{
const char CRLF[] = "\r\n"; /**< HTTP line terminator */
const char HTTP_EOH[] = "\r\n\r\n"; /**< HTTP end-of-headers mark */
extern const std::vector<std::string> HTTP_METHODS; /**< list of valid HTTP methods */
extern const std::vector<std::string> HTTP_VERSIONS; /**< list of valid HTTP versions */
struct URL {
struct URL
{
std::string schema;
std::string user;
std::string pass;
@ -90,7 +93,8 @@ namespace http { @@ -90,7 +93,8 @@ namespace http {
void AddHeader (const std::string& name, const std::string& value);
void UpdateHeader (const std::string& name, const std::string& value);
void RemoveHeader (const std::string& name);
void RemoveHeader (const std::string& name, const std::string& exempt); // remove all headers starting with name, but exempt
void RemoveHeader (const std::string& name) { RemoveHeader (name, ""); };
std::string GetHeader (const std::string& name) const;
};

25
libi2pd/Identity.cpp

@ -136,10 +136,7 @@ namespace data @@ -136,10 +136,7 @@ namespace data
delete[] excessBuf;
}
// calculate ident hash
uint8_t * buf = new uint8_t[GetFullLen ()];
ToBuffer (buf, GetFullLen ());
SHA256(buf, GetFullLen (), m_IdentHash);
delete[] buf;
RecalculateIdentHash();
}
else // DSA-SHA1
{
@ -152,6 +149,18 @@ namespace data @@ -152,6 +149,18 @@ namespace data
CreateVerifier ();
}
void IdentityEx::RecalculateIdentHash(uint8_t * buf)
{
bool dofree = buf == nullptr;
size_t sz = GetFullLen();
if(!buf)
buf = new uint8_t[sz];
ToBuffer (buf, sz);
SHA256(buf, sz, m_IdentHash);
if(dofree)
delete[] buf;
}
IdentityEx::IdentityEx (const uint8_t * buf, size_t len):
m_IsVerifierCreated (false), m_ExtendedLen (0), m_ExtendedBuffer (nullptr)
{
@ -556,6 +565,14 @@ namespace data @@ -556,6 +565,14 @@ namespace data
}
}
uint8_t * PrivateKeys::GetPadding()
{
if(m_Public->GetSigningKeyType () == SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519)
return m_Public->GetEncryptionPublicKeyBuffer() + 256;
else
return nullptr; // TODO: implement me
}
PrivateKeys PrivateKeys::CreateRandomKeys (SigningKeyType type)
{
if (type != SIGNING_KEY_TYPE_DSA_SHA1)

6
libi2pd/Identity.h

@ -90,8 +90,10 @@ namespace data @@ -90,8 +90,10 @@ namespace data
size_t FromBase64(const std::string& s);
std::string ToBase64 () const;
const Identity& GetStandardIdentity () const { return m_StandardIdentity; };
const IdentHash& GetIdentHash () const { return m_IdentHash; };
const uint8_t * GetEncryptionPublicKey () const { return m_StandardIdentity.publicKey; };
uint8_t * GetEncryptionPublicKeyBuffer () { return m_StandardIdentity.publicKey; };
size_t GetFullLen () const { return m_ExtendedLen + DEFAULT_IDENTITY_SIZE; };
size_t GetSigningPublicKeyLen () const;
size_t GetSigningPrivateKeyLen () const;
@ -103,6 +105,8 @@ namespace data @@ -103,6 +105,8 @@ namespace data
bool operator == (const IdentityEx & other) const { return GetIdentHash() == other.GetIdentHash(); }
void RecalculateIdentHash(uint8_t * buff=nullptr);
private:
void CreateVerifier () const;
@ -132,6 +136,8 @@ namespace data @@ -132,6 +136,8 @@ namespace data
std::shared_ptr<const IdentityEx> GetPublic () const { return m_Public; };
const uint8_t * GetPrivateKey () const { return m_PrivateKey; };
const uint8_t * GetSigningPrivateKey () const { return m_SigningPrivateKey; };
uint8_t * GetPadding();
void RecalculateIdentHash(uint8_t * buf=nullptr) { m_Public->RecalculateIdentHash(buf); }
void Sign (const uint8_t * buf, int len, uint8_t * signature) const;
size_t GetFullLen () const { return m_Public->GetFullLen () + 256 + m_Public->GetSigningPrivateKeyLen (); };

4
libi2pd/NetDb.cpp

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
#include <fstream>
#include <vector>
#include <boost/asio.hpp>
#include <stdexcept>
#include "I2PEndian.h"
#include "Base.h"
@ -139,8 +140,7 @@ namespace data @@ -139,8 +140,7 @@ namespace data
auto numRouters = m_RouterInfos.size ();
if (numRouters == 0)
{
LogPrint(eLogError, "NetDb: no known routers, reseed seems to be totally failed");
break;
throw std::runtime_error("No known routers, reseed seems to be totally failed");
}
else // we have peers now
m_FloodfillBootstrap = nullptr;

8
libi2pd/SSU.cpp

@ -433,7 +433,7 @@ namespace transport @@ -433,7 +433,7 @@ namespace transport
{
boost::asio::ip::udp::endpoint remoteEndpoint (address->host, address->port);
auto it = m_Sessions.find (remoteEndpoint);
// check if session if presented alredy
// check if session is presented already
if (it != m_Sessions.end ())
{
auto session = it->second;
@ -480,9 +480,14 @@ namespace transport @@ -480,9 +480,14 @@ namespace transport
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);
@ -492,6 +497,7 @@ namespace transport @@ -492,6 +497,7 @@ namespace transport
uint8_t buf[1];
Send (buf, 0, remoteEndpoint); // send HolePunch
}
}
introducerSession->Introduce (*introducer, router);
}
else

3
libi2pd/Tag.h

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
#define TAG_H__
/*
* Copyright (c) 2013-2016, The PurpleI2P Project
* Copyright (c) 2013-2017, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@ -28,6 +28,7 @@ public: @@ -28,6 +28,7 @@ public:
Tag (const uint8_t * buf) { memcpy (m_Buf, buf, sz); }
bool operator== (const Tag& other) const { return !memcmp (m_Buf, other.m_Buf, sz); }
bool operator!= (const Tag& other) const { return !(*this == other); }
bool operator< (const Tag& other) const { return memcmp (m_Buf, other.m_Buf, sz) < 0; }
uint8_t * operator()() { return m_Buf; }

11
libi2pd/Transports.cpp

@ -110,7 +110,7 @@ namespace transport @@ -110,7 +110,7 @@ namespace transport
Transports transports;
Transports::Transports ():
m_IsOnline (true), m_IsRunning (false), m_Thread (nullptr), m_Service (nullptr),
m_IsOnline (true), m_IsRunning (false), m_IsNAT (true), m_Thread (nullptr), m_Service (nullptr),
m_Work (nullptr), m_PeerCleanupTimer (nullptr), m_PeerTestTimer (nullptr),
m_NTCPServer (nullptr), m_SSUServer (nullptr), m_DHKeysPairSupplier (5), // 5 pre-generated keys
m_TotalSentBytes(0), m_TotalReceivedBytes(0), m_TotalTransitTransmittedBytes (0),
@ -142,6 +142,8 @@ namespace transport @@ -142,6 +142,8 @@ namespace transport
m_PeerTestTimer = new boost::asio::deadline_timer (*m_Service);
}
i2p::config::GetOption("nat", m_IsNAT);
m_DHKeysPairSupplier.Start ();
m_IsRunning = true;
m_Thread = new std::thread (std::bind (&Transports::Run, this));
@ -221,9 +223,13 @@ namespace transport @@ -221,9 +223,13 @@ namespace transport
}
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));
if (m_IsNAT)
{
m_PeerTestTimer->expires_from_now (boost::posix_time::minutes(PEER_TEST_INTERVAL));
m_PeerTestTimer->async_wait (std::bind (&Transports::HandlePeerTestTimer, this, std::placeholders::_1));
}
}
void Transports::Stop ()
{
@ -605,9 +611,8 @@ namespace transport @@ -605,9 +611,8 @@ namespace transport
}
if (m_SSUServer)
{
bool nat; i2p::config::GetOption("nat", nat);
bool isv4 = i2p::context.SupportsV4 ();
if (nat && isv4)
if (m_IsNAT && isv4)
i2p::context.SetStatus (eRouterStatusTesting);
for (int i = 0; i < 5; i++)
{

2
libi2pd/Transports.h

@ -146,7 +146,7 @@ namespace transport @@ -146,7 +146,7 @@ namespace transport
private:
bool m_IsOnline, m_IsRunning;
bool m_IsOnline, m_IsRunning, m_IsNAT;
std::thread * m_Thread;
boost::asio::io_service * m_Service;
boost::asio::io_service::work * m_Work;

2
libi2pd/Tunnel.h

@ -122,7 +122,7 @@ namespace tunnel @@ -122,7 +122,7 @@ namespace tunnel
void AddLatencySample(const uint64_t ms) { m_Latency = (m_Latency + ms) >> 1; }
/** @brief get this tunnel's estimated latency */
uint64_t GetMeanLatency() const { return m_Latency; }
/** @breif return true if this tunnel's latency fits in range [lowerbound, upperbound] */
/** @brief return true if this tunnel's latency fits in range [lowerbound, upperbound] */
bool LatencyFitsRange(uint64_t lowerbound, uint64_t upperbound) const;
bool LatencyIsKnown() const { return m_Latency > 0; }

4
libi2pd/version.h

@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
#define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c)
#define I2PD_VERSION_MAJOR 2
#define I2PD_VERSION_MINOR 14
#define I2PD_VERSION_MINOR 15
#define I2PD_VERSION_MICRO 0
#define I2PD_VERSION_PATCH 0
#define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO)
@ -21,7 +21,7 @@ @@ -21,7 +21,7 @@
#define I2P_VERSION_MAJOR 0
#define I2P_VERSION_MINOR 9
#define I2P_VERSION_MICRO 30
#define I2P_VERSION_MICRO 31
#define I2P_VERSION_PATCH 0
#define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)

19
libi2pd_client/AddressBook.cpp

@ -376,12 +376,23 @@ namespace client @@ -376,12 +376,23 @@ namespace client
continue;
}
numAddresses++;
if (m_Addresses.count(name) > 0)
continue; /* already exists */
m_Addresses[name] = ident->GetIdentHash ();
auto it = m_Addresses.find (name);
if (it != m_Addresses.end ()) // aleady exists ?
{
if (it->second != ident->GetIdentHash ()) // address changed?
{
it->second = ident->GetIdentHash ();
m_Storage->AddAddress (ident);
LogPrint (eLogInfo, "Addressbook: updated host: ", name);
}
}
else
{
m_Addresses.insert (std::make_pair (name, ident->GetIdentHash ()));
m_Storage->AddAddress (ident);
if (is_update)
LogPrint(eLogInfo, "Addressbook: added new host: ", name);
LogPrint (eLogInfo, "Addressbook: added new host: ", name);
}
}
else
incomplete = f.eof ();

102
libi2pd_client/ClientContext.cpp

@ -38,6 +38,7 @@ namespace client @@ -38,6 +38,7 @@ namespace client
if (!m_SharedLocalDestination)
{
m_SharedLocalDestination = CreateNewLocalDestination (); // non-public, DSA
m_SharedLocalDestination->Acquire ();
m_Destinations[m_SharedLocalDestination->GetIdentity ()->GetIdentHash ()] = m_SharedLocalDestination;
m_SharedLocalDestination->Start ();
}
@ -47,7 +48,8 @@ namespace client @@ -47,7 +48,8 @@ namespace client
std::shared_ptr<ClientDestination> localDestination;
bool httproxy; i2p::config::GetOption("httpproxy.enabled", httproxy);
if (httproxy) {
if (httproxy)
{
std::string httpProxyKeys; i2p::config::GetOption("httpproxy.keys", httpProxyKeys);
std::string httpProxyAddr; i2p::config::GetOption("httpproxy.address", httpProxyAddr);
uint16_t httpProxyPort; i2p::config::GetOption("httpproxy.port", httpProxyPort);
@ -61,14 +63,18 @@ namespace client @@ -61,14 +63,18 @@ namespace client
std::map<std::string, std::string> params;
ReadI2CPOptionsFromConfig ("httpproxy.", params);
localDestination = CreateNewLocalDestination (keys, false, &params);
localDestination->Acquire ();
}
else
LogPrint(eLogError, "Clients: failed to load HTTP Proxy key");
}
try {
try
{
m_HttpProxy = new i2p::proxy::HTTPProxy(httpProxyAddr, httpProxyPort, localDestination);
m_HttpProxy->Start();
} catch (std::exception& e) {
}
catch (std::exception& e)
{
LogPrint(eLogError, "Clients: Exception in HTTP Proxy: ", e.what());
}
}
@ -80,6 +86,7 @@ namespace client @@ -80,6 +86,7 @@ namespace client
std::string socksProxyKeys; i2p::config::GetOption("socksproxy.keys", socksProxyKeys);
std::string socksProxyAddr; i2p::config::GetOption("socksproxy.address", socksProxyAddr);
uint16_t socksProxyPort; i2p::config::GetOption("socksproxy.port", socksProxyPort);
bool socksOutProxy; i2p::config::GetOption("socksproxy.outproxy.enabled", socksOutProxy);
std::string socksOutProxyAddr; i2p::config::GetOption("socksproxy.outproxy", socksOutProxyAddr);
uint16_t socksOutProxyPort; i2p::config::GetOption("socksproxy.outproxyport", socksOutProxyPort);
i2p::data::SigningKeyType sigType; i2p::config::GetOption("socksproxy.signaturetype", sigType);
@ -92,14 +99,18 @@ namespace client @@ -92,14 +99,18 @@ namespace client
std::map<std::string, std::string> params;
ReadI2CPOptionsFromConfig ("socksproxy.", params);
localDestination = CreateNewLocalDestination (keys, false, &params);
localDestination->Acquire ();
}
else
LogPrint(eLogError, "Clients: failed to load SOCKS Proxy key");
}
try {
m_SocksProxy = new i2p::proxy::SOCKSProxy(socksProxyAddr, socksProxyPort, socksOutProxyAddr, socksOutProxyPort, localDestination);
try
{
m_SocksProxy = new i2p::proxy::SOCKSProxy(socksProxyAddr, socksProxyPort, socksOutProxy, socksOutProxyAddr, socksOutProxyPort, localDestination);
m_SocksProxy->Start();
} catch (std::exception& e) {
}
catch (std::exception& e)
{
LogPrint(eLogError, "Clients: Exception in SOCKS Proxy: ", e.what());
}
}
@ -242,10 +253,30 @@ namespace client @@ -242,10 +253,30 @@ namespace client
void ClientContext::ReloadConfig ()
{
std::string config; i2p::config::GetOption("conf", config);
i2p::config::ParseConfig(config);
Stop();
Start();
// TODO: handle config changes
/*std::string config; i2p::config::GetOption("conf", config);
i2p::config::ParseConfig(config);*/
// handle tunnels
// reset isUpdated for each tunnel
VisitTunnels ([](I2PService * s)->bool { s->isUpdated = false; return true; });
// reload tunnels
ReadTunnels();
// delete not updated tunnels (not in config anymore)
VisitTunnels ([](I2PService * s)->bool { return s->isUpdated; });
// delete unused destinations
std::unique_lock<std::mutex> l(m_DestinationsMutex);
for (auto it = m_Destinations.begin (); it != m_Destinations.end ();)
{
auto dest = it->second;
if (dest->GetRefCounter () > 0) ++it; // skip
else
{
dest->Stop ();
it = m_Destinations.erase (it);
}
}
}
bool ClientContext::LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename, i2p::data::SigningKeyType sigType)
@ -499,14 +530,14 @@ namespace client @@ -499,14 +530,14 @@ namespace client
if (type == I2P_TUNNELS_SECTION_TYPE_SOCKS)
{
// socks proxy
clientTunnel = new i2p::proxy::SOCKSProxy(address, port, "", destinationPort, localDestination);
clientEndpoint = ((i2p::proxy::SOCKSProxy*)clientTunnel)->GetAcceptor().local_endpoint();
clientTunnel = new i2p::proxy::SOCKSProxy(address, port, false, "", destinationPort, localDestination);
clientEndpoint = ((i2p::proxy::SOCKSProxy*)clientTunnel)->GetLocalEndpoint ();
}
else if (type == I2P_TUNNELS_SECTION_TYPE_HTTPPROXY)
{
// http proxy
clientTunnel = new i2p::proxy::HTTPProxy(address, port, localDestination);
clientEndpoint = ((i2p::proxy::HTTPProxy*)clientTunnel)->GetAcceptor().local_endpoint();
clientEndpoint = ((i2p::proxy::HTTPProxy*)clientTunnel)->GetLocalEndpoint ();
}
else if (type == I2P_TUNNELS_SECTION_TYPE_WEBSOCKS)
{
@ -518,15 +549,20 @@ namespace client @@ -518,15 +549,20 @@ namespace client
{
// tcp client
clientTunnel = new I2PClientTunnel (name, dest, address, port, localDestination, destinationPort);
clientEndpoint = ((I2PClientTunnel*)clientTunnel)->GetAcceptor().local_endpoint();
clientEndpoint = ((I2PClientTunnel*)clientTunnel)->GetLocalEndpoint ();
}
if (m_ClientTunnels.insert (std::make_pair (clientEndpoint, std::unique_ptr<I2PService>(clientTunnel))).second)
auto ins = m_ClientTunnels.insert (std::make_pair (clientEndpoint, std::unique_ptr<I2PService>(clientTunnel)));
if (ins.second)
{
clientTunnel->Start ();
numClientTunnels++;
}
else
LogPrint (eLogError, "Clients: I2P client tunnel for endpoint ", clientEndpoint, "already exists");
{
// TODO: update
ins.first->second->isUpdated = true;
LogPrint (eLogInfo, "Clients: I2P client tunnel for endpoint ", clientEndpoint, "already exists");
}
}
}
else if (type == I2P_TUNNELS_SECTION_TYPE_SERVER
@ -619,15 +655,20 @@ namespace client @@ -619,15 +655,20 @@ namespace client
while (comma != std::string::npos);
serverTunnel->SetAccessList (idents);
}
if (m_ServerTunnels.insert (std::make_pair (
auto ins = m_ServerTunnels.insert (std::make_pair (
std::make_pair (localDestination->GetIdentHash (), inPort),
std::unique_ptr<I2PServerTunnel>(serverTunnel))).second)
std::unique_ptr<I2PServerTunnel>(serverTunnel)));
if (ins.second)
{
serverTunnel->Start ();
numServerTunnels++;
}
else
LogPrint (eLogError, "Clients: I2P server tunnel for destination/port ", m_AddressBook.ToAddress(localDestination->GetIdentHash ()), "/", inPort, " already exists");
{
// TODO: update
ins.first->second->isUpdated = true;
LogPrint (eLogInfo, "Clients: I2P server tunnel for destination/port ", m_AddressBook.ToAddress(localDestination->GetIdentHash ()), "/", inPort, " already exists");
}
}
else
@ -662,5 +703,28 @@ namespace client @@ -662,5 +703,28 @@ namespace client
ScheduleCleanupUDP();
}
}
template<typename Container, typename Visitor>
void VisitTunnelsContainer (Container& c, Visitor v)
{
for (auto it = c.begin (); it != c.end ();)
{
if (!v (it->second.get ()))
{
it->second->Stop ();
it = c.erase (it);
}
else
it++;
}
}
template<typename Visitor>
void ClientContext::VisitTunnels (Visitor v)
{
VisitTunnelsContainer (m_ClientTunnels, v);
VisitTunnelsContainer (m_ServerTunnels, v);
// TODO: implement UDP forwards
}
}
}

3
libi2pd_client/ClientContext.h

@ -89,6 +89,9 @@ namespace client @@ -89,6 +89,9 @@ namespace client
void CleanupUDP(const boost::system::error_code & ecode);
void ScheduleCleanupUDP();
template<typename Visitor>
void VisitTunnels (Visitor v); // Visitor: (I2PService *) -> bool, true means retain
private:
std::mutex m_DestinationsMutex;

3
libi2pd_client/HTTPProxy.cpp

@ -203,9 +203,10 @@ namespace proxy { @@ -203,9 +203,10 @@ namespace proxy {
req.RemoveHeader ("Referer");
req.RemoveHeader("Via");
req.RemoveHeader("Forwarded");
req.RemoveHeader("Accept-", "Accept-Encoding"); // Accept-*, but Accept-Encoding
/* drop proxy-disclosing headers */
req.RemoveHeader("X-Forwarded");
req.RemoveHeader("Proxy-");
req.RemoveHeader("Proxy-"); // Proxy-*
/* replace headers */
req.UpdateHeader("User-Agent", "MYOB/6.66 (AN/ON)");
/* add headers */

32
libi2pd_client/I2PService.cpp

@ -11,13 +11,30 @@ namespace client @@ -11,13 +11,30 @@ namespace client
I2PService::I2PService (std::shared_ptr<ClientDestination> localDestination):
m_LocalDestination (localDestination ? localDestination :
i2p::client::context.CreateNewLocalDestination (false, I2P_SERVICE_DEFAULT_KEY_TYPE))
i2p::client::context.CreateNewLocalDestination (false, I2P_SERVICE_DEFAULT_KEY_TYPE)), isUpdated (true)
{
m_LocalDestination->Acquire ();
}
I2PService::I2PService (i2p::data::SigningKeyType kt):
m_LocalDestination (i2p::client::context.CreateNewLocalDestination (false, kt))
m_LocalDestination (i2p::client::context.CreateNewLocalDestination (false, kt)),
isUpdated (true)
{
m_LocalDestination->Acquire ();
}
I2PService::~I2PService ()
{
ClearHandlers ();
if (m_LocalDestination) m_LocalDestination->Release ();
}
void I2PService::ClearHandlers ()
{
std::unique_lock<std::mutex> l(m_HandlersMutex);
for (auto it: m_Handlers)
it->Terminate ();
m_Handlers.clear();
}
void I2PService::CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, int port) {
@ -173,13 +190,18 @@ namespace client @@ -173,13 +190,18 @@ namespace client
void TCPIPAcceptor::Start ()
{
m_Acceptor.listen ();
m_Acceptor.reset (new boost::asio::ip::tcp::acceptor (GetService (), m_LocalEndpoint));
m_Acceptor->listen ();
Accept ();
}
void TCPIPAcceptor::Stop ()
{
m_Acceptor.close();
if (m_Acceptor)
{
m_Acceptor->close();
m_Acceptor.reset (nullptr);
}
m_Timer.cancel ();
ClearHandlers();
}
@ -187,7 +209,7 @@ namespace client @@ -187,7 +209,7 @@ namespace client
void TCPIPAcceptor::Accept ()
{
auto newSocket = std::make_shared<boost::asio::ip::tcp::socket> (GetService ());
m_Acceptor.async_accept (*newSocket, std::bind (&TCPIPAcceptor::HandleAccept, this,
m_Acceptor->async_accept (*newSocket, std::bind (&TCPIPAcceptor::HandleAccept, this,
std::placeholders::_1, newSocket));
}

23
libi2pd_client/I2PService.h

@ -19,7 +19,7 @@ namespace client @@ -19,7 +19,7 @@ namespace client
public:
I2PService (std::shared_ptr<ClientDestination> localDestination = nullptr);
I2PService (i2p::data::SigningKeyType kt);
virtual ~I2PService () { ClearHandlers (); }
virtual ~I2PService ();
inline void AddHandler (std::shared_ptr<I2PServiceHandler> conn)
{
@ -31,11 +31,7 @@ namespace client @@ -31,11 +31,7 @@ namespace client
std::unique_lock<std::mutex> l(m_HandlersMutex);
m_Handlers.erase(conn);
}
inline void ClearHandlers ()
{
std::unique_lock<std::mutex> l(m_HandlersMutex);
m_Handlers.clear();
}
void ClearHandlers ();
inline std::shared_ptr<ClientDestination> GetLocalDestination () { return m_LocalDestination; }
inline std::shared_ptr<const ClientDestination> GetLocalDestination () const { return m_LocalDestination; }
@ -53,6 +49,9 @@ namespace client @@ -53,6 +49,9 @@ namespace client
std::shared_ptr<ClientDestination> m_LocalDestination;
std::unordered_set<std::shared_ptr<I2PServiceHandler> > m_Handlers;
std::mutex m_HandlersMutex;
public:
bool isUpdated; // transient, used during reload only
};
/*Simple interface for I2PHandlers, allows detection of finalization amongst other things */
@ -63,6 +62,9 @@ namespace client @@ -63,6 +62,9 @@ namespace client
virtual ~I2PServiceHandler() { }
//If you override this make sure you call it from the children
virtual void Handle() {}; //Start handling the socket
void Terminate () { Kill (); };
protected:
// Call when terminating or handing over to avoid race conditions
inline bool Kill () { return m_Dead.exchange(true); }
@ -108,11 +110,11 @@ namespace client @@ -108,11 +110,11 @@ namespace client
public:
TCPIPAcceptor (const std::string& address, int port, std::shared_ptr<ClientDestination> localDestination = nullptr) :
I2PService(localDestination),
m_Acceptor (GetService (), boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string(address), port)),
m_LocalEndpoint (boost::asio::ip::address::from_string(address), port),
m_Timer (GetService ()) {}
TCPIPAcceptor (const std::string& address, int port, i2p::data::SigningKeyType kt) :
I2PService(kt),
m_Acceptor (GetService (), boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string(address), port)),
m_LocalEndpoint (boost::asio::ip::address::from_string(address), port),
m_Timer (GetService ()) {}
virtual ~TCPIPAcceptor () { TCPIPAcceptor::Stop(); }
//If you override this make sure you call it from the children
@ -120,7 +122,7 @@ namespace client @@ -120,7 +122,7 @@ namespace client
//If you override this make sure you call it from the children
void Stop ();
const boost::asio::ip::tcp::acceptor& GetAcceptor () const { return m_Acceptor; };
const boost::asio::ip::tcp::endpoint& GetLocalEndpoint () const { return m_LocalEndpoint; };
virtual const char* GetName() { return "Generic TCP/IP accepting daemon"; }
@ -129,7 +131,8 @@ namespace client @@ -129,7 +131,8 @@ namespace client
private:
void Accept();
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket);
boost::asio::ip::tcp::acceptor m_Acceptor;
boost::asio::ip::tcp::endpoint m_LocalEndpoint;
std::unique_ptr<boost::asio::ip::tcp::acceptor> m_Acceptor;
boost::asio::deadline_timer m_Timer;
};
}

2
libi2pd_client/SAM.cpp

@ -921,6 +921,7 @@ namespace client @@ -921,6 +921,7 @@ namespace client
}
if (localDestination)
{
localDestination->Acquire ();
auto session = std::make_shared<SAMSession>(localDestination);
std::unique_lock<std::mutex> l(m_SessionsMutex);
auto ret = m_Sessions.insert (std::make_pair(id, session));
@ -945,6 +946,7 @@ namespace client @@ -945,6 +946,7 @@ namespace client
}
if (session)
{
session->localDestination->Release ();
session->localDestination->StopAcceptingStreams ();
session->CloseStreams ();
}

4
libi2pd_client/SOCKS.cpp

@ -768,12 +768,12 @@ namespace proxy @@ -768,12 +768,12 @@ namespace proxy
shared_from_this(), std::placeholders::_1, std::placeholders::_2));
}
SOCKSServer::SOCKSServer(const std::string& address, int port, const std::string& outAddress, uint16_t outPort,
SOCKSServer::SOCKSServer(const std::string& address, int port, bool outEnable, const std::string& outAddress, uint16_t outPort,
std::shared_ptr<i2p::client::ClientDestination> localDestination) :
TCPIPAcceptor (address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ())
{
m_UseUpstreamProxy = false;
if (outAddress.length() > 0)
if (outAddress.length() > 0 && outEnable)
SetUpstreamProxy(outAddress, outPort);
}

5
libi2pd_client/SOCKS.h

@ -14,8 +14,7 @@ namespace proxy @@ -14,8 +14,7 @@ namespace proxy
class SOCKSServer: public i2p::client::TCPIPAcceptor
{
public:
SOCKSServer(const std::string& address, int port, const std::string& outAddress, uint16_t outPort,
SOCKSServer(const std::string& address, int port, bool outEnable, const std::string& outAddress, uint16_t outPort,
std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr);
~SOCKSServer() {};
@ -35,6 +34,4 @@ namespace proxy @@ -35,6 +34,4 @@ namespace proxy
typedef SOCKSServer SOCKSProxy;
}
}
#endif

1
qt/i2pd_qt/ClientTunnelPane.h

@ -91,6 +91,7 @@ protected: @@ -91,6 +91,7 @@ protected:
ctc->setdestinationPort(dportInt);
ctc->setsigType(readSigTypeComboboxUI(sigTypeComboBox));
return true;
}
};

1
qt/i2pd_qt/DaemonQT.cpp

@ -161,6 +161,7 @@ namespace qt @@ -161,6 +161,7 @@ namespace qt
{
i2p::qt::Controller daemonQtController(daemon);
w.setI2PController(&daemonQtController);
qDebug("Starting the daemon...");
emit daemonQtController.startDaemon();
//daemon.start ();

1
qt/i2pd_qt/ServerTunnelPane.h

@ -155,6 +155,7 @@ protected: @@ -155,6 +155,7 @@ protected:
stc->setisUniqueLocal(isUniqueLocalCheckBox->isChecked());
stc->setsigType(readSigTypeComboboxUI(sigTypeComboBox));
return true;
}
};

11
qt/i2pd_qt/SignatureTypeComboboxFactory.h

@ -18,8 +18,11 @@ class SignatureTypeComboBoxFactory @@ -18,8 +18,11 @@ class SignatureTypeComboBoxFactory
}
public:
static QComboBox* createSignatureTypeComboBox(QWidget* parent, uint16_t selectedSigType) {
QComboBox* signatureTypeCombobox = new QComboBox(parent);
static const uint16_t getSigType(const QVariant& var) {
return (uint16_t)var.toInt();
}
static void fillComboBox(QComboBox* signatureTypeCombobox, uint16_t selectedSigType) {
/*
<orignal> https://geti2p.net/spec/common-structures#certificate
<orignal> все коды перечислены
@ -78,7 +81,11 @@ public: @@ -78,7 +81,11 @@ public:
addItem(signatureTypeCombobox, QString::number(selectedSigType), selectedSigType); //unknown sigtype
signatureTypeCombobox->setCurrentIndex(index);
}
}
static QComboBox* createSignatureTypeComboBox(QWidget* parent, uint16_t selectedSigType) {
QComboBox* signatureTypeCombobox = new QComboBox(parent);
fillComboBox(signatureTypeCombobox, selectedSigType);
return signatureTypeCombobox;
}
};

3
qt/i2pd_qt/TunnelConfig.h

@ -196,7 +196,8 @@ public: @@ -196,7 +196,8 @@ public:
gzip(gzip_),
sigType(sigType_),
maxConns(maxConns_),
address(address_) {}
address(address_),
isUniqueLocal(isUniqueLocal_) {}
std::string& gethost(){return host;}
int getport(){return port;}
std::string& getkeys(){return keys;}

1
qt/i2pd_qt/TunnelPane.h

@ -88,6 +88,7 @@ protected: @@ -88,6 +88,7 @@ protected:
i2cpParams.setOutbound_length(outbound_lengthLineEdit->text());
i2cpParams.setOutbound_quantity(outbound_quantityLineEdit->text());
i2cpParams.setCrypto_tagsToSend(crypto_tagsToSendLineEdit->text());
return true;
}
void setupTunnelPane(

2
qt/i2pd_qt/android/AndroidManifest.xml

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
<?xml version="1.0"?>
<manifest package="org.purplei2p.i2pd" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="2.14.0" android:versionCode="2" android:installLocation="auto">
<manifest package="org.purplei2p.i2pd" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="2.15.0" android:versionCode="2" android:installLocation="auto">
<uses-sdk android:minSdkVersion="11" android:targetSdkVersion="23"/>
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
<!-- <application android:hardwareAccelerated="true" -->

19
qt/i2pd_qt/mainwindow.cpp

@ -17,6 +17,9 @@ @@ -17,6 +17,9 @@
#include <fstream>
#include "DaemonQT.h"
#include "SignatureTypeComboboxFactory.h"
std::string programOptionsWriterCurrentSection;
MainWindow::MainWindow(QWidget *parent) :
@ -25,6 +28,7 @@ MainWindow::MainWindow(QWidget *parent) : @@ -25,6 +28,7 @@ MainWindow::MainWindow(QWidget *parent) :
,quitting(false)
#endif
,ui(new Ui::MainWindow)
,i2pController(nullptr)
,configItems()
,datadir()
,confpath()
@ -48,8 +52,6 @@ MainWindow::MainWindow(QWidget *parent) : @@ -48,8 +52,6 @@ MainWindow::MainWindow(QWidget *parent) :
int w = 683;
int h = 3060;
ui->settingsContents->setFixedSize(w, h);
//ui->settingsContents->resize(w, h);
//ui->settingsContents->adjustSize();
/*
QPalette pal(palette());
@ -77,6 +79,8 @@ MainWindow::MainWindow(QWidget *parent) : @@ -77,6 +79,8 @@ MainWindow::MainWindow(QWidget *parent) :
QObject::connect(ui->fastQuitPushButton, SIGNAL(released()), this, SLOT(handleQuitButton()));
QObject::connect(ui->gracefulQuitPushButton, SIGNAL(released()), this, SLOT(handleGracefulQuitButton()));
QObject::connect(ui->doRestartI2PDPushButton, SIGNAL(released()), this, SLOT(handleDoRestartButton()));
# define OPTION(section,option,defaultValueGetter) ConfigOption(QString(section),QString(option))
initFileChooser( OPTION("","conf",[](){return "";}), ui->configFileLineEdit, ui->configFileBrowsePushButton);
@ -120,6 +124,7 @@ MainWindow::MainWindow(QWidget *parent) : @@ -120,6 +124,7 @@ MainWindow::MainWindow(QWidget *parent) :
initIPAddressBox( OPTION("httpproxy","address",[]{return "";}), ui->httpProxyAddressLineEdit, tr("HTTP proxy -> IP address"));
initTCPPortBox( OPTION("httpproxy","port",[]{return "4444";}), ui->httpProxyPortLineEdit, tr("HTTP proxy -> Port"));
initFileChooser( OPTION("httpproxy","keys",[]{return "";}), ui->httpProxyKeyFileLineEdit, ui->httpProxyKeyFilePushButton);
initSignatureTypeCombobox(OPTION("httpproxy","signaturetype",[]{return "7";}), ui->comboBox_httpPorxySignatureType);
initStringBox( OPTION("httpproxy","inbound.length",[]{return "3";}), ui->httpProxyInboundTunnelsLenLineEdit);
initStringBox( OPTION("httpproxy","inbound.quantity",[]{return "5";}), ui->httpProxyInboundTunnQuantityLineEdit);
@ -328,6 +333,12 @@ void MainWindow::handleGracefulQuitButton() { @@ -328,6 +333,12 @@ void MainWindow::handleGracefulQuitButton() {
, this, SLOT(handleGracefulQuitTimerEvent()));
}
void MainWindow::handleDoRestartButton() {
qDebug()<<"Do Restart pressed.";
emit i2pController->restartDaemon();
}
void MainWindow::handleGracefulQuitTimerEvent() {
qDebug("Hiding the main window");
#ifndef ANDROID
@ -616,3 +627,7 @@ void MainWindow::addServerTunnelPushButtonReleased() { @@ -616,3 +627,7 @@ void MainWindow::addServerTunnelPushButtonReleased() {
void MainWindow::addClientTunnelPushButtonReleased() {
CreateDefaultClientTunnel();
}
void MainWindow::setI2PController(i2p::qt::Controller* controller_) {
this->i2pController = controller_;
}

27
qt/i2pd_qt/mainwindow.h

@ -51,6 +51,9 @@ @@ -51,6 +51,9 @@
#include "TunnelsPageUpdateListener.h"
#include "DaemonQT.h"
#include "SignatureTypeComboboxFactory.h"
template<typename ValueType>
bool isType(boost::any& a) {
return
@ -216,16 +219,15 @@ class SignatureTypeComboBoxItem : public ComboBoxItem { @@ -216,16 +219,15 @@ class SignatureTypeComboBoxItem : public ComboBoxItem {
public:
SignatureTypeComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : ComboBoxItem(option_, comboBox_) {};
virtual ~SignatureTypeComboBoxItem(){}
virtual void loadFromConfigOption(){//TODO
virtual void loadFromConfigOption(){
MainWindowItem::loadFromConfigOption();
comboBox->setCurrentText(QString::number(boost::any_cast<unsigned short>(optionValue)));
while(comboBox->count()>0)comboBox->removeItem(0);
uint16_t selected = (uint16_t) boost::any_cast<unsigned short>(optionValue);
SignatureTypeComboBoxFactory::fillComboBox(comboBox, selected);
}
virtual void saveToStringStream(std::stringstream& out){//TODO
QString txt = comboBox->currentText();
if(txt.isEmpty())
optionValue=std::string();
else
optionValue=(unsigned short)std::stoi(txt.toStdString());
virtual void saveToStringStream(std::stringstream& out){
uint16_t selected = SignatureTypeComboBoxFactory::getSigType(comboBox->currentData());
optionValue=(unsigned short)selected;
MainWindowItem::saveToStringStream(out);
}
virtual bool isValid() { return true; }
@ -311,6 +313,10 @@ using namespace i2p::client; @@ -311,6 +313,10 @@ using namespace i2p::client;
class TunnelPane;
using namespace i2p::qt;
class Controller;
class MainWindow : public QMainWindow {
Q_OBJECT
@ -318,6 +324,8 @@ public: @@ -318,6 +324,8 @@ public:
explicit MainWindow(QWidget *parent=0);
~MainWindow();
void setI2PController(i2p::qt::Controller* controller_);
//typedef std::function<QString ()> DefaultValueGetter;
//#ifndef ANDROID
@ -327,6 +335,7 @@ public: @@ -327,6 +335,7 @@ public:
private slots:
void handleQuitButton();
void handleGracefulQuitButton();
void handleDoRestartButton();
void handleGracefulQuitTimerEvent();
#ifndef ANDROID
void setIcon();
@ -351,6 +360,8 @@ private: @@ -351,6 +360,8 @@ private:
Ui::MainWindow* ui;
i2p::qt::Controller* i2pController;
protected:
#ifndef ANDROID
void closeEvent(QCloseEvent *event);

50
qt/i2pd_qt/mainwindow.ui

@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>816</width>
<height>5000</height>
<height>516</height>
</rect>
</property>
<property name="windowTitle">
@ -37,8 +37,8 @@ @@ -37,8 +37,8 @@
<rect>
<x>10</x>
<y>10</y>
<width>801</width>
<height>518</height>
<width>796</width>
<height>496</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
@ -126,17 +126,17 @@ @@ -126,17 +126,17 @@
<property name="minimumSize">
<size>
<width>0</width>
<height>516</height>
<height>496</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>516</height>
<height>496</height>
</size>
</property>
<property name="currentIndex">
<number>1</number>
<number>4</number>
</property>
<widget class="QWidget" name="statusPage">
<widget class="QWidget" name="verticalLayoutWidget_5">
@ -144,8 +144,8 @@ @@ -144,8 +144,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>671</width>
<height>5000</height>
<width>686</width>
<height>496</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
@ -192,8 +192,8 @@ @@ -192,8 +192,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>701</width>
<height>400</height>
<width>706</width>
<height>461</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
@ -232,7 +232,7 @@ @@ -232,7 +232,7 @@
<x>0</x>
<y>0</y>
<width>679</width>
<height>400</height>
<height>3000</height>
</rect>
</property>
<property name="sizePolicy">
@ -245,14 +245,13 @@ @@ -245,14 +245,13 @@
<property name="geometry">
<rect>
<x>10</x>
<y>11</y>
<y>10</y>
<width>679</width>
<height>2962</height>
<height>3000</height>
</rect>
</property>
<layout class="QGridLayout" name="settingsContentsGridLayout" rowstretch="0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">
<item row="14" column="0">
<widget class="QGroupBox" name="samGroupBox">
<property name="minimumSize">
<size>
@ -360,9 +359,6 @@ @@ -360,9 +359,6 @@
</layout>
</widget>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="winOptLabel">
@ -2570,13 +2566,13 @@ Comma separated list of base64 identities:</string> @@ -2570,13 +2566,13 @@ Comma separated list of base64 identities:</string>
<property name="minimumSize">
<size>
<width>0</width>
<height>370</height>
<height>400</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>370</height>
<height>400</height>
</size>
</property>
<property name="title">
@ -2997,8 +2993,8 @@ Comma separated list of base64 identities:</string> @@ -2997,8 +2993,8 @@ Comma separated list of base64 identities:</string>
<rect>
<x>0</x>
<y>0</y>
<width>681</width>
<height>460</height>
<width>706</width>
<height>461</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
@ -3064,8 +3060,8 @@ Comma separated list of base64 identities:</string> @@ -3064,8 +3060,8 @@ Comma separated list of base64 identities:</string>
<rect>
<x>0</x>
<y>0</y>
<width>663</width>
<height>395</height>
<width>699</width>
<height>425</height>
</rect>
</property>
</widget>
@ -3080,8 +3076,8 @@ Comma separated list of base64 identities:</string> @@ -3080,8 +3076,8 @@ Comma separated list of base64 identities:</string>
<rect>
<x>0</x>
<y>0</y>
<width>681</width>
<height>451</height>
<width>686</width>
<height>496</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
@ -3135,8 +3131,8 @@ Comma separated list of base64 identities:</string> @@ -3135,8 +3131,8 @@ Comma separated list of base64 identities:</string>
<rect>
<x>0</x>
<y>0</y>
<width>671</width>
<height>480</height>
<width>686</width>
<height>496</height>
</rect>
</property>
<layout class="QVBoxLayout" name="quitPageVerticalLayout">

Loading…
Cancel
Save