mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-03-07 06:09:42 +00:00
Compare commits
114 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b8baa85a3 | ||
|
|
73921b1024 | ||
|
|
ece140f18c | ||
|
|
5e42947fbd | ||
|
|
1bfb9b02f5 | ||
|
|
16a14c2b76 | ||
|
|
f6199c6c17 | ||
|
|
d7e7f06e88 | ||
|
|
4c4e856a1a | ||
|
|
07bbbbaf61 | ||
|
|
3236827781 | ||
|
|
0be664cc3d | ||
|
|
6cc6849ccc | ||
|
|
5d5cd71714 | ||
|
|
d248343517 | ||
|
|
64d800427f | ||
|
|
c4c896a833 | ||
|
|
b6b5bb3f75 | ||
|
|
5d69bb7383 | ||
|
|
76e222079a | ||
|
|
73abb9278d | ||
|
|
8fd843e7ce | ||
|
|
6a497a23d9 | ||
|
|
3ac74e1091 | ||
|
|
ef0fb48f1f | ||
|
|
414ef2bc3d | ||
|
|
ea791309ad | ||
|
|
706da6e431 | ||
|
|
ed116e7cea | ||
|
|
5b56f4007b | ||
|
|
e2071542bf | ||
|
|
cdb217b774 | ||
|
|
079798940b | ||
|
|
f1c24689bf | ||
|
|
1f9cf6ed7c | ||
|
|
43f218410f | ||
|
|
3fd9d5f641 | ||
|
|
f5ab8f2062 | ||
|
|
8774a8fbc2 | ||
|
|
6f4f0f03d2 | ||
|
|
00b5fdce03 | ||
|
|
baee6a0d91 | ||
|
|
ff44bcc489 | ||
|
|
c797ac4268 | ||
|
|
d22a76d4d1 | ||
|
|
a6642e0ebc | ||
|
|
3d4d260a34 | ||
|
|
8e4b9da97d | ||
|
|
2be80ba30f | ||
|
|
2e44c88d6c | ||
|
|
21eb1ce6c9 | ||
|
|
cdfd411df7 | ||
|
|
a6149ca90c | ||
|
|
642435486c | ||
|
|
fc84d6c4b7 | ||
|
|
aa4bddd6ec | ||
|
|
8ec12a1b65 | ||
|
|
0fbf552e95 | ||
|
|
09b1b120d7 | ||
|
|
557244bc3f | ||
|
|
24c5ed1cff | ||
|
|
32e55ebd0c | ||
|
|
ea3070d02b | ||
|
|
9aaba49a9f | ||
|
|
9b64be07a9 | ||
|
|
42c3c28ea7 | ||
|
|
9e9236badb | ||
|
|
560ebcec8d | ||
|
|
9b1fe4338b | ||
|
|
9188e3ad3f | ||
|
|
af65af5be9 | ||
|
|
2f0115c300 | ||
|
|
0646461342 | ||
|
|
ec30ec0996 | ||
|
|
cdecb7a43c | ||
|
|
aa9c1b66a0 | ||
|
|
846eac29dc | ||
|
|
0f9e3c5b33 | ||
|
|
aa27746982 | ||
|
|
d8a4954bf1 | ||
|
|
d40a029dae | ||
|
|
96d961c393 | ||
|
|
7b6814e32d | ||
|
|
6fee2d3536 | ||
|
|
636fc633d4 | ||
|
|
72a239838e | ||
|
|
a463dbc5fb | ||
|
|
016ae3b9e9 | ||
|
|
7d0d421724 | ||
|
|
83b5856a19 | ||
|
|
f617b27110 | ||
|
|
a91a0263cf | ||
|
|
80ffe13f3e | ||
|
|
1eb726c9bb | ||
|
|
1fa3ba8b42 | ||
|
|
b6bfd66a49 | ||
|
|
1be0e7ddaa | ||
|
|
2cac9b03ff | ||
|
|
f5f4190803 | ||
|
|
a14d554947 | ||
|
|
6d9e5147b5 | ||
|
|
841452cb9e | ||
|
|
9c76368dbc | ||
|
|
bd5122c6ea | ||
|
|
6643258618 | ||
|
|
bc3f02cb6b | ||
|
|
d848ae332a | ||
|
|
08ddc98303 | ||
|
|
a3344c4290 | ||
|
|
22c1ce3ea5 | ||
|
|
afb14e6782 | ||
|
|
e177363377 | ||
|
|
ce213934c9 | ||
|
|
af286ec52e |
36
ChangeLog
36
ChangeLog
@@ -1,6 +1,42 @@
|
|||||||
# for this file format description,
|
# for this file format description,
|
||||||
# see https://github.com/olivierlacan/keep-a-changelog
|
# see https://github.com/olivierlacan/keep-a-changelog
|
||||||
|
|
||||||
|
## [2.25.0] - 2019-05-09
|
||||||
|
### Added
|
||||||
|
- Create, publish and handle encrypted LeaseSet2
|
||||||
|
- Support of b33 addresses
|
||||||
|
- RedDSA key blinding
|
||||||
|
- .b32.i2p addresses in jump links
|
||||||
|
- ntcp2.addressv6 parameter
|
||||||
|
### Changed
|
||||||
|
- Allow HTTP headers without value
|
||||||
|
- Set data directory from external storage path for Android
|
||||||
|
- addresshelper support is configurable per tunnel
|
||||||
|
- gradlew script for android build
|
||||||
|
### Fixed
|
||||||
|
- Deletion of expired encrypted LeaseSet2 on floodfills
|
||||||
|
- ipv6 fallback address
|
||||||
|
- SSU incoming packets routing
|
||||||
|
|
||||||
|
## [2.24.0] - 2019-03-21
|
||||||
|
### Added
|
||||||
|
- Support of transient keys for LeaseSet2
|
||||||
|
- Support of encrypted LeaseSet2
|
||||||
|
- Recognize signature type 11 (RedDSA)
|
||||||
|
- Support websocket connections over HTTP proxy
|
||||||
|
- Ability to disable full addressbook persist
|
||||||
|
### Changed
|
||||||
|
- Don't load peer profiles if non-persistant
|
||||||
|
- REUSE_ADDR for ipv6 acceptors
|
||||||
|
- Reset eTags if addressbook can't be loaded
|
||||||
|
### Fixed
|
||||||
|
- Build with boost 1.70
|
||||||
|
- Filter out unspecified addresses from RouterInfo
|
||||||
|
- Check floodfill status change
|
||||||
|
- Correct SAM response for invalid key
|
||||||
|
- SAM crash on termination for Windows
|
||||||
|
- Race condition for publishing
|
||||||
|
|
||||||
## [2.23.0] - 2019-01-21
|
## [2.23.0] - 2019-01-21
|
||||||
### Added
|
### Added
|
||||||
- Standard LeaseSet2 support
|
- Standard LeaseSet2 support
|
||||||
|
|||||||
@@ -19,10 +19,7 @@ else ifeq ($(shell expr match ${CXXVER} "4\.[7-9]"),3) # >= 4.7
|
|||||||
NEEDED_CXXFLAGS += -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1
|
NEEDED_CXXFLAGS += -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1
|
||||||
else ifeq ($(shell expr match ${CXXVER} "4\.6"),3) # = 4.6
|
else ifeq ($(shell expr match ${CXXVER} "4\.6"),3) # = 4.6
|
||||||
NEEDED_CXXFLAGS += -std=c++0x
|
NEEDED_CXXFLAGS += -std=c++0x
|
||||||
else ifeq ($(shell expr match ${CXXVER} "[5-7]\.[0-9]"),3) # gcc >= 5.0
|
else ifeq ($(shell expr match ${CXXVER} "[5-9]"),1) # gcc >= 5
|
||||||
NEEDED_CXXFLAGS += -std=c++11
|
|
||||||
LDLIBS = -latomic
|
|
||||||
else ifeq ($(shell expr match ${CXXVER} "[7-8]"),1) # gcc 7 ubuntu or gcc 8 arch
|
|
||||||
NEEDED_CXXFLAGS += -std=c++11
|
NEEDED_CXXFLAGS += -std=c++11
|
||||||
LDLIBS = -latomic
|
LDLIBS = -latomic
|
||||||
else # not supported
|
else # not supported
|
||||||
|
|||||||
15
README.md
15
README.md
@@ -1,3 +1,6 @@
|
|||||||
|

|
||||||
|

|
||||||
|
|
||||||
i2pd
|
i2pd
|
||||||
====
|
====
|
||||||
|
|
||||||
@@ -38,8 +41,12 @@ Resources
|
|||||||
Installing
|
Installing
|
||||||
----------
|
----------
|
||||||
|
|
||||||
The easiest way to install i2pd is by using
|
The easiest way to install i2pd is by using precompiled packages and binaries.
|
||||||
[precompiled binaries](https://github.com/PurpleI2P/i2pd/releases/latest).
|
You can fetch most of them on [release](https://github.com/PurpleI2P/i2pd/releases/latest) page.
|
||||||
|
Please see [documentation](https://i2pd.readthedocs.io/en/latest/user-guide/install/) for more info.
|
||||||
|
|
||||||
|
Building
|
||||||
|
--------
|
||||||
See [documentation](https://i2pd.readthedocs.io/en/latest/) for how to build
|
See [documentation](https://i2pd.readthedocs.io/en/latest/) for how to build
|
||||||
i2pd from source on your OS.
|
i2pd from source on your OS.
|
||||||
|
|
||||||
@@ -54,10 +61,10 @@ Build instructions:
|
|||||||
|
|
||||||
**Supported systems:**
|
**Supported systems:**
|
||||||
|
|
||||||
* GNU/Linux x86/x64 - [](https://travis-ci.org/PurpleI2P/i2pd)
|
* GNU/Linux - [](https://travis-ci.org/PurpleI2P/i2pd)
|
||||||
* Windows - [](https://ci.appveyor.com/project/PurpleI2P/i2pd)
|
* Windows - [](https://ci.appveyor.com/project/PurpleI2P/i2pd)
|
||||||
* Mac OS X - [](https://travis-ci.org/PurpleI2P/i2pd)
|
* Mac OS X - [](https://travis-ci.org/PurpleI2P/i2pd)
|
||||||
* CentOS / Fedora - [](https://copr.fedorainfracloud.org/coprs/supervillain/i2pd/package/i2pd-git/)
|
* CentOS / Fedora / Mageia - [](https://copr.fedorainfracloud.org/coprs/supervillain/i2pd/package/i2pd-git/)
|
||||||
* Docker image - [](https://hub.docker.com/r/meeh/i2pd/builds/)
|
* Docker image - [](https://hub.docker.com/r/meeh/i2pd/builds/)
|
||||||
* FreeBSD
|
* FreeBSD
|
||||||
* Android
|
* Android
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ namespace util
|
|||||||
if (isDaemon)
|
if (isDaemon)
|
||||||
{
|
{
|
||||||
LogPrint(eLogDebug, "Daemon: running as service");
|
LogPrint(eLogDebug, "Daemon: running as service");
|
||||||
I2PService service(SERVICE_NAME);
|
I2PService service((PSTR)SERVICE_NAME);
|
||||||
if (!I2PService::Run(service))
|
if (!I2PService::Run(service))
|
||||||
{
|
{
|
||||||
LogPrint(eLogError, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError());
|
LogPrint(eLogError, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError());
|
||||||
|
|||||||
@@ -24,17 +24,22 @@
|
|||||||
#define ID_GRACEFUL_SHUTDOWN 2004
|
#define ID_GRACEFUL_SHUTDOWN 2004
|
||||||
#define ID_STOP_GRACEFUL_SHUTDOWN 2005
|
#define ID_STOP_GRACEFUL_SHUTDOWN 2005
|
||||||
#define ID_RELOAD 2006
|
#define ID_RELOAD 2006
|
||||||
|
#define ID_ACCEPT_TRANSIT 2007
|
||||||
|
#define ID_DECLINE_TRANSIT 2008
|
||||||
|
|
||||||
#define ID_TRAY_ICON 2050
|
#define ID_TRAY_ICON 2050
|
||||||
#define WM_TRAYICON (WM_USER + 1)
|
#define WM_TRAYICON (WM_USER + 1)
|
||||||
|
|
||||||
#define IDT_GRACEFUL_SHUTDOWN_TIMER 2100
|
#define IDT_GRACEFUL_SHUTDOWN_TIMER 2100
|
||||||
#define FRAME_UPDATE_TIMER 2101
|
#define FRAME_UPDATE_TIMER 2101
|
||||||
|
#define IDT_GRACEFUL_TUNNELCHECK_TIMER 2102
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace win32
|
namespace win32
|
||||||
{
|
{
|
||||||
|
static DWORD GracefulShutdownEndtime = 0;
|
||||||
|
|
||||||
static void ShowPopupMenu (HWND hWnd, POINT *curpos, int wDefaultItem)
|
static void ShowPopupMenu (HWND hWnd, POINT *curpos, int wDefaultItem)
|
||||||
{
|
{
|
||||||
HMENU hPopup = CreatePopupMenu();
|
HMENU hPopup = CreatePopupMenu();
|
||||||
@@ -42,11 +47,17 @@ namespace win32
|
|||||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_APP, "Show app");
|
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_APP, "Show app");
|
||||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_ABOUT, "&About...");
|
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_ABOUT, "&About...");
|
||||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
|
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
|
||||||
|
if(!i2p::context.AcceptsTunnels())
|
||||||
|
InsertMenu (hPopup, -1,
|
||||||
|
i2p::util::DaemonWin32::Instance ().isGraceful ? MF_BYPOSITION | MF_STRING | MF_GRAYED : MF_BYPOSITION | MF_STRING,
|
||||||
|
ID_ACCEPT_TRANSIT, "Accept &transit");
|
||||||
|
else
|
||||||
|
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_DECLINE_TRANSIT, "Decline &transit");
|
||||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_RELOAD, "&Reload configs");
|
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_RELOAD, "&Reload configs");
|
||||||
if (!i2p::util::DaemonWin32::Instance ().isGraceful)
|
if (!i2p::util::DaemonWin32::Instance ().isGraceful)
|
||||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_GRACEFUL_SHUTDOWN, "&Graceful shutdown");
|
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_GRACEFUL_SHUTDOWN, "&Graceful shutdown");
|
||||||
else
|
else
|
||||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_STOP_GRACEFUL_SHUTDOWN, "&Stop graceful shutdown");
|
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_STOP_GRACEFUL_SHUTDOWN, "Stop &graceful shutdown");
|
||||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_EXIT, "E&xit");
|
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_EXIT, "E&xit");
|
||||||
SetMenuDefaultItem (hPopup, ID_CONSOLE, FALSE);
|
SetMenuDefaultItem (hPopup, ID_CONSOLE, FALSE);
|
||||||
SendMessage (hWnd, WM_INITMENUPOPUP, (WPARAM)hPopup, 0);
|
SendMessage (hWnd, WM_INITMENUPOPUP, (WPARAM)hPopup, 0);
|
||||||
@@ -148,6 +159,12 @@ namespace win32
|
|||||||
s << "; ";
|
s << "; ";
|
||||||
s << "Success Rate: " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate() << "%\n";
|
s << "Success Rate: " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate() << "%\n";
|
||||||
s << "Uptime: "; ShowUptime(s, i2p::context.GetUptime ());
|
s << "Uptime: "; ShowUptime(s, i2p::context.GetUptime ());
|
||||||
|
if (GracefulShutdownEndtime != 0)
|
||||||
|
{
|
||||||
|
DWORD GracefulTimeLeft = (GracefulShutdownEndtime - GetTickCount()) / 1000;
|
||||||
|
s << "Graceful shutdown, time left: "; ShowUptime(s, GracefulTimeLeft);
|
||||||
|
}
|
||||||
|
else
|
||||||
s << "\n";
|
s << "\n";
|
||||||
s << "Inbound: " << i2p::transport::transports.GetInBandwidth() / 1024 << " KiB/s; ";
|
s << "Inbound: " << i2p::transport::transports.GetInBandwidth() / 1024 << " KiB/s; ";
|
||||||
s << "Outbound: " << i2p::transport::transports.GetOutBandwidth() / 1024 << " KiB/s\n";
|
s << "Outbound: " << i2p::transport::transports.GetOutBandwidth() / 1024 << " KiB/s\n";
|
||||||
@@ -166,10 +183,13 @@ namespace win32
|
|||||||
|
|
||||||
static LRESULT CALLBACK WndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
static LRESULT CALLBACK WndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
|
static UINT s_uTaskbarRestart;
|
||||||
|
|
||||||
switch (uMsg)
|
switch (uMsg)
|
||||||
{
|
{
|
||||||
case WM_CREATE:
|
case WM_CREATE:
|
||||||
{
|
{
|
||||||
|
s_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
|
||||||
AddTrayIcon (hWnd);
|
AddTrayIcon (hWnd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -178,6 +198,7 @@ namespace win32
|
|||||||
RemoveTrayIcon (hWnd);
|
RemoveTrayIcon (hWnd);
|
||||||
KillTimer (hWnd, FRAME_UPDATE_TIMER);
|
KillTimer (hWnd, FRAME_UPDATE_TIMER);
|
||||||
KillTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER);
|
KillTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER);
|
||||||
|
KillTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER);
|
||||||
PostQuitMessage (0);
|
PostQuitMessage (0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -197,10 +218,28 @@ namespace win32
|
|||||||
PostMessage (hWnd, WM_CLOSE, 0, 0);
|
PostMessage (hWnd, WM_CLOSE, 0, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
case ID_ACCEPT_TRANSIT:
|
||||||
|
{
|
||||||
|
i2p::context.SetAcceptsTunnels (true);
|
||||||
|
std::stringstream text;
|
||||||
|
text << "I2Pd now accept transit tunnels";
|
||||||
|
MessageBox( hWnd, TEXT(text.str ().c_str ()), TEXT("i2pd"), MB_ICONINFORMATION | MB_OK );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case ID_DECLINE_TRANSIT:
|
||||||
|
{
|
||||||
|
i2p::context.SetAcceptsTunnels (false);
|
||||||
|
std::stringstream text;
|
||||||
|
text << "I2Pd now decline new transit tunnels";
|
||||||
|
MessageBox( hWnd, TEXT(text.str ().c_str ()), TEXT("i2pd"), MB_ICONINFORMATION | MB_OK );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
case ID_GRACEFUL_SHUTDOWN:
|
case ID_GRACEFUL_SHUTDOWN:
|
||||||
{
|
{
|
||||||
i2p::context.SetAcceptsTunnels (false);
|
i2p::context.SetAcceptsTunnels (false);
|
||||||
SetTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER, 10*60*1000, nullptr); // 10 minutes
|
SetTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER, 10*60*1000, nullptr); // 10 minutes
|
||||||
|
SetTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER, 1000, nullptr); // check tunnels every second
|
||||||
|
GracefulShutdownEndtime = GetTickCount() + 10*60*1000;
|
||||||
i2p::util::DaemonWin32::Instance ().isGraceful = true;
|
i2p::util::DaemonWin32::Instance ().isGraceful = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -208,6 +247,8 @@ namespace win32
|
|||||||
{
|
{
|
||||||
i2p::context.SetAcceptsTunnels (true);
|
i2p::context.SetAcceptsTunnels (true);
|
||||||
KillTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER);
|
KillTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER);
|
||||||
|
KillTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER);
|
||||||
|
GracefulShutdownEndtime = 0;
|
||||||
i2p::util::DaemonWin32::Instance ().isGraceful = false;
|
i2p::util::DaemonWin32::Instance ().isGraceful = false;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -290,14 +331,27 @@ namespace win32
|
|||||||
}
|
}
|
||||||
case WM_TIMER:
|
case WM_TIMER:
|
||||||
{
|
{
|
||||||
if (wParam == IDT_GRACEFUL_SHUTDOWN_TIMER)
|
switch(wParam)
|
||||||
{
|
{
|
||||||
|
case IDT_GRACEFUL_SHUTDOWN_TIMER:
|
||||||
|
{
|
||||||
|
GracefulShutdownEndtime = 0;
|
||||||
PostMessage (hWnd, WM_CLOSE, 0, 0); // exit
|
PostMessage (hWnd, WM_CLOSE, 0, 0); // exit
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (wParam == FRAME_UPDATE_TIMER)
|
case FRAME_UPDATE_TIMER:
|
||||||
{
|
{
|
||||||
InvalidateRect(hWnd, NULL, TRUE);
|
InvalidateRect(hWnd, NULL, TRUE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case IDT_GRACEFUL_TUNNELCHECK_TIMER:
|
||||||
|
{
|
||||||
|
if (i2p::tunnel::tunnels.CountTransitTunnels() == 0)
|
||||||
|
PostMessage (hWnd, WM_CLOSE, 0, 0);
|
||||||
|
else
|
||||||
|
SetTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER, 1000, nullptr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -318,6 +372,12 @@ namespace win32
|
|||||||
EndPaint(hWnd, &ps);
|
EndPaint(hWnd, &ps);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
if (uMsg == s_uTaskbarRestart)
|
||||||
|
AddTrayIcon (hWnd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return DefWindowProc( hWnd, uMsg, wParam, lParam);
|
return DefWindowProc( hWnd, uMsg, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -297,7 +297,8 @@ void InstallService(PCSTR pszServiceName, PCSTR pszDisplayName, DWORD dwStartTyp
|
|||||||
FreeHandles(schSCManager, schService);
|
FreeHandles(schSCManager, schService);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
strncat(szPath, " --daemon", MAX_PATH);
|
char SvcOpt[] = " --daemon";
|
||||||
|
strncat(szPath, SvcOpt, strlen(SvcOpt));
|
||||||
|
|
||||||
// Open the local default service control manager database
|
// 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);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#define I2Pd_AppName "i2pd"
|
#define I2Pd_AppName "i2pd"
|
||||||
#define I2Pd_ver "2.23.0"
|
#define I2Pd_ver "2.25.0"
|
||||||
#define I2Pd_Publisher "PurpleI2P"
|
#define I2Pd_Publisher "PurpleI2P"
|
||||||
|
|
||||||
[Setup]
|
[Setup]
|
||||||
|
|||||||
4
android/.gitignore
vendored
4
android/.gitignore
vendored
@@ -12,7 +12,5 @@ local.properties
|
|||||||
build.sh
|
build.sh
|
||||||
android.iml
|
android.iml
|
||||||
build
|
build
|
||||||
gradle
|
|
||||||
gradlew
|
|
||||||
gradlew.bat
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,11 @@
|
|||||||
android:installLocation="auto">
|
android:installLocation="auto">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" /> <!-- normal perm, per https://developer.android.com/guide/topics/permissions/normal-permissions.html -->
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- normal perm -->
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- required in API 26+ -->
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
@@ -48,5 +48,4 @@
|
|||||||
android:value="org.purplei2p.i2pd.I2PDPermsAskerActivity" />
|
android:value="org.purplei2p.i2pd.I2PDPermsAskerActivity" />
|
||||||
</activity>
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
@@ -1,55 +1,42 @@
|
|||||||
00.i2p,zmzpltxslembpaupg3srh4bbhv5txgh5jmms6sfj4hzsvlv3xugq
|
00.i2p,zmzpltxslembpaupg3srh4bbhv5txgh5jmms6sfj4hzsvlv3xugq
|
||||||
|
0ipfs.i2p,cdii3ou5mve5sfxyirs6kogt4tbvivk2d6o25awbcbazjrlhjeza
|
||||||
0xcc.i2p,gawouxh2sg32cluwlqsnpy3dwedvoqtfroi4evvdvm2pfv7tdadq
|
0xcc.i2p,gawouxh2sg32cluwlqsnpy3dwedvoqtfroi4evvdvm2pfv7tdadq
|
||||||
1.fcp.freenet.i2p,cuxbeputgxn75ak4nr7ltp7fjktnzl5sul3wstwnsoytbbpb4ixq
|
1.fcp.freenet.i2p,cuxbeputgxn75ak4nr7ltp7fjktnzl5sul3wstwnsoytbbpb4ixq
|
||||||
102chan.i2p,xxu3lso4h2rh6wmrxiou3ax7r7la7x6dhoepnku3jvrlwp35pefq
|
102chan.i2p,xxu3lso4h2rh6wmrxiou3ax7r7la7x6dhoepnku3jvrlwp35pefq
|
||||||
1st.i2p,rduua7bhest6rwsmmyttzssfdw3p4eu6bgl3mb4hin32qo3x5zfq
|
1st.i2p,rduua7bhest6rwsmmyttzssfdw3p4eu6bgl3mb4hin32qo3x5zfq
|
||||||
2.fcp.freenet.i2p,ndsznnipoeyapnsg3gj3yi2dzsqduxwalmujm5mzjm7e6x374tta
|
2.fcp.freenet.i2p,ndsznnipoeyapnsg3gj3yi2dzsqduxwalmujm5mzjm7e6x374tta
|
||||||
2rqv7nn2.i2p,2rqv7nn2j4q3wcxe5lsrqpf73k4rmtutweft3dvbc2w245vpkdva
|
|
||||||
31337.i2p,ydlngh3dd52av3aalpd3uqi5iuvmby7nxpkwclan4xqjsttz4fbq
|
|
||||||
333.i2p,ctvfe2fimcsdfxmzmd42brnbf7ceenwrbroyjx3wzah5eudjyyza
|
333.i2p,ctvfe2fimcsdfxmzmd42brnbf7ceenwrbroyjx3wzah5eudjyyza
|
||||||
55cancri.i2p,b4iqenefh2fr4xtuq6civfc6nhnia6e2yo36pf7vcgdvrwmh7xua
|
55cancri.i2p,b4iqenefh2fr4xtuq6civfc6nhnia6e2yo36pf7vcgdvrwmh7xua
|
||||||
9.i2p,4serdqvuthqxeaovnfc5ybdjin3l7noperdgplthjwqovzxifvya
|
|
||||||
a-zine-repo.i2p,zt6okylza25s2ppso7ngqbz2ybeteatxezxqemvucwhbb5ajot7a
|
|
||||||
adab.i2p,pxjr6f2cig6v7v7ekam3smdnkqgmgseyy5cdwrozdyejm7jknkha
|
adab.i2p,pxjr6f2cig6v7v7ekam3smdnkqgmgseyy5cdwrozdyejm7jknkha
|
||||||
agaming468.i2p,4svcmhjnijtnclv2vdgf3ipdvzizgeyllysjfl6vu3xkqwa3w6sq
|
|
||||||
aktie.i2p,4qwhpshwlp6ndzvtiwvf7myc3lll3vizqcdvvuxrzgaxv4g2qogq
|
|
||||||
alice.i2p,iq26r2ls2qlkhbn62cvgb6a4iib7m5lkoulohdua5z6uvzlovjtq
|
alice.i2p,iq26r2ls2qlkhbn62cvgb6a4iib7m5lkoulohdua5z6uvzlovjtq
|
||||||
always.i2p,wp43sdtuxum6gxbjvyeor35r5yvgtkp3dcu7dv47lx22zeb3relq
|
always.i2p,wp43sdtuxum6gxbjvyeor35r5yvgtkp3dcu7dv47lx22zeb3relq
|
||||||
amazone.i2p,e6kq73lsxaeyiwpmykdbdo3uy4ppj64bl7y3viegp6mqrilqybqa
|
amazone.i2p,e6kq73lsxaeyiwpmykdbdo3uy4ppj64bl7y3viegp6mqrilqybqa
|
||||||
amiga.i2p,edy2xappzjjh7bxqounevji4wd2binqkv7gft4usrkan45xhbk5q
|
amiga.i2p,edy2xappzjjh7bxqounevji4wd2binqkv7gft4usrkan45xhbk5q
|
||||||
amobius.i2p,rj6432agdprun5baai2hj62xfhb4l75uvzl55dhj6z5zzoxv3htq
|
amobius.i2p,rj6432agdprun5baai2hj62xfhb4l75uvzl55dhj6z5zzoxv3htq
|
||||||
anarchistfaq.i2p,xosberjz2geveh5dcstztq5kwew6xx2brrqaorkjf2323bjzcd3q
|
anarchistfaq.i2p,xosberjz2geveh5dcstztq5kwew6xx2brrqaorkjf2323bjzcd3q
|
||||||
andmp.i2p,rv6zugykqdhmwwsuglv7j6ktjojdbf5fqta66hixejg33qb2su3q
|
|
||||||
animal.i2p,5iedafy32swqq4t2wcmjb4fvg3onscng7ct7wb237jkvrclaftla
|
animal.i2p,5iedafy32swqq4t2wcmjb4fvg3onscng7ct7wb237jkvrclaftla
|
||||||
anodex.i2p,25cb5kixhxm6i6c6wequrhi65mez4duc4l5qk6ictbik3tnxlu6a
|
anodex.i2p,25cb5kixhxm6i6c6wequrhi65mez4duc4l5qk6ictbik3tnxlu6a
|
||||||
anoncoin.i2p,nmi3loretkk4zbili32t2e5wyznwoxcsgzmd2z4ll3msgndyqpfa
|
anoncoin.i2p,nmi3loretkk4zbili32t2e5wyznwoxcsgzmd2z4ll3msgndyqpfa
|
||||||
anongw.i2p,owrnciwubb3f3dctvlmnaknb6tjdxtlzvv7klocb45mmhievdjhq
|
anongw.i2p,owrnciwubb3f3dctvlmnaknb6tjdxtlzvv7klocb45mmhievdjhq
|
||||||
anonsfw.i2p,ir6hzi66izmvqx3usjl6br3nndkpazonlckrzt3gtltqcy5ralyq
|
anonsfw.i2p,ir6hzi66izmvqx3usjl6br3nndkpazonlckrzt3gtltqcy5ralyq
|
||||||
anonymnet.i2p,77ouyl2ane7ffgydosd4ye42g67aomtc4jrusmi76lds5qonlffa
|
anonymnet.i2p,77ouyl2ane7ffgydosd4ye42g67aomtc4jrusmi76lds5qonlffa
|
||||||
anonymousfreeworld.i2p,ayt3o2lovn5vd5pal7p43bcqkbjymtqhoilbmhj5dj4yoo5qklia
|
|
||||||
anonymousfreeworldirc.i2p,7sshnegbgqk5grdoqx3qjgbd7vpr5jti3keemz4xt5x6wo3cqkoq
|
|
||||||
anonynanny.i2p,l2lnhq2dynnmf3m46tcbpcmbbn4kifjgt26go6n2hlapy4drhyja
|
anonynanny.i2p,l2lnhq2dynnmf3m46tcbpcmbbn4kifjgt26go6n2hlapy4drhyja
|
||||||
anonyradio.i2p,cbobsax3rhoyjbk7ii2nd2fnl5bxh3x7bbearokyxgvmudn7o5bq
|
anonyradio.i2p,cbobsax3rhoyjbk7ii2nd2fnl5bxh3x7bbearokyxgvmudn7o5bq
|
||||||
ansoma.i2p,rapsznfm3sgsiubmfwp5xs3uvdrx2j3zjipfgfqjem33kvikb6ta
|
|
||||||
antipiracyagency.i2p,by4kcmklz7xnkai6ndfio47kts3rndm6wwleegtxghllimikdapq
|
antipiracyagency.i2p,by4kcmklz7xnkai6ndfio47kts3rndm6wwleegtxghllimikdapq
|
||||||
antipiratbyran.i2p,y2qbhrvuciifbszaqqwxd5t75bomp7kzdqx4yxsrkaq542t75k3a
|
antipiratbyran.i2p,y2qbhrvuciifbszaqqwxd5t75bomp7kzdqx4yxsrkaq542t75k3a
|
||||||
aosp.i2p,ly7raldsh2na2cgw5yvueyvqqjgx3vbqinecjrqdldgya76i2p2q
|
aosp.i2p,ly7raldsh2na2cgw5yvueyvqqjgx3vbqinecjrqdldgya76i2p2q
|
||||||
arc2.i2p,rnmosuwvtftfcrk5sk7zoyhyadh2g4dhe2mif5ml7qjisgkyw2na
|
arc2.i2p,rnmosuwvtftfcrk5sk7zoyhyadh2g4dhe2mif5ml7qjisgkyw2na
|
||||||
archaicbinarybbs.i2p,t7o2tw36cffedgfr6kahewpkrntofnliuapji2e4rucl3os55epa
|
archaicbinarybbs.i2p,t7o2tw36cffedgfr6kahewpkrntofnliuapji2e4rucl3os55epa
|
||||||
archer.i2p,6i4xsdvh3xxvi2gp32rdbkoyobpvywr2drq5dyq5v6uqlqvh2mtq
|
|
||||||
archiv.tutorials.i2p,lldr2miowq6353fxy44pnxfk37d6yn2f6kaivzecbmvvnnf5exyq
|
archiv.tutorials.i2p,lldr2miowq6353fxy44pnxfk37d6yn2f6kaivzecbmvvnnf5exyq
|
||||||
archive.i2p,x54d5st3dl6mwgfxj6raiekqkypo5pdvuex3n62szwju7hgefiyq
|
archive.i2p,x54d5st3dl6mwgfxj6raiekqkypo5pdvuex3n62szwju7hgefiyq
|
||||||
archive.syndie.i2p,abbyu5n3mh3nj7pe3b6byldrxswvva5ttxcafsnnseidanurq3kq
|
archive.syndie.i2p,abbyu5n3mh3nj7pe3b6byldrxswvva5ttxcafsnnseidanurq3kq
|
||||||
ardor-wallet.i2p,tm23k5ny3umhf6vf3kghnnwacli5zywq5wrr3xcqowbcofuyr4gq
|
ardor-wallet.i2p,tm23k5ny3umhf6vf3kghnnwacli5zywq5wrr3xcqowbcofuyr4gq
|
||||||
ardvark.i2p,jcmw2sol3hruwc6rfinonx4e23pjkukkg7lg7xt7xb2gpiyyraiq
|
ardvark.i2p,jcmw2sol3hruwc6rfinonx4e23pjkukkg7lg7xt7xb2gpiyyraiq
|
||||||
arecords.i2p,pkp26u32ea6xrd4o53lzwm6pxzphu5heyrvyra37drfvn6vli7yq
|
|
||||||
arf.i2p,o46lsq4u7udxg3qqlidrmpj4lb4nr7ldxmbb2x53nftndaeyxqeq
|
arf.i2p,o46lsq4u7udxg3qqlidrmpj4lb4nr7ldxmbb2x53nftndaeyxqeq
|
||||||
arkan.i2p,7o5y2lyyrjx5tf6l4fyumywui7msjv5azaaheatvw5sqj7mxbuvq
|
arkan.i2p,7o5y2lyyrjx5tf6l4fyumywui7msjv5azaaheatvw5sqj7mxbuvq
|
||||||
armada.i2p,26qxgmyqczulza5ym3jij5er3onclacejyqzecuhjllwun3kxuzq
|
|
||||||
asciiwhite.i2p,itbzny5ktuenhjwjfqx3jravolhlj5wullhhr2m4qr6k2emnm5dq
|
asciiwhite.i2p,itbzny5ktuenhjwjfqx3jravolhlj5wullhhr2m4qr6k2emnm5dq
|
||||||
aspnet.i2p,tsb7zqru57p4q2a7cto2lko4w5cg4lieglwm6t27c44fkphqmf2a
|
aspnet.i2p,tsb7zqru57p4q2a7cto2lko4w5cg4lieglwm6t27c44fkphqmf2a
|
||||||
asylum.i2p,p45ejjw4p2q6nq3mzi6cm6ep35grtzshboidj2lojmrmic22noha
|
asylum.i2p,p45ejjw4p2q6nq3mzi6cm6ep35grtzshboidj2lojmrmic22noha
|
||||||
atesi2p.i2p,hlahr4wgobvhegluufw3ckzulr4etamxxborktgz3dkefok232ga
|
|
||||||
auchan.i2p,6vxz4yp3vhjwbkmxajj7wiikxafwujig63gkhjknbq6xh4rqpm5a
|
auchan.i2p,6vxz4yp3vhjwbkmxajj7wiikxafwujig63gkhjknbq6xh4rqpm5a
|
||||||
aum.i2p,ohdfneqxapfd3fwfbum4tut7z6k3rnr7rrguoxdrrfe2tln2kpbq
|
aum.i2p,ohdfneqxapfd3fwfbum4tut7z6k3rnr7rrguoxdrrfe2tln2kpbq
|
||||||
awup.i2p,v6g32duzrkacnrezfbll3pza5u37h7lnukr2wbsk6rqen6prhbga
|
awup.i2p,v6g32duzrkacnrezfbll3pza5u37h7lnukr2wbsk6rqen6prhbga
|
||||||
@@ -58,11 +45,8 @@ bacardi.i2p,hivhnx2v47vh234c7coi2urj5cyvbl4bu3ypjr7snklortyqeljq
|
|||||||
backup.i2p,kepphem42whle3rkfv26wcksmnegdbg6rdp6t3oobdkc2fmzrdkq
|
backup.i2p,kepphem42whle3rkfv26wcksmnegdbg6rdp6t3oobdkc2fmzrdkq
|
||||||
badfish.i2p,f6v26gyr4eipy3a7pi2voulw5qvob6dg7zij6xpo2ywbi5tvbu6a
|
badfish.i2p,f6v26gyr4eipy3a7pi2voulw5qvob6dg7zij6xpo2ywbi5tvbu6a
|
||||||
badtoyz.i2p,3qz6ubtwlt2c4iasofjirkckq43u5fgkzyg7mlutcsym5gzhijna
|
badtoyz.i2p,3qz6ubtwlt2c4iasofjirkckq43u5fgkzyg7mlutcsym5gzhijna
|
||||||
balrogbroadcasting.i2p,pqgjjmr2jgvr4rtjyscgbh3hby2qpuoiibldddwxied2f7flvika
|
|
||||||
barry.i2p,4kyahq53ol52n23l44tefgeaxqpp3cbb632t5k3umdvqcooevdzq
|
barry.i2p,4kyahq53ol52n23l44tefgeaxqpp3cbb632t5k3umdvqcooevdzq
|
||||||
bash.i2p,s3wouoilbl3mrefxjhp4qoyujgok34e7y6vmpbu6hx4342ivqo4q
|
bash.i2p,s3wouoilbl3mrefxjhp4qoyujgok34e7y6vmpbu6hx4342ivqo4q
|
||||||
bbs.i2p,7ubwrcixdcemzqwqzh2vaakjsnochj2biuzpo6dc2n4f7wqj4pua
|
|
||||||
bbs.tokachi.i2p,m2cjkyckmcib2pu65zdply5faymuewrq4b4yy5lajxoqivny2iia
|
|
||||||
bdl.i2p,kp6fnuulenbjm7r26pfbmjcq3u7c7kvxeajodvgr5flcnskdgi5a
|
bdl.i2p,kp6fnuulenbjm7r26pfbmjcq3u7c7kvxeajodvgr5flcnskdgi5a
|
||||||
bdsm.i2p,pa7fxql5jljegg7j5tglhnnaod2sptq3gxvdn3ji6muqyhgn3poq
|
bdsm.i2p,pa7fxql5jljegg7j5tglhnnaod2sptq3gxvdn3ji6muqyhgn3poq
|
||||||
betaguru.i2p,d7cduwwhrcc2voameqfkvd66u3advu4jw2p6pysgax35vq6ovriq
|
betaguru.i2p,d7cduwwhrcc2voameqfkvd66u3advu4jw2p6pysgax35vq6ovriq
|
||||||
@@ -74,57 +58,43 @@ bitlox.i2p,lqw5khxcdntlv3u4vhn53upcqirplvnc4etjlmoytrzs66ytettq
|
|||||||
bittorrent.i2p,pgax2vz572i4zsp6u6paox5xubmjrkqohq6g4hvlp6ruzzy56l5q
|
bittorrent.i2p,pgax2vz572i4zsp6u6paox5xubmjrkqohq6g4hvlp6ruzzy56l5q
|
||||||
bk1k.i2p,nlyegmtyfffo5jfgg5h4dxxnlmqko2g36gpaye5a7vd3is35xxfq
|
bk1k.i2p,nlyegmtyfffo5jfgg5h4dxxnlmqko2g36gpaye5a7vd3is35xxfq
|
||||||
bl.i2p,e73d6uhnfbylza6wqkhxejmqeyfb7thkzw35gn5ojmna64jzyk2a
|
bl.i2p,e73d6uhnfbylza6wqkhxejmqeyfb7thkzw35gn5ojmna64jzyk2a
|
||||||
blach.i2p,khjfx7pdxt4oqxqcgk6zupqvmelpjkpiafzjefe75sl3qxu5hcua
|
|
||||||
black.i2p,sjwueu62qpe6dtv5b322k3f23fl4uz3w6qe6wcrwauiwpnymypfq
|
black.i2p,sjwueu62qpe6dtv5b322k3f23fl4uz3w6qe6wcrwauiwpnymypfq
|
||||||
|
blackbox.i2p,7josyf7zjieoib3ovmr5a4dh5w64kmfh45lv5h436eljtgfegtqa
|
||||||
blackexchange.i2p,ztgr5kghkyn43fhhkuycroxgfti6cojo3vg4wdd3usqonyvrla5q
|
blackexchange.i2p,ztgr5kghkyn43fhhkuycroxgfti6cojo3vg4wdd3usqonyvrla5q
|
||||||
blacklong.i2p,dx2jfxy7pwj6bbmcnshunjgfyranab4xy2dmaid65cpxwt6idiba
|
|
||||||
blog.curiosity.i2p,yiz6jec5k7ccxdgnh7msqa4ze52bqqmf6rpq6bqdyojra2erd4ta
|
blog.curiosity.i2p,yiz6jec5k7ccxdgnh7msqa4ze52bqqmf6rpq6bqdyojra2erd4ta
|
||||||
blog.polecat.i2p,orlccceubewvxo3fbdyydq6e4uuidbs4xd5u2gyqbculnowo3ehq
|
blog.polecat.i2p,orlccceubewvxo3fbdyydq6e4uuidbs4xd5u2gyqbculnowo3ehq
|
||||||
blog.tinlans.i2p,ylkch2nkrwehakx4z6wiyjbeqwlgasknukdkex6r6yq4xusrjnda
|
blog.tinlans.i2p,ylkch2nkrwehakx4z6wiyjbeqwlgasknukdkex6r6yq4xusrjnda
|
||||||
bluebeam.i2p,lvxp3cbcfwtol57d5pmrsck32t7ndutlxubjb4smaf32bynhlk6a
|
bluebeam.i2p,lvxp3cbcfwtol57d5pmrsck32t7ndutlxubjb4smaf32bynhlk6a
|
||||||
blueheron.i2p,anfb5jrhixjmvkyxctqwkezqer7dbob22wge2bh6wsewbhgnftfa
|
blueheron.i2p,anfb5jrhixjmvkyxctqwkezqer7dbob22wge2bh6wsewbhgnftfa
|
||||||
bmw.i2p,6naudpj2zozw6aiiqusv6znfzyprwitrufauz3zuejtdbotp6mxq
|
bnc.i2p,fr4zbcygmx2vdct6nrabakfys4b4derm6jqu2ovppkgqillvlqxa
|
||||||
bmworc.i2p,w254y65la47elcmf6mo7xc2caamm3ikeusmjjfknwsavwsy4whzq
|
|
||||||
bob.i2p,i76m7dwm5hnapljendbie6fc5y3mjlkdlduo3tvbwiwmvhxbpyaa
|
bob.i2p,i76m7dwm5hnapljendbie6fc5y3mjlkdlduo3tvbwiwmvhxbpyaa
|
||||||
bobcat.i2p,ftuukjtcquuvppt726w37boit7gp5hf2yxwfop35prx3grzzzxlq
|
bobcat.i2p,ftuukjtcquuvppt726w37boit7gp5hf2yxwfop35prx3grzzzxlq
|
||||||
bobthebuilder.i2p,qlahgthqhr4uojkkwahnper2cl3ro5f5gtzy5t4lzapbzo4osy6q
|
bobthebuilder.i2p,qlahgthqhr4uojkkwahnper2cl3ro5f5gtzy5t4lzapbzo4osy6q
|
||||||
boerse.i2p,7633w56hd53sesr6b532r5qlbdnvyl5bnvama6ign6xryaxol4rq
|
boerse.i2p,7633w56hd53sesr6b532r5qlbdnvyl5bnvama6ign6xryaxol4rq
|
||||||
bofh.i2p,auvuinzogu6gc4pwsgbjijuszxgcjygciu2wy53pfz7mo5nfpc5a
|
bofh.i2p,auvuinzogu6gc4pwsgbjijuszxgcjygciu2wy53pfz7mo5nfpc5a
|
||||||
|
boing.i2p,bgsq33bh74j66hn4oh7oovlvuhhdyw22lq2qi2fnv3jyh2ryap3a
|
||||||
books.manveru.i2p,eb2tisc2vr5jvjqrixrozcujiucwxg4m722stxwho5666ipl67zq
|
books.manveru.i2p,eb2tisc2vr5jvjqrixrozcujiucwxg4m722stxwho5666ipl67zq
|
||||||
bote.i2p,bhjhc3lsdqzoyhxwzyrd63kvyg4br6n2337d74blyintae66mr2a
|
bote.i2p,bhjhc3lsdqzoyhxwzyrd63kvyg4br6n2337d74blyintae66mr2a
|
||||||
bozo.i2p,7a2d23h6htprhzrol36vgwgklsbqrnuya4tbaaaspmaeaodt57iq
|
bozo.i2p,7a2d23h6htprhzrol36vgwgklsbqrnuya4tbaaaspmaeaodt57iq
|
||||||
brittanyworld.i2p,e76umhhic3474sdxiuax25ixyfg7y3z7oojj4fmxvhgv3ruet6aa
|
brittanyworld.i2p,e76umhhic3474sdxiuax25ixyfg7y3z7oojj4fmxvhgv3ruet6aa
|
||||||
bronzong.i2p,qqboneeyhdea3rm2mjkr6fb7mfuzhyrvovexyxi2dk4nudgye3wa
|
|
||||||
bs.i2p,bcr355ziz6uupqzsmfffa6zbk4bdte4yvkk3qy4xryy7hmw5axzq
|
|
||||||
bt.i2p,uhkuu54pg47zey76h45tnvsdtpkf5bthbtrjgnaloi5m54h4hlaq
|
bt.i2p,uhkuu54pg47zey76h45tnvsdtpkf5bthbtrjgnaloi5m54h4hlaq
|
||||||
bt.nnm-club.i2p,bmqz3v5ulhkvyqeahmp7co76ea4mwrxvb5nmtuclltpthm4mb47a
|
|
||||||
bugfuzz.i2p,ubszn4gsf22vga67rvzzlg4qj2bfcq6o52fmxz46xruawqm6z7rq
|
bugfuzz.i2p,ubszn4gsf22vga67rvzzlg4qj2bfcq6o52fmxz46xruawqm6z7rq
|
||||||
burevestnik.i2p,ki5o6ia453fqxdrzekdlmkg5yaevipezzst2du4sgm7xv2vmleuq
|
burntout.i2p,lkep3fd7tjvxrs25crr2c3jy7xm4s7bqiua5r327zgpw37sgyerq
|
||||||
busyrider.i2p,sv7ksbdjctuhuf3ddcuj72ypepcfpy6tqolkokz3gd2jgbm4bjxa
|
|
||||||
bytepay.i2p,7amc4ztwkzu3cgsaaaw3223ohuihn5hlsqc6gpf2rxdyptdkyugq
|
bytepay.i2p,7amc4ztwkzu3cgsaaaw3223ohuihn5hlsqc6gpf2rxdyptdkyugq
|
||||||
ca.i2pd.i2p,u5safmawcxj5vlrdtqrsqbsndkr5cfenpicgg5euu4xqm73yicba
|
ca.i2pd.i2p,u5safmawcxj5vlrdtqrsqbsndkr5cfenpicgg5euu4xqm73yicba
|
||||||
cases.i2p,kmpmk2fmineaiwublteqlifg4fkmewnhmxqlcgg7qwecz6daj43a
|
cases.i2p,kmpmk2fmineaiwublteqlifg4fkmewnhmxqlcgg7qwecz6daj43a
|
||||||
cash.i2p,6qscc7avdla6lzs6u2nzbppoxndhioh5krmoauolpwixfeuylo2q
|
|
||||||
cathugger.i2p,vq43xjjcnejqpzfprws5qzrea2siieshu4tglpdepql2w3w3bpba
|
cathugger.i2p,vq43xjjcnejqpzfprws5qzrea2siieshu4tglpdepql2w3w3bpba
|
||||||
cbs.i2p,u3lp7wazvq6opodzwjg5sc5w5kwxehmxd4wcdpt4s4j2k4dx4apq
|
cbs.i2p,u3lp7wazvq6opodzwjg5sc5w5kwxehmxd4wcdpt4s4j2k4dx4apq
|
||||||
cerapadus.i2p,zroed2cxga5zeuu6rcvmp2yfi77nzduw7yhdplbeuqkuyxwbrzaq
|
cerapadus.i2p,zroed2cxga5zeuu6rcvmp2yfi77nzduw7yhdplbeuqkuyxwbrzaq
|
||||||
cerebrum.i2p,u5gtsfn267udwfh2uq35jiabkufifvcbgv456zz34cydutsiw2eq
|
cerebrum.i2p,u5gtsfn267udwfh2uq35jiabkufifvcbgv456zz34cydutsiw2eq
|
||||||
cgan.i2p,43z65gdr52xe3fxmkumwp3dzhedu4tu4rdtzr24hz5b4awcpfbqa
|
cgan.i2p,43z65gdr52xe3fxmkumwp3dzhedu4tu4rdtzr24hz5b4awcpfbqa
|
||||||
chaoswebs.i2p,fz7l3tv3urnnhjvlrdylbd4uhxpglmm2i3xfvuqrhksjccdfzx6q
|
|
||||||
chat.i2p,ollpwnp6yidc3obbb3famgt6rw5jg5w3k3a6z7hhaegj6gcohiuq
|
chat.i2p,ollpwnp6yidc3obbb3famgt6rw5jg5w3k3a6z7hhaegj6gcohiuq
|
||||||
check.kovri.i2p,7uea4hzuqwbow5c6hm3ghkr7mvyb5vafoo473wrcaa4rmua2d7pq
|
|
||||||
chen.i2p,l7fr75pvy3o66isse7bb4bdsy6coq2eb4irjkrsdlugbjanxqzzq
|
|
||||||
chess.fillament.i2p,tv6wbanei647yf5bie4dhg2wmybkjurezlpdfwftc5ajqlfswwya
|
chess.fillament.i2p,tv6wbanei647yf5bie4dhg2wmybkjurezlpdfwftc5ajqlfswwya
|
||||||
chess.i2p,sbnoqznp5yzxals3vs6nzyqaj2fetvonys4e3b3x4ktmfeus54sa
|
chess.i2p,sbnoqznp5yzxals3vs6nzyqaj2fetvonys4e3b3x4ktmfeus54sa
|
||||||
china.i2p,wit6f2zx6dtuqqze6nhbykrds3idppfirxvhf2f7ydqoqf4xdzeq
|
china.i2p,wit6f2zx6dtuqqze6nhbykrds3idppfirxvhf2f7ydqoqf4xdzeq
|
||||||
chinese.i2p,vvbwsllobaiugvwksrqyhaigbdwkmtnqmdrelzcxjutnnlmcqoqq
|
|
||||||
chitanka.i2p,u4s3jneepk3akoez46kqiwikoezi6zyj2ibjkjyi4uuvsbcojzba
|
chitanka.i2p,u4s3jneepk3akoez46kqiwikoezi6zyj2ibjkjyi4uuvsbcojzba
|
||||||
christian.i2p,7atkjb6iiru3z4dtb6q3k2hmcyhe4tigbgy55pqi5wwg33h6jwma
|
|
||||||
ciaran.i2p,2r3645eete6xwbfu62ogonudcrcgqq25sbnij5v4geru74yrscna
|
ciaran.i2p,2r3645eete6xwbfu62ogonudcrcgqq25sbnij5v4geru74yrscna
|
||||||
cicada3301.i2p,o24fedov6xocshjcksd2nimzww2iyjk65zamm6c5dm4vx4nfovkq
|
|
||||||
ciphercraft.i2p,7s5pkqbpbfdkxtwuu2e2iwstbikyewvvscy76lij4x5pfbygbjca
|
ciphercraft.i2p,7s5pkqbpbfdkxtwuu2e2iwstbikyewvvscy76lij4x5pfbygbjca
|
||||||
city.i2p,q3x6msrirtu5gy5vilpki7afqlgrduvs3f6ywixu3qt5q6qc6sca
|
|
||||||
cloakbuffer.i2p,rxjexx7dole53hiuaoqqjyq2nljknmnjfws5hwyfoc7jmmhmwrpa
|
|
||||||
closedshop.i2p,6fg67mbw2okopzyonsck4bsy3cy7l2fame56uiysr2cezhjhzdbq
|
closedshop.i2p,6fg67mbw2okopzyonsck4bsy3cy7l2fame56uiysr2cezhjhzdbq
|
||||||
cneal.i2p,g4za73ffigv3ht4jnhzy4dae52djjq7lqcguqsfg3w5cxzqm7nba
|
cneal.i2p,g4za73ffigv3ht4jnhzy4dae52djjq7lqcguqsfg3w5cxzqm7nba
|
||||||
co.i2p,3mvo5eifcwplcsoubtvqkzdahwo2sdhfygfdde7lj2glybk4q22q
|
co.i2p,3mvo5eifcwplcsoubtvqkzdahwo2sdhfygfdde7lj2glybk4q22q
|
||||||
@@ -134,18 +104,17 @@ complication.i2p,x2av6rwj5e5tp64yhdmifdyleo4wblw4ncrrcrabxwscuevpdv7a
|
|||||||
comwiz.i2p,6p7zqfotzbd66etl5xqy3p6xvr5ijucru3am2xqa7wmnj6vf3djq
|
comwiz.i2p,6p7zqfotzbd66etl5xqy3p6xvr5ijucru3am2xqa7wmnj6vf3djq
|
||||||
confessions.i2p,lh5vitshufxpmyr44zgyymebo5elc42eda7pxvn5lmtes47c7rxa
|
confessions.i2p,lh5vitshufxpmyr44zgyymebo5elc42eda7pxvn5lmtes47c7rxa
|
||||||
connelly.i2p,5yrris3nigb3fapvzrlrcaew6cdmzdknzvgrc7y2jpn3ntqurweq
|
connelly.i2p,5yrris3nigb3fapvzrlrcaew6cdmzdknzvgrc7y2jpn3ntqurweq
|
||||||
conscious.i2p,vuudgshaznyenftsfgpyqcmsy7bs33uege3bymsxs5vgjagparua
|
|
||||||
costeira.i2p,abhty5xlmnyab2kqdxcd56352kcescxoux3p6dbqdrghggyygnxa
|
costeira.i2p,abhty5xlmnyab2kqdxcd56352kcescxoux3p6dbqdrghggyygnxa
|
||||||
cowsay.i2p,q4ghzfpah4ffvm3bhc6fdkrznk5f6jxfjm2daytlparznai5d54q
|
cowsay.i2p,q4ghzfpah4ffvm3bhc6fdkrznk5f6jxfjm2daytlparznai5d54q
|
||||||
crstrack.i2p,mm3zx3besctrx6peq5wzzueil237jdgscuvn5ugwilxrwzyuajja
|
crstrack.i2p,mm3zx3besctrx6peq5wzzueil237jdgscuvn5ugwilxrwzyuajja
|
||||||
crumax.i2p,xg6ffstp3lnknou2ayhvnoc6nwdhic7fstzphy6idnjnner2wxnq
|
|
||||||
crypthost.i2p,zywhrxtnkjc3rxxvxbocom7ml4hnutomgtuvqrwyf3rhuupnq5ca
|
crypthost.i2p,zywhrxtnkjc3rxxvxbocom7ml4hnutomgtuvqrwyf3rhuupnq5ca
|
||||||
|
crypto.i2p,vffax5jzewwv6pfim55hvhqyynafkygdalvzoqd74lkib3hla3ta
|
||||||
|
cryptostorm.i2p,mlu7mswyirjf53usqq7gyamvqc6rqihezgdbevov3dkxmkfo57aq
|
||||||
curiosity.i2p,eomeif4xrykxlzhawc3icdilje5iammijos6tyizwhrfh3j7qdvq
|
curiosity.i2p,eomeif4xrykxlzhawc3icdilje5iammijos6tyizwhrfh3j7qdvq
|
||||||
cvs.i2p,yd6k7dzpsa2tnlzx4q7xqkmd4qsjk5xk5hbiqpiarwbeyvxaxgba
|
cvs.i2p,yd6k7dzpsa2tnlzx4q7xqkmd4qsjk5xk5hbiqpiarwbeyvxaxgba
|
||||||
daniella.i2p,543gbm3qfbb4nhwnl25dhunasx6q2fxy4h573lj45m2na5lbvucq
|
|
||||||
danwin1210.i2p,eoqdf4no5dxn4tw5n256kkd4lzz3uk4p47np4mepsykpsdzrnvba
|
danwin1210.i2p,eoqdf4no5dxn4tw5n256kkd4lzz3uk4p47np4mepsykpsdzrnvba
|
||||||
darklord1802.i2p,jnu3endfmzzf5t3gb6vdj745cl7yp3rmyqckqus77cki6a3lgoya
|
|
||||||
darknetnow.i2p,gkx3o5fy7mv7l4psqqnhp35d5iun7rt3soci6ylf3rgb7a5a655q
|
darknetnow.i2p,gkx3o5fy7mv7l4psqqnhp35d5iun7rt3soci6ylf3rgb7a5a655q
|
||||||
|
darknut.i2p,2mk37gtvpk2i63o6vl7vna4dr46rqexxetupgn5efuuins7x3qya
|
||||||
darkrealm.i2p,gbh4eerxdsph7etxsxznfhvmuiz54trlkenakqep343u4xcoekzq
|
darkrealm.i2p,gbh4eerxdsph7etxsxznfhvmuiz54trlkenakqep343u4xcoekzq
|
||||||
darrob.i2p,hz2xhtpeo6btgiwi6od4qj2575ml5o2246rd5orarruyjhd63zja
|
darrob.i2p,hz2xhtpeo6btgiwi6od4qj2575ml5o2246rd5orarruyjhd63zja
|
||||||
dashninja.i2p,dzjzoefy7fx57h5xkdknikvfv3ckbxu2bx5wryn6taud343g2jma
|
dashninja.i2p,dzjzoefy7fx57h5xkdknikvfv3ckbxu2bx5wryn6taud343g2jma
|
||||||
@@ -155,7 +124,7 @@ de-ebook-archiv.i2p,6mhurvyn6b6j6xa4a3wpuz7ovpsejbuncvyl6rnhepasfgdgmn7q
|
|||||||
de-ebooks.i2p,epqdyuuhtydkg5muwwq47n7jvr66pq4jheve7ky5euls6klzwuyq
|
de-ebooks.i2p,epqdyuuhtydkg5muwwq47n7jvr66pq4jheve7ky5euls6klzwuyq
|
||||||
dead.i2p,7ko27dxvicr2sezvykkrfiktlghx5y5onup3f2bas5ipocy6ibvq
|
dead.i2p,7ko27dxvicr2sezvykkrfiktlghx5y5onup3f2bas5ipocy6ibvq
|
||||||
deadgod.i2p,63bveyh7wefb44hlia7wtxxb3jal3r67thd6jekmwrtq4ulaaksa
|
deadgod.i2p,63bveyh7wefb44hlia7wtxxb3jal3r67thd6jekmwrtq4ulaaksa
|
||||||
deb-mirror.i2p,l6ly7szjqvbffz7hacvjxqsbvpxoguh34ypkddtgse6bq3fljayq
|
debian-multimedia.i2p,cylxxz2y35x6cvyrl57wu3brckurtexatyi2i5awz3eeamqwjspq
|
||||||
decadence.i2p,pw5ys7k2grjb5myydpv6ohikm6nna7y6u2dro44i4rucgulu3ikq
|
decadence.i2p,pw5ys7k2grjb5myydpv6ohikm6nna7y6u2dro44i4rucgulu3ikq
|
||||||
deepwebradio.i2p,2nait2gdeozkgf6gyhzjfij6mwldwkxxwcvtxobb4b5q5cvtm5la
|
deepwebradio.i2p,2nait2gdeozkgf6gyhzjfij6mwldwkxxwcvtxobb4b5q5cvtm5la
|
||||||
def2.i2p,cepsrw27kdegwo7ihzouwvgcvw2obswwjs23ollgj7hk2yrce3da
|
def2.i2p,cepsrw27kdegwo7ihzouwvgcvw2obswwjs23ollgj7hk2yrce3da
|
||||||
@@ -169,35 +138,32 @@ di.i2p,3irnooyt5spqiem66upksabez4f3yyrvvjwkmwyzlbealg64mgxa
|
|||||||
diasporg.i2p,edvccoobtjukjgw2os5eetywanbb2mpag5aknkrpia5qx2koksua
|
diasporg.i2p,edvccoobtjukjgw2os5eetywanbb2mpag5aknkrpia5qx2koksua
|
||||||
diftracker.i2p,m4mer767ipj7mq6l7gdrmrq37yzvsj3kzezd7n7nsfuctntjseka
|
diftracker.i2p,m4mer767ipj7mq6l7gdrmrq37yzvsj3kzezd7n7nsfuctntjseka
|
||||||
dm.i2p,heysbdivyeugdbggpscco5wje3dsvwgcpp5ot4sopooebnmiqvtq
|
dm.i2p,heysbdivyeugdbggpscco5wje3dsvwgcpp5ot4sopooebnmiqvtq
|
||||||
|
docs.i2p,ato242wckzs4eaawlr5matzxudt6t5enw73e4p6r3wajwkxsm3za
|
||||||
docs.i2p2.i2p,las5l45ulwwf5i72nht6vk33sfkidcpr2okpf5b6mvgbk3a2ujna
|
docs.i2p2.i2p,las5l45ulwwf5i72nht6vk33sfkidcpr2okpf5b6mvgbk3a2ujna
|
||||||
domenica.i2p,hbnbggujfnwnjjy2zg2e54gypwy432t25tb4nn2ydk3xbuslgiba
|
|
||||||
doom.i2p,yvnq6yyiluav647i7qc3hpjkprrbx7x4hb7e6djgwflu46vwqodq
|
|
||||||
downloads.legion.i2p,xpmxdpuuptlekyhs7mmdwkvry7h2jbvpqpzsijqe3a5ctxgodesq
|
downloads.legion.i2p,xpmxdpuuptlekyhs7mmdwkvry7h2jbvpqpzsijqe3a5ctxgodesq
|
||||||
dox.i2p,vk27cjdrtegfdnrjqutebgxkpyrfj42trdfbsupl5zn2kp34wb3a
|
dox.i2p,vk27cjdrtegfdnrjqutebgxkpyrfj42trdfbsupl5zn2kp34wb3a
|
||||||
dozzzer.i2p,u4tkzwghkjkdujctdcuk5p4qiwqqarvs3bhexmuhgwn5e2zg6ljq
|
dropbox.i2p,omax2s5n4mzvymidpuxp2yqknf23asvu54uon6cxl6gdrlblnuiq
|
||||||
duck.i2p,3u2mqm3mvcyc27yliky3xnr4khpgfd4eeadhwwjneaqhj25a65ua
|
duck.i2p,3u2mqm3mvcyc27yliky3xnr4khpgfd4eeadhwwjneaqhj25a65ua
|
||||||
dumpteam.i2p,2fwlpuouwxlk2nj4xklvm43m52tqyhqnu2fcfiuv7clvf3wd5nwa
|
dumpteam.i2p,2fwlpuouwxlk2nj4xklvm43m52tqyhqnu2fcfiuv7clvf3wd5nwa
|
||||||
dust.i2p,u6xgh6zhhhvdvefbqksfljfs3nyjvqcrmyamp5bryz5f4injmniq
|
dust.i2p,u6xgh6zhhhvdvefbqksfljfs3nyjvqcrmyamp5bryz5f4injmniq
|
||||||
dvdr-core.i2p,fg6l2ej6qrk5rkyfzdptxx5xkcm4kvdla4gg2tun7z7fm5cxxw5q
|
dvdr-core.i2p,fg6l2ej6qrk5rkyfzdptxx5xkcm4kvdla4gg2tun7z7fm5cxxw5q
|
||||||
dyad.i2p,7n2ljphvp2dep7imoujvydxp4myuxfld3axwfgcny5xc5x6jj6ka
|
dyad.i2p,7n2ljphvp2dep7imoujvydxp4myuxfld3axwfgcny5xc5x6jj6ka
|
||||||
e-reading.i2p,z54dnry6rxtmzcg7e6y3qtsig5yf5fmehuvakcg5wnuahx3iafuq
|
e-reading.i2p,z54dnry6rxtmzcg7e6y3qtsig5yf5fmehuvakcg5wnuahx3iafuq
|
||||||
easy.i2p,ndg6v7fw26bzjex3huvcxfyavpfbig2bdmfus5t2qnk2qte3wz7q
|
|
||||||
easygpg2.i2p,bwxry5alzx5ihgrd3glah4eotddblzhalvpheppnw4zcajzqoora
|
easygpg2.i2p,bwxry5alzx5ihgrd3glah4eotddblzhalvpheppnw4zcajzqoora
|
||||||
easysoft.i2p,ecbhsjzyt3pjp6zv6btqin5cbhlwqsgritljgyx5tc4aoarojeva
|
eboochka.i2p,ou7g64d5in4sugv5fgmmzwnunuw5hloixio7puthmrvrkwrp6egq
|
||||||
ebooks.i2p,bvpy6xf6ivyws6mshhqmdmr36pruh2hvoceznzeag52mpu647nzq
|
ebooks.i2p,bvpy6xf6ivyws6mshhqmdmr36pruh2hvoceznzeag52mpu647nzq
|
||||||
echelon.i2p,afvtspvugtd32rsalxircjglh3fhcjzk7gxrm3gw4s2yrpvzk6wq
|
echelon.i2p,afvtspvugtd32rsalxircjglh3fhcjzk7gxrm3gw4s2yrpvzk6wq
|
||||||
echo.baffled.i2p,bfr3lyicr72psxvt2umqfb562rtex66w6q3hi3tktzkoyane2iha
|
echo.baffled.i2p,bfr3lyicr72psxvt2umqfb562rtex66w6q3hi3tktzkoyane2iha
|
||||||
eco.i2p,2dq2o5h6c6a674qaduipp55mid5iktumjbswuwmpsrcqaeowdvwa
|
eco.i2p,2dq2o5h6c6a674qaduipp55mid5iktumjbswuwmpsrcqaeowdvwa
|
||||||
|
eddysblog.i2p,ieac3ub4g5sy3wuhsbqfembnpp7f3a37xgcx537ytzsmgfzexnbq
|
||||||
edge.i2p,aknsl5wmzjmwyc4wxutfdwy2w5vgd3vcx52mqx647hcgvyurmqta
|
edge.i2p,aknsl5wmzjmwyc4wxutfdwy2w5vgd3vcx52mqx647hcgvyurmqta
|
||||||
eepdot.i2p,t6edyotbxmxvy56fofdvmragvsj65te2gkhvzv5qnblicutyvgoa
|
eepdot.i2p,t6edyotbxmxvy56fofdvmragvsj65te2gkhvzv5qnblicutyvgoa
|
||||||
eepshare-project.i2p,sn26kom4qyuzouppv4lwnk6bqabdydcegtrilybviibwiq2s4nfq
|
eepshare-project.i2p,sn26kom4qyuzouppv4lwnk6bqabdydcegtrilybviibwiq2s4nfq
|
||||||
eepsites.i2p,isskhl4ak3g7qevrarlmblddgr4ugnn3ckalwpjcvxafk5rjgypq
|
eepsites.i2p,isskhl4ak3g7qevrarlmblddgr4ugnn3ckalwpjcvxafk5rjgypq
|
||||||
electrico.i2p,65yj7dwjbne26e7pfvf4grwn3ohttvxtsbt5l5kyr3v67rjucyya
|
|
||||||
elf.i2p,duz6ey27ohpcp3llylklzdb63lylolzcixad6bh7rt5tkq42qqpa
|
elf.i2p,duz6ey27ohpcp3llylklzdb63lylolzcixad6bh7rt5tkq42qqpa
|
||||||
elgoog.i2p,z6hrgkg2ajmuzlrddjlffrgctx7x7fkipm6c4hdzmohyn5wkr4ya
|
elgoog.i2p,z6hrgkg2ajmuzlrddjlffrgctx7x7fkipm6c4hdzmohyn5wkr4ya
|
||||||
ems.i2p,734zw4jsegdf55zl3z6s22tqkbxcghu4qvk6q2wevjfmx7xhbn6q
|
ems.i2p,734zw4jsegdf55zl3z6s22tqkbxcghu4qvk6q2wevjfmx7xhbn6q
|
||||||
epub-eepsite.i2p,yxvzjwd4vin6pnjauekdufh7lxaijal3kqe2bhakuf47g5zkb6xa
|
epub-eepsite.i2p,yxvzjwd4vin6pnjauekdufh7lxaijal3kqe2bhakuf47g5zkb6xa
|
||||||
erik-the-history.i2p,ab2lon2qoyiavdfofmukhsrspmiihnylucujmwouz632f7a5pqpa
|
|
||||||
es.hiddenanswers.i2p,cw7ge5ey4ekp5iep2kaw6j54boebtqytpcbnvio2bfpccd5ejzfa
|
es.hiddenanswers.i2p,cw7ge5ey4ekp5iep2kaw6j54boebtqytpcbnvio2bfpccd5ejzfa
|
||||||
eschaton.i2p,xe75f5hzmrq6rkhsef2geslmi2v2yfngdiysmlmxvh7b4pyyjk4q
|
eschaton.i2p,xe75f5hzmrq6rkhsef2geslmi2v2yfngdiysmlmxvh7b4pyyjk4q
|
||||||
esuwiki.i2p,cwxuiwcpymb72vm5vluba66ofhugyf5qeevvwo7e2fqrxl243coa
|
esuwiki.i2p,cwxuiwcpymb72vm5vluba66ofhugyf5qeevvwo7e2fqrxl243coa
|
||||||
@@ -211,7 +177,6 @@ exitpoint.i2p,5zmjurq3enudcenegnxu5hqmfmayz4lxvnik6ulch4xssa2ithta
|
|||||||
exotrack.i2p,blbgywsjubw3d2zih2giokakhe3o2cko7jtte4risb3hohbcoyva
|
exotrack.i2p,blbgywsjubw3d2zih2giokakhe3o2cko7jtte4risb3hohbcoyva
|
||||||
explorer.gostcoin.i2p,ktoacmumifddtqdw6ewns3szxths2hq2fat2o7xnwq4y3auga3za
|
explorer.gostcoin.i2p,ktoacmumifddtqdw6ewns3szxths2hq2fat2o7xnwq4y3auga3za
|
||||||
fa.i2p,6n6p3aj6xqhevfojj36dixwbl4reopkhymxmatz7ai5sroh75rka
|
fa.i2p,6n6p3aj6xqhevfojj36dixwbl4reopkhymxmatz7ai5sroh75rka
|
||||||
faksoc.i2p,l3lu7irgr2s24ot7eeqgutldoil33mv44qi5qdxwhwh6w5lyxcoa
|
|
||||||
falafel.i2p,djpn5cbcgmpumwcriuzqistbae66txca2j4apjd2xesfgb7r5zmq
|
falafel.i2p,djpn5cbcgmpumwcriuzqistbae66txca2j4apjd2xesfgb7r5zmq
|
||||||
false.i2p,77mpz4z6s4eenjexleclqb36uxvqjtztqikjfqa4sovojh6gwwha
|
false.i2p,77mpz4z6s4eenjexleclqb36uxvqjtztqikjfqa4sovojh6gwwha
|
||||||
false2.i2p,j5i2tfumh3ti5sdtafwzzbpupmlcbg5drysfay2kxbdpsaljrosa
|
false2.i2p,j5i2tfumh3ti5sdtafwzzbpupmlcbg5drysfay2kxbdpsaljrosa
|
||||||
@@ -228,7 +193,6 @@ files.i2p,w2sy74xe6oqnuz6sfh5fhkzu7boholgzd5f3anhj47srxwpj2vaa
|
|||||||
files.nickster.i2p,yil7dp2hg5pbqyovsiwb2ig6zjsq4tize3fnwemmqdrr6j5itdtq
|
files.nickster.i2p,yil7dp2hg5pbqyovsiwb2ig6zjsq4tize3fnwemmqdrr6j5itdtq
|
||||||
fillament.i2p,udj2kiino4cylstsj4edpz2jsls77e32jvffn2a4knjn4222s2oq
|
fillament.i2p,udj2kiino4cylstsj4edpz2jsls77e32jvffn2a4knjn4222s2oq
|
||||||
firerabbit.i2p,awqh7n3wskzl3epyvkdwgarmfybsncm7vye6psg4tpkmplh3mj2q
|
firerabbit.i2p,awqh7n3wskzl3epyvkdwgarmfybsncm7vye6psg4tpkmplh3mj2q
|
||||||
first-world.i2p,w35uyqjcbdrohmtwgk7pf36djxelyiq5gs76hzyrwovpnmkv2gcq
|
|
||||||
flibs.i2p,ocdm33e3h5tdml3yyholj4objdwsrhlugfqjnqgdkslmgdzb6b3a
|
flibs.i2p,ocdm33e3h5tdml3yyholj4objdwsrhlugfqjnqgdkslmgdzb6b3a
|
||||||
flibusta.i2p,zmw2cyw2vj7f6obx3msmdvdepdhnw2ctc4okza2zjxlukkdfckhq
|
flibusta.i2p,zmw2cyw2vj7f6obx3msmdvdepdhnw2ctc4okza2zjxlukkdfckhq
|
||||||
flipkick.i2p,aso5rzc4ym6g2bcbxjy2n573bmbenkjawva2jg7fhyqhwtwgu6lq
|
flipkick.i2p,aso5rzc4ym6g2bcbxjy2n573bmbenkjawva2jg7fhyqhwtwgu6lq
|
||||||
@@ -238,7 +202,6 @@ forum.fr.i2p,onvelkowkbuwrglhw2cnocggvbdudi75sll5mfirde3cbopjqivq
|
|||||||
forum.i2p,33pebl3dijgihcdxxuxm27m3m4rgldi5didiqmjqjtg4q6fla6ya
|
forum.i2p,33pebl3dijgihcdxxuxm27m3m4rgldi5didiqmjqjtg4q6fla6ya
|
||||||
forum.rus.i2p,zd37rfivydhkiyvau27qxwzmerlzbqtthsa5ohtcww62zrygjaga
|
forum.rus.i2p,zd37rfivydhkiyvau27qxwzmerlzbqtthsa5ohtcww62zrygjaga
|
||||||
forums.i2p,tmlxlzag7lmkgwf6g2msygby3qttxvm6ixlfkq6s6cpgwubp33ya
|
forums.i2p,tmlxlzag7lmkgwf6g2msygby3qttxvm6ixlfkq6s6cpgwubp33ya
|
||||||
foxatomic.i2p,obdyolrmtaxt4i2aeouun5shl7wqtxgbnkesty3sr5ofmhae32qq
|
|
||||||
fproxy.i2p,keknios3gm6kh6onez6x2bm2t7stv54oanvltuagphgdfjdw5e2a
|
fproxy.i2p,keknios3gm6kh6onez6x2bm2t7stv54oanvltuagphgdfjdw5e2a
|
||||||
fproxy.tino.i2p,fpaituvuvyxp6xdjnv3i27alnj2ifzcvqdweqb6yj5uybotzvyha
|
fproxy.tino.i2p,fpaituvuvyxp6xdjnv3i27alnj2ifzcvqdweqb6yj5uybotzvyha
|
||||||
fproxy2.i2p,r4lgw4wmza25g7j5fjocjbwzwthfg4ymcbm52ref3hh2hogskcza
|
fproxy2.i2p,r4lgw4wmza25g7j5fjocjbwzwthfg4ymcbm52ref3hh2hogskcza
|
||||||
@@ -247,22 +210,17 @@ freeciv.nightblade.i2p,rluupsgxbvw5t7jno3apyzlrdirjkljft4gdoy4mxxh4fmd4xzta
|
|||||||
freedomarchives.i2p,4ck6oliqfjz3sccpya2q4rh5xkj5xdxkqs76ieml37537nfhwd2q
|
freedomarchives.i2p,4ck6oliqfjz3sccpya2q4rh5xkj5xdxkqs76ieml37537nfhwd2q
|
||||||
freedomforum.i2p,abzmusjcm3p3llj4z7b5kkkexpsxcnsylikokouk5txfim3evqua
|
freedomforum.i2p,abzmusjcm3p3llj4z7b5kkkexpsxcnsylikokouk5txfim3evqua
|
||||||
freefallheavens.i2p,giqnkltyugfmsb4ot5ywpvf3ievuswfurk6bjie4hxi2hh2axajq
|
freefallheavens.i2p,giqnkltyugfmsb4ot5ywpvf3ievuswfurk6bjie4hxi2hh2axajq
|
||||||
freemind.i2p,6kjq2ohdni4fgqcypcfgi42lz573juf3inzeievm3euxklq4qeuq
|
|
||||||
freenet.eco.i2p,2kf7ovb35ztqkrurkm76y34jfpwi6go25xj7peznnmxrl7aieo7a
|
freenet.eco.i2p,2kf7ovb35ztqkrurkm76y34jfpwi6go25xj7peznnmxrl7aieo7a
|
||||||
freshcoffee.i2p,sscuukigp6alcb3ylhkcugoejjfw5jqgtqbsbafw4hyku42lgc3q
|
freshcoffee.i2p,sscuukigp6alcb3ylhkcugoejjfw5jqgtqbsbafw4hyku42lgc3q
|
||||||
fri3nds.i2p,y2s7xlezekt5ie5ij3mxhywol3rpo6hsu7velnh35vbdl25tj2ra
|
|
||||||
frooze.i2p,m6ofa5dmyse4b4jg7kfmluuuc4pw5jqu6zh4qnboin4vropxepja
|
frooze.i2p,m6ofa5dmyse4b4jg7kfmluuuc4pw5jqu6zh4qnboin4vropxepja
|
||||||
frosk.i2p,63naq7zb3hvbcppj2ng7qwf6ztusp4kwpyrzbt4ptafcdbu4pfjq
|
frosk.i2p,63naq7zb3hvbcppj2ng7qwf6ztusp4kwpyrzbt4ptafcdbu4pfjq
|
||||||
frostmirror.i2p,ycz3imuz6yte2zhlapmsm3bsvc46senvc2jxzwsbfdct5c72qulq
|
frostmirror.i2p,ycz3imuz6yte2zhlapmsm3bsvc46senvc2jxzwsbfdct5c72qulq
|
||||||
fs.i2p,ah4r4vzunzfa67atljlbrdgtg3zak5esh7ablpm6xno6fhqij35q
|
fs.i2p,ah4r4vzunzfa67atljlbrdgtg3zak5esh7ablpm6xno6fhqij35q
|
||||||
fsoc.i2p,vaqc4jm2trq7lx2kkglve7rkzxhhaptcwwl32uicx4ehf5k3hx6q
|
fsoc.i2p,vaqc4jm2trq7lx2kkglve7rkzxhhaptcwwl32uicx4ehf5k3hx6q
|
||||||
furry.i2p,nsp4dwzfkdldtly3z6fewmicrurncrie277catksd7mpt6xjmbna
|
|
||||||
galen.i2p,4weo7zkxscxbcouiqx4mlnb35uwl2lromikzk33er3fljktyvi2q
|
galen.i2p,4weo7zkxscxbcouiqx4mlnb35uwl2lromikzk33er3fljktyvi2q
|
||||||
games.nine.i2p,ov27guhkdyhgdkqcsi7ipxsbudytn7bj3qp6ovwk6ih2wwu6sl3q
|
|
||||||
gaming.i2p,rfxberwod6st2zc6gblqswxjl57nucgc3xrbwss43pe3dvqqzj4q
|
gaming.i2p,rfxberwod6st2zc6gblqswxjl57nucgc3xrbwss43pe3dvqqzj4q
|
||||||
garden.i2p,qkk2dqx6nocycgt3vinsoc76cxkb4jreybcpgz3fcps2dbe4rowq
|
garden.i2p,qkk2dqx6nocycgt3vinsoc76cxkb4jreybcpgz3fcps2dbe4rowq
|
||||||
gaytorrents.i2p,fnggbr2t2aulr6rvlo4aehotx6wecfob7u3k2nxsnvtm4xex424q
|
gaytorrents.i2p,fnggbr2t2aulr6rvlo4aehotx6wecfob7u3k2nxsnvtm4xex424q
|
||||||
geekcraft.i2p,g2xbibxoskudufabbgwe3hdpy54vb4l5jq2tr4om5rmmzyutmsua
|
|
||||||
general.i2p,5fklrsztdqpl3hkkwwrrw2rdowrq7wwhwb6h7avvk4fhansp4vvq
|
general.i2p,5fklrsztdqpl3hkkwwrrw2rdowrq7wwhwb6h7avvk4fhansp4vvq
|
||||||
gernika.i2p,wpzqv3lxpecdsvcaadvbmrhhwlc7kp4n2mijdv2qjw3zr3ye232a
|
gernika.i2p,wpzqv3lxpecdsvcaadvbmrhhwlc7kp4n2mijdv2qjw3zr3ye232a
|
||||||
ginnegappen.i2p,kbhfkzx5jeqhfgss4xixnf4cb3jpuo432l3hxc32feelcmnr3yja
|
ginnegappen.i2p,kbhfkzx5jeqhfgss4xixnf4cb3jpuo432l3hxc32feelcmnr3yja
|
||||||
@@ -276,44 +234,33 @@ gloinsblog.i2p,zqazjq6ttjtbf2psrtmmjthjeuxaubi742ujrk2eptcsaoam4k7a
|
|||||||
go.i2p,ll6q4lsirhwkln4dqxwqkh2xu4mu3jiy546b4uhe4fypyb4vvx2q
|
go.i2p,ll6q4lsirhwkln4dqxwqkh2xu4mu3jiy546b4uhe4fypyb4vvx2q
|
||||||
gonzo2000.i2p,nogsv7okydhbvrewv6hb4xdojncvhkusnyib4lglluc4uw67a37a
|
gonzo2000.i2p,nogsv7okydhbvrewv6hb4xdojncvhkusnyib4lglluc4uw67a37a
|
||||||
google.i2p,4p3ajq4cotnflmuv7fhef3ptop5qpm3uzzgp5bahxif3nc4w3ffq
|
google.i2p,4p3ajq4cotnflmuv7fhef3ptop5qpm3uzzgp5bahxif3nc4w3ffq
|
||||||
gopstop.i2p,s6g76ctfgxallpngw25sq47dd6w5sul3fiywdxd24zbhr66jk26q
|
|
||||||
gostcoin.i2p,4gzcllfxktrqzv3uys5k4vgkzbth4gqednwhfpt755yivm3davuq
|
gostcoin.i2p,4gzcllfxktrqzv3uys5k4vgkzbth4gqednwhfpt755yivm3davuq
|
||||||
gott.i2p,dqows7dpftxxl2bd4bgcpkck6knrysdun6mtqy4ms5dxobbvg3ja
|
gott.i2p,dqows7dpftxxl2bd4bgcpkck6knrysdun6mtqy4ms5dxobbvg3ja
|
||||||
greenflog.i2p,zny5ftmhzxulxzyczmeat53qjnue2xtqv2clisc7dg76lwfceecq
|
greenflog.i2p,zny5ftmhzxulxzyczmeat53qjnue2xtqv2clisc7dg76lwfceecq
|
||||||
gstbtc.i2p,n33uthzyqsbozl2qh5zii2bq2nnvbz6g6c4ew3mwp6uukk6u7wva
|
gstbtc.i2p,n33uthzyqsbozl2qh5zii2bq2nnvbz6g6c4ew3mwp6uukk6u7wva
|
||||||
gusion.i2p,4qyfdhizjixe2psu7wcvqufix5wlijocehpb2futurcmlhlktrta
|
gusion.i2p,4qyfdhizjixe2psu7wcvqufix5wlijocehpb2futurcmlhlktrta
|
||||||
guttersnipe.i2p,kizkhzes2bzp45widihremo6geepfk7dl6juourkvzuvlc6y3spq
|
guttersnipe.i2p,kizkhzes2bzp45widihremo6geepfk7dl6juourkvzuvlc6y3spq
|
||||||
h-f-j-i2p-site.i2p,bjtxnbci25zix2ydunmsin7cwsffleirat2aab7a7heksosdagha
|
hack8.i2p,un63fgjgi3auvi7zscznwqfol7ka4johgthvqf635mg3fefsjgpq
|
||||||
h13.i2p,tozb4vssixoccyqtgnpaatkg2ql52kkjwnsdo3dltezges2na4bq
|
|
||||||
hab.i2p,dtmzgkqferk2aobaneaeihwmadix2ljhcqr3z5zo2dv3zht3i2sq
|
|
||||||
hackerculture.i2p,pl4pccq65gaee64zgo2slvn3ggjui56ewrcgxkmfuua5p7dwek2q
|
|
||||||
hagen.i2p,e2t6rqd2ysbvs53t5nnaf7drllkgk6kfriq3lfuz6mip6xfg644q
|
hagen.i2p,e2t6rqd2ysbvs53t5nnaf7drllkgk6kfriq3lfuz6mip6xfg644q
|
||||||
hax0r.i2p,brvsdtvx5vdjai7sxapgksivsamty4dvrpw7g6qc52hqtvpjznpq
|
|
||||||
heisenberg.i2p,jz4quyw7zt63tmw65jfp76fblwadjss4iyi4puqdg3dye7oaqlvq
|
heisenberg.i2p,jz4quyw7zt63tmw65jfp76fblwadjss4iyi4puqdg3dye7oaqlvq
|
||||||
heligoland.i2p,gzrjm62ektpqjfsem3r3kwvg6zpjvvhvpjvwfxkm2ay4zu7sp6oq
|
heligoland.i2p,gzrjm62ektpqjfsem3r3kwvg6zpjvvhvpjvwfxkm2ay4zu7sp6oq
|
||||||
hello2600.i2p,khpazz3f747z5zet72s6g3dccw53bfdqyhxt5da4sv7ouve5veuq
|
|
||||||
hidden.i2p,iqodhhqo473qv5gwhjcs2bsrbhlqtpzgpnuumpastfiyhuwb2kyq
|
hidden.i2p,iqodhhqo473qv5gwhjcs2bsrbhlqtpzgpnuumpastfiyhuwb2kyq
|
||||||
hiddenanswers.i2p,kj2kbzt27naifij4ki6bklsa2qfewxnkzbkgvximr4ecm7y4ojdq
|
hiddenanswers.i2p,kj2kbzt27naifij4ki6bklsa2qfewxnkzbkgvximr4ecm7y4ojdq
|
||||||
hiddenbooru.i2p,zma5du344hy2ip5xcu6xmt4c7dgibnlv5jm4c2fre5nxv44sln3q
|
hiddenbooru.i2p,zma5du344hy2ip5xcu6xmt4c7dgibnlv5jm4c2fre5nxv44sln3q
|
||||||
hiddenchan.i2p,6y4tltjdgqwfdcz6tqwc7dxhhuradop2vejatisu64nwjzh5tuwa
|
hiddenchan.i2p,6y4tltjdgqwfdcz6tqwc7dxhhuradop2vejatisu64nwjzh5tuwa
|
||||||
hiddengate.i2p,rvblcu54jvkkfffp3fobhunsvpgfc6546crcgzielzwe2s5m5hbq
|
hiddengate.i2p,rvblcu54jvkkfffp3fobhunsvpgfc6546crcgzielzwe2s5m5hbq
|
||||||
hispagatos.space.i2p,tibqaokyoc74mljuwng5ugulim4jfv6ql7j5vocqfjyrjwxrz6qa
|
|
||||||
home.duck.i2p,jsh7yfvm2t5urdcnmfzdy4n6vegqskdtlwem53chgxli4ipfmuma
|
home.duck.i2p,jsh7yfvm2t5urdcnmfzdy4n6vegqskdtlwem53chgxli4ipfmuma
|
||||||
hopekiller.i2p,kcaelbgsvrkiwpx36b4wxofebrl3njx7rgm5amzfmqwbomt44cxa
|
hopekiller.i2p,kcaelbgsvrkiwpx36b4wxofebrl3njx7rgm5amzfmqwbomt44cxa
|
||||||
hostedtech.i2p,ja6nnovaq6j6umtzano54tvxq2zd5vwasymfad3av3ceixzxblea
|
|
||||||
hotline.i2p,6cczi27iuxkm3aivazaemzltdqgh42ljzurqp43uclbz2lid2uqq
|
hotline.i2p,6cczi27iuxkm3aivazaemzltdqgh42ljzurqp43uclbz2lid2uqq
|
||||||
hound.i2p,ovh4pszqnqhperfwn5rboxljkjemx7dymecl35sxa3dpdsz5f5va
|
|
||||||
hq.postman.i2p,27ivgyi2xhbwjyqmnx3ufjvc2slg6mv7767hxct74cfwzksjemaq
|
hq.postman.i2p,27ivgyi2xhbwjyqmnx3ufjvc2slg6mv7767hxct74cfwzksjemaq
|
||||||
http.entropy.i2p,ytu7kz5bdoc26nkpw2hajwt3q7n5rcbg2eokyefhmkxmmslimbdq
|
http.entropy.i2p,ytu7kz5bdoc26nkpw2hajwt3q7n5rcbg2eokyefhmkxmmslimbdq
|
||||||
human.i2p,nrtcelq3humyfvoxmzmngpka6tmyifweouku5mbi5av4lc43hzaa
|
human.i2p,nrtcelq3humyfvoxmzmngpka6tmyifweouku5mbi5av4lc43hzaa
|
||||||
i.i2p,5lpdk3gft3wccs4npmadb5mh3hwb7uh63ehym2x5rdre77xtfleq
|
|
||||||
i2host.i2p,awdf3nnmxxup5q2i6dobhozgcbir7fxpccejwruqcde2ptld443q
|
i2host.i2p,awdf3nnmxxup5q2i6dobhozgcbir7fxpccejwruqcde2ptld443q
|
||||||
i2jump.i2p,633kqgmwzzu6vhkevwvbf2pfyejt3gkes34i6upa4og57fgdfcxa
|
i2jump.i2p,633kqgmwzzu6vhkevwvbf2pfyejt3gkes34i6upa4og57fgdfcxa
|
||||||
i2p-bt.postman.i2p,jeudwnx7mekjcowpqo6xpkwn7263c57y5piurrjrdzinjziu4fla
|
i2p-bt.postman.i2p,jeudwnx7mekjcowpqo6xpkwn7263c57y5piurrjrdzinjziu4fla
|
||||||
i2p-epub-eepsite.i2p,yxvzjwd4vin6pnjauekdufh7lxaijal3kqe2bhakuf47g5zkb6xa
|
i2p-epub-eepsite.i2p,yxvzjwd4vin6pnjauekdufh7lxaijal3kqe2bhakuf47g5zkb6xa
|
||||||
i2p-javadocs.i2p,icgmr6hhjudl4yxhtuq4pxvss2pzypwddzowajgs5rdz6f55novq
|
i2p-javadocs.i2p,icgmr6hhjudl4yxhtuq4pxvss2pzypwddzowajgs5rdz6f55novq
|
||||||
i2p-projekt.i2p,udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna
|
i2p-projekt.i2p,udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna
|
||||||
i2p-scene.i2p,cc6z3xuw67d2mpq5horgu4mpk7hybmhutotmwvmzzpvoudggifuq
|
|
||||||
i2pbote.i2p,tjgidoycrw6s3guetge3kvrvynppqjmvqsosmtbmgqasa6vmsf6a
|
i2pbote.i2p,tjgidoycrw6s3guetge3kvrvynppqjmvqsosmtbmgqasa6vmsf6a
|
||||||
i2pbuggenie.i2p,bioq5jbcnfopqwvk7qssaxcl7avzeta6mu72jmxjeowflpcrhf6q
|
i2pbuggenie.i2p,bioq5jbcnfopqwvk7qssaxcl7avzeta6mu72jmxjeowflpcrhf6q
|
||||||
i2pchan.i2p,tduxyvfs7fzi26znvph3mu2d2ewaess7emomfci22wvownajphuq
|
i2pchan.i2p,tduxyvfs7fzi26znvph3mu2d2ewaess7emomfci22wvownajphuq
|
||||||
@@ -323,11 +270,13 @@ i2peek-a-boo.i2p,qgv64klyy4tgk4ranaznet5sjgi7ccsrawtjx3j5tvekvvfl67aa
|
|||||||
i2pforum.i2p,tmipbl5d7ctnz3cib4yd2yivlrssrtpmuuzyqdpqkelzmnqllhda
|
i2pforum.i2p,tmipbl5d7ctnz3cib4yd2yivlrssrtpmuuzyqdpqkelzmnqllhda
|
||||||
i2pjump.i2p,2mwcgdjvfvd3xwumzqzqntual3l57h3zo7lwdmkjboeraudpkyka
|
i2pjump.i2p,2mwcgdjvfvd3xwumzqzqntual3l57h3zo7lwdmkjboeraudpkyka
|
||||||
i2plugins.i2p,bb63kmnmbpitsdu45ez54kmogvvljn3yudksurcxiyq7dn5abt7a
|
i2plugins.i2p,bb63kmnmbpitsdu45ez54kmogvvljn3yudksurcxiyq7dn5abt7a
|
||||||
|
i2pmetrics.i2p,v65p4czypwxrn35zlrfkar2w77vr42acd7gbszegsrqq4u7sip5a
|
||||||
i2pnews.i2p,tc73n4kivdroccekirco7rhgxdg5f3cjvbaapabupeyzrqwv5guq
|
i2pnews.i2p,tc73n4kivdroccekirco7rhgxdg5f3cjvbaapabupeyzrqwv5guq
|
||||||
i2podisy.i2p,3c2jzypzjpxuq2ncr3wn3swn5d4isxlulqgccb6oq5f6zylcrvcq
|
i2podisy.i2p,3c2jzypzjpxuq2ncr3wn3swn5d4isxlulqgccb6oq5f6zylcrvcq
|
||||||
i2push.i2p,mabdiml4busx53hjh4el5wlyn4go5mgji2dxsfyelagi4v5mzjxq
|
i2push.i2p,mabdiml4busx53hjh4el5wlyn4go5mgji2dxsfyelagi4v5mzjxq
|
||||||
i2pwiki.i2p,nrbnshsndzb6homcipymkkngngw4s6twediqottzqdfyvrvjw3pq
|
i2pwiki.i2p,nrbnshsndzb6homcipymkkngngw4s6twediqottzqdfyvrvjw3pq
|
||||||
iamevil.i2p,au7jhslyt4cxkjp365bvqvend3hhykrrhbohtjqlgoqrlijbezja
|
iamevil.i2p,au7jhslyt4cxkjp365bvqvend3hhykrrhbohtjqlgoqrlijbezja
|
||||||
|
icu812.i2p,bxgqwfsnr3bgnr6adn62anjcin5nuthqglotb3wn3dgynsfofeva
|
||||||
id3nt.i2p,ufuqdzsxltiz224vq5gnuslt3a3t72dhy5kq6i2xway53m6pzv6q
|
id3nt.i2p,ufuqdzsxltiz224vq5gnuslt3a3t72dhy5kq6i2xway53m6pzv6q
|
||||||
identiguy.i2p,3mzmrus2oron5fxptw7hw2puho3bnqmw2hqy7nw64dsrrjwdilva
|
identiguy.i2p,3mzmrus2oron5fxptw7hw2puho3bnqmw2hqy7nw64dsrrjwdilva
|
||||||
ilcosmista.i2p,6u2rfuq3cyeb7ytjzjxgbfa73ipzpzen5wx3tihyast2f2oeo24q
|
ilcosmista.i2p,6u2rfuq3cyeb7ytjzjxgbfa73ipzpzen5wx3tihyast2f2oeo24q
|
||||||
@@ -335,13 +284,11 @@ ilita.i2p,isxls447iuumsb35pq5r3di6xrxr2igugvshqwhi5hj5gvhwvqba
|
|||||||
illuminati.i2p,syi6jakreatlm2z22u76izyqvbm4yi4yj7hr7jb63lgru5yhwwla
|
illuminati.i2p,syi6jakreatlm2z22u76izyqvbm4yi4yj7hr7jb63lgru5yhwwla
|
||||||
imhotep.i2p,qegmmhy52bdes2wqot4kfyqyg7xnxm5jzbafdb42rfoafadj2q7a
|
imhotep.i2p,qegmmhy52bdes2wqot4kfyqyg7xnxm5jzbafdb42rfoafadj2q7a
|
||||||
in.i2p,r5vbv2akbp6txy5amkftia757klgdy44s6cglqhmstpg65xycyjq
|
in.i2p,r5vbv2akbp6txy5amkftia757klgdy44s6cglqhmstpg65xycyjq
|
||||||
inclib.i2p,ux6prousphswf56bym7yo7kst4ybh45y2z2wrnw7dujmrz56hq4q
|
|
||||||
incobin.i2p,eorn2zs5nlj2noxflomqbbvo6qkl5xprz3jjoso6ap5ywupsxsjq
|
|
||||||
infosecurity.i2p,v3gkh5kqzawn2l3uzhw6xnszsh6w3nztjmlwil7p4kyrwrsm2dba
|
infosecurity.i2p,v3gkh5kqzawn2l3uzhw6xnszsh6w3nztjmlwil7p4kyrwrsm2dba
|
||||||
infoserver.i2p,jd3agbakybnhfvkeoxrx7t33iln6suzomv3kxkxf77j7rkonch6q
|
infoserver.i2p,jd3agbakybnhfvkeoxrx7t33iln6suzomv3kxkxf77j7rkonch6q
|
||||||
inproxy.tino.i2p,ex5yf6eqqmjkrzxnkn6cgvefgne24qxsskqnpmarmajoit43pgma
|
inproxy.tino.i2p,ex5yf6eqqmjkrzxnkn6cgvefgne24qxsskqnpmarmajoit43pgma
|
||||||
inr.i2p,joajgazyztfssty4w2on5oaqksz6tqoxbduy553y34mf4byv6gpq
|
inr.i2p,joajgazyztfssty4w2on5oaqksz6tqoxbduy553y34mf4byv6gpq
|
||||||
insanity.i2p,j7c45wpdoxxu2f3kfsvi2vr7bi4tc6femnycqi24qde2uucqurkq
|
instantexchange.i2p,5wiyndm44bysev22kxvczxt37p6o6qroiqykytrvn2yzi55aqfxq
|
||||||
investigaciones.i2p,n7hqd4asxrdwf3zwo7rzv27y2qkcfmakmz6mjar6aw6hlc4c7mha
|
investigaciones.i2p,n7hqd4asxrdwf3zwo7rzv27y2qkcfmakmz6mjar6aw6hlc4c7mha
|
||||||
invisible-internet.i2p,jnpykdpp46zenz4p64eb3opadl5g42dls3rurk2cvq6a3g3rvbvq
|
invisible-internet.i2p,jnpykdpp46zenz4p64eb3opadl5g42dls3rurk2cvq6a3g3rvbvq
|
||||||
io.i2p,tx22i6crnorzuti3x6va4mijsbhoqswy2cfdxjbvprgsq4eerg7q
|
io.i2p,tx22i6crnorzuti3x6va4mijsbhoqswy2cfdxjbvprgsq4eerg7q
|
||||||
@@ -350,37 +297,29 @@ irc.arcturus.i2p,5nywlbn35p2nwsymwpfmicu6fxono6g64vwusxbsvmm2qwz6vupq
|
|||||||
irc.baffled.i2p,5zmtoopscym6qagkvpgyn7jnkp6dwnfai745xevkxlou77c2fsjq
|
irc.baffled.i2p,5zmtoopscym6qagkvpgyn7jnkp6dwnfai745xevkxlou77c2fsjq
|
||||||
irc.carambar.i2p,hxzbpivxqxy6nuae4t6fnkhcgnhs4c72vt6mmsqfmfhrkn2ca6gq
|
irc.carambar.i2p,hxzbpivxqxy6nuae4t6fnkhcgnhs4c72vt6mmsqfmfhrkn2ca6gq
|
||||||
irc.cerapadus.i2p,e4ckznxcxvgyikzjmjsu72i2dbj2d76ogexyukklbjvpcnhp6zzq
|
irc.cerapadus.i2p,e4ckznxcxvgyikzjmjsu72i2dbj2d76ogexyukklbjvpcnhp6zzq
|
||||||
irc.chatfreedom.i2p,qaufwx3c47bnjyave4y2mpk7d4vsayxpz7tdi2kwpv6lykj2znja
|
|
||||||
irc.dg.i2p,fvp3pkcw4uvijqabwtekcdilklp73gyasuek67wdcs2mucep4caq
|
irc.dg.i2p,fvp3pkcw4uvijqabwtekcdilklp73gyasuek67wdcs2mucep4caq
|
||||||
irc.duck.i2p,chdpmm4gxffyn24xx5dhxvfd5httu42i5gtoe6cctjlsf4mbofeq
|
irc.duck.i2p,chdpmm4gxffyn24xx5dhxvfd5httu42i5gtoe6cctjlsf4mbofeq
|
||||||
irc.echelon.i2p,ez2czsvej5p3z5bquue5q3thujcodfze7ptybctqhnqc7hms5uzq
|
irc.echelon.i2p,ez2czsvej5p3z5bquue5q3thujcodfze7ptybctqhnqc7hms5uzq
|
||||||
irc.foxatomic.i2p,mkyylu5pmwvjo6koojlfcex3orjtbtoxaeelaybsb57ykub5hw5a
|
|
||||||
irc.freshcoffee.i2p,ubiu2ehtfnrleemgpzsqkahwnvzuaifqa3u4wmaz5maaisd5ycfa
|
irc.freshcoffee.i2p,ubiu2ehtfnrleemgpzsqkahwnvzuaifqa3u4wmaz5maaisd5ycfa
|
||||||
|
irc.i2p,l3ohmm4ccxvyuxuajeaddiptci5lsrnxtvtyq7iohphrt3oj2evq
|
||||||
irc.ilita.i2p,5xeoyfvtddmo5k3kxzv7b3d5risil6333ntqrr3yvx3yubz5tk3a
|
irc.ilita.i2p,5xeoyfvtddmo5k3kxzv7b3d5risil6333ntqrr3yvx3yubz5tk3a
|
||||||
irc.ircbnc.i2p,4rqcsqd7xif6r4v55blqvmqu5er6due4eyene3mjorfkts4o3rxa
|
irc.ircbnc.i2p,4rqcsqd7xif6r4v55blqvmqu5er6due4eyene3mjorfkts4o3rxa
|
||||||
irc.killyourtv.i2p,wre4majmg2vnbi6id27et7yw6lnpf56wkbm6ftnlwpvxnktq73hq
|
irc.killyourtv.i2p,wre4majmg2vnbi6id27et7yw6lnpf56wkbm6ftnlwpvxnktq73hq
|
||||||
irc.kitsune.i2p,cpesprosbsuycn4ui3neidqdtqz5ufekthob7cobl3p7bcuaoh3q
|
|
||||||
irc.nickster.i2p,dhq3fhd5scw3jqhj5ge7kqfpprfolcgxfjbaw24obohaiqjtdu7a
|
irc.nickster.i2p,dhq3fhd5scw3jqhj5ge7kqfpprfolcgxfjbaw24obohaiqjtdu7a
|
||||||
irc.orz.i2p,7gifacog4aoons3syybojbbnyqqaaqijhngrehn2xlq3eucuyjcq
|
irc.orz.i2p,7gifacog4aoons3syybojbbnyqqaaqijhngrehn2xlq3eucuyjcq
|
||||||
irc.pacman.i2p,ckxfx7oo5qbufui2i7tshzs5hef4yafgpw4jsogsyetcgk5tbn7a
|
|
||||||
irc.postman.i2p,mpvr7qmek2yz2ekegp5rur573z7e77vp3xqt2lfbco5i6nkfppcq
|
irc.postman.i2p,mpvr7qmek2yz2ekegp5rur573z7e77vp3xqt2lfbco5i6nkfppcq
|
||||||
irc.r4sas.i2p,hodhusp73gltozgrnianlbploon3rrvhrzfn5mf2g46o7aaau5la
|
irc.r4sas.i2p,hodhusp73gltozgrnianlbploon3rrvhrzfn5mf2g46o7aaau5la
|
||||||
irc.talkfreedom.i2p,bwicwfqn4kjotbxfwyflxmzqv3ohdeespcco6untb5c645hslebq
|
|
||||||
irc.trollirc.i2p,hci35hmgxc5xdieoqexyjgsbgsqlsoogxyhwnfkx6aioxkf2le6a
|
|
||||||
ircssl.cerapadus.i2p,4x2i745i4w52ss3he2kse6tzwt64pr62yvrcb72lgvrb63fup6ea
|
ircssl.cerapadus.i2p,4x2i745i4w52ss3he2kse6tzwt64pr62yvrcb72lgvrb63fup6ea
|
||||||
irongeeks.i2p,ecduxoion5uc5hnvzjxff6iiwhdwph6gse3dknyvlo7e6gaeho7a
|
irongeeks.i2p,ecduxoion5uc5hnvzjxff6iiwhdwph6gse3dknyvlo7e6gaeho7a
|
||||||
iscofsi.i2p,enjgdxs4um2dmhdb2ajff2egrdijkjji3g47m6unb74swbrqsddq
|
iscofsi.i2p,enjgdxs4um2dmhdb2ajff2egrdijkjji3g47m6unb74swbrqsddq
|
||||||
isitup.i2p,xk6ypey2az23vtdkitjxvanlshztmjs2ekd6sp77m4obszf6ocfq
|
|
||||||
isotoxin.i2p,wue3ycaccf4texikza3fh6p5yrmtgnooisuypnepo5mo67lmpcqq
|
isotoxin.i2p,wue3ycaccf4texikza3fh6p5yrmtgnooisuypnepo5mo67lmpcqq
|
||||||
itemname.i2p,o35ut7hgywy35okvgkjkv3ufzv2ejv4luap4oytwbyy2jqy6u4vq
|
itemname.i2p,o35ut7hgywy35okvgkjkv3ufzv2ejv4luap4oytwbyy2jqy6u4vq
|
||||||
ivorytower.i2p,fpwrfvidfexsz7dspofkwtkmmizm7lyralfz5kvykffk7gubvxsq
|
ivorytower.i2p,fpwrfvidfexsz7dspofkwtkmmizm7lyralfz5kvykffk7gubvxsq
|
||||||
j.i2p,kjxvohlsf5sdrzxzfcrmvquccnoevi6ytbl63mstsru5wt2dx3ea
|
j.i2p,kjxvohlsf5sdrzxzfcrmvquccnoevi6ytbl63mstsru5wt2dx3ea
|
||||||
jabber-2.i2p,pvnmzgemetkwcuvt45omgowmeznwk5xw3nc3ygeoz7yekqxy57na
|
jabber-2.i2p,pvnmzgemetkwcuvt45omgowmeznwk5xw3nc3ygeoz7yekqxy57na
|
||||||
jabber.duck.i2p,rhdzvvzraqzzm67zpyegb7knpfrjeffitixqzeyymdoz56uh2rtq
|
jabber.duck.i2p,rhdzvvzraqzzm67zpyegb7knpfrjeffitixqzeyymdoz56uh2rtq
|
||||||
jabber.i2p,32dft3x7pnwmgmc24yzl22r7kevefk22k66ms2dssd4w3skcgzqq
|
|
||||||
jake.i2p,v2axvy6pqefnla7gun5fmqs4lqe4xfyqovgzcundhxrpcdvfd7cq
|
jake.i2p,v2axvy6pqefnla7gun5fmqs4lqe4xfyqovgzcundhxrpcdvfd7cq
|
||||||
jar.i2p,2fthkmujup3xiiu3yple24n6g4emzdiiimbuqwvpdddtsr3c4nrq
|
jar.i2p,2fthkmujup3xiiu3yple24n6g4emzdiiimbuqwvpdddtsr3c4nrq
|
||||||
jaruga.i2p,bcqiblik2ccvhnjzammiujiluqzp2wz2bggp6o2vxmtivpmtq5nq
|
|
||||||
jazzy.i2p,ha5c3zafwkt6mwqwjcf4oqwvbwz473652ljjadiwrj4gfkfkjofa
|
jazzy.i2p,ha5c3zafwkt6mwqwjcf4oqwvbwz473652ljjadiwrj4gfkfkjofa
|
||||||
jdot.i2p,kw4jr5qw4bhnj33avkwankjdh3zi7wtahlmgkjwvsv2isskkzgpq
|
jdot.i2p,kw4jr5qw4bhnj33avkwankjdh3zi7wtahlmgkjwvsv2isskkzgpq
|
||||||
jhor.i2p,c6rnm7oemydhuwzmhwwwxphkzanez5rnn7fkcs3lpgu6gkgtssoa
|
jhor.i2p,c6rnm7oemydhuwzmhwwwxphkzanez5rnn7fkcs3lpgu6gkgtssoa
|
||||||
@@ -395,14 +334,13 @@ jwebcache.i2p,xdffxnxtjd6ji2zig3cgva7igvl2tiapyjoc7ylbzwqhxudbmvfa
|
|||||||
k1773r.i2p,zam7u6vslhemddz347uusuzjdk5wma4h5hcmcqlng4ybbpdbjhnq
|
k1773r.i2p,zam7u6vslhemddz347uusuzjdk5wma4h5hcmcqlng4ybbpdbjhnq
|
||||||
kaji.i2p,z5ic7gvm2k4doczphtrnrspl2w5sfbss2de4z3ihjijhtjw67ydq
|
kaji.i2p,z5ic7gvm2k4doczphtrnrspl2w5sfbss2de4z3ihjijhtjw67ydq
|
||||||
kaji2.i2p,4lscgc6napekfx7ay5fdcjofeja4fnl7tqcd3fek63t4saavur2a
|
kaji2.i2p,4lscgc6napekfx7ay5fdcjofeja4fnl7tqcd3fek63t4saavur2a
|
||||||
kellett.i2p,cmhgn2lsgvfrhrgo5l2fqxkzpngrl2potp2v3jw7juti3jrr2rhq
|
|
||||||
keys.echelon.i2p,mwfpkdmjur5ytq4og36ym3ychinv36b2a57f4rmgqmtrwepq3fva
|
keys.echelon.i2p,mwfpkdmjur5ytq4og36ym3ychinv36b2a57f4rmgqmtrwepq3fva
|
||||||
keys.i2p,6qv4x7ltaxckd4vbay5s4ntqqflq4efk6oke2d5yzicqrmk443ba
|
keys.i2p,6qv4x7ltaxckd4vbay5s4ntqqflq4efk6oke2d5yzicqrmk443ba
|
||||||
keyserver.sigterm.i2p,isoxvnflrdn7cm76yjlfg5tbcugoito2hur7eidbqmo33xmwz5ga
|
keyserver.sigterm.i2p,isoxvnflrdn7cm76yjlfg5tbcugoito2hur7eidbqmo33xmwz5ga
|
||||||
killyourtv.i2p,aululz24ugumppq56jsaw3d7mkbmcgo7dl2lgeanvpniyk2cbrda
|
killyourtv.i2p,aululz24ugumppq56jsaw3d7mkbmcgo7dl2lgeanvpniyk2cbrda
|
||||||
|
knijka.i2p,knjkodsakcxihwk5w5new76hibywia5zqcgoqgjttzsausnd22oa
|
||||||
knotwork.i2p,2yocdbcjiyfaqgxb4l6oenrrrrie6nydgmbnbfulqg7cik6bozxq
|
knotwork.i2p,2yocdbcjiyfaqgxb4l6oenrrrrie6nydgmbnbfulqg7cik6bozxq
|
||||||
kohaar.i2p,qchpjehbhqjbxdo7w3m55jbkrtsneb7oqoxcr24qttiq6j5g3z5q
|
kohaar.i2p,qchpjehbhqjbxdo7w3m55jbkrtsneb7oqoxcr24qttiq6j5g3z5q
|
||||||
kovri.i2p,j3hdkil4juppzdz2z3hiybauoagcq4rz3lcqygge5tmg2ea7vs3q
|
|
||||||
krabs.i2p,3yamyk5bgfgovg6zpvtvpdjk37ivjj2wog2w7wha5agzgxxkqaca
|
krabs.i2p,3yamyk5bgfgovg6zpvtvpdjk37ivjj2wog2w7wha5agzgxxkqaca
|
||||||
kuroneko.i2p,wbit2huhhwlyqp2j4undccuyrodh6qcmzdeyuaoy5o4ym7g5gdgq
|
kuroneko.i2p,wbit2huhhwlyqp2j4undccuyrodh6qcmzdeyuaoy5o4ym7g5gdgq
|
||||||
kycklingar.i2p,gctswdhp4447yibxfbqg3uq2bvx63qjeqnaoaux75zw73leakyva
|
kycklingar.i2p,gctswdhp4447yibxfbqg3uq2bvx63qjeqnaoaux75zw73leakyva
|
||||||
@@ -413,7 +351,6 @@ lenta.i2p,nevfjzoo3eeef3lbj2nqsuwj5qh3veiztiw6gzeu2eokcowns3ra
|
|||||||
libertor.i2p,7gajvk4dnnob6wlkoo2zcws7nor3gunvoi7ofalcps5lc76wruuq
|
libertor.i2p,7gajvk4dnnob6wlkoo2zcws7nor3gunvoi7ofalcps5lc76wruuq
|
||||||
library.i2p,brqqaq44vbeagesj5o3sxcnkc5yivkwouafyxa77ciu7l644ei2a
|
library.i2p,brqqaq44vbeagesj5o3sxcnkc5yivkwouafyxa77ciu7l644ei2a
|
||||||
lifebox.i2p,pyqjnycm55cuxow22voqj62qysrjdnb6nbyladaiaiirqi7vp2yq
|
lifebox.i2p,pyqjnycm55cuxow22voqj62qysrjdnb6nbyladaiaiirqi7vp2yq
|
||||||
linoleum.i2p,wvxi6vdf3jv75k2ib3cdzjuai7gxsxh36faf5y4tlk2jwiy2unua
|
|
||||||
linuxagent.i2p,ap5riaikrjq2uv5qvy7klzhhqywvqi7wqscyipsewcun7w2eynlq
|
linuxagent.i2p,ap5riaikrjq2uv5qvy7klzhhqywvqi7wqscyipsewcun7w2eynlq
|
||||||
lists.i2p2.i2p,vmfwbic2brek2ez223j6fc6bl5mmouzqvbsch45msvyyzih3iqua
|
lists.i2p2.i2p,vmfwbic2brek2ez223j6fc6bl5mmouzqvbsch45msvyyzih3iqua
|
||||||
lm.i2p,yeyar743vuwmm6fpgf3x6bzmj7fxb5uxhuoxx4ea76wqssdi4f3q
|
lm.i2p,yeyar743vuwmm6fpgf3x6bzmj7fxb5uxhuoxx4ea76wqssdi4f3q
|
||||||
@@ -422,38 +359,31 @@ lolicatgirls.i2p,a4lzmjyba7aq7hl6okqpds7znnwymolqnr7xhvno2wraqb7uhfla
|
|||||||
lolifox.i2p,7fd2clkiotjnaoeigdtxlkkb24eik675ovezjf67x26ysham4zca
|
lolifox.i2p,7fd2clkiotjnaoeigdtxlkkb24eik675ovezjf67x26ysham4zca
|
||||||
longhorn.i2p,pohcihzxzttjclrazhs3p76wt3ih737egb5bovqb6ym3du6z3o7a
|
longhorn.i2p,pohcihzxzttjclrazhs3p76wt3ih737egb5bovqb6ym3du6z3o7a
|
||||||
lp.i2p,jiklbujn3cbfikf4pca526jgmorx6mxhil3twqmfoteaplx6ddwq
|
lp.i2p,jiklbujn3cbfikf4pca526jgmorx6mxhil3twqmfoteaplx6ddwq
|
||||||
lua.i2p,kq33wpfdocw6sf5r3k36723tgjodb6csjnrthdsul7gsnmtay46a
|
|
||||||
lucky.i2p,wx36m3wnpt2y6bngdpg3ifrarvtkpwnluarx377bllpgvkuhybaa
|
lucky.i2p,wx36m3wnpt2y6bngdpg3ifrarvtkpwnluarx377bllpgvkuhybaa
|
||||||
luckypunk.i2p,y4t6cujjxnnrtln3rgmfbgbh46hic7wkef57krd7opitbgngohka
|
luckypunk.i2p,y4t6cujjxnnrtln3rgmfbgbh46hic7wkef57krd7opitbgngohka
|
||||||
lunokhod.i2p,3yc6sp7xic4grmpfecbwuij6z3dp5kdgoo362pszaco7io42mnwa
|
lunokhod.i2p,3yc6sp7xic4grmpfecbwuij6z3dp5kdgoo362pszaco7io42mnwa
|
||||||
lyra.i2p,xfinw5aapff3ajbm3vnk4t5wor3lzcuwtq73rxz4yb7umlnmyl3q
|
m16.i2p,ucsr3eveuc4mx5y6gxnoaywd4ojvbel5q3ynns6s5yfw3vusmfva
|
||||||
mac7.i2p,3yjowssqzydciwa5zx55kazgf7q7w6g7rkocr7bngy35ii44t34q
|
mac7.i2p,3yjowssqzydciwa5zx55kazgf7q7w6g7rkocr7bngy35ii44t34q
|
||||||
madman2003.i2p,a2sam2xbhxbzmeyobphbxrkdwlppoerewq5qvibbyk3ftsr643qq
|
madman2003.i2p,a2sam2xbhxbzmeyobphbxrkdwlppoerewq5qvibbyk3ftsr643qq
|
||||||
magix.i2p,cgfnyxv62msfynsfbv3kju22j2mt6tfnopshhmrcmpcrxyts6xwq
|
magix.i2p,cgfnyxv62msfynsfbv3kju22j2mt6tfnopshhmrcmpcrxyts6xwq
|
||||||
magnets.i2p,snz46nez6hrrpg6336neinflw56l3vwatk6bzzytwu77xmsfsoca
|
magnets.i2p,snz46nez6hrrpg6336neinflw56l3vwatk6bzzytwu77xmsfsoca
|
||||||
make.i2p,yr7r4o4ijrz5w4movfmfsn3yrlox2mjofrgiartn2qna7us7pd3q
|
|
||||||
manas.i2p,6qolj62ikkoq6wdn3hbvcbdmlvf2rcyv432kgi5uy7mvrczmjtba
|
manas.i2p,6qolj62ikkoq6wdn3hbvcbdmlvf2rcyv432kgi5uy7mvrczmjtba
|
||||||
manveru.i2p,pbmbofs76wpjnxi55eqtwg4y6ltyij72o4fm4sxfjol3y57ze5sq
|
manveru.i2p,pbmbofs76wpjnxi55eqtwg4y6ltyij72o4fm4sxfjol3y57ze5sq
|
||||||
marcos.i2p,vpo36bsil2voqaou53zshuegssqaroa5mbrzxfmhjywlbojckalq
|
marcos.i2p,vpo36bsil2voqaou53zshuegssqaroa5mbrzxfmhjywlbojckalq
|
||||||
marlin23732.i2p,wfpkmtqz5fzlkh4wpft2aei3itithbhthp5peyavx6zn3napipgq
|
|
||||||
marshmallow.i2p,svdqd6j3y3gwryufcl4fkzpmcujgvrvphvk2oy4r7m75xs327e2q
|
marshmallow.i2p,svdqd6j3y3gwryufcl4fkzpmcujgvrvphvk2oy4r7m75xs327e2q
|
||||||
marxists.i2p,lepah55qyp2fhuwxlz7bwrhzckn4gkuofivnofoeuyfpmke5x2hq
|
marxists.i2p,lepah55qyp2fhuwxlz7bwrhzckn4gkuofivnofoeuyfpmke5x2hq
|
||||||
mattermost.i2p,x5oovnhnuli5fnwtgkbd5z5jvrvdvprqyuofywx6uoxkk4bie6ya
|
mattermost.i2p,x5oovnhnuli5fnwtgkbd5z5jvrvdvprqyuofywx6uoxkk4bie6ya
|
||||||
me.i2p,dbpegthe42sx2yendpesxgispuohjixm4bds7ts5gjxzni5nu6na
|
me.i2p,dbpegthe42sx2yendpesxgispuohjixm4bds7ts5gjxzni5nu6na
|
||||||
mediabox.i2p,fpymagqfyjdcel3cddrj447fgic6ke3aztfkpwsg24gefoc62zvq
|
|
||||||
meeh.i2p,4oes3rlgrpbkmzv4lqcfili23h3cvpwslqcfjlk6vvguxyggspwa
|
meeh.i2p,4oes3rlgrpbkmzv4lqcfili23h3cvpwslqcfjlk6vvguxyggspwa
|
||||||
mesh.firerabbit.i2p,3x5wokr4bjy5z3ynji4fyhvwzv4fvgry3xafi5df5h75doezjytq
|
mesh.firerabbit.i2p,3x5wokr4bjy5z3ynji4fyhvwzv4fvgry3xafi5df5h75doezjytq
|
||||||
messageinabottle.i2p,avfhe3kvrrv7utxn2vre65lg7damxzzsewq3vukwie4llitd254a
|
messageinabottle.i2p,avfhe3kvrrv7utxn2vre65lg7damxzzsewq3vukwie4llitd254a
|
||||||
metrics.i2p,z45ieamhex2ihqv7oowk5fz4qq47rbvxhhhbaaiinpajbhuevtpq
|
metrics.i2p,z45ieamhex2ihqv7oowk5fz4qq47rbvxhhhbaaiinpajbhuevtpq
|
||||||
|
mhatta.i2p,o4rsxdeepfrnncsnjq675xogp5v5qkbfgbt6ooqeyfvlifobrjxq
|
||||||
microbleu.i2p,mtapervgibruizniems2yyr47pin2wpysyh7m632rigl26vjc6qa
|
microbleu.i2p,mtapervgibruizniems2yyr47pin2wpysyh7m632rigl26vjc6qa
|
||||||
micronations.i2p,xcxb2bir6arhavr2vlrcfnovtgaf4a5jlzv7lksxirsbgxuwc7sa
|
|
||||||
microsoft.i2p,hvaqr5idszdyrjph34amb4mjosqd3ynggoxlnj7ciqhnx7q6plza
|
microsoft.i2p,hvaqr5idszdyrjph34amb4mjosqd3ynggoxlnj7ciqhnx7q6plza
|
||||||
mindisl0st.i2p,u7rnqhvsuyxd3fabm4kyzn7brgz3i3cporj2emk2jmbpcmltyf7a
|
mindisl0st.i2p,u7rnqhvsuyxd3fabm4kyzn7brgz3i3cporj2emk2jmbpcmltyf7a
|
||||||
mindspore.i2p,uuh5dd3y2rqa7x2jpggm4p2pg6znarm5uanwsvybe4tk36ymwr4q
|
mindspore.i2p,uuh5dd3y2rqa7x2jpggm4p2pg6znarm5uanwsvybe4tk36ymwr4q
|
||||||
miraiex.i2p,mbdyxyxj4tliyvcc54xknkyg7ficigoyvfnfesevr64nytr33tiq
|
|
||||||
modulus.i2p,ctz3o6hdefrzwt3hlg6rjhdcbjk6irppbndq32u6jnn4lz72f62a
|
modulus.i2p,ctz3o6hdefrzwt3hlg6rjhdcbjk6irppbndq32u6jnn4lz72f62a
|
||||||
moeyoo.i2p,co6oemqjwvy563l7gar7ybb4nva3k6mnifakyk6bt4idfr2kjwka
|
|
||||||
monero-build.i2p,wc7qzr43g2o33wsluagjhhd4rvrcx7h5hhhtfwl6i42kk3iuouja
|
|
||||||
monerotools.i2p,5bal7dngxde2ddmhuzbtfken6w5nmxmixtjlrlmxt3wbhnemv73q
|
monerotools.i2p,5bal7dngxde2ddmhuzbtfken6w5nmxmixtjlrlmxt3wbhnemv73q
|
||||||
monerujo.i2p,puri6y5dtwh6zr4u77ep6ozatun6iz7v4wai2dzxppz7654corlq
|
monerujo.i2p,puri6y5dtwh6zr4u77ep6ozatun6iz7v4wai2dzxppz7654corlq
|
||||||
morph.i2p,iovyp2dao5rta6g5v6hke2s4ugx2btkpcljddak2yhxfrx3l4dqa
|
morph.i2p,iovyp2dao5rta6g5v6hke2s4ugx2btkpcljddak2yhxfrx3l4dqa
|
||||||
@@ -463,7 +393,6 @@ moxonom.i2p,gcjdrvnlobgexh7ebv276pwmnoj3yoyaqm3w4vmmdha4lgxfinqq
|
|||||||
mp3.aum.i2p,n7bmu5dwux7f6gedmdik6zrm77bnls4lkzo2vo3bf4bwegk7vkjq
|
mp3.aum.i2p,n7bmu5dwux7f6gedmdik6zrm77bnls4lkzo2vo3bf4bwegk7vkjq
|
||||||
mp3.tc.i2p,w3ied5s7ldjcvnhxu2gyofe3oogzbplkyxshzfkhspiy2526snsa
|
mp3.tc.i2p,w3ied5s7ldjcvnhxu2gyofe3oogzbplkyxshzfkhspiy2526snsa
|
||||||
mpaa.i2p,m6cqnglo7xlytwxkdsmwf3d23d6lq5r446c3tktb2tdmuah36zya
|
mpaa.i2p,m6cqnglo7xlytwxkdsmwf3d23d6lq5r446c3tktb2tdmuah36zya
|
||||||
mr-fox.i2p,kjxtkdcqqde2fvtrhrkpkpejth4vt2cudavqdjhnuglhlboups4a
|
|
||||||
mrbamboo.i2p,tmpmkx6wlbbrgsnexrqlrib7laoegpbfeop7bnyezegii7hecpxa
|
mrbamboo.i2p,tmpmkx6wlbbrgsnexrqlrib7laoegpbfeop7bnyezegii7hecpxa
|
||||||
mrflibble.i2p,u7k2qcmkrril6yvudvwxjqz7k3dzgp3jdejjjeapej7liselj3eq
|
mrflibble.i2p,u7k2qcmkrril6yvudvwxjqz7k3dzgp3jdejjjeapej7liselj3eq
|
||||||
mrplod.i2p,fjn5hxtybxyfyvdf6u5v5seg2sjd47hb5by6sa6ais4w3xnrxwyq
|
mrplod.i2p,fjn5hxtybxyfyvdf6u5v5seg2sjd47hb5by6sa6ais4w3xnrxwyq
|
||||||
@@ -471,18 +400,16 @@ mtn.i2p,xisk3h6sku3iqj52uriogaajmnku7pwjux7wa4omx2zloamuw6eq
|
|||||||
mtn.i2p-projekt.i2p,f52x5fp6uhq53f5zle5d6rq5un34xgmxgazvilvmzcby37xcmsfa
|
mtn.i2p-projekt.i2p,f52x5fp6uhq53f5zle5d6rq5un34xgmxgazvilvmzcby37xcmsfa
|
||||||
mtn.i2p2.i2p,l6kuhtmgvbp57d7jwalj5nksi6nr4gfzbz4oit62lxgipb3llt5a
|
mtn.i2p2.i2p,l6kuhtmgvbp57d7jwalj5nksi6nr4gfzbz4oit62lxgipb3llt5a
|
||||||
mtn.meeh.i2p,h7ylrsuzzynrxp3jql7anoozyqblavj7eqces6o3wngvuuxhs2la
|
mtn.meeh.i2p,h7ylrsuzzynrxp3jql7anoozyqblavj7eqces6o3wngvuuxhs2la
|
||||||
mud.i2p,qcjtmicd3ow3q26iwcs62m5zu3dceu6emo3afezulh4c3fsgrkia
|
|
||||||
mudgaard.i2p,yz32lk42gtoesknesfolq3tt4erxxcejcote5pontaeqev3bj2kq
|
mudgaard.i2p,yz32lk42gtoesknesfolq3tt4erxxcejcote5pontaeqev3bj2kq
|
||||||
mush.zeit.i2p,dk3sg23kljawxqp3cb6xz5mnzjlyckzvq5jhqs5gnvdsv7wqn6ha
|
mush.zeit.i2p,dk3sg23kljawxqp3cb6xz5mnzjlyckzvq5jhqs5gnvdsv7wqn6ha
|
||||||
music.i2p,akamh76yi6p7xxbvl3qv3yhaockne57yfuh77acogbgpjmwypvia
|
music.i2p,akamh76yi6p7xxbvl3qv3yhaockne57yfuh77acogbgpjmwypvia
|
||||||
mysterious.i2p,p66g2a4nzfkvidd3l7nwphcnfa3ttyu5kiolcb4czec2rn2kvwsq
|
mysterious.i2p,p66g2a4nzfkvidd3l7nwphcnfa3ttyu5kiolcb4czec2rn2kvwsq
|
||||||
mystery.i2p,ccea4jybmr3xbfiykaoagfw7ezbvzyhtg44x2jgwhv7wscsxaa7a
|
|
||||||
mywastedlife.i2p,ceumy3puvvsrru5bmfmtgsajsx5qyehqac7l7a23xpwtfs2bvcgq
|
mywastedlife.i2p,ceumy3puvvsrru5bmfmtgsajsx5qyehqac7l7a23xpwtfs2bvcgq
|
||||||
nacl.i2p,bm2fib3tumer72lopjh4nmqomwvqu2sdfyb2hmr6lnk7jbw3vvia
|
nacl.i2p,bm2fib3tumer72lopjh4nmqomwvqu2sdfyb2hmr6lnk7jbw3vvia
|
||||||
nano.i2p,ex5ssv7s3hj6jp7hvadxfw3wvbjbvnczxr4pbk7qw26ihiorjmba
|
nano.i2p,ex5ssv7s3hj6jp7hvadxfw3wvbjbvnczxr4pbk7qw26ihiorjmba
|
||||||
nassai.i2p,v653cocvn3i6bgjdm3ciwbdnu32supglv6gn4fh23bohemsp545q
|
nassai.i2p,v653cocvn3i6bgjdm3ciwbdnu32supglv6gn4fh23bohemsp545q
|
||||||
nastycomics.i2p,rq4nabt5yzlkqfzqc7aqh6dex63pf4v6ip6tunb24jkqsh26ez4a
|
|
||||||
neodome.i2p,5hkhjehj3ct2pvcah7dcylwef2oti3xij5myxbv3pd7rocio5vkq
|
neodome.i2p,5hkhjehj3ct2pvcah7dcylwef2oti3xij5myxbv3pd7rocio5vkq
|
||||||
|
news-i2pn.i2p,wwcqkwfo5yhe6uribv5tzylk25j5hkdk6gdnyftzd3k7dawlzwca
|
||||||
news.neodome.i2p,trhwcnygfkeqjj6g4xhmrdp4gsjqsye47lsxshbmwbten4ywt5oq
|
news.neodome.i2p,trhwcnygfkeqjj6g4xhmrdp4gsjqsye47lsxshbmwbten4ywt5oq
|
||||||
news.underscore.i2p,rl7t3kspoktuatjcu7gf7xleu7y6biibs4fspzo24kll6n7hbq4q
|
news.underscore.i2p,rl7t3kspoktuatjcu7gf7xleu7y6biibs4fspzo24kll6n7hbq4q
|
||||||
newsbyte.i2p,gsk3rgsejxxrfabjxu5w5plplxsu47aoeoke22vvhlwwllzosnxq
|
newsbyte.i2p,gsk3rgsejxxrfabjxu5w5plplxsu47aoeoke22vvhlwwllzosnxq
|
||||||
@@ -491,26 +418,21 @@ nic.i2p,vzu5ymab6klevpcdudv4ypisjqaznmt44e6lcg7dwiuza4saibxq
|
|||||||
nickster.i2p,zkwsa6kvq2wdhovw5g5wqakpb7rlaylyhfriwmurots5pvwbqauq
|
nickster.i2p,zkwsa6kvq2wdhovw5g5wqakpb7rlaylyhfriwmurots5pvwbqauq
|
||||||
nickster2.i2p,eofzi7npzpk4p5gb4qper4hmwgxo6kepo3dheeblakewedxj2bwq
|
nickster2.i2p,eofzi7npzpk4p5gb4qper4hmwgxo6kepo3dheeblakewedxj2bwq
|
||||||
nickyb.i2p,gmpxk4tje7mnud32kg2kjmf36f6cpwqakzc2dxuzjnnz4qr5w4sa
|
nickyb.i2p,gmpxk4tje7mnud32kg2kjmf36f6cpwqakzc2dxuzjnnz4qr5w4sa
|
||||||
niconiconi.i2p,p5h4klccaaldvphjw7fllgj3x5tfy7thqnqu5yr6py7dofemeqiq
|
|
||||||
nightblade.i2p,p4gkon7ytswxrbwkl7vruw6mg7kfw5aofovqjgt4c7tnqmbq6lha
|
nightblade.i2p,p4gkon7ytswxrbwkl7vruw6mg7kfw5aofovqjgt4c7tnqmbq6lha
|
||||||
nine.i2p,gniusiswp2zhjwh6bxdlyzk2ocg2cx6xxjwcmih4mohjs5sokqsa
|
|
||||||
ninja.i2p,q6dg6hlb3egzdqz352ri5rc4fx4gcrdeu3tpiyfxlv73yfjgrhya
|
ninja.i2p,q6dg6hlb3egzdqz352ri5rc4fx4gcrdeu3tpiyfxlv73yfjgrhya
|
||||||
nisankhacharjya.i2p,63env37dvsdtbcwh3kcskfkln7awly7hv42io6vsi6g4gmepqhma
|
|
||||||
njust.i2p,gz7a3bgarghus4xaf4t7fgqvklrdwixxfzyexqrzp7g2b4cq6x3a
|
|
||||||
nm.i2p,3itdpqzyn3ii7sivppo4sxxwhvgtpskzkbokrdibim6gqpvlw5ya
|
nm.i2p,3itdpqzyn3ii7sivppo4sxxwhvgtpskzkbokrdibim6gqpvlw5ya
|
||||||
nnm-club.i2p,xkk5fzxdmjra4xlijoa43h5cfcbusdjc6dbfplulvouxdbztokwq
|
|
||||||
nnmc.i2p,7xizivpjkrpkb76x3yf2yktxscax3wf5vrpofwqgp3wcrnuru53a
|
|
||||||
nntp.baffled.i2p,kc6muo2tih5mttbpzecteegvtonuysjidk3emcy4cm4yifzild2a
|
nntp.baffled.i2p,kc6muo2tih5mttbpzecteegvtonuysjidk3emcy4cm4yifzild2a
|
||||||
nntp.duck.i2p,gvzzor4utsqxswvf6jaglfks7yxudlz2s326ftrk56i4lpd2s47q
|
nntp.duck.i2p,gvzzor4utsqxswvf6jaglfks7yxudlz2s326ftrk56i4lpd2s47q
|
||||||
nntp.fr.i2p,npoztnqadfnu4vrokoh6rusoi3yne47s6jurc3lzhcrzzia5eqva
|
nntp.fr.i2p,npoztnqadfnu4vrokoh6rusoi3yne47s6jurc3lzhcrzzia5eqva
|
||||||
nntp.i2p,wwdzmeyler4djegvyt2bxmkwrckfgg3epkkwowyb75s47he6df6q
|
nntp.i2p,wwdzmeyler4djegvyt2bxmkwrckfgg3epkkwowyb75s47he6df6q
|
||||||
no.i2p,lpsg4x4gdrf7antxcdy47cl6abcqei5ommgzt55retq7go5ku3ba
|
no.i2p,lpsg4x4gdrf7antxcdy47cl6abcqei5ommgzt55retq7go5ku3ba
|
||||||
|
noname56.i2p,oiyoslismzyxuw7ehxoigmtkdj35idim6flmlplddxuiiif6msfa
|
||||||
nop.i2p,ssag45lathm4gqp46si7c4w4tioyvjpcza5uvz5x2zuljnplylca
|
nop.i2p,ssag45lathm4gqp46si7c4w4tioyvjpcza5uvz5x2zuljnplylca
|
||||||
normal.i2p,j5fex634r2altzb3kjvu35qekt2r3hgsqzg5qxoy7dp53heu5pma
|
normal.i2p,j5fex634r2altzb3kjvu35qekt2r3hgsqzg5qxoy7dp53heu5pma
|
||||||
|
normanabcd.i2p,si2vh43gvxjnw2shwr24j76xyanow4oa6gbu4idookbraoxl3s3a
|
||||||
nothingburger.i2p,tesfpn757ysc7nih7mxher2b3jstkc3l5fhfcyb5kxhzhvv52trq
|
nothingburger.i2p,tesfpn757ysc7nih7mxher2b3jstkc3l5fhfcyb5kxhzhvv52trq
|
||||||
nothingspecial.i2p,wzrwqrp52bilqijrlboclynuev4kzpjzfzlvzl5aqxqt5fdnpbga
|
nothingspecial.i2p,wzrwqrp52bilqijrlboclynuev4kzpjzfzlvzl5aqxqt5fdnpbga
|
||||||
novospice.i2p,ukqap24nwac4gns77s4zy7j5cagt7l7syb5zo7eukfg3zn5gg5qq
|
novospice.i2p,ukqap24nwac4gns77s4zy7j5cagt7l7syb5zo7eukfg3zn5gg5qq
|
||||||
noxan.i2p,yses7dxf262wxdwq4plpfv4eu5vb3pqijjkqw77ee3craudlefvq
|
|
||||||
nsa.i2p,nsetvbclpomqxfcit4mghn6z7vdhnza6jdzczby4crnto32uykga
|
nsa.i2p,nsetvbclpomqxfcit4mghn6z7vdhnza6jdzczby4crnto32uykga
|
||||||
nvspc.i2p,anlncoi2fzbsadbujidqmtji7hshfw3nrkqvbgdleepbxx3d5xra
|
nvspc.i2p,anlncoi2fzbsadbujidqmtji7hshfw3nrkqvbgdleepbxx3d5xra
|
||||||
nxt-wallet.i2p,33pp74k4ivy67z332qpyl3qlcqmi6gxqumrow4bldkblxxlxqq5a
|
nxt-wallet.i2p,33pp74k4ivy67z332qpyl3qlcqmi6gxqumrow4bldkblxxlxqq5a
|
||||||
@@ -521,7 +443,6 @@ ogg.baffled.i2p,tfbvj2xal6lcuxv3hzuw7cw4g3whguombcv2zuotzvul4qtrimgq
|
|||||||
ol.i2p,bnb46culzbssz6aipcjkuytanflz6dtndyhmlaxn3pfiv6zqrohq
|
ol.i2p,bnb46culzbssz6aipcjkuytanflz6dtndyhmlaxn3pfiv6zqrohq
|
||||||
onboard.i2p,qwlgxrmv62mhdu6bgkh4ufnxowxsatfb6tbs2zr666qyunwqnecq
|
onboard.i2p,qwlgxrmv62mhdu6bgkh4ufnxowxsatfb6tbs2zr666qyunwqnecq
|
||||||
onelon.i2p,irkvgdnlc6tidoqomre4qr7q4w4qcjfyvbovatgyolk6d4uvcyha
|
onelon.i2p,irkvgdnlc6tidoqomre4qr7q4w4qcjfyvbovatgyolk6d4uvcyha
|
||||||
onhax.i2p,m7i6oe4i3bygx6pn44vn22pgf5kzikw7edr2y5t4cpe5gnqpt3ta
|
|
||||||
onhere.i2p,vwjowg5exhxxsmt4uhjeumuecf5tvticndq2qilfnhzrdumcnuva
|
onhere.i2p,vwjowg5exhxxsmt4uhjeumuecf5tvticndq2qilfnhzrdumcnuva
|
||||||
oniichan.i2p,nnkikjorplul4dlytwfovkne66lwo7ln26xzuq33isvixw3wu3yq
|
oniichan.i2p,nnkikjorplul4dlytwfovkne66lwo7ln26xzuq33isvixw3wu3yq
|
||||||
onionforum.i2p,yadam2bp6hccgy7uvcigf5cabknovj5hrplcqxnufcu4ey33pu5q
|
onionforum.i2p,yadam2bp6hccgy7uvcigf5cabknovj5hrplcqxnufcu4ey33pu5q
|
||||||
@@ -531,23 +452,18 @@ open4you.i2p,ice6ax5qrzwfwzsy64bctffj6zlzpuzdr5np65zsxlbt7hztyc6a
|
|||||||
opendiftracker.i2p,bikpeyxci4zuyy36eau5ycw665dplun4yxamn7vmsastejdqtfoq
|
opendiftracker.i2p,bikpeyxci4zuyy36eau5ycw665dplun4yxamn7vmsastejdqtfoq
|
||||||
openforums.i2p,lho7cvuuzddql24utu7x6mzfsdmxqq7virxp5bcqsxzry2vmwj5q
|
openforums.i2p,lho7cvuuzddql24utu7x6mzfsdmxqq7virxp5bcqsxzry2vmwj5q
|
||||||
opentracker.dg2.i2p,w7tpbzncbcocrqtwwm3nezhnnsw4ozadvi2hmvzdhrqzfxfum7wa
|
opentracker.dg2.i2p,w7tpbzncbcocrqtwwm3nezhnnsw4ozadvi2hmvzdhrqzfxfum7wa
|
||||||
opsec.i2p,rlsjbyy5beucaiedaggyo2tpbq75ituqwnfx4a4qghyifpdk3rra
|
|
||||||
orc.i2p,orcnge47kqnpdj4wb22bg6aqcv5v6yu7kmjf5ll3htvseiqayntq
|
|
||||||
orion.i2p,5vntdqqckjex274sma3uqckwqep2czxs5zew25zlntwoofxk3sga
|
orion.i2p,5vntdqqckjex274sma3uqckwqep2czxs5zew25zlntwoofxk3sga
|
||||||
orz.i2p,oxomqkekybmyk6befjlouesit5mhstonzvzd2xnvsk7i6uyrqsfq
|
orz.i2p,oxomqkekybmyk6befjlouesit5mhstonzvzd2xnvsk7i6uyrqsfq
|
||||||
|
os3.i2p,s7x4ww5osrrfein3xgwyq67wnk6lgliw4mzt7shtu66wrb2zdojq
|
||||||
osiristomb.i2p,t3slf77axkv3qm7c3gzpv3jgmkraoqqe2bojr6h66eipibofsyzq
|
osiristomb.i2p,t3slf77axkv3qm7c3gzpv3jgmkraoqqe2bojr6h66eipibofsyzq
|
||||||
ot.knotwork.i2p,cxhvvfkbp2qbv5qojph7zb46molpe2ffanghnerjag3xdmy6ltxq
|
ot.knotwork.i2p,cxhvvfkbp2qbv5qojph7zb46molpe2ffanghnerjag3xdmy6ltxq
|
||||||
outproxy-tor.an0n.i2p,hpa7ojiz6wdjowwpaegzuczmufnaydggk5qw7vj6utakggkcd2kq
|
|
||||||
outproxy-tor.meeh.i2p,77igjr2pbg73ox5ngqy5ohzvrnur3ezqcogtl4vpuqtrcl3irsqq
|
outproxy-tor.meeh.i2p,77igjr2pbg73ox5ngqy5ohzvrnur3ezqcogtl4vpuqtrcl3irsqq
|
||||||
outproxy.h2ik.i2p,nwgvfpfarpnyjjl4pwsxr2zdsppcx5we3kos2vlwicbiukopgaza
|
outproxy.h2ik.i2p,nwgvfpfarpnyjjl4pwsxr2zdsppcx5we3kos2vlwicbiukopgaza
|
||||||
outproxyng.h2ik.i2p,v32zse2zczzgegelwxbx7n5i2lm2xhh2avltg76h6fz5tb53sfxq
|
outproxyng.h2ik.i2p,v32zse2zczzgegelwxbx7n5i2lm2xhh2avltg76h6fz5tb53sfxq
|
||||||
overchan.oniichan.i2p,g7c54d4b7yva4ktpbaabqeu2yx6axalh4gevb44afpbwm23xuuya
|
overchan.oniichan.i2p,g7c54d4b7yva4ktpbaabqeu2yx6axalh4gevb44afpbwm23xuuya
|
||||||
p4bl0.i2p,lkgdfm4w6e2kkjhcdzr4ahhz26s3aunhrn6t2or436o73qh4z7ga
|
p4bl0.i2p,lkgdfm4w6e2kkjhcdzr4ahhz26s3aunhrn6t2or436o73qh4z7ga
|
||||||
pacman.i2p,hlkzt7mbciez64gf325u5ko3353hfxseblbj7bu4loti3lk2zfha
|
|
||||||
pakalaw43044.i2p,wc36u377c6zonb2o7jn22bbkj3gvjw27vq6nnnj6os2ct6n5qzyq
|
|
||||||
pants.i2p,xez3clscjfafkqwk6f473ccp3yvac4kh6rdp6dptwxa2lhixizgq
|
pants.i2p,xez3clscjfafkqwk6f473ccp3yvac4kh6rdp6dptwxa2lhixizgq
|
||||||
papel.i2p,mxskjqntn2d34q4ovsnd5mud7cgde734tdjldd3lt4hczh2645zq
|
papel.i2p,mxskjqntn2d34q4ovsnd5mud7cgde734tdjldd3lt4hczh2645zq
|
||||||
passwd.i2p,ojugl3kbejhzcmyq7x52ms5lraxsig4ofkhvbgzleraer4zczroa
|
|
||||||
pasta-nojs.i2p,dkkl3ab6iovxfqnp44wsjgqaabznvu7u3hugpzyagbeqlxgvx3la
|
pasta-nojs.i2p,dkkl3ab6iovxfqnp44wsjgqaabznvu7u3hugpzyagbeqlxgvx3la
|
||||||
paste.crypthost.i2p,2zaj4u4s4l3lgas2h5p6c6pvzr2dckylkrh5ngabursj4oh25ozq
|
paste.crypthost.i2p,2zaj4u4s4l3lgas2h5p6c6pvzr2dckylkrh5ngabursj4oh25ozq
|
||||||
paste.i2p2.i2p,b2gizskfea4sjxlw6ru2tb6kdrj47dsjc77cijsf5mzh4ogbmfvq
|
paste.i2p2.i2p,b2gizskfea4sjxlw6ru2tb6kdrj47dsjc77cijsf5mzh4ogbmfvq
|
||||||
@@ -561,7 +477,6 @@ pharos.i2p,vathk2pyvaskeie63yyg4tshjkx5xt6zfvhwhgr3de67q46ob3sa
|
|||||||
pharoz.i2p,vathk2pyvaskeie63yyg4tshjkx5xt6zfvhwhgr3de67q46ob3sa
|
pharoz.i2p,vathk2pyvaskeie63yyg4tshjkx5xt6zfvhwhgr3de67q46ob3sa
|
||||||
phonebooth.i2p,noxia7rv6uvamoy2fkcgyj4ssjpdt4io6lzgx6jl6wujpufxedrq
|
phonebooth.i2p,noxia7rv6uvamoy2fkcgyj4ssjpdt4io6lzgx6jl6wujpufxedrq
|
||||||
photo.i2p,fqhuy77ugd5htnubzkyy5guvwboqn6goahtmn2g7feewvdj7k3iq
|
photo.i2p,fqhuy77ugd5htnubzkyy5guvwboqn6goahtmn2g7feewvdj7k3iq
|
||||||
pidorchan.i2p,5fd222yoxytnmffvh73obszownatnoy3f7ewn565fqw5x4eh7orq
|
|
||||||
piespy.i2p,vzusfjzcu5ntnvobcvyzc4dcu4j6ommtnpmba2puk3kexgdzrl7a
|
piespy.i2p,vzusfjzcu5ntnvobcvyzc4dcu4j6ommtnpmba2puk3kexgdzrl7a
|
||||||
pisekot.i2p,7yzdwhy723fodqz4onp6k3nyvixra2sa6dl45tcblhmyoa7i36nq
|
pisekot.i2p,7yzdwhy723fodqz4onp6k3nyvixra2sa6dl45tcblhmyoa7i36nq
|
||||||
pizdabol.i2p,5vik2232yfwyltuwzq7ht2yocla46q76ioacin2bfofgy63hz6wa
|
pizdabol.i2p,5vik2232yfwyltuwzq7ht2yocla46q76ioacin2bfofgy63hz6wa
|
||||||
@@ -573,39 +488,31 @@ pomoyka.i2p,omt56v4jxa4hurbwk44vqbbcwn3eavuynyc24c25cy7grucjh24q
|
|||||||
pool.gostcoin.i2p,m4f4k3eeaj7otbc254ccj7d5hivguqgnohwelkibr4ddk43qhywa
|
pool.gostcoin.i2p,m4f4k3eeaj7otbc254ccj7d5hivguqgnohwelkibr4ddk43qhywa
|
||||||
pop.mail.i2p,bup6pmac7adgzkb5r6eknk2juczkxigolkwqkbmenawkes5s5qfq
|
pop.mail.i2p,bup6pmac7adgzkb5r6eknk2juczkxigolkwqkbmenawkes5s5qfq
|
||||||
pop.postman.i2p,ipkiowj7x4yjj7jc35yay3c6gauynkkl64gzzyxra3wmyhtfxlya
|
pop.postman.i2p,ipkiowj7x4yjj7jc35yay3c6gauynkkl64gzzyxra3wmyhtfxlya
|
||||||
popeye.i2p,pbvpqyrtxe65flkry32fhms4ztq5y5yh4i6mecze53ykqk36wzua
|
|
||||||
pravtor.i2p,2sr27o5x2v2pyqro7wl5nl6krrsbizwrzsky5y7pkohwh24gn6xq
|
pravtor.i2p,2sr27o5x2v2pyqro7wl5nl6krrsbizwrzsky5y7pkohwh24gn6xq
|
||||||
prepperse.i2p,tjyy6zebjp5ckkkriqcwv5vlrgyhs3wohzngzqmh6brrqo7ewiuq
|
|
||||||
pris.i2p,ahiwycgzuutdxvfqu3wseqffdnhy675nes57s4it2uysy5pxmz6a
|
pris.i2p,ahiwycgzuutdxvfqu3wseqffdnhy675nes57s4it2uysy5pxmz6a
|
||||||
priv.i2p,h4asmxnsw2xz2ve43qt22mhoua7icerhx66ujog5msk6cretnaoq
|
|
||||||
project-future.i2p,ivqynpfwxzl746gxf376lxqvgktql2lqshzwnwjk2twut6xq7xta
|
project-future.i2p,ivqynpfwxzl746gxf376lxqvgktql2lqshzwnwjk2twut6xq7xta
|
||||||
projectencrypt.i2p,lduaunhyg2ohkqth7srhwitnosnaq2dajfafgkhtvz7esluh7mha
|
|
||||||
projectencrypt2.i2p,fiiwjpya6gewxnzw3n2s4uc3smfe5cty4ujyaf5p65kwjmkoggwa
|
|
||||||
projectmayhem2012-086.i2p,ehkjj4ptsagxlo27wpv4a5dk4zxqf4kg4p6fh35xrlz4y6mhe4eq
|
projectmayhem2012-086.i2p,ehkjj4ptsagxlo27wpv4a5dk4zxqf4kg4p6fh35xrlz4y6mhe4eq
|
||||||
protokol.i2p,f4xre35ehc5l6ianjvt3zcktxkjlyp2iwdje65qnu2j6vurhy6nq
|
protokol.i2p,f4xre35ehc5l6ianjvt3zcktxkjlyp2iwdje65qnu2j6vurhy6nq
|
||||||
|
proxynet.i2p,7gar5a3n4hzvsgi73iizo65mjza4kujf7feopfxuwu5p6wtwog5a
|
||||||
psi.i2p,avviiexdngd32ccoy4kuckvc3mkf53ycvzbz6vz75vzhv4tbpk5a
|
psi.i2p,avviiexdngd32ccoy4kuckvc3mkf53ycvzbz6vz75vzhv4tbpk5a
|
||||||
psy.i2p,s3elzoj3wo6v6wqu5ehd56vevpz2vrhhjc5m6mxoazicrl43y62q
|
psy.i2p,s3elzoj3wo6v6wqu5ehd56vevpz2vrhhjc5m6mxoazicrl43y62q
|
||||||
psyco.i2p,eoilbrgyaiikxzdtmk2zeoalteupjrvcu3ui23p4wvfqo25bb73q
|
psyco.i2p,eoilbrgyaiikxzdtmk2zeoalteupjrvcu3ui23p4wvfqo25bb73q
|
||||||
pt.hiddenanswers.i2p,o5jlxbbnx3byzgmihqye3kysop5jgl3unsrkmurbtr2nrnl2y74a
|
pt.hiddenanswers.i2p,o5jlxbbnx3byzgmihqye3kysop5jgl3unsrkmurbtr2nrnl2y74a
|
||||||
ptm.i2p,7dna5745ynxgogpjermnq26hwrqyjdlsibpjfmjxlwig247bjisa
|
ptm.i2p,7dna5745ynxgogpjermnq26hwrqyjdlsibpjfmjxlwig247bjisa
|
||||||
ptt.i2p,q7r32j7lc3xgrcw2ym33wv4lfgqbez7vtm4lts7n34qfe3iygeha
|
ptt.i2p,q7r32j7lc3xgrcw2ym33wv4lfgqbez7vtm4lts7n34qfe3iygeha
|
||||||
publicwww.i2p,oitoja234mwfbeuhtuibnxn6hd5v4nbtf7oxfgdhk5igrg6wkiqq
|
|
||||||
pull.git.repo.i2p,3so7htzxzz6h46qvjm3fbd735zl3lrblerlj2xxybhobublcv67q
|
pull.git.repo.i2p,3so7htzxzz6h46qvjm3fbd735zl3lrblerlj2xxybhobublcv67q
|
||||||
push.git.repo.i2p,jef4g5vxnqybm4zpouum3lzbl6ti6456q57nbyj5kfyldkempm3a
|
push.git.repo.i2p,jef4g5vxnqybm4zpouum3lzbl6ti6456q57nbyj5kfyldkempm3a
|
||||||
pycache.awup.i2p,w45lkxdnqhil4sgzanmxce62sv3q4szeowcjb2e72a5y5vbhm4ra
|
pycache.awup.i2p,w45lkxdnqhil4sgzanmxce62sv3q4szeowcjb2e72a5y5vbhm4ra
|
||||||
r4sas.i2p,2gafixvoztrndawkmhfxamci5lgd3urwnilxqmlo6ittu552cndq
|
r4sas.i2p,2gafixvoztrndawkmhfxamci5lgd3urwnilxqmlo6ittu552cndq
|
||||||
radio.r4sas.i2p,cv72xsje5ihg6e24atitmhyk2cbml6eggi6b6fjfh2vgw62gdpla
|
radio.r4sas.i2p,cv72xsje5ihg6e24atitmhyk2cbml6eggi6b6fjfh2vgw62gdpla
|
||||||
ragnarok.i2p,jpzw6kbuzz3ll2mfi3emcaan4gidyt7ysdhu62r5k5xawrva7kca
|
ragnarok.i2p,jpzw6kbuzz3ll2mfi3emcaan4gidyt7ysdhu62r5k5xawrva7kca
|
||||||
ramsay.i2p,svezv4xrp4l57ankyhu6qisd5jnk423n7oa5as3zd2554aaz6lkq
|
|
||||||
ransack.i2p,mqamk4cfykdvhw5kjez2gnvse56gmnqxn7vkvvbuor4k4j2lbbnq
|
ransack.i2p,mqamk4cfykdvhw5kjez2gnvse56gmnqxn7vkvvbuor4k4j2lbbnq
|
||||||
rasputin-sucks.i2p,fdozdbyak4rul4jwpqfisbkcx4xbrkuvf2o5r6fd3xryyrjgvjiq
|
rasputin-sucks.i2p,fdozdbyak4rul4jwpqfisbkcx4xbrkuvf2o5r6fd3xryyrjgvjiq
|
||||||
rebel.i2p,nch2arl45crkyk6bklyk2hrdwjf5nztyxdtoshy6llhwqgxho5jq
|
rebel.i2p,nch2arl45crkyk6bklyk2hrdwjf5nztyxdtoshy6llhwqgxho5jq
|
||||||
red.i2p,fzbdltgsg7jrpz7gmjfvhpcdnw5yrglwspnxqp4zoym3bglntzfa
|
red.i2p,fzbdltgsg7jrpz7gmjfvhpcdnw5yrglwspnxqp4zoym3bglntzfa
|
||||||
redliberty.i2p,co4edoxfpapksavjpbkd4h33s6pijr6xyfioqdbbdh22y3zrwoba
|
|
||||||
redpanda.i2p,3wcnp6afz4cikqzdu2ktb5wfz7hb3ejdbpn7ocpy7fmeqyzbaiea
|
redpanda.i2p,3wcnp6afz4cikqzdu2ktb5wfz7hb3ejdbpn7ocpy7fmeqyzbaiea
|
||||||
redzara.i2p,ty7bt62rw5ryvk44dd3v5sua6c7wnbpxxqb6v4dohajmwmezi7va
|
redzara.i2p,ty7bt62rw5ryvk44dd3v5sua6c7wnbpxxqb6v4dohajmwmezi7va
|
||||||
reefer.i2p,4cde25mrrnt5n4nvp5tl62gej33nekfvq2viubmx4xdakhm5pfaa
|
reefer.i2p,4cde25mrrnt5n4nvp5tl62gej33nekfvq2viubmx4xdakhm5pfaa
|
||||||
reg.rus.i2p,k2r2wda4eavt4hoq5hptprqfmixusirq3gi5bl3z2pqzcd6felwa
|
|
||||||
relatelist.i2p,utrer5zgnou72hs4eztmk37pmzdtfw3d6s23wwl7nk3lkqpzbdiq
|
relatelist.i2p,utrer5zgnou72hs4eztmk37pmzdtfw3d6s23wwl7nk3lkqpzbdiq
|
||||||
repo.i2p,uxe3lqueuuyklel23sf5h25zwgqgjwsofrqchhnptd5y6pedzbxa
|
repo.i2p,uxe3lqueuuyklel23sf5h25zwgqgjwsofrqchhnptd5y6pedzbxa
|
||||||
repo.r4sas.i2p,ymzx5zgt6qzdg6nhxnecdgbqjd34ery6mpqolnbyo5kcwxadnodq
|
repo.r4sas.i2p,ymzx5zgt6qzdg6nhxnecdgbqjd34ery6mpqolnbyo5kcwxadnodq
|
||||||
@@ -621,8 +528,6 @@ rootd.i2p,mzbe5wofwn7eaqq4yefrmxizqaxoslwqxrv5qcv2opx5lnhg64dq
|
|||||||
rospravosudie.i2p,z55khrnlj6bzhs5zielutm6ae6t2bbhfuiujwlrp3teubqyc4w7q
|
rospravosudie.i2p,z55khrnlj6bzhs5zielutm6ae6t2bbhfuiujwlrp3teubqyc4w7q
|
||||||
rotten.i2p,j4bm3rvezlejnb44elniagi5v2gazh7jaqrzhbod2pbxmgeb2frq
|
rotten.i2p,j4bm3rvezlejnb44elniagi5v2gazh7jaqrzhbod2pbxmgeb2frq
|
||||||
rpi.i2p,56p5qxsrvo5ereibevetw2qbj5bronmos7wxunku27g2s4kpbnlq
|
rpi.i2p,56p5qxsrvo5ereibevetw2qbj5bronmos7wxunku27g2s4kpbnlq
|
||||||
rs-freenet.i2p,jhpvnnhfrozore2wlhi5m5bzggz5jcz5uwhou4w62ylkewtoxqba
|
|
||||||
rs-tor.i2p,zv2etzurnqjuuajmeb5gg3sjhfdcotxvlae6igxbfyahkjhhsx4a
|
|
||||||
rslight.i2p,bitag46q3465nylvzuikfwjcj7ewi4gjkjtvuxhn73f6vsxffyiq
|
rslight.i2p,bitag46q3465nylvzuikfwjcj7ewi4gjkjtvuxhn73f6vsxffyiq
|
||||||
rsync.thetower.i2p,w4brpcdod7wnfqhwqrxyt4sbf2acouqfk5wyosfpq4mxq4s35kqa
|
rsync.thetower.i2p,w4brpcdod7wnfqhwqrxyt4sbf2acouqfk5wyosfpq4mxq4s35kqa
|
||||||
ru.hiddenanswers.i2p,o6rmndvggfwnuvxwyq54y667fmmurgveerlzufyrhub6w3vkagva
|
ru.hiddenanswers.i2p,o6rmndvggfwnuvxwyq54y667fmmurgveerlzufyrhub6w3vkagva
|
||||||
@@ -630,22 +535,16 @@ ru.i2p,m7fqktjgtmsb3x7bvfrdx4tf7htnhytnz5qi2ujjcnph33u3hnja
|
|||||||
rufurus.i2p,7msryymfdta3ssyz34qur6gi4jyfkvca5iyfmnceviipwu7g2wca
|
rufurus.i2p,7msryymfdta3ssyz34qur6gi4jyfkvca5iyfmnceviipwu7g2wca
|
||||||
rus.i2p,gh6655arkncnbrzq5tmq4xpn36734d4tdza6flbw5xppye2dt6ga
|
rus.i2p,gh6655arkncnbrzq5tmq4xpn36734d4tdza6flbw5xppye2dt6ga
|
||||||
ruslibgen.i2p,kk566cv37hivbjafiij5ryoui2ebxnm7b25gb3troniixopaj6nq
|
ruslibgen.i2p,kk566cv37hivbjafiij5ryoui2ebxnm7b25gb3troniixopaj6nq
|
||||||
rust.i2p,xbl2dh2qugfgoobebkvkjje3ovp5owhqdlu3l4briiqnhyuihjwa
|
|
||||||
rutor.i2p,tro5tvvtd2qg34naxhvqp4236it36jjaipbda5vnjmggp55navdq
|
rutor.i2p,tro5tvvtd2qg34naxhvqp4236it36jjaipbda5vnjmggp55navdq
|
||||||
rutracker.i2p,ujyqbawolalwvdpy33v2wjuaspnu4ym3fsl3fd6mldjblzzqlvlq
|
|
||||||
s.i2p,bnpc454fvuzqk22ywguqb4m4vkhrcfj3pydrbfw4esqklymd7t3a
|
|
||||||
salt.i2p,6aflphlze6btsbez5cm4x53ydrmwhqrkxsud535d3qjh4wq62rxq
|
salt.i2p,6aflphlze6btsbez5cm4x53ydrmwhqrkxsud535d3qjh4wq62rxq
|
||||||
sasquotch.i2p,p6535uyfk2y6etc3t47vd3oqxydznqior5jxcvq5bdxe5kw5th6q
|
sasquotch.i2p,p6535uyfk2y6etc3t47vd3oqxydznqior5jxcvq5bdxe5kw5th6q
|
||||||
schwarzwald.i2p,4gokilzy73mmudufy3pohgatm42fcstx7uzg5hjvnfyphxpnphuq
|
schwarzwald.i2p,4gokilzy73mmudufy3pohgatm42fcstx7uzg5hjvnfyphxpnphuq
|
||||||
sciencebooks.i2p,ypftjpgck75swz3bnsu4nw7rmrlr2vqsn4mwivwt3zcc3rxln5cq
|
sciencebooks.i2p,ypftjpgck75swz3bnsu4nw7rmrlr2vqsn4mwivwt3zcc3rxln5cq
|
||||||
scp.duck.i2p,ghbpsolpnveizxu4wbs7jbs2vj3kntnsexfcdleyhpqdhfpxleda
|
scp.duck.i2p,ghbpsolpnveizxu4wbs7jbs2vj3kntnsexfcdleyhpqdhfpxleda
|
||||||
search.i2p,nz4qj6xaw5fda3rsmsax6yjthqy4c7uak2j3dzcehtkgyso4q46q
|
search.i2p,nz4qj6xaw5fda3rsmsax6yjthqy4c7uak2j3dzcehtkgyso4q46q
|
||||||
searx.i2p,lcjxhuo5lbrol3e5ijj3ga4gdhhelzdyslc7bm4blw6jy6cx4p5a
|
|
||||||
searxes.i2p,2v2wkxi52vukbmcfkyg356pml2nwrca3rf6xjnw7bstblxfmcldq
|
|
||||||
secretchat.i2p,cl3j2zxhpw6u6jevny45i557ojhwfxn4g375nnuqhy6lp27mry2q
|
secretchat.i2p,cl3j2zxhpw6u6jevny45i557ojhwfxn4g375nnuqhy6lp27mry2q
|
||||||
secure.thetinhat.i2p,4q3qyzgz3ub5npbmt3vqqege5lg4zy62rhbgage4lpvnujwfpala
|
secure.thetinhat.i2p,4q3qyzgz3ub5npbmt3vqqege5lg4zy62rhbgage4lpvnujwfpala
|
||||||
seeker.i2p,ipll7sit24oyhnwawpvokz5u7dabq6klveuqpx3sbi6o5qemy2bq
|
seeker.i2p,ipll7sit24oyhnwawpvokz5u7dabq6klveuqpx3sbi6o5qemy2bq
|
||||||
sendyourdreamswherenobodyhides.i2p,jvdg3yqjqthtcfjitzqdp2cc3zjloit46xafprevl3bhpeqxf5pq
|
|
||||||
seomon.i2p,5mvpsy4h45w4fx7upen7ay3vkrs5klphz5nptmtcqvc3fsajsm4q
|
seomon.i2p,5mvpsy4h45w4fx7upen7ay3vkrs5klphz5nptmtcqvc3fsajsm4q
|
||||||
septu.i2p,5lqvih7yzbqacfi63hwnmih57dxopu5g2o5o4e2aorq7bt4ooyra
|
septu.i2p,5lqvih7yzbqacfi63hwnmih57dxopu5g2o5o4e2aorq7bt4ooyra
|
||||||
serien.i2p,3z5k3anbbk32thinvwcy4g5al7dmb75fagcm3zgh4rzrt3maphda
|
serien.i2p,3z5k3anbbk32thinvwcy4g5al7dmb75fagcm3zgh4rzrt3maphda
|
||||||
@@ -654,8 +553,6 @@ shiftfox.i2p,wpvnuzslu7hjy4gujvnphtyckchdoxccrlhbyomsmjizykczyseq
|
|||||||
shoieq3.i2p,3fjk4nfk3mccch4hdreghnyijcvovsi3yucjz3qzj5sxngqk5j6q
|
shoieq3.i2p,3fjk4nfk3mccch4hdreghnyijcvovsi3yucjz3qzj5sxngqk5j6q
|
||||||
shoronil.i2p,7shqzgmb6tabiwrnwlasruq7pswy2d3emvfhaitehkqgod7i62sa
|
shoronil.i2p,7shqzgmb6tabiwrnwlasruq7pswy2d3emvfhaitehkqgod7i62sa
|
||||||
short.i2p,z5mt5rvnanlex6r3x3jnjhzzfqpv36r4ylesynigytegjmebauba
|
short.i2p,z5mt5rvnanlex6r3x3jnjhzzfqpv36r4ylesynigytegjmebauba
|
||||||
silc2p.i2p,wt4mvbvnpqniywcpkrrjubvcwyskskujxjkhk24xmhrojdeisoja
|
|
||||||
silence.i2p,v4oc37covf4tze2wjhtgn3xkpgg4cx6oam44xvnpw2snhtvpslyq
|
|
||||||
sion.i2p,lcbmmw2tvplvqh2dq5lmpxl3vnd5o4j3bdul5moa23deakjrso5q
|
sion.i2p,lcbmmw2tvplvqh2dq5lmpxl3vnd5o4j3bdul5moa23deakjrso5q
|
||||||
sirup.i2p,aohdp4yajnkitrtw7v2mo3sp7swuqhjfwlsi5xwd7dudzftumsma
|
sirup.i2p,aohdp4yajnkitrtw7v2mo3sp7swuqhjfwlsi5xwd7dudzftumsma
|
||||||
site.games.i2p,zeuczucfxeev3k7tvqlfcdpfbnqggheiknyyb5r2q4utn3d2auja
|
site.games.i2p,zeuczucfxeev3k7tvqlfcdpfbnqggheiknyyb5r2q4utn3d2auja
|
||||||
@@ -665,8 +562,6 @@ slacker.i2p,wq7m2wdguzweleb666ygv3bmfhha63zj74rub76vfesbyhsyk6iq
|
|||||||
smeghead.i2p,ojf4czveeuekxqkjvkszvv7eiop5dg7x2p6rgfzl4ng4xrjk6lja
|
smeghead.i2p,ojf4czveeuekxqkjvkszvv7eiop5dg7x2p6rgfzl4ng4xrjk6lja
|
||||||
smtp.mail.i2p,kdn7zx7fgoe4bn5abaaj5cb3e4ql22fklb5veui5yajpj4cxapya
|
smtp.mail.i2p,kdn7zx7fgoe4bn5abaaj5cb3e4ql22fklb5veui5yajpj4cxapya
|
||||||
smtp.postman.i2p,jj7pt6chsziz6oxxnzpqj7mzhxm2xfhcrbh7dl3tegifb577vx5q
|
smtp.postman.i2p,jj7pt6chsziz6oxxnzpqj7mzhxm2xfhcrbh7dl3tegifb577vx5q
|
||||||
snscib.i2p,x2jvcrskymvnfxnrtpji5orivskmltl3ochad4cedxe4ceklc4va
|
|
||||||
socialhub.i2p,fznbboc5py5rqyxwa76jw5zo4e6x53pcnfyts76vnt4vwaqj6paq
|
|
||||||
socks1.tor.i2p,sifawcdexgdmoc3krv46pvvz74nzd6fkju2vzykjxsx3egqsb6wq
|
socks1.tor.i2p,sifawcdexgdmoc3krv46pvvz74nzd6fkju2vzykjxsx3egqsb6wq
|
||||||
sonax.i2p,jmuxdhlok5ggojehesfjlit2e2q3fhzwwfxjndts7vzdshucbjjq
|
sonax.i2p,jmuxdhlok5ggojehesfjlit2e2q3fhzwwfxjndts7vzdshucbjjq
|
||||||
sponge.i2p,o5hu7phy7udffuhts6w5wn5mw3sepwe3hyvw6kthti33wa2xn5tq
|
sponge.i2p,o5hu7phy7udffuhts6w5wn5mw3sepwe3hyvw6kthti33wa2xn5tq
|
||||||
@@ -682,60 +577,38 @@ str4d.i2p,wrrwzdgsppwl2g2bdohhajz3dh45ui6u3y7yuop5ivvfzxtwnipa
|
|||||||
stream.i2p,prmbv3xm63ksoetnhbzqg4nzu2lhqdnqytgsydb7u3quxfrg7rna
|
stream.i2p,prmbv3xm63ksoetnhbzqg4nzu2lhqdnqytgsydb7u3quxfrg7rna
|
||||||
streams.darkrealm.i2p,ud3gcmvysjch4lbjr2khmhqpf7r2x5if4q43xkqdptl4k7lc4muq
|
streams.darkrealm.i2p,ud3gcmvysjch4lbjr2khmhqpf7r2x5if4q43xkqdptl4k7lc4muq
|
||||||
striker.i2p,4gswsrfpbd44hwjoj33jbqfbwzxfkwpuplb3ydq5zm7nfu2pxvdq
|
striker.i2p,4gswsrfpbd44hwjoj33jbqfbwzxfkwpuplb3ydq5zm7nfu2pxvdq
|
||||||
studentbookshop.i2p,d2ejfxjt3n2nsj6hlkepwjgxua5jg766znrxz65d5eixsmiwvr3q
|
|
||||||
subrosa.i2p,g3lnglrnoual7wyabnwwv37uwhadgbxiqz36pf3f5cwfuxsx4mxq
|
subrosa.i2p,g3lnglrnoual7wyabnwwv37uwhadgbxiqz36pf3f5cwfuxsx4mxq
|
||||||
subterra.i2p,vdmhe4u26unzgd7ysq6w36ubjncms5wzbhzr2gq576sq4xut5zwq
|
subterra.i2p,vdmhe4u26unzgd7ysq6w36ubjncms5wzbhzr2gq576sq4xut5zwq
|
||||||
sugadude.i2p,yzjn76iyqard64wgggfrnywkxi7tbfkw7mjhpviqz3p2dguey4yq
|
sugadude.i2p,yzjn76iyqard64wgggfrnywkxi7tbfkw7mjhpviqz3p2dguey4yq
|
||||||
suicidal.i2p,yfamynllow5xiqbbca7eh5xn733wtnuti5bi4ovc7dwycntqmiuq
|
suicidal.i2p,yfamynllow5xiqbbca7eh5xn733wtnuti5bi4ovc7dwycntqmiuq
|
||||||
sun.i2p,33mt3psjrtauk6wzt35ke7w4bkyizesnsjlal45fbosja2j5i74q
|
|
||||||
sungo.i2p,h67s3jw56rwfyoxqxj3fngrluybsgxc2meendngkehzqowxnpj3q
|
sungo.i2p,h67s3jw56rwfyoxqxj3fngrluybsgxc2meendngkehzqowxnpj3q
|
||||||
super.i2p,2oopfqdsylutqnxstwq4ppafbk5cmrl3be7pid3orcia4bnoisfa
|
|
||||||
surrender.adab.i2p,jgz7xglgfgnjfklrytyn427np2ubipztlm5bxrtbiucayglukrta
|
surrender.adab.i2p,jgz7xglgfgnjfklrytyn427np2ubipztlm5bxrtbiucayglukrta
|
||||||
susi.i2p,qc6g2qfi2ccw7vjwpst6rwuofgzbeoewsb2usv7rubutf4gzqveq
|
susi.i2p,qc6g2qfi2ccw7vjwpst6rwuofgzbeoewsb2usv7rubutf4gzqveq
|
||||||
syncline.i2p,5kcqmhislu3lmr7llgmdl72yu3efhyriljdc6wp774ftpwlcs5ra
|
syncline.i2p,5kcqmhislu3lmr7llgmdl72yu3efhyriljdc6wp774ftpwlcs5ra
|
||||||
syndie-project.i2p,xa63tpfoaqt3zru2ehxjjfbpadwj4ha6qsdvtcqtyr3b7hmt4iaq
|
syndie-project.i2p,xa63tpfoaqt3zru2ehxjjfbpadwj4ha6qsdvtcqtyr3b7hmt4iaq
|
||||||
syndie.echelon.i2p,vwrl2qmcif722fdkn3ldxcgz76df5cq4qypbndzthxwgmykyewta
|
syndie.echelon.i2p,vwrl2qmcif722fdkn3ldxcgz76df5cq4qypbndzthxwgmykyewta
|
||||||
syndie.i2p,7lm3yzpuejhpl4tt4l7o4ndqlu7hgijohofh7oaydx7q7kelenbq
|
syndie.i2p,7lm3yzpuejhpl4tt4l7o4ndqlu7hgijohofh7oaydx7q7kelenbq
|
||||||
syndie.tiny.i2p,lvxboy6ni52i7dwe4a54xe7uxz3dwhy66jaqcmn4q6yzdrrf2xya
|
|
||||||
syndie2.tiny.i2p,5iov5rqup5ji6os3zpxvgzfztnbpfp3d7jh2xchwyx6dmykwdzua
|
|
||||||
syndiemedia.i2p,4lrbbblclodhobn3jadt5bf2yab2pxzoz4ey4a2cvrl44tdv3jma
|
syndiemedia.i2p,4lrbbblclodhobn3jadt5bf2yab2pxzoz4ey4a2cvrl44tdv3jma
|
||||||
t3chkommie.i2p,o5avgwuwjdyefw4xddn77jxaljs5gg3adg3gnpu26s2hijnrfvca
|
|
||||||
tabak.i2p,y5o2vwb6kart7ivpnbpk4yte3i7kf2dsx7fy3i6w7htqtxhmbzia
|
tabak.i2p,y5o2vwb6kart7ivpnbpk4yte3i7kf2dsx7fy3i6w7htqtxhmbzia
|
||||||
tahoeserve.i2p,yhs7tsjeznxdenmdho5gjmk755wtredfzipb5t272oi5otipfkoa
|
tahoeserve.i2p,yhs7tsjeznxdenmdho5gjmk755wtredfzipb5t272oi5otipfkoa
|
||||||
talkfreedom.i2p,tbbikimv62ltdurcljry5fp3riokah3oi2dyksfa26e2pjugddwa
|
|
||||||
tbofh.i2p,lmj2gu6d27pgrknbxxsyapjxnlprau4ayamcam6csljzlupr2rtq
|
|
||||||
tc.i2p,qkv2yk6rof3rh7n3eelg5niujae6cmdzcpqbv3wsttedxtqqqj7a
|
tc.i2p,qkv2yk6rof3rh7n3eelg5niujae6cmdzcpqbv3wsttedxtqqqj7a
|
||||||
telegram.i2p,i6jow7hymogz2s42xq62gqgej2zdm4xtnmpc6vjcwktdxpdoupja
|
telegram.i2p,i6jow7hymogz2s42xq62gqgej2zdm4xtnmpc6vjcwktdxpdoupja
|
||||||
templar.i2p,zxeralsujowfpyi2ynyjooxy222pzz4apc2qcwrfx5ikhf64et7q
|
templar.i2p,zxeralsujowfpyi2ynyjooxy222pzz4apc2qcwrfx5ikhf64et7q
|
||||||
templeofmetal.i2p,cwtbmqx3cg7ae3jcrzgjzwcilpypnyz2biojrn4ca7ry5gukaixa
|
|
||||||
terror.i2p,wsijm6aqz4qtuyn2jedpx6imar5uq4yuhjdgtfqumxbqww47vbnq
|
terror.i2p,wsijm6aqz4qtuyn2jedpx6imar5uq4yuhjdgtfqumxbqww47vbnq
|
||||||
textboard.i2p,7ubwrcixdcemzqwqzh2vaakjsnochj2biuzpo6dc2n4f7wqj4pua
|
|
||||||
thebland.i2p,oiviukgwapzxsrwxsoucpqa47s3wt6nfuhfjxvgbqsyrze2mwrda
|
thebland.i2p,oiviukgwapzxsrwxsoucpqa47s3wt6nfuhfjxvgbqsyrze2mwrda
|
||||||
thebreton.i2p,woutbsflcrlgppx4y7ag2kawlqijyenvlwrhbbvbkoaksuhf2hkq
|
thebreton.i2p,woutbsflcrlgppx4y7ag2kawlqijyenvlwrhbbvbkoaksuhf2hkq
|
||||||
theclonedome.i2p,jyezrlobwwbhar2xbntf2d64yugcje6z2d3oxb5addyho72co2gq
|
|
||||||
thedarkside.i2p,fxt3z33nzkrg5kjrk7bp5vvmu7w2vsn4i6jo6cily3hsm6u664ca
|
thedarkside.i2p,fxt3z33nzkrg5kjrk7bp5vvmu7w2vsn4i6jo6cily3hsm6u664ca
|
||||||
theland.i2p,26ppxbseda6xmim37ksarccdb4q5ctdagfmt2u5aba6xjh452zsa
|
theland.i2p,26ppxbseda6xmim37ksarccdb4q5ctdagfmt2u5aba6xjh452zsa
|
||||||
thematrix.i2p,kgh3va66n5fqrtlhqsen2km6x7k2362hn5edk5o5q5dcr72nnajq
|
|
||||||
therealprojectencrypt.i2p,vrdaftozwabkzy26adg77adhszpyil4xbswkogbituhkhsl7tlzq
|
|
||||||
thetower.i2p,3xqa5nype64y6fxgqjq6r5w2qpiqftoraj2niebumseat4cj654a
|
thetower.i2p,3xqa5nype64y6fxgqjq6r5w2qpiqftoraj2niebumseat4cj654a
|
||||||
thisthingimade.i2p,bga2ae2ff3s5p2nskg2l37ns2ad6smczpvgjhm2olgxequogepja
|
|
||||||
thornworld.i2p,vinz4ygmodxarocntyjlfwk2wjpvzndlf4hxss2w2t3fk52oplva
|
thornworld.i2p,vinz4ygmodxarocntyjlfwk2wjpvzndlf4hxss2w2t3fk52oplva
|
||||||
thoughtfoundryblog.i2p,beoipfwqq5ebx2ywh2rcjwi7th5diaax23mvktppl4gk2pddrf5a
|
|
||||||
tino.i2p,e4bfnhvaofu4s67ztcgiskos2mqyhskid64dvlqexxs2c2bno3iq
|
tino.i2p,e4bfnhvaofu4s67ztcgiskos2mqyhskid64dvlqexxs2c2bno3iq
|
||||||
tiny.i2p,elmeki5nvczhe4mnq6yb64wpocilkwacw2cshyvq2hrvkhbivqya
|
|
||||||
tinyslibrary.i2p,nv5ysd44xz6dgc6y3hxe22tfonmcikegm76l633oqfuyfo26odva
|
|
||||||
tinyurl.i2p,mc4oxv3v7dnyzpvok7v5qxkwtgjprgyz6w7x3tag4fipsen6rdwa
|
tinyurl.i2p,mc4oxv3v7dnyzpvok7v5qxkwtgjprgyz6w7x3tag4fipsen6rdwa
|
||||||
tipped8.i2p,5l2mzforxf5kok7ndc6m53nfxve75m5tozb37m6eg2xsaf6hdlmq
|
|
||||||
tome.i2p,qktkxwawgixrm5lzofnj5n24zspbnzxy4pvjm7uvaxvmgwrsuvgq
|
tome.i2p,qktkxwawgixrm5lzofnj5n24zspbnzxy4pvjm7uvaxvmgwrsuvgq
|
||||||
tooman.i2p,auo7cuq4dovgniwojq5fbwyjuvmks3zv7aopu5f6onsckuihsdpa
|
|
||||||
top4ek.i2p,hm3fpmxchlvqc3p4atnu7igwbenqpn7f3czbptnnqataemputl4q
|
|
||||||
tor-gw.meeh.i2p,ounrqi7cfemnt66yhnhigt2u27fkctbvct527cp2522ozy3btjza
|
tor-gw.meeh.i2p,ounrqi7cfemnt66yhnhigt2u27fkctbvct527cp2522ozy3btjza
|
||||||
tor-www-proxy.i2p,xov45rvjks5fe4ofmpblkj23bnwxgslbypbgvchbr7yul2ujej2q
|
tor-www-proxy.i2p,xov45rvjks5fe4ofmpblkj23bnwxgslbypbgvchbr7yul2ujej2q
|
||||||
torapa.i2p,eejqjtpko6mdd4opvntbpsuandstrebxpbymfhix7avp5obrw5ta
|
torapa.i2p,eejqjtpko6mdd4opvntbpsuandstrebxpbymfhix7avp5obrw5ta
|
||||||
tordox.i2p,3wv6wn3h5tr57evns5bgf2rbwivai7zhajlgt5fr3blxvp6bybbq
|
|
||||||
torrentfinder.i2p,mpc73okj7wq2xl6clofl64cn6v7vrvhpmi6d524nrsvbeuvjxalq
|
torrentfinder.i2p,mpc73okj7wq2xl6clofl64cn6v7vrvhpmi6d524nrsvbeuvjxalq
|
||||||
torrfreedom.i2p,nfrjvknwcw47itotkzmk6mdlxmxfxsxhbhlr5ozhlsuavcogv4hq
|
torrfreedom.i2p,nfrjvknwcw47itotkzmk6mdlxmxfxsxhbhlr5ozhlsuavcogv4hq
|
||||||
tourist-destinations.i2p,s4lyjsubxnlw5zytyvq2v2lroscuqwoxu3ukrg3akh6tybm25qfa
|
|
||||||
trac.i2p,kyioa2lgdi2za2fwfwajnb3ljz6zwlx7yzjdpnxnch5uw3iqn6ca
|
trac.i2p,kyioa2lgdi2za2fwfwajnb3ljz6zwlx7yzjdpnxnch5uw3iqn6ca
|
||||||
trac.i2p2.i2p,i43xzkihpdq34f2jlmtgiyyay5quafg5rebog7tk7xil2c6kbyoa
|
trac.i2p2.i2p,i43xzkihpdq34f2jlmtgiyyay5quafg5rebog7tk7xil2c6kbyoa
|
||||||
tracker-fr.i2p,qfrvqrfoqkistgzo2oxpfduz4ktkhtqopleozs3emblmm36fepea
|
tracker-fr.i2p,qfrvqrfoqkistgzo2oxpfduz4ktkhtqopleozs3emblmm36fepea
|
||||||
@@ -753,17 +626,15 @@ tracker2.postman.i2p,ahsplxkbhemefwvvml7qovzl5a2b5xo5i7lyai7ntdunvcyfdtna
|
|||||||
traditio.i2p,wkpjjloylf6jopu2itgpktr45t2xvpjijxilxd5tq4i7wkqgwhhq
|
traditio.i2p,wkpjjloylf6jopu2itgpktr45t2xvpjijxilxd5tq4i7wkqgwhhq
|
||||||
trevorreznik.i2p,wc2z6o5fxm2saqzpfcawr63lejwccvzkysmgtfudkrigqopzfdma
|
trevorreznik.i2p,wc2z6o5fxm2saqzpfcawr63lejwccvzkysmgtfudkrigqopzfdma
|
||||||
true.i2p,pdilhl5vmefyzrrnmak5bnmxqxk2pmw7rpy4f7wbaeppqu2vvugq
|
true.i2p,pdilhl5vmefyzrrnmak5bnmxqxk2pmw7rpy4f7wbaeppqu2vvugq
|
||||||
trumpusa.i2p,vopyffqj3il2uapcvfxq2zkcdybf7ekmpvnrt6d4dbeuecbvs2ea
|
|
||||||
trwcln.i2p,evml6jiiujhulsgxkdu3wcmkwbokxlv4is6w5qj46tp3ajz3hqzq
|
trwcln.i2p,evml6jiiujhulsgxkdu3wcmkwbokxlv4is6w5qj46tp3ajz3hqzq
|
||||||
|
trypanom.i2p,tgv5acj4khwvr6t44cmryohybd2e5o2kndysnzae6qwcr4hzda3q
|
||||||
ts.i2p,nebcjgfx3f7q4wzihqmguwcdeopaf7f6wyk2dojw4bcuku472zxq
|
ts.i2p,nebcjgfx3f7q4wzihqmguwcdeopaf7f6wyk2dojw4bcuku472zxq
|
||||||
ttc.i2p,wb4tsfyvfv4idgrultsq6o7inza4fxkc7dijsfpncbx7zko4cdlq
|
ttc.i2p,wb4tsfyvfv4idgrultsq6o7inza4fxkc7dijsfpncbx7zko4cdlq
|
||||||
ttp.i2p,uuczclxejmetohwf2vqewovx3qcumdfh5zecjb3xkcdmk6e5j72a
|
ttp.i2p,uuczclxejmetohwf2vqewovx3qcumdfh5zecjb3xkcdmk6e5j72a
|
||||||
tumbach.i2p,u6pciacxnpbsq7nwc3tgutywochfd6aysgayijr7jxzoysgxklvq
|
tumbach.i2p,u6pciacxnpbsq7nwc3tgutywochfd6aysgayijr7jxzoysgxklvq
|
||||||
tutorials.i2p,zy37tq6ynucp3ufoyeegswqjaeofmj57cpm5ecd7nbanh2h6f2ja
|
tutorials.i2p,zy37tq6ynucp3ufoyeegswqjaeofmj57cpm5ecd7nbanh2h6f2ja
|
||||||
ubuntudvm.i2p,wpsw5eon3ecsys5pe4whbbetga6znznmiiwwynhp37qdlxxcqwca
|
|
||||||
ugha.i2p,z3f3owc72awbywk4p6qb5l2mxgitvs6ejztggbpn2a3ddmymfjda
|
ugha.i2p,z3f3owc72awbywk4p6qb5l2mxgitvs6ejztggbpn2a3ddmymfjda
|
||||||
uk.i2p,vydbychnep3mzkzhg43ptewp242issy47whamfbxodc4ma6wc63a
|
uk.i2p,vydbychnep3mzkzhg43ptewp242issy47whamfbxodc4ma6wc63a
|
||||||
ukiyo.i2p,ytd3loo226pogdcx3ajdtew6vl5rsidppqzh6phbo5vlmigdxclq
|
|
||||||
underground.i2p,dlnuthb6tpw3kchlb7xoztyspy4ehlggjhl44l64vbcrulrfeica
|
underground.i2p,dlnuthb6tpw3kchlb7xoztyspy4ehlggjhl44l64vbcrulrfeica
|
||||||
underscore.i2p,3gmezyig6gvsjbpkq2kihoskpuqpkfrajmhhm7hpyrjuvtasgepa
|
underscore.i2p,3gmezyig6gvsjbpkq2kihoskpuqpkfrajmhhm7hpyrjuvtasgepa
|
||||||
unqueued.i2p,3gvn4kwd7z74jxc2sn4ucx52dpvpscxbzjluux3ul4t3eu5g64xq
|
unqueued.i2p,3gvn4kwd7z74jxc2sn4ucx52dpvpscxbzjluux3ul4t3eu5g64xq
|
||||||
@@ -777,14 +648,13 @@ vadino.i2p,aalttzlt3z25ktokesceweabm5yyhhvml2z3rfotndgpfyh6myra
|
|||||||
visibility.i2p,pwgma3snbsgkddxgb54mrxxkt3l4jzchrtp52vxmw7rbkjygylxq
|
visibility.i2p,pwgma3snbsgkddxgb54mrxxkt3l4jzchrtp52vxmw7rbkjygylxq
|
||||||
volatile.i2p,q6rve733tvhgyys57jfw4fymqf3xsnza6dqailcdjcq7w4fa5m3a
|
volatile.i2p,q6rve733tvhgyys57jfw4fymqf3xsnza6dqailcdjcq7w4fa5m3a
|
||||||
vpnbest.i2p,ov5f74ndsy5rfkuyps56waf42vxncufqu5rzm3vsnxkdtogccaea
|
vpnbest.i2p,ov5f74ndsy5rfkuyps56waf42vxncufqu5rzm3vsnxkdtogccaea
|
||||||
|
vudu.i2p,3zlwci7pvgep2igygzyjej24ue7mjsktlhaff6crpsr75yquak2q
|
||||||
w.i2p,j2xorlcb3qxubnthzqu7lt4fvxqn63it4ikwmze55yjkzeeampuq
|
w.i2p,j2xorlcb3qxubnthzqu7lt4fvxqn63it4ikwmze55yjkzeeampuq
|
||||||
wa11ed.city.i2p,7mxwtmala3ycg2sybjwwfil7s6dqck2fbemeutghhwu73rznmqoa
|
wa11ed.city.i2p,7mxwtmala3ycg2sybjwwfil7s6dqck2fbemeutghhwu73rznmqoa
|
||||||
wahoo.i2p,vqe5vkpe5wbda7lwekcd2jaj44ar3rawgv54u5rcolezbg5f5vwa
|
wahoo.i2p,vqe5vkpe5wbda7lwekcd2jaj44ar3rawgv54u5rcolezbg5f5vwa
|
||||||
wallet.gostcoin.i2p,reuvum7lgetglafn72chypesvto773oy53zumagrpigkckybrwda
|
wallet.gostcoin.i2p,reuvum7lgetglafn72chypesvto773oy53zumagrpigkckybrwda
|
||||||
wallsgetbombed.i2p,tzhea5d65fllm4263wztghgw4ijdgibsca5xsecp6lk4xlsbdeuq
|
wallsgetbombed.i2p,tzhea5d65fllm4263wztghgw4ijdgibsca5xsecp6lk4xlsbdeuq
|
||||||
web.telegram.i2p,re6cgwg2yrkgaixlqvt5ufajbb3w42fsldlq7k5brpvnd5gp6x5a
|
web.telegram.i2p,re6cgwg2yrkgaixlqvt5ufajbb3w42fsldlq7k5brpvnd5gp6x5a
|
||||||
webviewer.aktie.i2p,gvofjbuvkl65f2npmyyig6wmi4ryvzdyli2pj4ufu56vtabc5pmq
|
|
||||||
whoopboo.i2p,7i4err7ik6r5sno33sfmanmu4x7tsbqc6a7dmg3ijel57zhoosma
|
|
||||||
wiht.i2p,yojmpj3sh76g3i6ogzgsf7eouipdgdij5o2blcpdgmu5oyjk5xca
|
wiht.i2p,yojmpj3sh76g3i6ogzgsf7eouipdgdij5o2blcpdgmu5oyjk5xca
|
||||||
wiki.fr.i2p,lrqa7hw52uxjb5q3pedmjs6hzos5zrod4y6a4e25hu7vcjhohvxq
|
wiki.fr.i2p,lrqa7hw52uxjb5q3pedmjs6hzos5zrod4y6a4e25hu7vcjhohvxq
|
||||||
wiki.ilita.i2p,r233yskmowqe4od4he4b37wydr5fqzvj3z77v5fdei2etp2kg34a
|
wiki.ilita.i2p,r233yskmowqe4od4he4b37wydr5fqzvj3z77v5fdei2etp2kg34a
|
||||||
@@ -811,8 +681,6 @@ xmpp.rpi.i2p,3yv65pfwiwfuv4ciwtx34clqps6o2mc3vtyltcbqdkcki6untbca
|
|||||||
xn--l2bl5aw.i2p,d2epikjh5crt2l5xjmtceqw2ho44hzp6x3u7hgjrd4mi4wywikwa
|
xn--l2bl5aw.i2p,d2epikjh5crt2l5xjmtceqw2ho44hzp6x3u7hgjrd4mi4wywikwa
|
||||||
xolotl.i2p,rwr6rrlmrotxfkxt22mah42cycliy2g5k7hgxyxkpcyyxkd2bgwq
|
xolotl.i2p,rwr6rrlmrotxfkxt22mah42cycliy2g5k7hgxyxkpcyyxkd2bgwq
|
||||||
xotc.i2p,gqgvzum3xdgtaahkjfw3layb33vjrucmw5btyhrppm463cz3c5oq
|
xotc.i2p,gqgvzum3xdgtaahkjfw3layb33vjrucmw5btyhrppm463cz3c5oq
|
||||||
xpyxpy.i2p,vwzdbqs7p4z5i6zob4gqrl7kejnkaxfo7haabowdq6tjqwltatuq
|
|
||||||
yottabyte.i2p,zsdqh2ozauksuyeiaqypgcxus5ldmxgxxgz4yp76pglrjxzzu2ra
|
|
||||||
z-lab.i2p,s6g2pz3mrwzsl4ts65ox3scqawfj7mzvd7hn2ekiiycawopkriba
|
z-lab.i2p,s6g2pz3mrwzsl4ts65ox3scqawfj7mzvd7hn2ekiiycawopkriba
|
||||||
zab.i2p,n4xen5sohufgjhv327ex4qra77f4tpqohlcyoa3atoboknzqazeq
|
zab.i2p,n4xen5sohufgjhv327ex4qra77f4tpqohlcyoa3atoboknzqazeq
|
||||||
zcash.i2p,zcashmliuw3yd2ptfyd5sadatcpyxj4ldiqahtjzg73cgoevxp4q
|
zcash.i2p,zcashmliuw3yd2ptfyd5sadatcpyxj4ldiqahtjzg73cgoevxp4q
|
||||||
@@ -820,5 +688,6 @@ zener.i2p,mcbyglflte3dhwhqyafsfpnqtcapqkv2sepqd62wzd7fo2dzz4ca
|
|||||||
zerobin.i2p,3564erslxzaoucqasxsjerk4jz2xril7j2cbzd4p7flpb4ut67hq
|
zerobin.i2p,3564erslxzaoucqasxsjerk4jz2xril7j2cbzd4p7flpb4ut67hq
|
||||||
zeroman.i2p,gq77fmto535koofcd53f6yzcc5y57ccrxg3pb6twhcodc7v5dutq
|
zeroman.i2p,gq77fmto535koofcd53f6yzcc5y57ccrxg3pb6twhcodc7v5dutq
|
||||||
zeronet.i2p,fe6pk5sibhkr64veqxkfochdfptehyxrrbs3edwjs5ckjbjn4bna
|
zeronet.i2p,fe6pk5sibhkr64veqxkfochdfptehyxrrbs3edwjs5ckjbjn4bna
|
||||||
|
znc.i2p,uw2yt6njjl676fupd72hiezwmd4ouuywowrph6fvhkzhlnvp7jwa
|
||||||
znc.str4d.i2p,ufkajv3stxpxlwgwwb2ae6oixdjircnbwog77qxpxv7nt67rpcxq
|
znc.str4d.i2p,ufkajv3stxpxlwgwwb2ae6oixdjircnbwog77qxpxv7nt67rpcxq
|
||||||
zzz.i2p,ukeu3k5oycgaauneqgtnvselmt4yemvoilkln7jpvamvfx7dnkdq
|
zzz.i2p,ukeu3k5oycgaauneqgtnvselmt4yemvoilkln7jpvamvfx7dnkdq
|
||||||
|
|||||||
|
@@ -2,9 +2,10 @@ buildscript {
|
|||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
jcenter()
|
jcenter()
|
||||||
|
google()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:2.3.3'
|
classpath 'com.android.tools.build:gradle:3.3.2'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -18,18 +19,18 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile 'com.android.support:support-compat:28.0.0'
|
implementation 'com.android.support:support-compat:28.0.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 28
|
compileSdkVersion 28
|
||||||
buildToolsVersion "28.0.1"
|
buildToolsVersion "28.0.3"
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "org.purplei2p.i2pd"
|
applicationId "org.purplei2p.i2pd"
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
versionCode 2230
|
versionCode 2250
|
||||||
versionName "2.23.0"
|
versionName "2.25.0"
|
||||||
ndk {
|
ndk {
|
||||||
abiFilters 'armeabi-v7a'
|
abiFilters 'armeabi-v7a'
|
||||||
abiFilters 'x86'
|
abiFilters 'x86'
|
||||||
|
|||||||
BIN
android/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
android/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#Thu Mar 14 18:21:08 MSK 2019
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
|
||||||
172
android/gradlew
vendored
Executable file
172
android/gradlew
vendored
Executable file
@@ -0,0 +1,172 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
##
|
||||||
|
## Gradle start up script for UN*X
|
||||||
|
##
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
PRG="$0"
|
||||||
|
# Need this for relative symlinks.
|
||||||
|
while [ -h "$PRG" ] ; do
|
||||||
|
ls=`ls -ld "$PRG"`
|
||||||
|
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||||
|
if expr "$link" : '/.*' > /dev/null; then
|
||||||
|
PRG="$link"
|
||||||
|
else
|
||||||
|
PRG=`dirname "$PRG"`"/$link"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
SAVED="`pwd`"
|
||||||
|
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||||
|
APP_HOME="`pwd -P`"
|
||||||
|
cd "$SAVED" >/dev/null
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=`basename "$0"`
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS=""
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD="maximum"
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "`uname`" in
|
||||||
|
CYGWIN* )
|
||||||
|
cygwin=true
|
||||||
|
;;
|
||||||
|
Darwin* )
|
||||||
|
darwin=true
|
||||||
|
;;
|
||||||
|
MINGW* )
|
||||||
|
msys=true
|
||||||
|
;;
|
||||||
|
NONSTOP* )
|
||||||
|
nonstop=true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="java"
|
||||||
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||||
|
MAX_FD_LIMIT=`ulimit -H -n`
|
||||||
|
if [ $? -eq 0 ] ; then
|
||||||
|
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||||
|
MAX_FD="$MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
ulimit -n $MAX_FD
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Darwin, add options to specify how the application appears in the dock
|
||||||
|
if $darwin; then
|
||||||
|
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Cygwin, switch paths to Windows format before running java
|
||||||
|
if $cygwin ; then
|
||||||
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
|
||||||
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
|
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||||
|
SEP=""
|
||||||
|
for dir in $ROOTDIRSRAW ; do
|
||||||
|
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||||
|
SEP="|"
|
||||||
|
done
|
||||||
|
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||||
|
# Add a user-defined pattern to the cygpath arguments
|
||||||
|
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||||
|
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||||
|
fi
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
i=0
|
||||||
|
for arg in "$@" ; do
|
||||||
|
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||||
|
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||||
|
|
||||||
|
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||||
|
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||||
|
else
|
||||||
|
eval `echo args$i`="\"$arg\""
|
||||||
|
fi
|
||||||
|
i=$((i+1))
|
||||||
|
done
|
||||||
|
case $i in
|
||||||
|
(0) set -- ;;
|
||||||
|
(1) set -- "$args0" ;;
|
||||||
|
(2) set -- "$args0" "$args1" ;;
|
||||||
|
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
|
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
|
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
|
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
|
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
|
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
|
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Escape application args
|
||||||
|
save () {
|
||||||
|
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||||
|
echo " "
|
||||||
|
}
|
||||||
|
APP_ARGS=$(save "$@")
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||||
|
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||||
|
|
||||||
|
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||||
|
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
||||||
84
android/gradlew.bat
vendored
Normal file
84
android/gradlew.bat
vendored
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
@if "%DEBUG%" == "" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS=
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if "%ERRORLEVEL%" == "0" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:init
|
||||||
|
@rem Get command-line arguments, handling Windows variants
|
||||||
|
|
||||||
|
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||||
|
|
||||||
|
:win9xME_args
|
||||||
|
@rem Slurp the command line arguments.
|
||||||
|
set CMD_LINE_ARGS=
|
||||||
|
set _SKIP=2
|
||||||
|
|
||||||
|
:win9xME_args_slurp
|
||||||
|
if "x%~1" == "x" goto execute
|
||||||
|
|
||||||
|
set CMD_LINE_ARGS=%*
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
||||||
@@ -65,6 +65,8 @@ namespace android
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
std::string dataDir = "";
|
||||||
|
|
||||||
DaemonAndroidImpl::DaemonAndroidImpl ()
|
DaemonAndroidImpl::DaemonAndroidImpl ()
|
||||||
//:
|
//:
|
||||||
/*mutex(nullptr), */
|
/*mutex(nullptr), */
|
||||||
@@ -85,7 +87,7 @@ namespace android
|
|||||||
//m_IsRunning=false;
|
//m_IsRunning=false;
|
||||||
|
|
||||||
// make sure assets are ready before proceed
|
// make sure assets are ready before proceed
|
||||||
i2p::fs::DetectDataDir("", false);
|
i2p::fs::DetectDataDir(dataDir, false);
|
||||||
int numAttempts = 0;
|
int numAttempts = 0;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@@ -203,5 +205,10 @@ namespace android
|
|||||||
{
|
{
|
||||||
daemon.stop();
|
daemon.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetDataDir(std::string jdataDir)
|
||||||
|
{
|
||||||
|
dataDir = jdataDir;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ namespace android
|
|||||||
// stops the daemon
|
// stops the daemon
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
|
// set datadir received from jni
|
||||||
|
void SetDataDir(std::string jdataDir);
|
||||||
/*
|
/*
|
||||||
class Worker : public QObject
|
class Worker : public QObject
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -66,3 +66,29 @@ JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged
|
|||||||
bool isConnectedBool = (bool) isConnected;
|
bool isConnectedBool = (bool) isConnected;
|
||||||
i2p::transport::transports.SetOnline (isConnectedBool);
|
i2p::transport::transports.SetOnline (isConnectedBool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_setDataDir
|
||||||
|
(JNIEnv *env, jclass clazz, jstring jdataDir) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Method 1: convert UTF-16 jstring to std::string (https://stackoverflow.com/a/41820336)
|
||||||
|
const jclass stringClass = env->GetObjectClass(jdataDir);
|
||||||
|
const jmethodID getBytes = env->GetMethodID(stringClass, "getBytes", "(Ljava/lang/String;)[B");
|
||||||
|
const jbyteArray stringJbytes = (jbyteArray) env->CallObjectMethod(jdataDir, getBytes, env->NewStringUTF("UTF-8"));
|
||||||
|
|
||||||
|
size_t length = (size_t) env->GetArrayLength(stringJbytes);
|
||||||
|
jbyte* pBytes = env->GetByteArrayElements(stringJbytes, NULL);
|
||||||
|
|
||||||
|
std::string dataDir = std::string((char *)pBytes, length);
|
||||||
|
env->ReleaseByteArrayElements(stringJbytes, pBytes, JNI_ABORT);
|
||||||
|
|
||||||
|
env->DeleteLocalRef(stringJbytes);
|
||||||
|
env->DeleteLocalRef(stringClass); */
|
||||||
|
|
||||||
|
// Method 2: get string chars and make char array.
|
||||||
|
auto dataDir = env->GetStringUTFChars(jdataDir, NULL);
|
||||||
|
env->ReleaseStringUTFChars(jdataDir, dataDir);
|
||||||
|
|
||||||
|
// Set DataDir
|
||||||
|
i2p::android::SetDataDir(dataDir);
|
||||||
|
}
|
||||||
|
|||||||
@@ -30,6 +30,9 @@ JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startAcceptingTunnels
|
|||||||
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged
|
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged
|
||||||
(JNIEnv * env, jclass clazz, jboolean isConnected);
|
(JNIEnv * env, jclass clazz, jboolean isConnected);
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_setDataDir
|
||||||
|
(JNIEnv *env, jclass clazz, jstring jdataDir);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -16,4 +16,5 @@
|
|||||||
<string name="stopped">Приложение было остановлено</string>
|
<string name="stopped">Приложение было остановлено</string>
|
||||||
<string name="remaining">осталось</string>
|
<string name="remaining">осталось</string>
|
||||||
<string name="title_activity_i2_pdperms_asker_prompt">Запрос</string>
|
<string name="title_activity_i2_pdperms_asker_prompt">Запрос</string>
|
||||||
|
<string name="permDenied">Права для записи на SD карту отклонены, вам необходимо предоставить их для продолжения</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -16,4 +16,5 @@
|
|||||||
<string name="stopped">Application stopped</string>
|
<string name="stopped">Application stopped</string>
|
||||||
<string name="remaining">remaining</string>
|
<string name="remaining">remaining</string>
|
||||||
<string name="title_activity_i2_pdperms_asker_prompt">Prompt</string>
|
<string name="title_activity_i2_pdperms_asker_prompt">Prompt</string>
|
||||||
|
<string name="permDenied">SD card write permission denied, you need to allow this to continue</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ package org.purplei2p.i2pd;
|
|||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import android.os.Environment;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.purplei2p.i2pd.R;
|
import org.purplei2p.i2pd.R;
|
||||||
|
|
||||||
public class DaemonSingleton {
|
public class DaemonSingleton {
|
||||||
@@ -11,9 +13,7 @@ public class DaemonSingleton {
|
|||||||
public interface StateUpdateListener { void daemonStateUpdate(); }
|
public interface StateUpdateListener { void daemonStateUpdate(); }
|
||||||
private final Set<StateUpdateListener> stateUpdateListeners = new HashSet<>();
|
private final Set<StateUpdateListener> stateUpdateListeners = new HashSet<>();
|
||||||
|
|
||||||
public static DaemonSingleton getInstance() {
|
public static DaemonSingleton getInstance() { return instance; }
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void addStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.add(listener); }
|
public synchronized void addStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.add(listener); }
|
||||||
public synchronized void removeStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.remove(listener); }
|
public synchronized void removeStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.remove(listener); }
|
||||||
@@ -82,6 +82,7 @@ public class DaemonSingleton {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
synchronized (DaemonSingleton.this) {
|
synchronized (DaemonSingleton.this) {
|
||||||
|
I2PD_JNI.setDataDir(Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd");
|
||||||
daemonStartResult = I2PD_JNI.startDaemon();
|
daemonStartResult = I2PD_JNI.startDaemon();
|
||||||
if("ok".equals(daemonStartResult)){
|
if("ok".equals(daemonStartResult)){
|
||||||
setState(State.startedOkay);
|
setState(State.startedOkay);
|
||||||
@@ -91,7 +92,6 @@ public class DaemonSingleton {
|
|||||||
} catch (Throwable tr) {
|
} catch (Throwable tr) {
|
||||||
lastThrowable=tr;
|
lastThrowable=tr;
|
||||||
setState(State.startFailed);
|
setState(State.startFailed);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.purplei2p.i2pd;
|
package org.purplei2p.i2pd;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.NotificationChannel;
|
import android.app.NotificationChannel;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
|
|||||||
@@ -119,11 +119,10 @@ public class I2PDPermsAskerActivity extends Activity {
|
|||||||
|
|
||||||
// permission denied, boo! Disable the
|
// permission denied, boo! Disable the
|
||||||
// functionality that depends on this permission.
|
// functionality that depends on this permission.
|
||||||
textview_retry.setText("SD card write permission denied, you need to allow this to continue");
|
textview_retry.setText(R.string.permDenied);
|
||||||
textview_retry.setVisibility(TextView.VISIBLE);
|
textview_retry.setVisibility(TextView.VISIBLE);
|
||||||
button_request_write_ext_storage_perms.setVisibility(Button.VISIBLE);
|
button_request_write_ext_storage_perms.setVisibility(Button.VISIBLE);
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// other 'case' lines to check for other
|
// other 'case' lines to check for other
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ public class I2PD_JNI {
|
|||||||
|
|
||||||
public static native void onNetworkStateChanged(boolean isConnected);
|
public static native void onNetworkStateChanged(boolean isConnected);
|
||||||
|
|
||||||
|
public static native void setDataDir(String jdataDir);
|
||||||
|
|
||||||
public static void loadLibraries() {
|
public static void loadLibraries() {
|
||||||
//System.loadLibrary("c++_shared");
|
//System.loadLibrary("c++_shared");
|
||||||
System.loadLibrary("i2pd");
|
System.loadLibrary("i2pd");
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#APP_ABI := all
|
APP_ABI := all
|
||||||
#APP_ABI := armeabi-v7a x86
|
#APP_ABI += x86
|
||||||
#APP_ABI := x86
|
#APP_ABI += x86_64
|
||||||
#APP_ABI := x86_64
|
#APP_ABI += armeabi-v7a
|
||||||
APP_ABI := armeabi-v7a
|
#APP_ABI += arm64-v8a
|
||||||
#can be android-3 but will fail for x86 since arch-x86 is not present at ndkroot/platforms/android-3/ . libz is taken from there.
|
#can be android-3 but will fail for x86 since arch-x86 is not present at ndkroot/platforms/android-3/ . libz is taken from there.
|
||||||
APP_PLATFORM := android-14
|
APP_PLATFORM := android-14
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
version: 2.23.0.{build}
|
version: 2.25.0.{build}
|
||||||
pull_requests:
|
pull_requests:
|
||||||
do_not_increment_build_number: true
|
do_not_increment_build_number: true
|
||||||
branches:
|
branches:
|
||||||
|
|||||||
2
contrib/android_binary_pack/.gitignore
vendored
Normal file
2
contrib/android_binary_pack/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
archive
|
||||||
|
i2pd_*_android_binary.zip
|
||||||
45
contrib/android_binary_pack/build-archive
Executable file
45
contrib/android_binary_pack/build-archive
Executable file
@@ -0,0 +1,45 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Copyright (c) 2013-2017, The PurpleI2P Project
|
||||||
|
#
|
||||||
|
# This file is part of Purple i2pd project and licensed under BSD3
|
||||||
|
#
|
||||||
|
# See full license text in LICENSE file at top of project tree
|
||||||
|
|
||||||
|
GITDESC=$(git describe --tags)
|
||||||
|
|
||||||
|
declare -A ABILIST=(
|
||||||
|
["armeabi-v7a"]="armv7l"
|
||||||
|
["arm64-v8a"]="aarch64"
|
||||||
|
["x86"]="x86"
|
||||||
|
["x86_64"]="x86_64"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Remove old files and archives
|
||||||
|
if [ -d archive ]; then
|
||||||
|
rm -r archive
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f i2pd_*_android_binary.zip ]; then
|
||||||
|
rm i2pd_*_android_binary.zip
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Prepare files for package
|
||||||
|
mkdir archive
|
||||||
|
|
||||||
|
for ABI in "${!ABILIST[@]}"; do
|
||||||
|
if [ -f ../../android_binary_only/libs/${ABI}/i2pd ]; then
|
||||||
|
cp ../../android_binary_only/libs/${ABI}/i2pd archive/i2pd-${ABILIST[$ABI]}
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
cp i2pd archive/i2pd
|
||||||
|
cp -rH ../../android/assets/* archive/
|
||||||
|
|
||||||
|
# Compress files
|
||||||
|
cd archive
|
||||||
|
zip -r6 ../i2pd_${GITDESC}_android_binary.zip .
|
||||||
|
|
||||||
|
# Remove temporary folder
|
||||||
|
cd ..
|
||||||
|
rm -r archive
|
||||||
33
contrib/android_binary_pack/i2pd
Executable file
33
contrib/android_binary_pack/i2pd
Executable file
@@ -0,0 +1,33 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Copyright (c) 2013-2019, The PurpleI2P Project
|
||||||
|
#
|
||||||
|
# This file is part of Purple i2pd project and licensed under BSD3
|
||||||
|
#
|
||||||
|
# See full license text in LICENSE file at top of project tree
|
||||||
|
#
|
||||||
|
# That script written for use with Termux.
|
||||||
|
|
||||||
|
# https://stackoverflow.com/a/246128
|
||||||
|
SOURCE="${0}"
|
||||||
|
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
|
||||||
|
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
|
||||||
|
SOURCE="$(readlink "$SOURCE")"
|
||||||
|
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
|
||||||
|
done
|
||||||
|
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
|
||||||
|
|
||||||
|
arch=$(uname -m)
|
||||||
|
|
||||||
|
screenfind=$(which screen)
|
||||||
|
if [ -z $screenfind ]; then
|
||||||
|
echo "Can't find 'screen' installed. That script needs it!";
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z i2pd-$arch ]; then
|
||||||
|
echo "Can't find i2pd binary for your archtecture.";
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
screen -AmdS i2pd ./i2pd-$arch --datadir=$DIR
|
||||||
@@ -24,7 +24,7 @@ RUN mkdir -p "$I2PD_HOME" "$DATA_DIR" \
|
|||||||
# 1. install deps, clone and build.
|
# 1. install deps, clone and build.
|
||||||
# 2. strip binaries.
|
# 2. strip binaries.
|
||||||
# 3. Purge all dependencies and other unrelated packages, including build directory.
|
# 3. Purge all dependencies and other unrelated packages, including build directory.
|
||||||
RUN apk --no-cache --virtual build-dependendencies add make gcc g++ libtool boost-dev build-base openssl-dev openssl git \
|
RUN apk --no-cache --virtual build-dependendencies add make gcc g++ libtool zlib-dev boost-dev build-base openssl-dev openssl git \
|
||||||
&& mkdir -p /tmp/build \
|
&& mkdir -p /tmp/build \
|
||||||
&& cd /tmp/build && git clone -b ${GIT_BRANCH} ${REPO_URL} \
|
&& cd /tmp/build && git clone -b ${GIT_BRANCH} ${REPO_URL} \
|
||||||
&& cd i2pd \
|
&& cd i2pd \
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
%define git_hash %(git rev-parse HEAD | cut -c -7)
|
%define git_hash %(git rev-parse HEAD | cut -c -7)
|
||||||
|
|
||||||
Name: i2pd-git
|
Name: i2pd-git
|
||||||
Version: 2.23.0
|
Version: 2.25.0
|
||||||
Release: git%{git_hash}%{?dist}
|
Release: git%{git_hash}%{?dist}
|
||||||
Summary: I2P router written in C++
|
Summary: I2P router written in C++
|
||||||
Conflicts: i2pd
|
Conflicts: i2pd
|
||||||
@@ -47,8 +47,13 @@ cd build
|
|||||||
-DWITH_LIBRARY=OFF \
|
-DWITH_LIBRARY=OFF \
|
||||||
-DWITH_UPNP=ON \
|
-DWITH_UPNP=ON \
|
||||||
-DWITH_HARDENING=ON \
|
-DWITH_HARDENING=ON \
|
||||||
|
%if 0%{?fedora} > 29
|
||||||
|
-DBUILD_SHARED_LIBS:BOOL=OFF \
|
||||||
|
.
|
||||||
|
%else
|
||||||
-DBUILD_SHARED_LIBS:BOOL=OFF
|
-DBUILD_SHARED_LIBS:BOOL=OFF
|
||||||
%endif
|
%endif
|
||||||
|
%endif
|
||||||
|
|
||||||
make %{?_smp_mflags}
|
make %{?_smp_mflags}
|
||||||
|
|
||||||
@@ -105,6 +110,12 @@ getent passwd i2pd >/dev/null || \
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Thu May 9 2019 orignal <i2porignal@yandex.ru> - 2.25.0
|
||||||
|
- update to 2.25.0
|
||||||
|
|
||||||
|
* Thu Mar 21 2019 orignal <i2porignal@yandex.ru> - 2.24.0
|
||||||
|
- update to 2.24.0
|
||||||
|
|
||||||
* Mon Jan 21 2019 orignal <i2porignal@yandex.ru> - 2.23.0
|
* Mon Jan 21 2019 orignal <i2porignal@yandex.ru> - 2.23.0
|
||||||
- update to 2.23.0
|
- update to 2.23.0
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
Name: i2pd
|
Name: i2pd
|
||||||
Version: 2.23.0
|
Version: 2.25.0
|
||||||
Release: 1%{?dist}
|
Release: 1%{?dist}
|
||||||
Summary: I2P router written in C++
|
Summary: I2P router written in C++
|
||||||
Conflicts: i2pd-git
|
Conflicts: i2pd-git
|
||||||
@@ -45,8 +45,13 @@ cd build
|
|||||||
-DWITH_LIBRARY=OFF \
|
-DWITH_LIBRARY=OFF \
|
||||||
-DWITH_UPNP=ON \
|
-DWITH_UPNP=ON \
|
||||||
-DWITH_HARDENING=ON \
|
-DWITH_HARDENING=ON \
|
||||||
|
%if 0%{?fedora} > 29
|
||||||
|
-DBUILD_SHARED_LIBS:BOOL=OFF \
|
||||||
|
.
|
||||||
|
%else
|
||||||
-DBUILD_SHARED_LIBS:BOOL=OFF
|
-DBUILD_SHARED_LIBS:BOOL=OFF
|
||||||
%endif
|
%endif
|
||||||
|
%endif
|
||||||
|
|
||||||
make %{?_smp_mflags}
|
make %{?_smp_mflags}
|
||||||
|
|
||||||
@@ -103,6 +108,12 @@ getent passwd i2pd >/dev/null || \
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Thu May 9 2019 orignal <i2porignal@yandex.ru> - 2.25.0
|
||||||
|
- update to 2.25.0
|
||||||
|
|
||||||
|
* Thu Mar 21 2019 orignal <i2porignal@yandex.ru> - 2.24.0
|
||||||
|
- update to 2.24.0
|
||||||
|
|
||||||
* Mon Jan 21 2019 orignal <i2porignal@yandex.ru> - 2.23.0
|
* Mon Jan 21 2019 orignal <i2porignal@yandex.ru> - 2.23.0
|
||||||
- update to 2.23.0
|
- update to 2.23.0
|
||||||
|
|
||||||
|
|||||||
@@ -154,14 +154,24 @@ namespace i2p
|
|||||||
i2p::context.SetSupportsV6 (ipv6);
|
i2p::context.SetSupportsV6 (ipv6);
|
||||||
i2p::context.SetSupportsV4 (ipv4);
|
i2p::context.SetSupportsV4 (ipv4);
|
||||||
|
|
||||||
|
bool ntcp; i2p::config::GetOption("ntcp", ntcp);
|
||||||
|
i2p::context.PublishNTCPAddress (ntcp, !ipv6);
|
||||||
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
||||||
if (ntcp2)
|
if (ntcp2)
|
||||||
{
|
{
|
||||||
bool published; i2p::config::GetOption("ntcp2.published", published);
|
bool published; i2p::config::GetOption("ntcp2.published", published);
|
||||||
if (published)
|
if (published)
|
||||||
{
|
{
|
||||||
uint16_t port; i2p::config::GetOption("ntcp2.port", port);
|
uint16_t ntcp2port; i2p::config::GetOption("ntcp2.port", ntcp2port);
|
||||||
i2p::context.PublishNTCP2Address (port, true); // publish
|
if (!ntcp && !ntcp2port) ntcp2port = port; // use standard port
|
||||||
|
i2p::context.PublishNTCP2Address (ntcp2port, true); // publish
|
||||||
|
if (ipv6)
|
||||||
|
{
|
||||||
|
std::string ipv6Addr; i2p::config::GetOption("ntcp2.addressv6", ipv6Addr);
|
||||||
|
auto addr = boost::asio::ip::address_v6::from_string (ipv6Addr);
|
||||||
|
if (!addr.is_unspecified () && addr != boost::asio::ip::address_v6::any ())
|
||||||
|
i2p::context.UpdateNTCP2V6Address (addr); // set ipv6 address if configured
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
i2p::context.PublishNTCP2Address (port, false); // unpublish
|
i2p::context.PublishNTCP2Address (port, false); // unpublish
|
||||||
@@ -256,7 +266,7 @@ namespace i2p
|
|||||||
pos = comma + 1;
|
pos = comma + 1;
|
||||||
}
|
}
|
||||||
while (comma != std::string::npos);
|
while (comma != std::string::npos);
|
||||||
LogPrint(eLogInfo, "Daemon: setting restricted routes to use ", idents.size(), " trusted routesrs");
|
LogPrint(eLogInfo, "Daemon: setting restricted routes to use ", idents.size(), " trusted routers");
|
||||||
i2p::transport::transports.RestrictRoutesToRouters(idents);
|
i2p::transport::transports.RestrictRoutesToRouters(idents);
|
||||||
restricted = idents.size() > 0;
|
restricted = idents.size() > 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -358,7 +358,7 @@ namespace http {
|
|||||||
{
|
{
|
||||||
s << "<div class='slide'><label for='slide-lease'><b>LeaseSets:</b> <i>" << dest->GetNumRemoteLeaseSets () << "</i></label>\r\n<input type='checkbox' id='slide-lease'/>\r\n<p class='content'>\r\n";
|
s << "<div class='slide'><label for='slide-lease'><b>LeaseSets:</b> <i>" << dest->GetNumRemoteLeaseSets () << "</i></label>\r\n<input type='checkbox' id='slide-lease'/>\r\n<p class='content'>\r\n";
|
||||||
for(auto& it: dest->GetLeaseSets ())
|
for(auto& it: dest->GetLeaseSets ())
|
||||||
s << it.second->GetIdentHash ().ToBase32 () << " " << (int)it.second->GetStoreType () << "<br>\r\n";
|
s << it.first.ToBase32 () << " " << (int)it.second->GetStoreType () << "<br>\r\n";
|
||||||
s << "</p>\r\n</div>\r\n";
|
s << "</p>\r\n</div>\r\n";
|
||||||
} else
|
} else
|
||||||
s << "<b>LeaseSets:</b> <i>0</i><br>\r\n";
|
s << "<b>LeaseSets:</b> <i>0</i><br>\r\n";
|
||||||
@@ -798,8 +798,7 @@ namespace http {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HTTPConnection::HTTPConnection (std::string hostname, std::shared_ptr<boost::asio::ip::tcp::socket> socket):
|
HTTPConnection::HTTPConnection (std::string hostname, std::shared_ptr<boost::asio::ip::tcp::socket> socket):
|
||||||
m_Socket (socket), m_Timer (socket->get_io_service ()), m_BufferLen (0),
|
m_Socket (socket), m_BufferLen (0), expected_host(hostname)
|
||||||
expected_host(hostname)
|
|
||||||
{
|
{
|
||||||
/* cache options */
|
/* cache options */
|
||||||
i2p::config::GetOption("http.auth", needAuth);
|
i2p::config::GetOption("http.auth", needAuth);
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ namespace http
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
std::shared_ptr<boost::asio::ip::tcp::socket> m_Socket;
|
std::shared_ptr<boost::asio::ip::tcp::socket> m_Socket;
|
||||||
boost::asio::deadline_timer m_Timer;
|
|
||||||
char m_Buffer[HTTP_CONNECTION_BUFFER_SIZE + 1];
|
char m_Buffer[HTTP_CONNECTION_BUFFER_SIZE + 1];
|
||||||
size_t m_BufferLen;
|
size_t m_BufferLen;
|
||||||
std::string m_SendBuffer;
|
std::string m_SendBuffer;
|
||||||
|
|||||||
12
debian/changelog
vendored
12
debian/changelog
vendored
@@ -1,3 +1,15 @@
|
|||||||
|
i2pd (2.25.0-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* updated to version 2.25.0/0.9.40
|
||||||
|
|
||||||
|
-- orignal <orignal@i2pmail.org> Thu, 9 May 2019 16:00:00 +0000
|
||||||
|
|
||||||
|
i2pd (2.24.0-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* updated to version 2.24.0/0.9.39
|
||||||
|
|
||||||
|
-- orignal <orignal@i2pmail.org> Thu, 21 Mar 2019 16:00:00 +0000
|
||||||
|
|
||||||
i2pd (2.23.0-1) unstable; urgency=medium
|
i2pd (2.23.0-1) unstable; urgency=medium
|
||||||
|
|
||||||
* updated to version 2.23.0/0.9.38
|
* updated to version 2.23.0/0.9.38
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "I2PEndian.h"
|
||||||
#include "ChaCha20.h"
|
#include "ChaCha20.h"
|
||||||
|
|
||||||
#if !OPENSSL_AEAD_CHACHA20_POLY1305
|
#if !OPENSSL_AEAD_CHACHA20_POLY1305
|
||||||
@@ -89,14 +90,14 @@ void Chacha20Init (Chacha20State& state, const uint8_t * nonce, const uint8_t *
|
|||||||
for (size_t i = 0; i < 8; i++)
|
for (size_t i = 0; i < 8; i++)
|
||||||
state.data[4 + i] = chacha::u8t32le(key + i * 4);
|
state.data[4 + i] = chacha::u8t32le(key + i * 4);
|
||||||
|
|
||||||
state.data[12] = counter;
|
state.data[12] = htole32 (counter);
|
||||||
for (size_t i = 0; i < 3; i++)
|
for (size_t i = 0; i < 3; i++)
|
||||||
state.data[13 + i] = chacha::u8t32le(nonce + i * 4);
|
state.data[13 + i] = chacha::u8t32le(nonce + i * 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Chacha20SetCounter (Chacha20State& state, uint32_t counter)
|
void Chacha20SetCounter (Chacha20State& state, uint32_t counter)
|
||||||
{
|
{
|
||||||
state.data[12] = counter;
|
state.data[12] = htole32 (counter);
|
||||||
state.offset = 0;
|
state.offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ namespace config {
|
|||||||
("limits.coresize", value<uint32_t>()->default_value(0), "Maximum size of corefile in Kb (0 - use system limit)")
|
("limits.coresize", value<uint32_t>()->default_value(0), "Maximum size of corefile in Kb (0 - use system limit)")
|
||||||
("limits.openfiles", value<uint16_t>()->default_value(0), "Maximum number of open files (0 - use system default)")
|
("limits.openfiles", value<uint16_t>()->default_value(0), "Maximum number of open files (0 - use system default)")
|
||||||
("limits.transittunnels", value<uint16_t>()->default_value(2500), "Maximum active transit sessions (default:2500)")
|
("limits.transittunnels", value<uint16_t>()->default_value(2500), "Maximum active transit sessions (default:2500)")
|
||||||
("limits.ntcpsoft", value<uint16_t>()->default_value(0), "Threshold to start probabalistic backoff with ntcp sessions (default: use system limit)")
|
("limits.ntcpsoft", value<uint16_t>()->default_value(0), "Threshold to start probabilistic backoff with ntcp sessions (default: use system limit)")
|
||||||
("limits.ntcphard", value<uint16_t>()->default_value(0), "Maximum number of ntcp sessions (default: use system limit)")
|
("limits.ntcphard", value<uint16_t>()->default_value(0), "Maximum number of ntcp sessions (default: use system limit)")
|
||||||
("limits.ntcpthreads", value<uint16_t>()->default_value(1), "Maximum number of threads used by NTCP DH worker (default: 1)")
|
("limits.ntcpthreads", value<uint16_t>()->default_value(1), "Maximum number of threads used by NTCP DH worker (default: 1)")
|
||||||
;
|
;
|
||||||
@@ -153,8 +153,8 @@ namespace config {
|
|||||||
("i2pcontrol.address", value<std::string>()->default_value("127.0.0.1"), "I2PCP listen address")
|
("i2pcontrol.address", value<std::string>()->default_value("127.0.0.1"), "I2PCP listen address")
|
||||||
("i2pcontrol.port", value<uint16_t>()->default_value(7650), "I2PCP listen port")
|
("i2pcontrol.port", value<uint16_t>()->default_value(7650), "I2PCP listen port")
|
||||||
("i2pcontrol.password", value<std::string>()->default_value("itoopie"), "I2PCP access password")
|
("i2pcontrol.password", value<std::string>()->default_value("itoopie"), "I2PCP access password")
|
||||||
("i2pcontrol.cert", value<std::string>()->default_value("i2pcontrol.crt.pem"), "I2PCP connection cerificate")
|
("i2pcontrol.cert", value<std::string>()->default_value("i2pcontrol.crt.pem"), "I2PCP connection certificate")
|
||||||
("i2pcontrol.key", value<std::string>()->default_value("i2pcontrol.key.pem"), "I2PCP connection cerificate key")
|
("i2pcontrol.key", value<std::string>()->default_value("i2pcontrol.key.pem"), "I2PCP connection certificate key")
|
||||||
;
|
;
|
||||||
|
|
||||||
bool upnp_default = false;
|
bool upnp_default = false;
|
||||||
@@ -164,7 +164,7 @@ namespace config {
|
|||||||
options_description upnp("UPnP options");
|
options_description upnp("UPnP options");
|
||||||
upnp.add_options()
|
upnp.add_options()
|
||||||
("upnp.enabled", value<bool>()->default_value(upnp_default), "Enable or disable UPnP: automatic port forwarding")
|
("upnp.enabled", value<bool>()->default_value(upnp_default), "Enable or disable UPnP: automatic port forwarding")
|
||||||
("upnp.name", value<std::string>()->default_value("I2Pd"), "Name i2pd appears in UPnP forwardings list")
|
("upnp.name", value<std::string>()->default_value("I2Pd"), "Name i2pd appears in UPnP forwarding list")
|
||||||
;
|
;
|
||||||
|
|
||||||
options_description precomputation("Precomputation options");
|
options_description precomputation("Precomputation options");
|
||||||
@@ -239,6 +239,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(false), "Publish NTCP2 (default: disabled)")
|
("ntcp2.published", value<bool>()->default_value(false), "Publish NTCP2 (default: disabled)")
|
||||||
("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")
|
||||||
;
|
;
|
||||||
|
|
||||||
options_description nettime("Time sync options");
|
options_description nettime("Time sync options");
|
||||||
@@ -256,6 +257,7 @@ namespace config {
|
|||||||
options_description persist("Network information persisting options");
|
options_description persist("Network information persisting options");
|
||||||
persist.add_options()
|
persist.add_options()
|
||||||
("persist.profiles", value<bool>()->default_value(true), "Persist peer profiles (default: true)")
|
("persist.profiles", value<bool>()->default_value(true), "Persist peer profiles (default: true)")
|
||||||
|
("persist.addressbook", value<bool>()->default_value(true), "Persist full addresses (default: true)")
|
||||||
;
|
;
|
||||||
|
|
||||||
m_OptionsDesc
|
m_OptionsDesc
|
||||||
|
|||||||
@@ -32,12 +32,12 @@ namespace config {
|
|||||||
* @param argc Cmdline arguments count, should be passed from main().
|
* @param argc Cmdline arguments count, should be passed from main().
|
||||||
* @param argv Cmdline parameters array, should be passed from main()
|
* @param argv Cmdline parameters array, should be passed from main()
|
||||||
*
|
*
|
||||||
* If --help is given in parameters, shows it's list with description
|
* If --help is given in parameters, shows its list with description
|
||||||
* terminates the program with exitcode 0.
|
* and terminates the program with exitcode 0.
|
||||||
*
|
*
|
||||||
* In case of parameter misuse boost throws an exception.
|
* In case of parameter misuse boost throws an exception.
|
||||||
* We internally handle type boost::program_options::unknown_option,
|
* We internally handle type boost::program_options::unknown_option,
|
||||||
* and then terminate program with exitcode 1.
|
* and then terminate the program with exitcode 1.
|
||||||
*
|
*
|
||||||
* Other exceptions will be passed to higher level.
|
* Other exceptions will be passed to higher level.
|
||||||
*/
|
*/
|
||||||
@@ -107,7 +107,7 @@ namespace config {
|
|||||||
/**
|
/**
|
||||||
* @brief Check is value explicitly given or default
|
* @brief Check is value explicitly given or default
|
||||||
* @param name Name of checked parameter
|
* @param name Name of checked parameter
|
||||||
* @return true if value set to default, false othervise
|
* @return true if value set to default, false otherwise
|
||||||
*/
|
*/
|
||||||
bool IsDefault(const char *name);
|
bool IsDefault(const char *name);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,11 +8,14 @@
|
|||||||
#include <openssl/crypto.h>
|
#include <openssl/crypto.h>
|
||||||
#include "TunnelBase.h"
|
#include "TunnelBase.h"
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#include "Crypto.h"
|
#if OPENSSL_HKDF
|
||||||
|
#include <openssl/kdf.h>
|
||||||
|
#endif
|
||||||
#if !OPENSSL_AEAD_CHACHA20_POLY1305
|
#if !OPENSSL_AEAD_CHACHA20_POLY1305
|
||||||
#include "ChaCha20.h"
|
#include "ChaCha20.h"
|
||||||
#include "Poly1305.h"
|
#include "Poly1305.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "Crypto.h"
|
||||||
#include "Ed25519.h"
|
#include "Ed25519.h"
|
||||||
#include "I2PEndian.h"
|
#include "I2PEndian.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
@@ -1228,6 +1231,49 @@ namespace crypto
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChaCha20 (const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out)
|
||||||
|
{
|
||||||
|
#if OPENSSL_AEAD_CHACHA20_POLY1305
|
||||||
|
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new ();
|
||||||
|
uint32_t iv[4];
|
||||||
|
iv[0] = htole32 (1); memcpy (iv + 1, nonce, 12); // counter | nonce
|
||||||
|
EVP_EncryptInit_ex(ctx, EVP_chacha20 (), NULL, key, (const uint8_t *)iv);
|
||||||
|
int outlen = 0;
|
||||||
|
EVP_EncryptUpdate(ctx, out, &outlen, msg, msgLen);
|
||||||
|
EVP_EncryptFinal_ex(ctx, NULL, &outlen);
|
||||||
|
EVP_CIPHER_CTX_free (ctx);
|
||||||
|
#else
|
||||||
|
chacha::Chacha20State state;
|
||||||
|
chacha::Chacha20Init (state, nonce, key, 1);
|
||||||
|
if (out != msg) memcpy (out, msg, msgLen);
|
||||||
|
chacha::Chacha20Encrypt (state, out, msgLen);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, const std::string& info, uint8_t * out)
|
||||||
|
{
|
||||||
|
#if OPENSSL_HKDF
|
||||||
|
EVP_PKEY_CTX * pctx = EVP_PKEY_CTX_new_id (EVP_PKEY_HKDF, NULL);
|
||||||
|
EVP_PKEY_derive_init (pctx);
|
||||||
|
EVP_PKEY_CTX_set_hkdf_md (pctx, EVP_sha256());
|
||||||
|
EVP_PKEY_CTX_set1_hkdf_salt (pctx, salt, 32);
|
||||||
|
EVP_PKEY_CTX_set1_hkdf_key (pctx, key, keyLen);
|
||||||
|
if (info.length () > 0)
|
||||||
|
EVP_PKEY_CTX_add1_hkdf_info (pctx, info.c_str (), info.length ());
|
||||||
|
size_t outlen = 64;
|
||||||
|
EVP_PKEY_derive (pctx, out, &outlen);
|
||||||
|
EVP_PKEY_CTX_free (pctx);
|
||||||
|
#else
|
||||||
|
uint8_t prk[32]; unsigned int len;
|
||||||
|
HMAC(EVP_sha256(), salt, 32, key, keyLen, prk, &len);
|
||||||
|
auto l = info.length ();
|
||||||
|
memcpy (out, info.c_str (), l); out[l] = 0x01;
|
||||||
|
HMAC(EVP_sha256(), prk, 32, out, l + 1, out, &len);
|
||||||
|
memcpy (out + 32, info.c_str (), l); out[l + 32] = 0x02;
|
||||||
|
HMAC(EVP_sha256(), prk, 32, out, l + 33, out + 32, &len);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// init and terminate
|
// init and terminate
|
||||||
|
|
||||||
/* std::vector <std::unique_ptr<std::mutex> > m_OpenSSLMutexes;
|
/* std::vector <std::unique_ptr<std::mutex> > m_OpenSSLMutexes;
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
# define X509_getm_notAfter X509_get_notAfter
|
# define X509_getm_notAfter X509_get_notAfter
|
||||||
#else
|
#else
|
||||||
# define LEGACY_OPENSSL 0
|
# define LEGACY_OPENSSL 0
|
||||||
|
# define OPENSSL_HKDF 1
|
||||||
# if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1
|
# if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1
|
||||||
# define OPENSSL_EDDSA 1
|
# define OPENSSL_EDDSA 1
|
||||||
# define OPENSSL_X25519 1
|
# define OPENSSL_X25519 1
|
||||||
@@ -290,6 +291,13 @@ namespace crypto
|
|||||||
|
|
||||||
void AEADChaCha20Poly1305Encrypt (const std::vector<std::pair<uint8_t *, size_t> >& bufs, const uint8_t * key, const uint8_t * nonce, uint8_t * mac); // encrypt multiple buffers with zero ad
|
void AEADChaCha20Poly1305Encrypt (const std::vector<std::pair<uint8_t *, size_t> >& bufs, const uint8_t * key, const uint8_t * nonce, uint8_t * mac); // encrypt multiple buffers with zero ad
|
||||||
|
|
||||||
|
// ChaCha20
|
||||||
|
void ChaCha20 (const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out);
|
||||||
|
|
||||||
|
// HKDF
|
||||||
|
|
||||||
|
void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, const std::string& info, uint8_t * out); // salt - 32, out - 64, info <= 32
|
||||||
|
|
||||||
// init and terminate
|
// init and terminate
|
||||||
void InitCrypto (bool precomputation);
|
void InitCrypto (bool precomputation);
|
||||||
void TerminateCrypto ();
|
void TerminateCrypto ();
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ namespace client
|
|||||||
return pool->Reconfigure(inLen, outLen, inQuant, outQuant);
|
return pool->Reconfigure(inLen, outLen, inQuant, outQuant);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const i2p::data::LeaseSet> LeaseSetDestination::FindLeaseSet (const i2p::data::IdentHash& ident)
|
std::shared_ptr<i2p::data::LeaseSet> LeaseSetDestination::FindLeaseSet (const i2p::data::IdentHash& ident)
|
||||||
{
|
{
|
||||||
std::shared_ptr<i2p::data::LeaseSet> remoteLS;
|
std::shared_ptr<i2p::data::LeaseSet> remoteLS;
|
||||||
{
|
{
|
||||||
@@ -272,15 +272,21 @@ namespace client
|
|||||||
if (!m_Pool) return nullptr;
|
if (!m_Pool) return nullptr;
|
||||||
if (!m_LeaseSet)
|
if (!m_LeaseSet)
|
||||||
UpdateLeaseSet ();
|
UpdateLeaseSet ();
|
||||||
|
auto ls = GetLeaseSetMt ();
|
||||||
|
return (ls && ls->GetInnerLeaseSet ()) ? ls->GetInnerLeaseSet () : ls; // always non-encrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<const i2p::data::LocalLeaseSet> LeaseSetDestination::GetLeaseSetMt ()
|
||||||
|
{
|
||||||
std::lock_guard<std::mutex> l(m_LeaseSetMutex);
|
std::lock_guard<std::mutex> l(m_LeaseSetMutex);
|
||||||
return m_LeaseSet;
|
return m_LeaseSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LeaseSetDestination::SetLeaseSet (i2p::data::LocalLeaseSet * newLeaseSet)
|
void LeaseSetDestination::SetLeaseSet (std::shared_ptr<const i2p::data::LocalLeaseSet> newLeaseSet)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> l(m_LeaseSetMutex);
|
std::lock_guard<std::mutex> l(m_LeaseSetMutex);
|
||||||
m_LeaseSet.reset (newLeaseSet);
|
m_LeaseSet = newLeaseSet;
|
||||||
}
|
}
|
||||||
i2p::garlic::GarlicDestination::SetLeaseSetUpdated ();
|
i2p::garlic::GarlicDestination::SetLeaseSetUpdated ();
|
||||||
if (m_IsPublic)
|
if (m_IsPublic)
|
||||||
@@ -361,8 +367,10 @@ namespace client
|
|||||||
}
|
}
|
||||||
i2p::data::IdentHash key (buf + DATABASE_STORE_KEY_OFFSET);
|
i2p::data::IdentHash key (buf + DATABASE_STORE_KEY_OFFSET);
|
||||||
std::shared_ptr<i2p::data::LeaseSet> leaseSet;
|
std::shared_ptr<i2p::data::LeaseSet> leaseSet;
|
||||||
if (buf[DATABASE_STORE_TYPE_OFFSET] == i2p::data::NETDB_STORE_TYPE_LEASESET || // 1
|
switch (buf[DATABASE_STORE_TYPE_OFFSET])
|
||||||
buf[DATABASE_STORE_TYPE_OFFSET] == i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2) // 3
|
{
|
||||||
|
case i2p::data::NETDB_STORE_TYPE_LEASESET: // 1
|
||||||
|
case i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2: // 3
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "Destination: Remote LeaseSet");
|
LogPrint (eLogDebug, "Destination: Remote LeaseSet");
|
||||||
std::lock_guard<std::mutex> lock(m_RemoteLeaseSetsMutex);
|
std::lock_guard<std::mutex> lock(m_RemoteLeaseSetsMutex);
|
||||||
@@ -407,9 +415,28 @@ namespace client
|
|||||||
leaseSet = nullptr;
|
leaseSet = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2: // 5
|
||||||
|
{
|
||||||
|
auto it2 = m_LeaseSetRequests.find (key);
|
||||||
|
if (it2 != m_LeaseSetRequests.end () && it2->second->requestedBlindedKey)
|
||||||
|
{
|
||||||
|
auto ls2 = std::make_shared<i2p::data::LeaseSet2> (buf + offset, len - offset, it2->second->requestedBlindedKey);
|
||||||
|
if (ls2->IsValid ())
|
||||||
|
{
|
||||||
|
m_RemoteLeaseSets[ls2->GetIdentHash ()] = ls2; // ident is not key
|
||||||
|
m_RemoteLeaseSets[key] = ls2; // also store as key for next lookup
|
||||||
|
leaseSet = ls2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
LogPrint (eLogInfo, "Destination: Couldn't find request for encrypted LeaseSet2");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
LogPrint (eLogError, "Destination: Unexpected client's DatabaseStore type ", buf[DATABASE_STORE_TYPE_OFFSET], ", dropped");
|
LogPrint (eLogError, "Destination: Unexpected client's DatabaseStore type ", buf[DATABASE_STORE_TYPE_OFFSET], ", dropped");
|
||||||
|
}
|
||||||
|
|
||||||
auto it1 = m_LeaseSetRequests.find (key);
|
auto it1 = m_LeaseSetRequests.find (key);
|
||||||
if (it1 != m_LeaseSetRequests.end ())
|
if (it1 != m_LeaseSetRequests.end ())
|
||||||
@@ -485,7 +512,8 @@ namespace client
|
|||||||
|
|
||||||
void LeaseSetDestination::Publish ()
|
void LeaseSetDestination::Publish ()
|
||||||
{
|
{
|
||||||
if (!m_LeaseSet || !m_Pool)
|
auto leaseSet = GetLeaseSetMt ();
|
||||||
|
if (!leaseSet || !m_Pool)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "Destination: Can't publish non-existing LeaseSet");
|
LogPrint (eLogError, "Destination: Can't publish non-existing LeaseSet");
|
||||||
return;
|
return;
|
||||||
@@ -517,7 +545,7 @@ namespace client
|
|||||||
LogPrint (eLogError, "Destination: Can't publish LeaseSet. No inbound tunnels");
|
LogPrint (eLogError, "Destination: Can't publish LeaseSet. No inbound tunnels");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto floodfill = i2p::data::netdb.GetClosestFloodfill (m_LeaseSet->GetIdentHash (), m_ExcludedFloodfills);
|
auto floodfill = i2p::data::netdb.GetClosestFloodfill (leaseSet->GetIdentHash (), m_ExcludedFloodfills);
|
||||||
if (!floodfill)
|
if (!floodfill)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "Destination: Can't publish LeaseSet, no more floodfills found");
|
LogPrint (eLogError, "Destination: Can't publish LeaseSet, no more floodfills found");
|
||||||
@@ -527,7 +555,7 @@ namespace client
|
|||||||
m_ExcludedFloodfills.insert (floodfill->GetIdentHash ());
|
m_ExcludedFloodfills.insert (floodfill->GetIdentHash ());
|
||||||
LogPrint (eLogDebug, "Destination: Publish LeaseSet of ", GetIdentHash ().ToBase32 ());
|
LogPrint (eLogDebug, "Destination: Publish LeaseSet of ", GetIdentHash ().ToBase32 ());
|
||||||
RAND_bytes ((uint8_t *)&m_PublishReplyToken, 4);
|
RAND_bytes ((uint8_t *)&m_PublishReplyToken, 4);
|
||||||
auto msg = WrapMessage (floodfill, i2p::CreateDatabaseStoreMsg (m_LeaseSet, m_PublishReplyToken, inbound));
|
auto msg = WrapMessage (floodfill, i2p::CreateDatabaseStoreMsg (leaseSet, m_PublishReplyToken, inbound));
|
||||||
m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT));
|
m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT));
|
||||||
m_PublishConfirmationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishConfirmationTimer,
|
m_PublishConfirmationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishConfirmationTimer,
|
||||||
shared_from_this (), std::placeholders::_1));
|
shared_from_this (), std::placeholders::_1));
|
||||||
@@ -550,7 +578,7 @@ namespace client
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds from Java floodfill for crypto type ", (int)GetIdentity ()->GetCryptoKeyType ());
|
LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds from Java floodfill for crypto type ", (int)GetIdentity ()->GetCryptoKeyType ());
|
||||||
// Java floodfill never sends confirmantion back for unknown crypto type
|
// Java floodfill never sends confirmation back for unknown crypto type
|
||||||
// assume it successive and try to verify
|
// assume it successive and try to verify
|
||||||
m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_VERIFICATION_TIMEOUT));
|
m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_VERIFICATION_TIMEOUT));
|
||||||
m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer,
|
m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer,
|
||||||
@@ -565,26 +593,32 @@ namespace client
|
|||||||
{
|
{
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
{
|
{
|
||||||
|
auto ls = GetLeaseSetMt ();
|
||||||
|
if (!ls)
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "Destination: couldn't verify LeaseSet for ", GetIdentHash().ToBase32());
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto s = shared_from_this ();
|
auto s = shared_from_this ();
|
||||||
RequestLeaseSet (GetIdentHash (),
|
// we must capture this for gcc 4.7 due the bug
|
||||||
// "this" added due to bug in gcc 4.7-4.8
|
RequestLeaseSet (ls->GetStoreHash (),
|
||||||
[s,this](std::shared_ptr<i2p::data::LeaseSet> leaseSet)
|
[s, ls, this](std::shared_ptr<const i2p::data::LeaseSet> leaseSet)
|
||||||
{
|
{
|
||||||
if (leaseSet)
|
if (leaseSet)
|
||||||
{
|
{
|
||||||
if (s->m_LeaseSet && *s->m_LeaseSet == *leaseSet)
|
if (*ls == *leaseSet)
|
||||||
{
|
{
|
||||||
// we got latest LeasetSet
|
// we got latest LeasetSet
|
||||||
LogPrint (eLogDebug, "Destination: published LeaseSet verified for ", GetIdentHash().ToBase32());
|
LogPrint (eLogDebug, "Destination: published LeaseSet verified for ", s->GetIdentHash().ToBase32());
|
||||||
s->m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_REGULAR_VERIFICATION_INTERNAL));
|
s->m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_REGULAR_VERIFICATION_INTERNAL));
|
||||||
s->m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, s, std::placeholders::_1));
|
s->m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, s, std::placeholders::_1));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogDebug, "Destination: LeaseSet is different than just published for ", GetIdentHash().ToBase32());
|
LogPrint (eLogDebug, "Destination: LeaseSet is different than just published for ", s->GetIdentHash().ToBase32());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogWarning, "Destination: couldn't find published LeaseSet for ", GetIdentHash().ToBase32());
|
LogPrint (eLogWarning, "Destination: couldn't find published LeaseSet for ", s->GetIdentHash().ToBase32());
|
||||||
// we have to publish again
|
// we have to publish again
|
||||||
s->Publish ();
|
s->Publish ();
|
||||||
});
|
});
|
||||||
@@ -605,7 +639,27 @@ namespace client
|
|||||||
m_Service.post ([requestComplete](void){requestComplete (nullptr);});
|
m_Service.post ([requestComplete](void){requestComplete (nullptr);});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
m_Service.post (std::bind (&LeaseSetDestination::RequestLeaseSet, shared_from_this (), dest, requestComplete));
|
m_Service.post (std::bind (&LeaseSetDestination::RequestLeaseSet, shared_from_this (), dest, requestComplete, nullptr));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LeaseSetDestination::RequestDestinationWithEncryptedLeaseSet (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, RequestComplete requestComplete)
|
||||||
|
{
|
||||||
|
if (!dest || !m_Pool || !IsReady ())
|
||||||
|
{
|
||||||
|
if (requestComplete)
|
||||||
|
m_Service.post ([requestComplete](void){requestComplete (nullptr);});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto storeHash = dest->GetStoreHash ();
|
||||||
|
auto leaseSet = FindLeaseSet (storeHash);
|
||||||
|
if (leaseSet)
|
||||||
|
{
|
||||||
|
if (requestComplete)
|
||||||
|
m_Service.post ([requestComplete, leaseSet](void){requestComplete (leaseSet);});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
m_Service.post (std::bind (&LeaseSetDestination::RequestLeaseSet, shared_from_this (), storeHash, requestComplete, dest));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -624,13 +678,20 @@ namespace client
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void LeaseSetDestination::RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete)
|
void LeaseSetDestination::CancelDestinationRequestWithEncryptedLeaseSet (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, bool notify)
|
||||||
|
{
|
||||||
|
if (dest)
|
||||||
|
CancelDestinationRequest (dest->GetStoreHash (), notify);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LeaseSetDestination::RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> requestedBlindedKey)
|
||||||
{
|
{
|
||||||
std::set<i2p::data::IdentHash> excluded;
|
std::set<i2p::data::IdentHash> excluded;
|
||||||
auto floodfill = i2p::data::netdb.GetClosestFloodfill (dest, excluded);
|
auto floodfill = i2p::data::netdb.GetClosestFloodfill (dest, excluded);
|
||||||
if (floodfill)
|
if (floodfill)
|
||||||
{
|
{
|
||||||
auto request = std::make_shared<LeaseSetRequest> (m_Service);
|
auto request = std::make_shared<LeaseSetRequest> (m_Service);
|
||||||
|
request->requestedBlindedKey = requestedBlindedKey; // for encrypted LeaseSet2
|
||||||
if (requestComplete)
|
if (requestComplete)
|
||||||
request->requestComplete.push_back (requestComplete);
|
request->requestComplete.push_back (requestComplete);
|
||||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
@@ -777,6 +838,9 @@ namespace client
|
|||||||
m_DatagramDestination (nullptr), m_RefCounter (0),
|
m_DatagramDestination (nullptr), m_RefCounter (0),
|
||||||
m_ReadyChecker(GetService())
|
m_ReadyChecker(GetService())
|
||||||
{
|
{
|
||||||
|
if (keys.IsOfflineSignature () && GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET)
|
||||||
|
SetLeaseSetType (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2); // offline keys can be published with LS2 only
|
||||||
|
|
||||||
m_EncryptionKeyType = GetIdentity ()->GetCryptoKeyType ();
|
m_EncryptionKeyType = GetIdentity ()->GetCryptoKeyType ();
|
||||||
// extract encryption type params for LS2
|
// extract encryption type params for LS2
|
||||||
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2 && params)
|
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2 && params)
|
||||||
@@ -922,7 +986,7 @@ namespace client
|
|||||||
{
|
{
|
||||||
auto s = GetSharedFromThis ();
|
auto s = GetSharedFromThis ();
|
||||||
RequestDestination (dest,
|
RequestDestination (dest,
|
||||||
[s, streamRequestComplete, port](std::shared_ptr<i2p::data::LeaseSet> ls)
|
[s, streamRequestComplete, port](std::shared_ptr<const i2p::data::LeaseSet> ls)
|
||||||
{
|
{
|
||||||
if (ls)
|
if (ls)
|
||||||
streamRequestComplete(s->CreateStream (ls, port));
|
streamRequestComplete(s->CreateStream (ls, port));
|
||||||
@@ -932,6 +996,24 @@ namespace client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClientDestination::CreateStream (StreamRequestComplete streamRequestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> dest, int port)
|
||||||
|
{
|
||||||
|
if (!streamRequestComplete)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "Destination: request callback is not specified in CreateStream");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto s = GetSharedFromThis ();
|
||||||
|
RequestDestinationWithEncryptedLeaseSet (dest,
|
||||||
|
[s, streamRequestComplete, port](std::shared_ptr<i2p::data::LeaseSet> ls)
|
||||||
|
{
|
||||||
|
if (ls)
|
||||||
|
streamRequestComplete(s->CreateStream (ls, port));
|
||||||
|
else
|
||||||
|
streamRequestComplete (nullptr);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port)
|
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port)
|
||||||
{
|
{
|
||||||
if (m_StreamingDestination)
|
if (m_StreamingDestination)
|
||||||
@@ -1036,21 +1118,22 @@ namespace client
|
|||||||
|
|
||||||
void ClientDestination::CreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels)
|
void ClientDestination::CreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels)
|
||||||
{
|
{
|
||||||
i2p::data::LocalLeaseSet * leaseSet = nullptr;
|
std::shared_ptr<i2p::data::LocalLeaseSet> leaseSet;
|
||||||
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET)
|
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET)
|
||||||
{
|
{
|
||||||
leaseSet = new i2p::data::LocalLeaseSet (GetIdentity (), m_EncryptionPublicKey, tunnels);
|
leaseSet = std::make_shared<i2p::data::LocalLeaseSet> (GetIdentity (), m_EncryptionPublicKey, tunnels);
|
||||||
// sign
|
// sign
|
||||||
Sign (leaseSet->GetBuffer (), leaseSet->GetBufferLen () - leaseSet->GetSignatureLen (), leaseSet->GetSignature ());
|
Sign (leaseSet->GetBuffer (), leaseSet->GetBufferLen () - leaseSet->GetSignatureLen (), leaseSet->GetSignature ());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// standard LS2 (type 3) assumed for now. TODO: implement others
|
// standard LS2 (type 3) first
|
||||||
auto keyLen = m_Decryptor ? m_Decryptor->GetPublicKeyLen () : 256;
|
auto keyLen = m_Decryptor ? m_Decryptor->GetPublicKeyLen () : 256;
|
||||||
leaseSet = new i2p::data::LocalLeaseSet2 (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2,
|
auto ls2 = std::make_shared<i2p::data::LocalLeaseSet2> (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2,
|
||||||
GetIdentity (), m_EncryptionKeyType, keyLen, m_EncryptionPublicKey, tunnels);
|
m_Keys, m_EncryptionKeyType, keyLen, m_EncryptionPublicKey, tunnels);
|
||||||
// sign
|
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) // encrypt if type 5
|
||||||
Sign (leaseSet->GetBuffer () - 1, leaseSet->GetBufferLen () - leaseSet->GetSignatureLen () + 1, leaseSet->GetSignature ()); // + leading store type
|
ls2 = std::make_shared<i2p::data::LocalEncryptedLeaseSet2> (ls2, m_Keys);
|
||||||
|
leaseSet = ls2;
|
||||||
}
|
}
|
||||||
SetLeaseSet (leaseSet);
|
SetLeaseSet (leaseSet);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ namespace client
|
|||||||
std::list<RequestComplete> requestComplete;
|
std::list<RequestComplete> requestComplete;
|
||||||
std::shared_ptr<i2p::tunnel::OutboundTunnel> outboundTunnel;
|
std::shared_ptr<i2p::tunnel::OutboundTunnel> outboundTunnel;
|
||||||
std::shared_ptr<i2p::tunnel::InboundTunnel> replyTunnel;
|
std::shared_ptr<i2p::tunnel::InboundTunnel> replyTunnel;
|
||||||
|
std::shared_ptr<const i2p::data::BlindedPublicKey> requestedBlindedKey; // for encrypted LeaseSet2 only
|
||||||
|
|
||||||
void Complete (std::shared_ptr<i2p::data::LeaseSet> ls)
|
void Complete (std::shared_ptr<i2p::data::LeaseSet> ls)
|
||||||
{
|
{
|
||||||
@@ -107,9 +108,11 @@ namespace client
|
|||||||
boost::asio::io_service& GetService () { return m_Service; };
|
boost::asio::io_service& GetService () { return m_Service; };
|
||||||
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () { return m_Pool; };
|
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () { return m_Pool; };
|
||||||
bool IsReady () const { return m_LeaseSet && !m_LeaseSet->IsExpired () && m_Pool->GetOutboundTunnels ().size () > 0; };
|
bool IsReady () const { return m_LeaseSet && !m_LeaseSet->IsExpired () && m_Pool->GetOutboundTunnels ().size () > 0; };
|
||||||
std::shared_ptr<const i2p::data::LeaseSet> FindLeaseSet (const i2p::data::IdentHash& ident);
|
std::shared_ptr<i2p::data::LeaseSet> FindLeaseSet (const i2p::data::IdentHash& ident);
|
||||||
bool RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete = nullptr);
|
bool RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete = nullptr);
|
||||||
|
bool RequestDestinationWithEncryptedLeaseSet (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, RequestComplete requestComplete = nullptr);
|
||||||
void CancelDestinationRequest (const i2p::data::IdentHash& dest, bool notify = true);
|
void CancelDestinationRequest (const i2p::data::IdentHash& dest, bool notify = true);
|
||||||
|
void CancelDestinationRequestWithEncryptedLeaseSet (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, bool notify = true);
|
||||||
|
|
||||||
// implements GarlicDestination
|
// implements GarlicDestination
|
||||||
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet ();
|
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet ();
|
||||||
@@ -124,8 +127,9 @@ namespace client
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void SetLeaseSet (i2p::data::LocalLeaseSet * newLeaseSet);
|
void SetLeaseSet (std::shared_ptr<const i2p::data::LocalLeaseSet> newLeaseSet);
|
||||||
int GetLeaseSetType () const { return m_LeaseSetType; };
|
int GetLeaseSetType () const { return m_LeaseSetType; };
|
||||||
|
void SetLeaseSetType (int leaseSetType) { m_LeaseSetType = leaseSetType; };
|
||||||
virtual void CleanupDestination () {}; // additional clean up in derived classes
|
virtual void CleanupDestination () {}; // additional clean up in derived classes
|
||||||
// I2CP
|
// I2CP
|
||||||
virtual void HandleDataMessage (const uint8_t * buf, size_t len) = 0;
|
virtual void HandleDataMessage (const uint8_t * buf, size_t len) = 0;
|
||||||
@@ -135,6 +139,7 @@ namespace client
|
|||||||
|
|
||||||
void Run ();
|
void Run ();
|
||||||
void UpdateLeaseSet ();
|
void UpdateLeaseSet ();
|
||||||
|
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSetMt ();
|
||||||
void Publish ();
|
void Publish ();
|
||||||
void HandlePublishConfirmationTimer (const boost::system::error_code& ecode);
|
void HandlePublishConfirmationTimer (const boost::system::error_code& ecode);
|
||||||
void HandlePublishVerificationTimer (const boost::system::error_code& ecode);
|
void HandlePublishVerificationTimer (const boost::system::error_code& ecode);
|
||||||
@@ -143,7 +148,7 @@ namespace client
|
|||||||
void HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len);
|
void HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len);
|
||||||
void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
||||||
|
|
||||||
void RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete);
|
void RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> requestedBlindedKey = nullptr);
|
||||||
bool SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request);
|
bool SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request);
|
||||||
void HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest);
|
void HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest);
|
||||||
void HandleCleanupTimer (const boost::system::error_code& ecode);
|
void HandleCleanupTimer (const boost::system::error_code& ecode);
|
||||||
@@ -160,7 +165,7 @@ namespace client
|
|||||||
|
|
||||||
std::shared_ptr<i2p::tunnel::TunnelPool> m_Pool;
|
std::shared_ptr<i2p::tunnel::TunnelPool> m_Pool;
|
||||||
std::mutex m_LeaseSetMutex;
|
std::mutex m_LeaseSetMutex;
|
||||||
std::shared_ptr<i2p::data::LocalLeaseSet> m_LeaseSet;
|
std::shared_ptr<const i2p::data::LocalLeaseSet> m_LeaseSet;
|
||||||
bool m_IsPublic;
|
bool m_IsPublic;
|
||||||
uint32_t m_PublishReplyToken;
|
uint32_t m_PublishReplyToken;
|
||||||
uint64_t m_LastSubmissionTime; // in seconds
|
uint64_t m_LastSubmissionTime; // in seconds
|
||||||
@@ -208,6 +213,7 @@ namespace client
|
|||||||
std::shared_ptr<i2p::stream::StreamingDestination> GetStreamingDestination (int port = 0) const;
|
std::shared_ptr<i2p::stream::StreamingDestination> GetStreamingDestination (int port = 0) const;
|
||||||
// following methods operate with default streaming destination
|
// following methods operate with default streaming destination
|
||||||
void CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port = 0);
|
void CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port = 0);
|
||||||
|
void CreateStream (StreamRequestComplete streamRequestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> dest, int port = 0);
|
||||||
std::shared_ptr<i2p::stream::Stream> CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0);
|
std::shared_ptr<i2p::stream::Stream> CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0);
|
||||||
void AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor);
|
void AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor);
|
||||||
void StopAcceptingStreams ();
|
void StopAcceptingStreams ();
|
||||||
|
|||||||
@@ -121,8 +121,8 @@ namespace crypto
|
|||||||
return passed;
|
return passed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Ed25519::Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len,
|
void Ed25519::Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded,
|
||||||
uint8_t * signature) const
|
const uint8_t * buf, size_t len, uint8_t * signature) const
|
||||||
{
|
{
|
||||||
BN_CTX * bnCtx = BN_CTX_new ();
|
BN_CTX * bnCtx = BN_CTX_new ();
|
||||||
// calculate r
|
// calculate r
|
||||||
@@ -153,6 +153,44 @@ namespace crypto
|
|||||||
BN_CTX_free (bnCtx);
|
BN_CTX_free (bnCtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Ed25519::SignRedDSA (const uint8_t * privateKey, const uint8_t * publicKeyEncoded,
|
||||||
|
const uint8_t * buf, size_t len, uint8_t * signature) const
|
||||||
|
{
|
||||||
|
BN_CTX * bnCtx = BN_CTX_new ();
|
||||||
|
// T = 80 random bytes
|
||||||
|
uint8_t T[80];
|
||||||
|
RAND_bytes (T, 80);
|
||||||
|
// calculate r = H*(T || publickey || data)
|
||||||
|
SHA512_CTX ctx;
|
||||||
|
SHA512_Init (&ctx);
|
||||||
|
SHA512_Update (&ctx, T, 80);
|
||||||
|
SHA512_Update (&ctx, publicKeyEncoded, 32);
|
||||||
|
SHA512_Update (&ctx, buf, len); // data
|
||||||
|
uint8_t digest[64];
|
||||||
|
SHA512_Final (digest, &ctx);
|
||||||
|
BIGNUM * r = DecodeBN<64> (digest);
|
||||||
|
BN_mod (r, r, l, bnCtx); // % l
|
||||||
|
EncodeBN (r, digest, 32);
|
||||||
|
// calculate R
|
||||||
|
uint8_t R[EDDSA25519_SIGNATURE_LENGTH/2]; // we must use separate buffer because signature might be inside buf
|
||||||
|
EncodePoint (Normalize (MulB (digest, bnCtx), bnCtx), R);
|
||||||
|
// calculate S
|
||||||
|
SHA512_Init (&ctx);
|
||||||
|
SHA512_Update (&ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R
|
||||||
|
SHA512_Update (&ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key
|
||||||
|
SHA512_Update (&ctx, buf, len); // data
|
||||||
|
SHA512_Final (digest, &ctx);
|
||||||
|
BIGNUM * h = DecodeBN<64> (digest);
|
||||||
|
// S = (r + h*a) % l
|
||||||
|
BIGNUM * a = DecodeBN<EDDSA25519_PRIVATE_KEY_LENGTH> (privateKey);
|
||||||
|
BN_mod_mul (h, h, a, l, bnCtx); // %l
|
||||||
|
BN_mod_add (h, h, r, l, bnCtx); // %l
|
||||||
|
memcpy (signature, R, EDDSA25519_SIGNATURE_LENGTH/2);
|
||||||
|
EncodeBN (h, signature + EDDSA25519_SIGNATURE_LENGTH/2, EDDSA25519_SIGNATURE_LENGTH/2); // S
|
||||||
|
BN_free (r); BN_free (h); BN_free (a);
|
||||||
|
BN_CTX_free (bnCtx);
|
||||||
|
}
|
||||||
|
|
||||||
EDDSAPoint Ed25519::Sum (const EDDSAPoint& p1, const EDDSAPoint& p2, BN_CTX * ctx) const
|
EDDSAPoint Ed25519::Sum (const EDDSAPoint& p1, const EDDSAPoint& p2, BN_CTX * ctx) const
|
||||||
{
|
{
|
||||||
// x3 = (x1*y2+y1*x2)*(z1*z2-d*t1*t2)
|
// x3 = (x1*y2+y1*x2)*(z1*z2-d*t1*t2)
|
||||||
@@ -491,6 +529,39 @@ namespace crypto
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void Ed25519::BlindPublicKey (const uint8_t * pub, const uint8_t * seed, uint8_t * blinded)
|
||||||
|
{
|
||||||
|
BN_CTX * ctx = BN_CTX_new ();
|
||||||
|
// calculate alpha = seed mod l
|
||||||
|
BIGNUM * alpha = DecodeBN<64> (seed); // seed is in Little Endian
|
||||||
|
BN_mod (alpha, alpha, l, ctx); // % l
|
||||||
|
uint8_t priv[32];
|
||||||
|
EncodeBN (alpha, priv, 32); // back to Little Endian
|
||||||
|
BN_free (alpha);
|
||||||
|
// A' = BLIND_PUBKEY(A, alpha) = A + DERIVE_PUBLIC(alpha)
|
||||||
|
auto A1 = Sum (DecodePublicKey (pub, ctx), MulB (priv, ctx), ctx); // pub + B*alpha
|
||||||
|
EncodePublicKey (A1, blinded, ctx);
|
||||||
|
BN_CTX_free (ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ed25519::BlindPrivateKey (const uint8_t * priv, const uint8_t * seed, uint8_t * blindedPriv, uint8_t * blindedPub)
|
||||||
|
{
|
||||||
|
BN_CTX * ctx = BN_CTX_new ();
|
||||||
|
// calculate alpha = seed mod l
|
||||||
|
BIGNUM * alpha = DecodeBN<64> (seed); // seed is in Little Endian
|
||||||
|
BN_mod (alpha, alpha, l, ctx); // % l
|
||||||
|
BIGNUM * p = DecodeBN<32> (priv); // priv is in Little Endian
|
||||||
|
BN_add (alpha, alpha, p); // alpha = alpha + priv
|
||||||
|
// a' = BLIND_PRIVKEY(a, alpha) = (a + alpha) mod L
|
||||||
|
BN_mod (alpha, alpha, l, ctx); // % l
|
||||||
|
EncodeBN (alpha, blindedPriv, 32);
|
||||||
|
// A' = DERIVE_PUBLIC(a')
|
||||||
|
auto A1 = MulB (blindedPriv, ctx);
|
||||||
|
EncodePublicKey (A1, blindedPub, ctx);
|
||||||
|
BN_free (alpha); BN_free (p);
|
||||||
|
BN_CTX_free (ctx);
|
||||||
|
}
|
||||||
|
|
||||||
void Ed25519::ExpandPrivateKey (const uint8_t * key, uint8_t * expandedKey)
|
void Ed25519::ExpandPrivateKey (const uint8_t * key, uint8_t * expandedKey)
|
||||||
{
|
{
|
||||||
SHA512 (key, EDDSA25519_PRIVATE_KEY_LENGTH, expandedKey);
|
SHA512 (key, EDDSA25519_PRIVATE_KEY_LENGTH, expandedKey);
|
||||||
@@ -499,6 +570,18 @@ namespace crypto
|
|||||||
expandedKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] |= 0x40; // set second bit
|
expandedKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] |= 0x40; // set second bit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Ed25519::CreateRedDSAPrivateKey (uint8_t * priv)
|
||||||
|
{
|
||||||
|
uint8_t seed[32];
|
||||||
|
RAND_bytes (seed, 32);
|
||||||
|
BIGNUM * p = DecodeBN<32> (seed);
|
||||||
|
BN_CTX * ctx = BN_CTX_new ();
|
||||||
|
BN_mod (p, p, l, ctx); // % l
|
||||||
|
EncodeBN (p, priv, 32);
|
||||||
|
BN_CTX_free (ctx);
|
||||||
|
BN_free (p);
|
||||||
|
}
|
||||||
|
|
||||||
static std::unique_ptr<Ed25519> g_Ed25519;
|
static std::unique_ptr<Ed25519> g_Ed25519;
|
||||||
std::unique_ptr<Ed25519>& GetEd25519 ()
|
std::unique_ptr<Ed25519>& GetEd25519 ()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -80,11 +80,15 @@ namespace crypto
|
|||||||
void ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; // p is point, e is number for x25519
|
void ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; // p is point, e is number for x25519
|
||||||
void ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const;
|
void ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const;
|
||||||
#endif
|
#endif
|
||||||
|
void BlindPublicKey (const uint8_t * pub, const uint8_t * seed, uint8_t * blinded); // for encrypted LeaseSet2, pub - 32, seed - 64, blinded - 32
|
||||||
|
void BlindPrivateKey (const uint8_t * priv, const uint8_t * seed, uint8_t * blindedPriv, uint8_t * blindedPub); // for encrypted LeaseSet2, pub - 32, seed - 64, blinded - 32
|
||||||
|
|
||||||
bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const;
|
bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const;
|
||||||
void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, uint8_t * signature) const;
|
void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, uint8_t * signature) const;
|
||||||
|
void SignRedDSA (const uint8_t * privateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, uint8_t * signature) const;
|
||||||
|
|
||||||
static void ExpandPrivateKey (const uint8_t * key, uint8_t * expandedKey); // key - 32 bytes, expandedKey - 64 bytes
|
static void ExpandPrivateKey (const uint8_t * key, uint8_t * expandedKey); // key - 32 bytes, expandedKey - 64 bytes
|
||||||
|
void CreateRedDSAPrivateKey (uint8_t * priv); // priv is 32 bytes
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <shlobj.h>
|
#include <shlobj.h>
|
||||||
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "Base.h"
|
#include "Base.h"
|
||||||
@@ -47,18 +48,39 @@ namespace fs {
|
|||||||
}
|
}
|
||||||
#if defined(WIN32) || defined(_WIN32)
|
#if defined(WIN32) || defined(_WIN32)
|
||||||
char localAppData[MAX_PATH];
|
char localAppData[MAX_PATH];
|
||||||
|
|
||||||
// check executable directory first
|
// check executable directory first
|
||||||
GetModuleFileName (NULL, localAppData, MAX_PATH);
|
if(!GetModuleFileName(NULL, localAppData, MAX_PATH))
|
||||||
|
{
|
||||||
|
#if defined(WIN32_APP)
|
||||||
|
MessageBox(NULL, TEXT("Unable to get application path!"), TEXT("I2Pd: error"), MB_ICONERROR | MB_OK);
|
||||||
|
#else
|
||||||
|
fprintf(stderr, "Error: Unable to get application path!");
|
||||||
|
#endif
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
auto execPath = boost::filesystem::path(localAppData).parent_path();
|
auto execPath = boost::filesystem::path(localAppData).parent_path();
|
||||||
|
|
||||||
// if config file exists in .exe's folder use it
|
// if config file exists in .exe's folder use it
|
||||||
if(boost::filesystem::exists(execPath/"i2pd.conf")) // TODO: magic string
|
if(boost::filesystem::exists(execPath/"i2pd.conf")) // TODO: magic string
|
||||||
dataDir = execPath.string ();
|
dataDir = execPath.string ();
|
||||||
else
|
else // otherwise %appdata%
|
||||||
{
|
{
|
||||||
// otherwise %appdata%
|
if(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, localAppData) != S_OK)
|
||||||
SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, localAppData);
|
{
|
||||||
|
#if defined(WIN32_APP)
|
||||||
|
MessageBox(NULL, TEXT("Unable to get AppData path!"), TEXT("I2Pd: error"), MB_ICONERROR | MB_OK);
|
||||||
|
#else
|
||||||
|
fprintf(stderr, "Error: Unable to get AppData path!");
|
||||||
|
#endif
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
dataDir = std::string(localAppData) + "\\" + appName;
|
dataDir = std::string(localAppData) + "\\" + appName;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
#elif defined(MAC_OSX)
|
#elif defined(MAC_OSX)
|
||||||
char *home = getenv("HOME");
|
char *home = getenv("HOME");
|
||||||
@@ -74,8 +96,8 @@ namespace fs {
|
|||||||
dataDir = std::string (ext) + "/" + appName;
|
dataDir = std::string (ext) + "/" + appName;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// otherwise use /data/files
|
|
||||||
#endif
|
#endif
|
||||||
|
// otherwise use /data/files
|
||||||
char *home = getenv("HOME");
|
char *home = getenv("HOME");
|
||||||
if (isService) {
|
if (isService) {
|
||||||
dataDir = "/var/lib/" + appName;
|
dataDir = "/var/lib/" + appName;
|
||||||
@@ -91,9 +113,11 @@ namespace fs {
|
|||||||
bool Init() {
|
bool Init() {
|
||||||
if (!boost::filesystem::exists(dataDir))
|
if (!boost::filesystem::exists(dataDir))
|
||||||
boost::filesystem::create_directory(dataDir);
|
boost::filesystem::create_directory(dataDir);
|
||||||
|
|
||||||
std::string destinations = DataDirPath("destinations");
|
std::string destinations = DataDirPath("destinations");
|
||||||
if (!boost::filesystem::exists(destinations))
|
if (!boost::filesystem::exists(destinations))
|
||||||
boost::filesystem::create_directory(destinations);
|
boost::filesystem::create_directory(destinations);
|
||||||
|
|
||||||
std::string tags = DataDirPath("tags");
|
std::string tags = DataDirPath("tags");
|
||||||
if (!boost::filesystem::exists(tags))
|
if (!boost::filesystem::exists(tags))
|
||||||
boost::filesystem::create_directory(tags);
|
boost::filesystem::create_directory(tags);
|
||||||
@@ -124,7 +148,8 @@ namespace fs {
|
|||||||
|
|
||||||
uint32_t GetLastUpdateTime (const std::string & path)
|
uint32_t GetLastUpdateTime (const std::string & path)
|
||||||
{
|
{
|
||||||
if (!boost::filesystem::exists(path)) return 0;
|
if (!boost::filesystem::exists(path))
|
||||||
|
return 0;
|
||||||
boost::system::error_code ec;
|
boost::system::error_code ec;
|
||||||
auto t = boost::filesystem::last_write_time (path, ec);
|
auto t = boost::filesystem::last_write_time (path, ec);
|
||||||
return ec ? 0 : t;
|
return ec ? 0 : t;
|
||||||
@@ -138,8 +163,8 @@ namespace fs {
|
|||||||
|
|
||||||
bool CreateDirectory (const std::string& path)
|
bool CreateDirectory (const std::string& path)
|
||||||
{
|
{
|
||||||
if (boost::filesystem::exists(path) &&
|
if (boost::filesystem::exists(path) && boost::filesystem::is_directory (boost::filesystem::status (path)))
|
||||||
boost::filesystem::is_directory (boost::filesystem::status (path))) return true;
|
return true;
|
||||||
return boost::filesystem::create_directory(path);
|
return boost::filesystem::create_directory(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ namespace fs {
|
|||||||
|
|
||||||
/** @brief Returns current application name, default 'i2pd' */
|
/** @brief Returns current application name, default 'i2pd' */
|
||||||
const std::string & GetAppName ();
|
const std::string & GetAppName ();
|
||||||
/** @brief Set applicaton name, affects autodetection of datadir */
|
/** @brief Set application name, affects autodetection of datadir */
|
||||||
void SetAppName (const std::string& name);
|
void SetAppName (const std::string& name);
|
||||||
|
|
||||||
/** @brief Returns datadir path */
|
/** @brief Returns datadir path */
|
||||||
|
|||||||
@@ -578,7 +578,7 @@ namespace garlic
|
|||||||
tunnel = from->GetTunnelPool ()->GetNextOutboundTunnel ();
|
tunnel = from->GetTunnelPool ()->GetNextOutboundTunnel ();
|
||||||
else
|
else
|
||||||
LogPrint (eLogError, "Garlic: Tunnel pool is not set for inbound tunnel");
|
LogPrint (eLogError, "Garlic: Tunnel pool is not set for inbound tunnel");
|
||||||
if (tunnel) // we have send it through an outbound tunnel
|
if (tunnel) // we have sent it through an outbound tunnel
|
||||||
tunnel->SendTunnelDataMsg (gwHash, gwTunnel, msg);
|
tunnel->SendTunnelDataMsg (gwHash, gwTunnel, msg);
|
||||||
else
|
else
|
||||||
LogPrint (eLogWarning, "Garlic: No outbound tunnels available for garlic clove");
|
LogPrint (eLogWarning, "Garlic: No outbound tunnels available for garlic clove");
|
||||||
|
|||||||
@@ -55,12 +55,16 @@ namespace http {
|
|||||||
static std::pair<std::string, std::string> parse_header_line(const std::string& line)
|
static std::pair<std::string, std::string> parse_header_line(const std::string& line)
|
||||||
{
|
{
|
||||||
std::size_t pos = 0;
|
std::size_t pos = 0;
|
||||||
std::size_t len = 2; /* strlen(": ") */
|
std::size_t len = 1; /*: */
|
||||||
std::size_t max = line.length();
|
std::size_t max = line.length();
|
||||||
if ((pos = line.find(": ", pos)) == std::string::npos)
|
if ((pos = line.find(':', pos)) == std::string::npos)
|
||||||
return std::make_pair("", "");
|
return std::make_pair("", ""); // no ':' found
|
||||||
|
if (pos + 1 < max) // ':' at the end of header is valid
|
||||||
|
{
|
||||||
while ((pos + len) < max && isspace(line.at(pos + len)))
|
while ((pos + len) < max && isspace(line.at(pos + len)))
|
||||||
len++;
|
len++;
|
||||||
|
if (len == 1) return std::make_pair("", ""); // no following space, but something else
|
||||||
|
}
|
||||||
return std::make_pair(line.substr(0, pos), line.substr(pos + len));
|
return std::make_pair(line.substr(0, pos), line.substr(pos + len));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -279,7 +279,7 @@ namespace i2p
|
|||||||
if (!leaseSet) return nullptr;
|
if (!leaseSet) return nullptr;
|
||||||
auto m = NewI2NPShortMessage ();
|
auto m = NewI2NPShortMessage ();
|
||||||
uint8_t * payload = m->GetPayload ();
|
uint8_t * payload = m->GetPayload ();
|
||||||
memcpy (payload + DATABASE_STORE_KEY_OFFSET, leaseSet->GetIdentHash (), 32);
|
memcpy (payload + DATABASE_STORE_KEY_OFFSET, leaseSet->GetStoreHash (), 32);
|
||||||
payload[DATABASE_STORE_TYPE_OFFSET] = leaseSet->GetStoreType (); // LeaseSet or LeaseSet2
|
payload[DATABASE_STORE_TYPE_OFFSET] = leaseSet->GetStoreType (); // LeaseSet or LeaseSet2
|
||||||
htobe32buf (payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, replyToken);
|
htobe32buf (payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, replyToken);
|
||||||
size_t size = DATABASE_STORE_HEADER_SIZE;
|
size_t size = DATABASE_STORE_HEADER_SIZE;
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
#include <time.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "Crypto.h"
|
#include "Crypto.h"
|
||||||
#include "I2PEndian.h"
|
#include "I2PEndian.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
#include "Timestamp.h"
|
||||||
#include "Identity.h"
|
#include "Identity.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
@@ -77,6 +76,7 @@ namespace data
|
|||||||
LogPrint (eLogError, "Identity: RSA signing key type ", (int)type, " is not supported");
|
LogPrint (eLogError, "Identity: RSA signing key type ", (int)type, " is not supported");
|
||||||
break;
|
break;
|
||||||
case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
|
case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
|
||||||
|
case SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519:
|
||||||
{
|
{
|
||||||
size_t padding = 128 - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; // 96 = 128 - 32
|
size_t padding = 128 - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; // 96 = 128 - 32
|
||||||
RAND_bytes (m_StandardIdentity.signingKey, padding);
|
RAND_bytes (m_StandardIdentity.signingKey, padding);
|
||||||
@@ -275,6 +275,13 @@ namespace data
|
|||||||
return 128;
|
return 128;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const uint8_t * IdentityEx::GetSigningPublicKeyBuffer () const
|
||||||
|
{
|
||||||
|
auto keyLen = GetSigningPublicKeyLen ();
|
||||||
|
if (keyLen > 128) return nullptr; // P521
|
||||||
|
return m_StandardIdentity.signingKey + 128 - keyLen;
|
||||||
|
}
|
||||||
|
|
||||||
size_t IdentityEx::GetSigningPrivateKeyLen () const
|
size_t IdentityEx::GetSigningPrivateKeyLen () const
|
||||||
{
|
{
|
||||||
if (!m_Verifier) CreateVerifier ();
|
if (!m_Verifier) CreateVerifier ();
|
||||||
@@ -336,6 +343,8 @@ namespace data
|
|||||||
return new i2p::crypto::GOSTR3410_256_Verifier (i2p::crypto::eGOSTR3410CryptoProA);
|
return new i2p::crypto::GOSTR3410_256_Verifier (i2p::crypto::eGOSTR3410CryptoProA);
|
||||||
case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512:
|
case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512:
|
||||||
return new i2p::crypto::GOSTR3410_512_Verifier (i2p::crypto::eGOSTR3410TC26A512);
|
return new i2p::crypto::GOSTR3410_512_Verifier (i2p::crypto::eGOSTR3410TC26A512);
|
||||||
|
case SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519:
|
||||||
|
return new i2p::crypto::RedDSA25519Verifier ();
|
||||||
case SIGNING_KEY_TYPE_RSA_SHA256_2048:
|
case SIGNING_KEY_TYPE_RSA_SHA256_2048:
|
||||||
case SIGNING_KEY_TYPE_RSA_SHA384_3072:
|
case SIGNING_KEY_TYPE_RSA_SHA384_3072:
|
||||||
case SIGNING_KEY_TYPE_RSA_SHA512_4096:
|
case SIGNING_KEY_TYPE_RSA_SHA512_4096:
|
||||||
@@ -432,6 +441,9 @@ namespace data
|
|||||||
m_Public = std::make_shared<IdentityEx>(Identity (keys));
|
m_Public = std::make_shared<IdentityEx>(Identity (keys));
|
||||||
memcpy (m_PrivateKey, keys.privateKey, 256); // 256
|
memcpy (m_PrivateKey, keys.privateKey, 256); // 256
|
||||||
memcpy (m_SigningPrivateKey, keys.signingPrivateKey, m_Public->GetSigningPrivateKeyLen ());
|
memcpy (m_SigningPrivateKey, keys.signingPrivateKey, m_Public->GetSigningPrivateKeyLen ());
|
||||||
|
m_OfflineSignature.resize (0);
|
||||||
|
m_TransientSignatureLen = 0;
|
||||||
|
m_TransientSigningPrivateKeyLen = 0;
|
||||||
m_Signer = nullptr;
|
m_Signer = nullptr;
|
||||||
CreateSigner ();
|
CreateSigner ();
|
||||||
return *this;
|
return *this;
|
||||||
@@ -441,12 +453,23 @@ namespace data
|
|||||||
{
|
{
|
||||||
m_Public = std::make_shared<IdentityEx>(*other.m_Public);
|
m_Public = std::make_shared<IdentityEx>(*other.m_Public);
|
||||||
memcpy (m_PrivateKey, other.m_PrivateKey, 256); // 256
|
memcpy (m_PrivateKey, other.m_PrivateKey, 256); // 256
|
||||||
memcpy (m_SigningPrivateKey, other.m_SigningPrivateKey, m_Public->GetSigningPrivateKeyLen ());
|
m_OfflineSignature = other.m_OfflineSignature;
|
||||||
|
m_TransientSignatureLen = other.m_TransientSignatureLen;
|
||||||
|
m_TransientSigningPrivateKeyLen = other.m_TransientSigningPrivateKeyLen;
|
||||||
|
memcpy (m_SigningPrivateKey, other.m_SigningPrivateKey, m_TransientSigningPrivateKeyLen > 0 ? m_TransientSigningPrivateKeyLen : m_Public->GetSigningPrivateKeyLen ());
|
||||||
m_Signer = nullptr;
|
m_Signer = nullptr;
|
||||||
CreateSigner ();
|
CreateSigner ();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t PrivateKeys::GetFullLen () const
|
||||||
|
{
|
||||||
|
size_t ret = m_Public->GetFullLen () + 256 + m_Public->GetSigningPrivateKeyLen ();
|
||||||
|
if (IsOfflineSignature ())
|
||||||
|
ret += m_OfflineSignature.size () + m_TransientSigningPrivateKeyLen;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
size_t PrivateKeys::FromBuffer (const uint8_t * buf, size_t len)
|
size_t PrivateKeys::FromBuffer (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
m_Public = std::make_shared<IdentityEx>();
|
m_Public = std::make_shared<IdentityEx>();
|
||||||
@@ -455,11 +478,50 @@ namespace data
|
|||||||
memcpy (m_PrivateKey, buf + ret, 256); // private key always 256
|
memcpy (m_PrivateKey, buf + ret, 256); // private key always 256
|
||||||
ret += 256;
|
ret += 256;
|
||||||
size_t signingPrivateKeySize = m_Public->GetSigningPrivateKeyLen ();
|
size_t signingPrivateKeySize = m_Public->GetSigningPrivateKeyLen ();
|
||||||
if(signingPrivateKeySize + ret > len) return 0; // overflow
|
if(signingPrivateKeySize + ret > len || signingPrivateKeySize > 128) return 0; // overflow
|
||||||
memcpy (m_SigningPrivateKey, buf + ret, signingPrivateKeySize);
|
memcpy (m_SigningPrivateKey, buf + ret, signingPrivateKeySize);
|
||||||
ret += signingPrivateKeySize;
|
ret += signingPrivateKeySize;
|
||||||
m_Signer = nullptr;
|
m_Signer = nullptr;
|
||||||
CreateSigner ();
|
// check if signing private key is all zeros
|
||||||
|
bool allzeros = true;
|
||||||
|
for (size_t i = 0; i < signingPrivateKeySize; i++)
|
||||||
|
if (m_SigningPrivateKey[i])
|
||||||
|
{
|
||||||
|
allzeros = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (allzeros)
|
||||||
|
{
|
||||||
|
// offline information
|
||||||
|
const uint8_t * offlineInfo = buf + ret;
|
||||||
|
ret += 4; // expires timestamp
|
||||||
|
SigningKeyType keyType = bufbe16toh (buf + ret); ret += 2; // key type
|
||||||
|
std::unique_ptr<i2p::crypto::Verifier> transientVerifier (IdentityEx::CreateVerifier (keyType));
|
||||||
|
if (!transientVerifier) return 0;
|
||||||
|
auto keyLen = transientVerifier->GetPublicKeyLen ();
|
||||||
|
if (keyLen + ret > len) return 0;
|
||||||
|
transientVerifier->SetPublicKey (buf + ret); ret += keyLen;
|
||||||
|
if (m_Public->GetSignatureLen () + ret > len) return 0;
|
||||||
|
if (!m_Public->Verify (offlineInfo, keyLen + 6, buf + ret))
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "Identity: offline signature verification failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ret += m_Public->GetSignatureLen ();
|
||||||
|
m_TransientSignatureLen = transientVerifier->GetSignatureLen ();
|
||||||
|
// copy offline signature
|
||||||
|
size_t offlineInfoLen = buf + ret - offlineInfo;
|
||||||
|
m_OfflineSignature.resize (offlineInfoLen);
|
||||||
|
memcpy (m_OfflineSignature.data (), offlineInfo, offlineInfoLen);
|
||||||
|
// override signing private key
|
||||||
|
m_TransientSigningPrivateKeyLen = transientVerifier->GetPrivateKeyLen ();
|
||||||
|
if (m_TransientSigningPrivateKeyLen + ret > len || m_TransientSigningPrivateKeyLen > 128) return 0;
|
||||||
|
memcpy (m_SigningPrivateKey, buf + ret, m_TransientSigningPrivateKeyLen);
|
||||||
|
ret += m_TransientSigningPrivateKeyLen;
|
||||||
|
CreateSigner (keyType);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
CreateSigner (m_Public->GetSigningKeyType ());
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,8 +532,23 @@ namespace data
|
|||||||
ret += 256;
|
ret += 256;
|
||||||
size_t signingPrivateKeySize = m_Public->GetSigningPrivateKeyLen ();
|
size_t signingPrivateKeySize = m_Public->GetSigningPrivateKeyLen ();
|
||||||
if(ret + signingPrivateKeySize > len) return 0; // overflow
|
if(ret + signingPrivateKeySize > len) return 0; // overflow
|
||||||
|
if (IsOfflineSignature ())
|
||||||
|
memset (buf + ret, 0, signingPrivateKeySize);
|
||||||
|
else
|
||||||
memcpy (buf + ret, m_SigningPrivateKey, signingPrivateKeySize);
|
memcpy (buf + ret, m_SigningPrivateKey, signingPrivateKeySize);
|
||||||
ret += signingPrivateKeySize;
|
ret += signingPrivateKeySize;
|
||||||
|
if (IsOfflineSignature ())
|
||||||
|
{
|
||||||
|
// offline signature
|
||||||
|
auto offlineSignatureLen = m_OfflineSignature.size ();
|
||||||
|
if (ret + offlineSignatureLen > len) return 0;
|
||||||
|
memcpy (buf + ret, m_OfflineSignature.data (), offlineSignatureLen);
|
||||||
|
ret += offlineSignatureLen;
|
||||||
|
// transient private key
|
||||||
|
if (ret + m_TransientSigningPrivateKeyLen > len) return 0;
|
||||||
|
memcpy (buf + ret, m_SigningPrivateKey, m_TransientSigningPrivateKeyLen);
|
||||||
|
ret += m_TransientSigningPrivateKeyLen;
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,38 +583,66 @@ namespace data
|
|||||||
|
|
||||||
void PrivateKeys::CreateSigner () const
|
void PrivateKeys::CreateSigner () const
|
||||||
{
|
{
|
||||||
if (m_Signer) return;
|
if (IsOfflineSignature ())
|
||||||
switch (m_Public->GetSigningKeyType ())
|
CreateSigner (bufbe16toh (m_OfflineSignature.data () + 4)); // key type
|
||||||
|
else
|
||||||
|
CreateSigner (m_Public->GetSigningKeyType ());
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrivateKeys::CreateSigner (SigningKeyType keyType) const
|
||||||
{
|
{
|
||||||
case SIGNING_KEY_TYPE_DSA_SHA1:
|
if (m_Signer) return;
|
||||||
|
if (keyType == SIGNING_KEY_TYPE_DSA_SHA1)
|
||||||
m_Signer.reset (new i2p::crypto::DSASigner (m_SigningPrivateKey, m_Public->GetStandardIdentity ().signingKey));
|
m_Signer.reset (new i2p::crypto::DSASigner (m_SigningPrivateKey, m_Public->GetStandardIdentity ().signingKey));
|
||||||
break;
|
else if (keyType == SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519 && !IsOfflineSignature ())
|
||||||
|
m_Signer.reset (new i2p::crypto::EDDSA25519Signer (m_SigningPrivateKey, m_Public->GetStandardIdentity ().certificate - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH)); // TODO: remove public key check
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// public key is not required
|
||||||
|
auto signer = CreateSigner (keyType, m_SigningPrivateKey);
|
||||||
|
if (signer) m_Signer.reset (signer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i2p::crypto::Signer * PrivateKeys::CreateSigner (SigningKeyType keyType, const uint8_t * priv)
|
||||||
|
{
|
||||||
|
switch (keyType)
|
||||||
|
{
|
||||||
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
|
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
|
||||||
m_Signer.reset (new i2p::crypto::ECDSAP256Signer (m_SigningPrivateKey));
|
return new i2p::crypto::ECDSAP256Signer (priv);
|
||||||
break;
|
break;
|
||||||
case SIGNING_KEY_TYPE_ECDSA_SHA384_P384:
|
case SIGNING_KEY_TYPE_ECDSA_SHA384_P384:
|
||||||
m_Signer.reset (new i2p::crypto::ECDSAP384Signer (m_SigningPrivateKey));
|
return new i2p::crypto::ECDSAP384Signer (priv);
|
||||||
break;
|
break;
|
||||||
case SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
|
case SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
|
||||||
m_Signer.reset (new i2p::crypto::ECDSAP521Signer (m_SigningPrivateKey));
|
return new i2p::crypto::ECDSAP521Signer (priv);
|
||||||
break;
|
break;
|
||||||
case SIGNING_KEY_TYPE_RSA_SHA256_2048:
|
case SIGNING_KEY_TYPE_RSA_SHA256_2048:
|
||||||
case SIGNING_KEY_TYPE_RSA_SHA384_3072:
|
case SIGNING_KEY_TYPE_RSA_SHA384_3072:
|
||||||
case SIGNING_KEY_TYPE_RSA_SHA512_4096:
|
case SIGNING_KEY_TYPE_RSA_SHA512_4096:
|
||||||
LogPrint (eLogError, "Identity: RSA signing key type ", (int)m_Public->GetSigningKeyType (), " is not supported");
|
LogPrint (eLogError, "Identity: RSA signing key type ", (int)keyType, " is not supported");
|
||||||
break;
|
break;
|
||||||
case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
|
case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
|
||||||
m_Signer.reset (new i2p::crypto::EDDSA25519Signer (m_SigningPrivateKey, m_Public->GetStandardIdentity ().certificate - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH));
|
return new i2p::crypto::EDDSA25519Signer (priv, nullptr);
|
||||||
break;
|
break;
|
||||||
case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256:
|
case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256:
|
||||||
m_Signer.reset (new i2p::crypto::GOSTR3410_256_Signer (i2p::crypto::eGOSTR3410CryptoProA, m_SigningPrivateKey));
|
return new i2p::crypto::GOSTR3410_256_Signer (i2p::crypto::eGOSTR3410CryptoProA, priv);
|
||||||
break;
|
break;
|
||||||
case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512:
|
case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512:
|
||||||
m_Signer.reset (new i2p::crypto::GOSTR3410_512_Signer (i2p::crypto::eGOSTR3410TC26A512, m_SigningPrivateKey));
|
return new i2p::crypto::GOSTR3410_512_Signer (i2p::crypto::eGOSTR3410TC26A512, priv);
|
||||||
|
break;
|
||||||
|
case SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519:
|
||||||
|
return new i2p::crypto::RedDSA25519Signer (priv);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LogPrint (eLogError, "Identity: Signing key type ", (int)m_Public->GetSigningKeyType (), " is not supported");
|
LogPrint (eLogError, "Identity: Signing key type ", (int)keyType, " is not supported");
|
||||||
}
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t PrivateKeys::GetSignatureLen () const
|
||||||
|
{
|
||||||
|
return IsOfflineSignature () ? m_TransientSignatureLen : m_Public->GetSignatureLen ();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t * PrivateKeys::GetPadding()
|
uint8_t * PrivateKeys::GetPadding()
|
||||||
@@ -582,35 +687,7 @@ namespace data
|
|||||||
PrivateKeys keys;
|
PrivateKeys keys;
|
||||||
// signature
|
// signature
|
||||||
uint8_t signingPublicKey[512]; // signing public key is 512 bytes max
|
uint8_t signingPublicKey[512]; // signing public key is 512 bytes max
|
||||||
switch (type)
|
GenerateSigningKeyPair (type, keys.m_SigningPrivateKey, signingPublicKey);
|
||||||
{
|
|
||||||
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
|
|
||||||
i2p::crypto::CreateECDSAP256RandomKeys (keys.m_SigningPrivateKey, signingPublicKey);
|
|
||||||
break;
|
|
||||||
case SIGNING_KEY_TYPE_ECDSA_SHA384_P384:
|
|
||||||
i2p::crypto::CreateECDSAP384RandomKeys (keys.m_SigningPrivateKey, signingPublicKey);
|
|
||||||
break;
|
|
||||||
case SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
|
|
||||||
i2p::crypto::CreateECDSAP521RandomKeys (keys.m_SigningPrivateKey, signingPublicKey);
|
|
||||||
break;
|
|
||||||
case SIGNING_KEY_TYPE_RSA_SHA256_2048:
|
|
||||||
case SIGNING_KEY_TYPE_RSA_SHA384_3072:
|
|
||||||
case SIGNING_KEY_TYPE_RSA_SHA512_4096:
|
|
||||||
LogPrint (eLogWarning, "Identity: RSA signature type is not supported. Creating EdDSA");
|
|
||||||
// no break here
|
|
||||||
case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
|
|
||||||
i2p::crypto::CreateEDDSA25519RandomKeys (keys.m_SigningPrivateKey, signingPublicKey);
|
|
||||||
break;
|
|
||||||
case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256:
|
|
||||||
i2p::crypto::CreateGOSTR3410RandomKeys (i2p::crypto::eGOSTR3410CryptoProA, keys.m_SigningPrivateKey, signingPublicKey);
|
|
||||||
break;
|
|
||||||
case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512:
|
|
||||||
i2p::crypto::CreateGOSTR3410RandomKeys (i2p::crypto::eGOSTR3410TC26A512, keys.m_SigningPrivateKey, signingPublicKey);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LogPrint (eLogWarning, "Identity: Signing key type ", (int)type, " is not supported. Create DSA-SHA1");
|
|
||||||
return PrivateKeys (i2p::data::CreateRandomKeys ()); // DSA-SHA1
|
|
||||||
}
|
|
||||||
// encryption
|
// encryption
|
||||||
uint8_t publicKey[256];
|
uint8_t publicKey[256];
|
||||||
GenerateCryptoKeyPair (cryptoType, keys.m_PrivateKey, publicKey);
|
GenerateCryptoKeyPair (cryptoType, keys.m_PrivateKey, publicKey);
|
||||||
@@ -623,6 +700,42 @@ namespace data
|
|||||||
return PrivateKeys (i2p::data::CreateRandomKeys ()); // DSA-SHA1
|
return PrivateKeys (i2p::data::CreateRandomKeys ()); // DSA-SHA1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PrivateKeys::GenerateSigningKeyPair (SigningKeyType type, uint8_t * priv, uint8_t * pub)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
|
||||||
|
i2p::crypto::CreateECDSAP256RandomKeys (priv, pub);
|
||||||
|
break;
|
||||||
|
case SIGNING_KEY_TYPE_ECDSA_SHA384_P384:
|
||||||
|
i2p::crypto::CreateECDSAP384RandomKeys (priv, pub);
|
||||||
|
break;
|
||||||
|
case SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
|
||||||
|
i2p::crypto::CreateECDSAP521RandomKeys (priv, pub);
|
||||||
|
break;
|
||||||
|
case SIGNING_KEY_TYPE_RSA_SHA256_2048:
|
||||||
|
case SIGNING_KEY_TYPE_RSA_SHA384_3072:
|
||||||
|
case SIGNING_KEY_TYPE_RSA_SHA512_4096:
|
||||||
|
LogPrint (eLogWarning, "Identity: RSA signature type is not supported. Creating EdDSA");
|
||||||
|
// no break here
|
||||||
|
case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
|
||||||
|
i2p::crypto::CreateEDDSA25519RandomKeys (priv, pub);
|
||||||
|
break;
|
||||||
|
case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256:
|
||||||
|
i2p::crypto::CreateGOSTR3410RandomKeys (i2p::crypto::eGOSTR3410CryptoProA, priv, pub);
|
||||||
|
break;
|
||||||
|
case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512:
|
||||||
|
i2p::crypto::CreateGOSTR3410RandomKeys (i2p::crypto::eGOSTR3410TC26A512, priv, pub);
|
||||||
|
break;
|
||||||
|
case SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519:
|
||||||
|
i2p::crypto::CreateRedDSA25519RandomKeys (priv, pub);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LogPrint (eLogWarning, "Identity: Signing key type ", (int)type, " is not supported. Create DSA-SHA1");
|
||||||
|
i2p::crypto::CreateDSARandomKeys (priv, pub); // DSA-SHA1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PrivateKeys::GenerateCryptoKeyPair (CryptoKeyType type, uint8_t * priv, uint8_t * pub)
|
void PrivateKeys::GenerateCryptoKeyPair (CryptoKeyType type, uint8_t * priv, uint8_t * pub)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
@@ -642,6 +755,27 @@ namespace data
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PrivateKeys PrivateKeys::CreateOfflineKeys (SigningKeyType type, uint32_t expires) const
|
||||||
|
{
|
||||||
|
PrivateKeys keys (*this);
|
||||||
|
std::unique_ptr<i2p::crypto::Verifier> verifier (IdentityEx::CreateVerifier (type));
|
||||||
|
if (verifier)
|
||||||
|
{
|
||||||
|
size_t pubKeyLen = verifier->GetPublicKeyLen ();
|
||||||
|
keys.m_TransientSigningPrivateKeyLen = verifier->GetPrivateKeyLen ();
|
||||||
|
keys.m_TransientSignatureLen = verifier->GetSignatureLen ();
|
||||||
|
keys.m_OfflineSignature.resize (pubKeyLen + m_Public->GetSignatureLen () + 6);
|
||||||
|
htobe32buf (keys.m_OfflineSignature.data (), expires); // expires
|
||||||
|
htobe16buf (keys.m_OfflineSignature.data () + 4, type); // type
|
||||||
|
GenerateSigningKeyPair (type, keys.m_SigningPrivateKey, keys.m_OfflineSignature.data () + 6); // public key
|
||||||
|
Sign (keys.m_OfflineSignature.data (), pubKeyLen + 6, keys.m_OfflineSignature.data () + 6 + pubKeyLen); // signature
|
||||||
|
// recreate signer
|
||||||
|
keys.m_Signer = nullptr;
|
||||||
|
keys.CreateSigner (type);
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
Keys CreateRandomKeys ()
|
Keys CreateRandomKeys ()
|
||||||
{
|
{
|
||||||
Keys keys;
|
Keys keys;
|
||||||
@@ -656,15 +790,7 @@ namespace data
|
|||||||
{
|
{
|
||||||
uint8_t buf[41]; // ident + yyyymmdd
|
uint8_t buf[41]; // ident + yyyymmdd
|
||||||
memcpy (buf, (const uint8_t *)ident, 32);
|
memcpy (buf, (const uint8_t *)ident, 32);
|
||||||
time_t t = time (nullptr);
|
i2p::util::GetCurrentDate ((char *)(buf + 32));
|
||||||
struct tm tm;
|
|
||||||
#ifdef _WIN32
|
|
||||||
gmtime_s(&tm, &t);
|
|
||||||
sprintf_s((char *)(buf + 32), 9, "%04i%02i%02i", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
|
|
||||||
#else
|
|
||||||
gmtime_r(&t, &tm);
|
|
||||||
sprintf((char *)(buf + 32), "%04i%02i%02i", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
|
|
||||||
#endif
|
|
||||||
IdentHash key;
|
IdentHash key;
|
||||||
SHA256(buf, 40, key);
|
SHA256(buf, 40, key);
|
||||||
return key;
|
return key;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <vector>
|
||||||
#include "Base.h"
|
#include "Base.h"
|
||||||
#include "Signature.h"
|
#include "Signature.h"
|
||||||
#include "CryptoKey.h"
|
#include "CryptoKey.h"
|
||||||
@@ -66,9 +67,9 @@ namespace data
|
|||||||
const uint16_t SIGNING_KEY_TYPE_RSA_SHA512_4096 = 6;
|
const uint16_t SIGNING_KEY_TYPE_RSA_SHA512_4096 = 6;
|
||||||
const uint16_t SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519 = 7;
|
const uint16_t SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519 = 7;
|
||||||
const uint16_t SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519ph = 8; // not implemented
|
const uint16_t SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519ph = 8; // not implemented
|
||||||
// following signature type should never appear in netid=2
|
|
||||||
const uint16_t SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256 = 9;
|
const uint16_t SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256 = 9;
|
||||||
const uint16_t SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512 = 10; // approved by FSB
|
const uint16_t SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512 = 10; // approved by FSB
|
||||||
|
const uint16_t SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519 = 11; // for LeaseSet2 only
|
||||||
|
|
||||||
typedef uint16_t SigningKeyType;
|
typedef uint16_t SigningKeyType;
|
||||||
typedef uint16_t CryptoKeyType;
|
typedef uint16_t CryptoKeyType;
|
||||||
@@ -99,6 +100,7 @@ namespace data
|
|||||||
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> CreateEncryptor (const uint8_t * key) const;
|
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> CreateEncryptor (const uint8_t * key) const;
|
||||||
size_t GetFullLen () const { return m_ExtendedLen + DEFAULT_IDENTITY_SIZE; };
|
size_t GetFullLen () const { return m_ExtendedLen + DEFAULT_IDENTITY_SIZE; };
|
||||||
size_t GetSigningPublicKeyLen () const;
|
size_t GetSigningPublicKeyLen () const;
|
||||||
|
const uint8_t * GetSigningPublicKeyBuffer () const; // returns NULL for P521
|
||||||
size_t GetSigningPrivateKeyLen () const;
|
size_t GetSigningPrivateKeyLen () const;
|
||||||
size_t GetSignatureLen () const;
|
size_t GetSignatureLen () const;
|
||||||
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const;
|
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const;
|
||||||
@@ -142,11 +144,13 @@ namespace data
|
|||||||
std::shared_ptr<const IdentityEx> GetPublic () const { return m_Public; };
|
std::shared_ptr<const IdentityEx> GetPublic () const { return m_Public; };
|
||||||
const uint8_t * GetPrivateKey () const { return m_PrivateKey; };
|
const uint8_t * GetPrivateKey () const { return m_PrivateKey; };
|
||||||
const uint8_t * GetSigningPrivateKey () const { return m_SigningPrivateKey; };
|
const uint8_t * GetSigningPrivateKey () const { return m_SigningPrivateKey; };
|
||||||
|
size_t GetSignatureLen () const; // might not match identity
|
||||||
|
bool IsOfflineSignature () const { return m_TransientSignatureLen > 0; };
|
||||||
uint8_t * GetPadding();
|
uint8_t * GetPadding();
|
||||||
void RecalculateIdentHash(uint8_t * buf=nullptr) { m_Public->RecalculateIdentHash(buf); }
|
void RecalculateIdentHash(uint8_t * buf=nullptr) { m_Public->RecalculateIdentHash(buf); }
|
||||||
void Sign (const uint8_t * buf, int len, uint8_t * signature) const;
|
void Sign (const uint8_t * buf, int len, uint8_t * signature) const;
|
||||||
|
|
||||||
size_t GetFullLen () const { return m_Public->GetFullLen () + 256 + m_Public->GetSigningPrivateKeyLen (); };
|
size_t GetFullLen () const;
|
||||||
size_t FromBuffer (const uint8_t * buf, size_t len);
|
size_t FromBuffer (const uint8_t * buf, size_t len);
|
||||||
size_t ToBuffer (uint8_t * buf, size_t len) const;
|
size_t ToBuffer (uint8_t * buf, size_t len) const;
|
||||||
|
|
||||||
@@ -157,18 +161,28 @@ namespace data
|
|||||||
|
|
||||||
static std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> CreateDecryptor (CryptoKeyType cryptoType, const uint8_t * key);
|
static std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> CreateDecryptor (CryptoKeyType cryptoType, const uint8_t * key);
|
||||||
static PrivateKeys CreateRandomKeys (SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1, CryptoKeyType cryptoType = CRYPTO_KEY_TYPE_ELGAMAL);
|
static PrivateKeys CreateRandomKeys (SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1, CryptoKeyType cryptoType = CRYPTO_KEY_TYPE_ELGAMAL);
|
||||||
|
static void GenerateSigningKeyPair (SigningKeyType type, uint8_t * priv, uint8_t * pub);
|
||||||
static void GenerateCryptoKeyPair (CryptoKeyType type, uint8_t * priv, uint8_t * pub); // priv and pub are 256 bytes long
|
static void GenerateCryptoKeyPair (CryptoKeyType type, uint8_t * priv, uint8_t * pub); // priv and pub are 256 bytes long
|
||||||
|
static i2p::crypto::Signer * CreateSigner (SigningKeyType keyType, const uint8_t * priv);
|
||||||
|
|
||||||
|
// offline keys
|
||||||
|
PrivateKeys CreateOfflineKeys (SigningKeyType type, uint32_t expires) const;
|
||||||
|
const std::vector<uint8_t>& GetOfflineSignature () const { return m_OfflineSignature; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void CreateSigner () const;
|
void CreateSigner () const;
|
||||||
|
void CreateSigner (SigningKeyType keyType) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::shared_ptr<IdentityEx> m_Public;
|
std::shared_ptr<IdentityEx> m_Public;
|
||||||
uint8_t m_PrivateKey[256];
|
uint8_t m_PrivateKey[256];
|
||||||
uint8_t m_SigningPrivateKey[1024]; // assume private key doesn't exceed 1024 bytes
|
uint8_t m_SigningPrivateKey[128]; // assume private key doesn't exceed 128 bytes
|
||||||
mutable std::unique_ptr<i2p::crypto::Signer> m_Signer;
|
mutable std::unique_ptr<i2p::crypto::Signer> m_Signer;
|
||||||
|
std::vector<uint8_t> m_OfflineSignature; // non zero length, if applicable
|
||||||
|
size_t m_TransientSignatureLen = 0;
|
||||||
|
size_t m_TransientSigningPrivateKeyLen = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// kademlia
|
// kademlia
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
#include <openssl/hmac.h>
|
||||||
|
#include <zlib.h> // for crc32
|
||||||
#include "I2PEndian.h"
|
#include "I2PEndian.h"
|
||||||
#include "Crypto.h"
|
#include "Crypto.h"
|
||||||
|
#include "Ed25519.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Timestamp.h"
|
#include "Timestamp.h"
|
||||||
#include "NetDb.hpp"
|
#include "NetDb.hpp"
|
||||||
@@ -250,55 +254,195 @@ namespace data
|
|||||||
memcpy (m_Buffer, buf, len);
|
memcpy (m_Buffer, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BlindedPublicKey::BlindedPublicKey (std::shared_ptr<const IdentityEx> identity, SigningKeyType blindedKeyType):
|
||||||
|
m_BlindedSigType (blindedKeyType)
|
||||||
|
{
|
||||||
|
if (!identity) return;
|
||||||
|
auto len = identity->GetSigningPublicKeyLen ();
|
||||||
|
m_PublicKey.resize (len);
|
||||||
|
memcpy (m_PublicKey.data (), identity->GetSigningPublicKeyBuffer (), len);
|
||||||
|
m_SigType = identity->GetSigningKeyType ();
|
||||||
|
}
|
||||||
|
|
||||||
|
BlindedPublicKey::BlindedPublicKey (const std::string& b33)
|
||||||
|
{
|
||||||
|
uint8_t addr[40]; // TODO: define length from b33
|
||||||
|
size_t l = i2p::data::Base32ToByteStream (b33.c_str (), b33.length (), addr, 40);
|
||||||
|
uint32_t checksum = crc32 (0, addr + 3, l - 3);
|
||||||
|
// checksum is Little Endian
|
||||||
|
addr[0] ^= checksum; addr[1] ^= (checksum >> 8); addr[2] ^= (checksum >> 16);
|
||||||
|
uint8_t flag = addr[0];
|
||||||
|
size_t offset = 1;
|
||||||
|
if (flag & 0x01) // two bytes signatures
|
||||||
|
{
|
||||||
|
m_SigType = bufbe16toh (addr + offset); offset += 2;
|
||||||
|
m_BlindedSigType = bufbe16toh (addr + offset); offset += 2;
|
||||||
|
}
|
||||||
|
else // one byte sig
|
||||||
|
{
|
||||||
|
m_SigType = addr[offset]; offset++;
|
||||||
|
m_BlindedSigType = addr[offset]; offset++;
|
||||||
|
}
|
||||||
|
std::unique_ptr<i2p::crypto::Verifier> blindedVerifier (i2p::data::IdentityEx::CreateVerifier (m_SigType));
|
||||||
|
if (blindedVerifier)
|
||||||
|
{
|
||||||
|
auto len = blindedVerifier->GetPublicKeyLen ();
|
||||||
|
if (offset + len <= l)
|
||||||
|
{
|
||||||
|
m_PublicKey.resize (len);
|
||||||
|
memcpy (m_PublicKey.data (), addr + offset, len);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint (eLogError, "LeaseSet2: public key in b33 address is too short for signature type ", (int)m_SigType);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint (eLogError, "LeaseSet2: unknown signature type ", (int)m_SigType, " in b33");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BlindedPublicKey::ToB33 () const
|
||||||
|
{
|
||||||
|
if (m_PublicKey.size () > 32) return ""; // assume 25519
|
||||||
|
uint8_t addr[35]; char str[60]; // TODO: define actual length
|
||||||
|
addr[0] = 0; // flags
|
||||||
|
addr[1] = m_SigType; // sig type
|
||||||
|
addr[2] = m_BlindedSigType; // blinded sig type
|
||||||
|
memcpy (addr + 3, m_PublicKey.data (), m_PublicKey.size ());
|
||||||
|
uint32_t checksum = crc32 (0, addr + 3, m_PublicKey.size ());
|
||||||
|
// checksum is Little Endian
|
||||||
|
addr[0] ^= checksum; addr[1] ^= (checksum >> 8); addr[2] ^= (checksum >> 16);
|
||||||
|
auto l = ByteStreamToBase32 (addr, m_PublicKey.size () + 3, str, 60);
|
||||||
|
return std::string (str, str + l);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlindedPublicKey::GetCredential (uint8_t * credential) const
|
||||||
|
{
|
||||||
|
// A = destination's signing public key
|
||||||
|
// stA = signature type of A, 2 bytes big endian
|
||||||
|
uint16_t stA = htobe16 (GetSigType ());
|
||||||
|
// stA1 = signature type of blinded A, 2 bytes big endian
|
||||||
|
uint16_t stA1 = htobe16 (GetBlindedSigType ());
|
||||||
|
// credential = H("credential", A || stA || stA1)
|
||||||
|
H ("credential", { {GetPublicKey (), GetPublicKeyLen ()}, {(const uint8_t *)&stA, 2}, {(const uint8_t *)&stA1, 2} }, credential);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlindedPublicKey::GetSubcredential (const uint8_t * blinded, size_t len, uint8_t * subcredential) const
|
||||||
|
{
|
||||||
|
uint8_t credential[32];
|
||||||
|
GetCredential (credential);
|
||||||
|
// subcredential = H("subcredential", credential || blindedPublicKey)
|
||||||
|
H ("subcredential", { {credential, 32}, {blinded, len} }, subcredential);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlindedPublicKey::GenerateAlpha (const char * date, uint8_t * seed) const
|
||||||
|
{
|
||||||
|
uint16_t stA = htobe16 (GetSigType ()), stA1 = htobe16 (GetBlindedSigType ());
|
||||||
|
uint8_t salt[32];
|
||||||
|
//seed = HKDF(H("I2PGenerateAlpha", keydata), datestring || secret, "i2pblinding1", 64)
|
||||||
|
H ("I2PGenerateAlpha", { {GetPublicKey (), GetPublicKeyLen ()}, {(const uint8_t *)&stA, 2}, {(const uint8_t *)&stA1, 2} }, salt);
|
||||||
|
i2p::crypto::HKDF (salt, (const uint8_t *)date, 8, "i2pblinding1", seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlindedPublicKey::GetBlindedKey (const char * date, uint8_t * blindedKey) const
|
||||||
|
{
|
||||||
|
uint8_t seed[64];
|
||||||
|
GenerateAlpha (date, seed);
|
||||||
|
i2p::crypto::GetEd25519 ()->BlindPublicKey (GetPublicKey (), seed, blindedKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlindedPublicKey::BlindPrivateKey (const uint8_t * priv, const char * date, uint8_t * blindedPriv, uint8_t * blindedPub) const
|
||||||
|
{
|
||||||
|
uint8_t seed[64];
|
||||||
|
GenerateAlpha (date, seed);
|
||||||
|
i2p::crypto::GetEd25519 ()->BlindPrivateKey (priv, seed, blindedPriv, blindedPub);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlindedPublicKey::H (const std::string& p, const std::vector<std::pair<const uint8_t *, size_t> >& bufs, uint8_t * hash) const
|
||||||
|
{
|
||||||
|
SHA256_CTX ctx;
|
||||||
|
SHA256_Init (&ctx);
|
||||||
|
SHA256_Update (&ctx, p.c_str (), p.length ());
|
||||||
|
for (const auto& it: bufs)
|
||||||
|
SHA256_Update (&ctx, it.first, it.second);
|
||||||
|
SHA256_Final (hash, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
i2p::data::IdentHash BlindedPublicKey::GetStoreHash (const char * date) const
|
||||||
|
{
|
||||||
|
i2p::data::IdentHash hash;
|
||||||
|
if (m_BlindedSigType == i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519 ||
|
||||||
|
m_BlindedSigType == SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519)
|
||||||
|
{
|
||||||
|
uint8_t blinded[32];
|
||||||
|
if (date)
|
||||||
|
GetBlindedKey (date, blinded);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char currentDate[9];
|
||||||
|
i2p::util::GetCurrentDate (currentDate);
|
||||||
|
GetBlindedKey (currentDate, blinded);
|
||||||
|
}
|
||||||
|
auto stA1 = htobe16 (m_BlindedSigType);
|
||||||
|
SHA256_CTX ctx;
|
||||||
|
SHA256_Init (&ctx);
|
||||||
|
SHA256_Update (&ctx, (const uint8_t *)&stA1, 2);
|
||||||
|
SHA256_Update (&ctx, blinded, 32);
|
||||||
|
SHA256_Final ((uint8_t *)hash, &ctx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint (eLogError, "LeaseSet2: blinded key type ", (int)m_BlindedSigType, " is not supported");
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
LeaseSet2::LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases):
|
LeaseSet2::LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases):
|
||||||
LeaseSet (storeLeases), m_StoreType (storeType)
|
LeaseSet (storeLeases), m_StoreType (storeType), m_OrigStoreType (storeType)
|
||||||
{
|
{
|
||||||
SetBuffer (buf, len);
|
SetBuffer (buf, len);
|
||||||
if (storeType == NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
|
if (storeType == NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
|
||||||
ReadFromBufferEncrypted (buf, len);
|
ReadFromBufferEncrypted (buf, len, nullptr);
|
||||||
else
|
else
|
||||||
ReadFromBuffer (buf, len);
|
ReadFromBuffer (buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LeaseSet2::Update (const uint8_t * buf, size_t len, bool verifySignature)
|
LeaseSet2::LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr<const BlindedPublicKey> key):
|
||||||
|
LeaseSet (true), m_StoreType (NETDB_STORE_TYPE_ENCRYPTED_LEASESET2), m_OrigStoreType (NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
|
||||||
{
|
{
|
||||||
// shouldn't be called for now. Must be called from NetDb::AddLeaseSet later
|
ReadFromBufferEncrypted (buf, len, key);
|
||||||
SetBuffer (buf, len);
|
|
||||||
// TODO:verify signature if requested
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LeaseSet2::ReadFromBuffer (const uint8_t * buf, size_t len)
|
void LeaseSet2::Update (const uint8_t * buf, size_t len, bool verifySignature)
|
||||||
|
{
|
||||||
|
SetBuffer (buf, len);
|
||||||
|
if (GetStoreType () != NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
|
||||||
|
ReadFromBuffer (buf, len, false, verifySignature);
|
||||||
|
// TODO: implement encrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
void LeaseSet2::ReadFromBuffer (const uint8_t * buf, size_t len, bool readIdentity, bool verifySignature)
|
||||||
{
|
{
|
||||||
// standard LS2 header
|
// standard LS2 header
|
||||||
auto identity = std::make_shared<IdentityEx>(buf, len);
|
std::shared_ptr<const IdentityEx> identity;
|
||||||
|
if (readIdentity)
|
||||||
|
{
|
||||||
|
identity = std::make_shared<IdentityEx>(buf, len);
|
||||||
SetIdentity (identity);
|
SetIdentity (identity);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
identity = GetIdentity ();
|
||||||
size_t offset = identity->GetFullLen ();
|
size_t offset = identity->GetFullLen ();
|
||||||
if (offset + 8 >= len) return;
|
if (offset + 8 >= len) return;
|
||||||
uint32_t timestamp = bufbe32toh (buf + offset); offset += 4; // published timestamp (seconds)
|
m_PublishedTimestamp = bufbe32toh (buf + offset); offset += 4; // published timestamp (seconds)
|
||||||
uint16_t expires = bufbe16toh (buf + offset); offset += 2; // expires (seconds)
|
uint16_t expires = bufbe16toh (buf + offset); offset += 2; // expires (seconds)
|
||||||
SetExpirationTime ((timestamp + expires)*1000LL); // in milliseconds
|
SetExpirationTime ((m_PublishedTimestamp + expires)*1000LL); // in milliseconds
|
||||||
uint16_t flags = bufbe16toh (buf + offset); offset += 2; // flags
|
uint16_t flags = bufbe16toh (buf + offset); offset += 2; // flags
|
||||||
std::unique_ptr<i2p::crypto::Verifier> transientVerifier;
|
if (flags & LEASESET2_FLAG_OFFLINE_KEYS)
|
||||||
if (flags & 0x0001)
|
|
||||||
{
|
{
|
||||||
// transient key
|
// transient key
|
||||||
if (offset + 6 >= len) return;
|
m_TransientVerifier = ProcessOfflineSignature (identity, buf, len, offset);
|
||||||
const uint8_t * signedData = buf + offset;
|
if (!m_TransientVerifier)
|
||||||
uint32_t expiresTimestamp = bufbe32toh (buf + offset); offset += 4; // expires timestamp
|
|
||||||
if (expiresTimestamp < i2p::util::GetSecondsSinceEpoch ())
|
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "LeaseSet2: transient key expired");
|
LogPrint (eLogError, "LeaseSet2: offline signature failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint16_t keyType = bufbe16toh (buf + offset); offset += 2;
|
|
||||||
transientVerifier.reset (i2p::data::IdentityEx::CreateVerifier (keyType));
|
|
||||||
if (!transientVerifier) return;
|
|
||||||
auto keyLen = transientVerifier->GetPublicKeyLen ();
|
|
||||||
if (offset + keyLen >= len) return;
|
|
||||||
transientVerifier->SetPublicKey (buf + offset); offset += keyLen;
|
|
||||||
if (offset + identity->GetSignatureLen () >= len) return;
|
|
||||||
if (!identity->Verify (signedData, keyLen + 6, buf + offset)) return;
|
|
||||||
offset += identity->GetSignatureLen ();
|
|
||||||
}
|
}
|
||||||
// type specific part
|
// type specific part
|
||||||
size_t s = 0;
|
size_t s = 0;
|
||||||
@@ -315,11 +459,14 @@ namespace data
|
|||||||
}
|
}
|
||||||
if (!s) return;
|
if (!s) return;
|
||||||
offset += s;
|
offset += s;
|
||||||
|
if (verifySignature || m_TransientVerifier)
|
||||||
|
{
|
||||||
// verify signature
|
// verify signature
|
||||||
bool verified = transientVerifier ? VerifySignature (transientVerifier, buf, len, offset) :
|
bool verified = m_TransientVerifier ? VerifySignature (m_TransientVerifier, buf, len, offset) :
|
||||||
VerifySignature (identity, buf, len, offset);
|
VerifySignature (identity, buf, len, offset);
|
||||||
SetIsValid (verified);
|
SetIsValid (verified);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Verifier>
|
template<typename Verifier>
|
||||||
bool LeaseSet2::VerifySignature (Verifier& verifier, const uint8_t * buf, size_t len, size_t signatureOffset)
|
bool LeaseSet2::VerifySignature (Verifier& verifier, const uint8_t * buf, size_t len, size_t signatureOffset)
|
||||||
@@ -344,6 +491,7 @@ namespace data
|
|||||||
offset += propertiesLen; // skip for now. TODO: implement properties
|
offset += propertiesLen; // skip for now. TODO: implement properties
|
||||||
if (offset + 1 >= len) return 0;
|
if (offset + 1 >= len) return 0;
|
||||||
// key sections
|
// key sections
|
||||||
|
uint16_t currentKeyType = 0;
|
||||||
int numKeySections = buf[offset]; offset++;
|
int numKeySections = buf[offset]; offset++;
|
||||||
for (int i = 0; i < numKeySections; i++)
|
for (int i = 0; i < numKeySections; i++)
|
||||||
{
|
{
|
||||||
@@ -351,10 +499,16 @@ namespace data
|
|||||||
if (offset + 2 >= len) return 0;
|
if (offset + 2 >= len) return 0;
|
||||||
uint16_t encryptionKeyLen = bufbe16toh (buf + offset); offset += 2;
|
uint16_t encryptionKeyLen = bufbe16toh (buf + offset); offset += 2;
|
||||||
if (offset + encryptionKeyLen >= len) return 0;
|
if (offset + encryptionKeyLen >= len) return 0;
|
||||||
if (!m_Encryptor && IsStoreLeases ()) // create encryptor with leases only, first key
|
if (IsStoreLeases ()) // create encryptor with leases only
|
||||||
{
|
{
|
||||||
|
// we pick first valid key, higher key type has higher priority 4-1-0
|
||||||
|
// if two keys with of the same type, pick first
|
||||||
auto encryptor = i2p::data::IdentityEx::CreateEncryptor (keyType, buf + offset);
|
auto encryptor = i2p::data::IdentityEx::CreateEncryptor (keyType, buf + offset);
|
||||||
|
if (encryptor && (!m_Encryptor || keyType > currentKeyType))
|
||||||
|
{
|
||||||
m_Encryptor = encryptor; // TODO: atomic
|
m_Encryptor = encryptor; // TODO: atomic
|
||||||
|
currentKeyType = keyType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
offset += encryptionKeyLen;
|
offset += encryptionKeyLen;
|
||||||
}
|
}
|
||||||
@@ -409,52 +563,100 @@ namespace data
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LeaseSet2::ReadFromBufferEncrypted (const uint8_t * buf, size_t len)
|
void LeaseSet2::ReadFromBufferEncrypted (const uint8_t * buf, size_t len, std::shared_ptr<const BlindedPublicKey> key)
|
||||||
{
|
{
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
// blinded key
|
// blinded key
|
||||||
if (len < 2) return;
|
if (len < 2) return;
|
||||||
uint16_t blindedKeyType = bufbe16toh (buf + offset); offset += 2;
|
const uint8_t * stA1 = buf + offset; // stA1 = blinded signature type, 2 bytes big endian
|
||||||
|
uint16_t blindedKeyType = bufbe16toh (stA1); offset += 2;
|
||||||
std::unique_ptr<i2p::crypto::Verifier> blindedVerifier (i2p::data::IdentityEx::CreateVerifier (blindedKeyType));
|
std::unique_ptr<i2p::crypto::Verifier> blindedVerifier (i2p::data::IdentityEx::CreateVerifier (blindedKeyType));
|
||||||
if (!blindedVerifier) return;
|
if (!blindedVerifier) return;
|
||||||
auto blindedKeyLen = blindedVerifier->GetPublicKeyLen ();
|
auto blindedKeyLen = blindedVerifier->GetPublicKeyLen ();
|
||||||
if (offset + blindedKeyLen >= len) return;
|
if (offset + blindedKeyLen >= len) return;
|
||||||
blindedVerifier->SetPublicKey (buf + offset); offset += blindedKeyLen;
|
const uint8_t * blindedPublicKey = buf + offset;
|
||||||
|
blindedVerifier->SetPublicKey (blindedPublicKey); offset += blindedKeyLen;
|
||||||
// expiration
|
// expiration
|
||||||
if (offset + 8 >= len) return;
|
if (offset + 8 >= len) return;
|
||||||
uint32_t timestamp = bufbe32toh (buf + offset); offset += 4; // published timestamp (seconds)
|
const uint8_t * publishedTimestamp = buf + offset;
|
||||||
|
m_PublishedTimestamp = bufbe32toh (publishedTimestamp); offset += 4; // published timestamp (seconds)
|
||||||
uint16_t expires = bufbe16toh (buf + offset); offset += 2; // expires (seconds)
|
uint16_t expires = bufbe16toh (buf + offset); offset += 2; // expires (seconds)
|
||||||
SetExpirationTime ((timestamp + expires)*1000LL); // in milliseconds
|
SetExpirationTime ((m_PublishedTimestamp + expires)*1000LL); // in milliseconds
|
||||||
uint16_t flags = bufbe16toh (buf + offset); offset += 2; // flags
|
uint16_t flags = bufbe16toh (buf + offset); offset += 2; // flags
|
||||||
std::unique_ptr<i2p::crypto::Verifier> transientVerifier;
|
if (flags & LEASESET2_FLAG_OFFLINE_KEYS)
|
||||||
if (flags & 0x0001)
|
|
||||||
{
|
{
|
||||||
// transient key
|
// transient key
|
||||||
if (offset + 6 >= len) return;
|
m_TransientVerifier = ProcessOfflineSignature (blindedVerifier, buf, len, offset);
|
||||||
const uint8_t * signedData = buf + offset;
|
if (!m_TransientVerifier)
|
||||||
uint32_t expiresTimestamp = bufbe32toh (buf + offset); offset += 4; // expires timestamp
|
|
||||||
if (expiresTimestamp < i2p::util::GetSecondsSinceEpoch ())
|
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "LeaseSet2: transient key expired");
|
LogPrint (eLogError, "LeaseSet2: offline signature failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint16_t keyType = bufbe16toh (buf + offset); offset += 2;
|
|
||||||
transientVerifier.reset (i2p::data::IdentityEx::CreateVerifier (keyType));
|
|
||||||
if (!transientVerifier) return;
|
|
||||||
auto keyLen = transientVerifier->GetPublicKeyLen ();
|
|
||||||
if (offset + keyLen >= len) return;
|
|
||||||
transientVerifier->SetPublicKey (buf + offset); offset += keyLen;
|
|
||||||
if (offset + blindedVerifier->GetSignatureLen () >= len) return;
|
|
||||||
if (!blindedVerifier->Verify (signedData, keyLen + 6, buf + offset)) return;
|
|
||||||
offset += blindedVerifier->GetSignatureLen ();
|
|
||||||
}
|
}
|
||||||
// outer ciphertext
|
// outer ciphertext
|
||||||
if (offset + 2 > len) return;
|
if (offset + 2 > len) return;
|
||||||
uint16_t lenOuterCiphertext = bufbe16toh (buf + offset); offset += 2 + lenOuterCiphertext;
|
uint16_t lenOuterCiphertext = bufbe16toh (buf + offset); offset += 2;
|
||||||
|
const uint8_t * outerCiphertext = buf + offset;
|
||||||
|
offset += lenOuterCiphertext;
|
||||||
// verify signature
|
// verify signature
|
||||||
bool verified = transientVerifier ? VerifySignature (transientVerifier, buf, len, offset) :
|
bool verified = m_TransientVerifier ? VerifySignature (m_TransientVerifier, buf, len, offset) :
|
||||||
VerifySignature (blindedVerifier, buf, len, offset);
|
VerifySignature (blindedVerifier, buf, len, offset);
|
||||||
SetIsValid (verified);
|
SetIsValid (verified);
|
||||||
|
// handle ciphertext
|
||||||
|
if (verified && key && lenOuterCiphertext >= 32)
|
||||||
|
{
|
||||||
|
SetIsValid (false); // we must verify it again in Layer 2
|
||||||
|
if (blindedKeyType == i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519)
|
||||||
|
{
|
||||||
|
// verify blinding
|
||||||
|
char date[9];
|
||||||
|
i2p::util::GetDateString (m_PublishedTimestamp, date);
|
||||||
|
uint8_t blinded[32];
|
||||||
|
key->GetBlindedKey (date, blinded);
|
||||||
|
if (memcmp (blindedPublicKey, blinded, 32))
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "LeaseSet2: blinded public key doesn't match");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// outer key
|
||||||
|
// outerInput = subcredential || publishedTimestamp
|
||||||
|
uint8_t subcredential[36];
|
||||||
|
key->GetSubcredential (blindedPublicKey, blindedKeyLen, subcredential);
|
||||||
|
memcpy (subcredential + 32, publishedTimestamp, 4);
|
||||||
|
// outerSalt = outerCiphertext[0:32]
|
||||||
|
// keys = HKDF(outerSalt, outerInput, "ELS2_L1K", 44)
|
||||||
|
uint8_t keys[64]; // 44 bytes actual data
|
||||||
|
i2p::crypto::HKDF (outerCiphertext, subcredential, 36, "ELS2_L1K", keys);
|
||||||
|
// decrypt Layer 1
|
||||||
|
// outerKey = keys[0:31]
|
||||||
|
// outerIV = keys[32:43]
|
||||||
|
size_t lenOuterPlaintext = lenOuterCiphertext - 32;
|
||||||
|
std::vector<uint8_t> outerPlainText (lenOuterPlaintext);
|
||||||
|
i2p::crypto::ChaCha20 (outerCiphertext + 32, lenOuterPlaintext, keys, keys + 32, outerPlainText.data ());
|
||||||
|
// inner key
|
||||||
|
// innerInput = authCookie || subcredential || publishedTimestamp, TODO: non-empty authCookie
|
||||||
|
// innerSalt = innerCiphertext[0:32]
|
||||||
|
// keys = HKDF(innerSalt, innerInput, "ELS2_L2K", 44)
|
||||||
|
// skip 1 byte flags
|
||||||
|
i2p::crypto::HKDF (outerPlainText.data () + 1, subcredential, 36, "ELS2_L2K", keys); // no authCookie
|
||||||
|
// decrypt Layer 2
|
||||||
|
// innerKey = keys[0:31]
|
||||||
|
// innerIV = keys[32:43]
|
||||||
|
size_t lenInnerPlaintext = lenOuterPlaintext - 32 - 1;
|
||||||
|
std::vector<uint8_t> innerPlainText (lenInnerPlaintext);
|
||||||
|
i2p::crypto::ChaCha20 (outerPlainText.data () + 32 + 1, lenInnerPlaintext, keys, keys + 32, innerPlainText.data ());
|
||||||
|
if (innerPlainText[0] == NETDB_STORE_TYPE_STANDARD_LEASESET2 || innerPlainText[0] == NETDB_STORE_TYPE_META_LEASESET2)
|
||||||
|
{
|
||||||
|
// override store type and buffer
|
||||||
|
m_StoreType = innerPlainText[0];
|
||||||
|
SetBuffer (innerPlainText.data () + 1, lenInnerPlaintext - 1);
|
||||||
|
// parse and verify Layer 2
|
||||||
|
ReadFromBuffer (innerPlainText.data () + 1, lenInnerPlaintext - 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint (eLogError, "LeaseSet2: unexpected LeaseSet type ", (int)innerPlainText[0], " inside encrypted LeaseSet");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LeaseSet2::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const
|
void LeaseSet2::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const
|
||||||
@@ -586,16 +788,24 @@ namespace data
|
|||||||
return ident.Verify(ptr, leases - ptr, leases);
|
return ident.Verify(ptr, leases - ptr, leases);
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalLeaseSet2::LocalLeaseSet2 (uint8_t storeType, std::shared_ptr<const IdentityEx> identity,
|
LocalLeaseSet2::LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys,
|
||||||
uint16_t keyType, uint16_t keyLen, const uint8_t * encryptionPublicKey,
|
uint16_t keyType, uint16_t keyLen, const uint8_t * encryptionPublicKey,
|
||||||
std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels):
|
std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels):
|
||||||
LocalLeaseSet (identity, nullptr, 0)
|
LocalLeaseSet (keys.GetPublic (), nullptr, 0)
|
||||||
{
|
{
|
||||||
|
auto identity = keys.GetPublic ();
|
||||||
// assume standard LS2
|
// assume standard LS2
|
||||||
int num = tunnels.size ();
|
int num = tunnels.size ();
|
||||||
if (num > MAX_NUM_LEASES) num = MAX_NUM_LEASES;
|
if (num > MAX_NUM_LEASES) num = MAX_NUM_LEASES;
|
||||||
m_BufferLen = identity->GetFullLen () + 4/*published*/ + 2/*expires*/ + 2/*flag*/ + 2/*properties len*/ +
|
m_BufferLen = identity->GetFullLen () + 4/*published*/ + 2/*expires*/ + 2/*flag*/ + 2/*properties len*/ +
|
||||||
1/*num keys*/ + 2/*key type*/ + 2/*key len*/ + keyLen/*key*/ + 1/*num leases*/ + num*LEASE2_SIZE + identity->GetSignatureLen ();
|
1/*num keys*/ + 2/*key type*/ + 2/*key len*/ + keyLen/*key*/ + 1/*num leases*/ + num*LEASE2_SIZE + keys.GetSignatureLen ();
|
||||||
|
uint16_t flags = 0;
|
||||||
|
if (keys.IsOfflineSignature ())
|
||||||
|
{
|
||||||
|
flags |= LEASESET2_FLAG_OFFLINE_KEYS;
|
||||||
|
m_BufferLen += keys.GetOfflineSignature ().size ();
|
||||||
|
}
|
||||||
|
|
||||||
m_Buffer = new uint8_t[m_BufferLen + 1];
|
m_Buffer = new uint8_t[m_BufferLen + 1];
|
||||||
m_Buffer[0] = storeType;
|
m_Buffer[0] = storeType;
|
||||||
// LS2 header
|
// LS2 header
|
||||||
@@ -603,7 +813,14 @@ namespace data
|
|||||||
auto timestamp = i2p::util::GetSecondsSinceEpoch ();
|
auto timestamp = i2p::util::GetSecondsSinceEpoch ();
|
||||||
htobe32buf (m_Buffer + offset, timestamp); offset += 4; // published timestamp (seconds)
|
htobe32buf (m_Buffer + offset, timestamp); offset += 4; // published timestamp (seconds)
|
||||||
uint8_t * expiresBuf = m_Buffer + offset; offset += 2; // expires, fill later
|
uint8_t * expiresBuf = m_Buffer + offset; offset += 2; // expires, fill later
|
||||||
htobe16buf (m_Buffer + offset, 0); offset += 2; // flags
|
htobe16buf (m_Buffer + offset, flags); offset += 2; // flags
|
||||||
|
if (keys.IsOfflineSignature ())
|
||||||
|
{
|
||||||
|
// offline signature
|
||||||
|
const auto& offlineSignature = keys.GetOfflineSignature ();
|
||||||
|
memcpy (m_Buffer + offset, offlineSignature.data (), offlineSignature.size ());
|
||||||
|
offset += offlineSignature.size ();
|
||||||
|
}
|
||||||
htobe16buf (m_Buffer + offset, 0); offset += 2; // properties len
|
htobe16buf (m_Buffer + offset, 0); offset += 2; // properties len
|
||||||
// keys
|
// keys
|
||||||
m_Buffer[offset] = 1; offset++; // 1 key
|
m_Buffer[offset] = 1; offset++; // 1 key
|
||||||
@@ -628,7 +845,89 @@ namespace data
|
|||||||
SetExpirationTime (expirationTime*1000LL);
|
SetExpirationTime (expirationTime*1000LL);
|
||||||
auto expires = expirationTime - timestamp;
|
auto expires = expirationTime - timestamp;
|
||||||
htobe16buf (expiresBuf, expires > 0 ? expires : 0);
|
htobe16buf (expiresBuf, expires > 0 ? expires : 0);
|
||||||
// we don't sign it yet. must be signed later on
|
// sign
|
||||||
}
|
keys.Sign (m_Buffer, offset, m_Buffer + offset); // LS + leading store type
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalLeaseSet2::LocalLeaseSet2 (uint8_t storeType, std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len):
|
||||||
|
LocalLeaseSet (identity, nullptr, 0)
|
||||||
|
{
|
||||||
|
m_BufferLen = len;
|
||||||
|
m_Buffer = new uint8_t[m_BufferLen + 1];
|
||||||
|
memcpy (m_Buffer + 1, buf, len);
|
||||||
|
m_Buffer[0] = storeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalEncryptedLeaseSet2::LocalEncryptedLeaseSet2 (std::shared_ptr<const LocalLeaseSet2> ls, const i2p::data::PrivateKeys& keys, i2p::data::SigningKeyType blindedKeyType):
|
||||||
|
LocalLeaseSet2 (ls->GetIdentity ()), m_InnerLeaseSet (ls)
|
||||||
|
{
|
||||||
|
size_t lenInnerPlaintext = ls->GetBufferLen () + 1, lenOuterPlaintext = lenInnerPlaintext + 32 + 1,
|
||||||
|
lenOuterCiphertext = lenOuterPlaintext + 32;
|
||||||
|
m_BufferLen = 2/*blinded sig type*/ + 32/*blinded pub key*/ + 4/*published*/ + 2/*expires*/ + 2/*flags*/ + 2/*lenOuterCiphertext*/ + lenOuterCiphertext + 64/*signature*/;
|
||||||
|
m_Buffer = new uint8_t[m_BufferLen + 1];
|
||||||
|
m_Buffer[0] = NETDB_STORE_TYPE_ENCRYPTED_LEASESET2;
|
||||||
|
BlindedPublicKey blindedKey (ls->GetIdentity ());
|
||||||
|
auto timestamp = i2p::util::GetSecondsSinceEpoch ();
|
||||||
|
char date[9];
|
||||||
|
i2p::util::GetDateString (timestamp, date);
|
||||||
|
uint8_t blindedPriv[32], blindedPub[32];
|
||||||
|
blindedKey.BlindPrivateKey (keys.GetSigningPrivateKey (), date, blindedPriv, blindedPub);
|
||||||
|
std::unique_ptr<i2p::crypto::Signer> blindedSigner (i2p::data::PrivateKeys::CreateSigner (blindedKeyType, blindedPriv));
|
||||||
|
auto offset = 1;
|
||||||
|
htobe16buf (m_Buffer + offset, blindedKeyType); offset += 2; // Blinded Public Key Sig Type
|
||||||
|
memcpy (m_Buffer + offset, blindedPub, 32); offset += 32; // Blinded Public Key
|
||||||
|
htobe32buf (m_Buffer + offset, timestamp); offset += 4; // published timestamp (seconds)
|
||||||
|
auto nextMidnight = (timestamp/86400LL + 1)*86400LL; // 86400 = 24*3600 seconds
|
||||||
|
auto expirationTime = ls->GetExpirationTime ()/1000LL;
|
||||||
|
if (expirationTime > nextMidnight) expirationTime = nextMidnight;
|
||||||
|
SetExpirationTime (expirationTime*1000LL);
|
||||||
|
htobe16buf (m_Buffer + offset, expirationTime > timestamp ? expirationTime - timestamp : 0); offset += 2; // expires
|
||||||
|
uint16_t flags = 0;
|
||||||
|
htobe16buf (m_Buffer + offset, flags); offset += 2; // flags
|
||||||
|
htobe16buf (m_Buffer + offset, lenOuterCiphertext); offset += 2; // lenOuterCiphertext
|
||||||
|
// outerChipherText
|
||||||
|
// Layer 1
|
||||||
|
uint8_t subcredential[36];
|
||||||
|
blindedKey.GetSubcredential (blindedPub, 32, subcredential);
|
||||||
|
htobe32buf (subcredential + 32, timestamp); // outerInput = subcredential || publishedTimestamp
|
||||||
|
// keys = HKDF(outerSalt, outerInput, "ELS2_L1K", 44)
|
||||||
|
uint8_t keys1[64]; // 44 bytes actual data
|
||||||
|
RAND_bytes (m_Buffer + offset, 32); // outerSalt = CSRNG(32)
|
||||||
|
i2p::crypto::HKDF (m_Buffer + offset, subcredential, 36, "ELS2_L1K", keys1);
|
||||||
|
offset += 32; // outerSalt
|
||||||
|
uint8_t * outerPlainText = m_Buffer + offset;
|
||||||
|
m_Buffer[offset] = 0; offset++; // flag
|
||||||
|
// Layer 2
|
||||||
|
// keys = HKDF(outerSalt, outerInput, "ELS2_L2K", 44)
|
||||||
|
uint8_t keys2[64]; // 44 bytes actual data
|
||||||
|
RAND_bytes (m_Buffer + offset, 32); // innerSalt = CSRNG(32)
|
||||||
|
i2p::crypto::HKDF (m_Buffer + offset, subcredential, 36, "ELS2_L2K", keys2);
|
||||||
|
offset += 32; // innerSalt
|
||||||
|
m_Buffer[offset] = ls->GetStoreType ();
|
||||||
|
memcpy (m_Buffer + offset + 1, ls->GetBuffer (), ls->GetBufferLen ());
|
||||||
|
i2p::crypto::ChaCha20 (m_Buffer + offset, lenInnerPlaintext, keys2, keys2 + 32, m_Buffer + offset); // encrypt Layer 2
|
||||||
|
offset += lenInnerPlaintext;
|
||||||
|
i2p::crypto::ChaCha20 (outerPlainText, lenOuterPlaintext, keys1, keys1 + 32, outerPlainText); // encrypt Layer 1
|
||||||
|
// signature
|
||||||
|
blindedSigner->Sign (m_Buffer, offset, m_Buffer + offset);
|
||||||
|
// store hash
|
||||||
|
m_StoreHash = blindedKey.GetStoreHash (date);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalEncryptedLeaseSet2::LocalEncryptedLeaseSet2 (std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len):
|
||||||
|
LocalLeaseSet2 (NETDB_STORE_TYPE_ENCRYPTED_LEASESET2, identity, buf, len)
|
||||||
|
{
|
||||||
|
// fill inner LeaseSet2
|
||||||
|
auto blindedKey = std::make_shared<BlindedPublicKey>(identity);
|
||||||
|
i2p::data::LeaseSet2 ls (buf, len, blindedKey); // inner layer
|
||||||
|
if (ls.IsValid ())
|
||||||
|
{
|
||||||
|
m_InnerLeaseSet = std::make_shared<LocalLeaseSet2>(ls.GetStoreType (), identity, ls.GetBuffer (), ls.GetBufferLen ());
|
||||||
|
m_StoreHash = blindedKey->GetStoreHash ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint (eLogError, "LeaseSet2: couldn't extract inner layer");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include "Identity.h"
|
#include "Identity.h"
|
||||||
#include "Timestamp.h"
|
#include "Timestamp.h"
|
||||||
|
#include "I2PEndian.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
@@ -25,7 +26,7 @@ namespace data
|
|||||||
IdentHash tunnelGateway;
|
IdentHash tunnelGateway;
|
||||||
uint32_t tunnelID;
|
uint32_t tunnelID;
|
||||||
uint64_t endDate; // 0 means invalid
|
uint64_t endDate; // 0 means invalid
|
||||||
bool isUpdated; // trasient
|
bool isUpdated; // transient
|
||||||
/* return true if this lease expires within t millisecond + fudge factor */
|
/* return true if this lease expires within t millisecond + fudge factor */
|
||||||
bool ExpiresWithin( const uint64_t t, const uint64_t fudge = 1000 ) const {
|
bool ExpiresWithin( const uint64_t t, const uint64_t fudge = 1000 ) const {
|
||||||
auto expire = i2p::util::GetMillisecondsSinceEpoch ();
|
auto expire = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
@@ -77,6 +78,9 @@ namespace data
|
|||||||
bool operator== (const LeaseSet& other) const
|
bool operator== (const LeaseSet& other) const
|
||||||
{ return m_BufferLen == other.m_BufferLen && !memcmp (m_Buffer, other.m_Buffer, m_BufferLen); };
|
{ return m_BufferLen == other.m_BufferLen && !memcmp (m_Buffer, other.m_Buffer, m_BufferLen); };
|
||||||
virtual uint8_t GetStoreType () const { return NETDB_STORE_TYPE_LEASESET; };
|
virtual uint8_t GetStoreType () const { return NETDB_STORE_TYPE_LEASESET; };
|
||||||
|
virtual uint8_t GetOrigStoreType () const { return NETDB_STORE_TYPE_LEASESET; };
|
||||||
|
virtual uint32_t GetPublishedTimestamp () const { return 0; }; // should be set for LeaseSet2 only
|
||||||
|
virtual std::shared_ptr<const i2p::crypto::Verifier> GetTransientVerifier () const { return nullptr; };
|
||||||
|
|
||||||
// implements RoutingDestination
|
// implements RoutingDestination
|
||||||
std::shared_ptr<const IdentityEx> GetIdentity () const { return m_Identity; };
|
std::shared_ptr<const IdentityEx> GetIdentity () const { return m_Identity; };
|
||||||
@@ -122,12 +126,49 @@ namespace data
|
|||||||
const uint8_t NETDB_STORE_TYPE_STANDARD_LEASESET2 = 3;
|
const uint8_t NETDB_STORE_TYPE_STANDARD_LEASESET2 = 3;
|
||||||
const uint8_t NETDB_STORE_TYPE_ENCRYPTED_LEASESET2 = 5;
|
const uint8_t NETDB_STORE_TYPE_ENCRYPTED_LEASESET2 = 5;
|
||||||
const uint8_t NETDB_STORE_TYPE_META_LEASESET2 = 7;
|
const uint8_t NETDB_STORE_TYPE_META_LEASESET2 = 7;
|
||||||
|
|
||||||
|
const uint16_t LEASESET2_FLAG_OFFLINE_KEYS = 0x0001;
|
||||||
|
|
||||||
|
class BlindedPublicKey // for encrypted LS2
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
BlindedPublicKey (std::shared_ptr<const IdentityEx> identity, SigningKeyType blindedKeyType = i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519);
|
||||||
|
BlindedPublicKey (const std::string& b33); // from b33 without .b32.i2p
|
||||||
|
std::string ToB33 () const;
|
||||||
|
|
||||||
|
const uint8_t * GetPublicKey () const { return m_PublicKey.data (); };
|
||||||
|
size_t GetPublicKeyLen () const { return m_PublicKey.size (); };
|
||||||
|
SigningKeyType GetSigType () const { return m_SigType; };
|
||||||
|
SigningKeyType GetBlindedSigType () const { return m_BlindedSigType; };
|
||||||
|
|
||||||
|
void GetSubcredential (const uint8_t * blinded, size_t len, uint8_t * subcredential) const; // 32 bytes
|
||||||
|
void GetBlindedKey (const char * date, uint8_t * blindedKey) const; // blinded key 32 bytes, date is 8 chars "YYYYMMDD"
|
||||||
|
void BlindPrivateKey (const uint8_t * priv, const char * date, uint8_t * blindedPriv, uint8_t * blindedPub) const; // blinded key 32 bytes, date is 8 chars "YYYYMMDD"
|
||||||
|
i2p::data::IdentHash GetStoreHash (const char * date = nullptr) const; // date is 8 chars "YYYYMMDD", use current if null
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void GetCredential (uint8_t * credential) const; // 32 bytes
|
||||||
|
void GenerateAlpha (const char * date, uint8_t * seed) const; // 64 bytes, date is 8 chars "YYYYMMDD"
|
||||||
|
void H (const std::string& p, const std::vector<std::pair<const uint8_t *, size_t> >& bufs, uint8_t * hash) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::vector<uint8_t> m_PublicKey;
|
||||||
|
i2p::data::SigningKeyType m_SigType, m_BlindedSigType;
|
||||||
|
};
|
||||||
|
|
||||||
class LeaseSet2: public LeaseSet
|
class LeaseSet2: public LeaseSet
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases = true);
|
LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases = true);
|
||||||
|
LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr<const BlindedPublicKey> key); // store type 5, called from local netdb only
|
||||||
uint8_t GetStoreType () const { return m_StoreType; };
|
uint8_t GetStoreType () const { return m_StoreType; };
|
||||||
|
uint8_t GetOrigStoreType () const { return m_OrigStoreType; };
|
||||||
|
uint32_t GetPublishedTimestamp () const { return m_PublishedTimestamp; };
|
||||||
|
std::shared_ptr<const i2p::crypto::Verifier> GetTransientVerifier () const { return m_TransientVerifier; };
|
||||||
void Update (const uint8_t * buf, size_t len, bool verifySignature);
|
void Update (const uint8_t * buf, size_t len, bool verifySignature);
|
||||||
|
|
||||||
// implements RoutingDestination
|
// implements RoutingDestination
|
||||||
@@ -135,8 +176,8 @@ namespace data
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void ReadFromBuffer (const uint8_t * buf, size_t len);
|
void ReadFromBuffer (const uint8_t * buf, size_t len, bool readIdentity = true, bool verifySignature = true);
|
||||||
void ReadFromBufferEncrypted (const uint8_t * buf, size_t len);
|
void ReadFromBufferEncrypted (const uint8_t * buf, size_t len, std::shared_ptr<const BlindedPublicKey> key);
|
||||||
size_t ReadStandardLS2TypeSpecificPart (const uint8_t * buf, size_t len);
|
size_t ReadStandardLS2TypeSpecificPart (const uint8_t * buf, size_t len);
|
||||||
size_t ReadMetaLS2TypeSpecificPart (const uint8_t * buf, size_t len);
|
size_t ReadMetaLS2TypeSpecificPart (const uint8_t * buf, size_t len);
|
||||||
|
|
||||||
@@ -147,10 +188,33 @@ namespace data
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
uint8_t m_StoreType;
|
uint8_t m_StoreType, m_OrigStoreType;
|
||||||
|
uint32_t m_PublishedTimestamp = 0;
|
||||||
|
std::shared_ptr<i2p::crypto::Verifier> m_TransientVerifier;
|
||||||
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> m_Encryptor; // for standardLS2
|
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> m_Encryptor; // for standardLS2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// also called from Streaming.cpp
|
||||||
|
template<typename Verifier>
|
||||||
|
std::shared_ptr<i2p::crypto::Verifier> ProcessOfflineSignature (const Verifier& verifier, const uint8_t * buf, size_t len, size_t& offset)
|
||||||
|
{
|
||||||
|
if (offset + 6 >= len) return nullptr;
|
||||||
|
const uint8_t * signedData = buf + offset;
|
||||||
|
uint32_t expiresTimestamp = bufbe32toh (buf + offset); offset += 4; // expires timestamp
|
||||||
|
if (expiresTimestamp < i2p::util::GetSecondsSinceEpoch ()) return nullptr;
|
||||||
|
uint16_t keyType = bufbe16toh (buf + offset); offset += 2;
|
||||||
|
std::shared_ptr<i2p::crypto::Verifier> transientVerifier (i2p::data::IdentityEx::CreateVerifier (keyType));
|
||||||
|
if (!transientVerifier) return nullptr;
|
||||||
|
auto keyLen = transientVerifier->GetPublicKeyLen ();
|
||||||
|
if (offset + keyLen >= len) return nullptr;
|
||||||
|
transientVerifier->SetPublicKey (buf + offset); offset += keyLen;
|
||||||
|
if (offset + verifier->GetSignatureLen () >= len) return nullptr;
|
||||||
|
if (!verifier->Verify (signedData, keyLen + 6, buf + offset)) return nullptr;
|
||||||
|
offset += verifier->GetSignatureLen ();
|
||||||
|
return transientVerifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
class LocalLeaseSet
|
class LocalLeaseSet
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -166,6 +230,7 @@ namespace data
|
|||||||
uint8_t * GetLeases () { return m_Leases; };
|
uint8_t * GetLeases () { return m_Leases; };
|
||||||
|
|
||||||
const IdentHash& GetIdentHash () const { return m_Identity->GetIdentHash (); };
|
const IdentHash& GetIdentHash () const { return m_Identity->GetIdentHash (); };
|
||||||
|
std::shared_ptr<const IdentityEx> GetIdentity () const { return m_Identity; };
|
||||||
bool IsExpired () const;
|
bool IsExpired () const;
|
||||||
uint64_t GetExpirationTime () const { return m_ExpirationTime; };
|
uint64_t GetExpirationTime () const { return m_ExpirationTime; };
|
||||||
void SetExpirationTime (uint64_t expirationTime) { m_ExpirationTime = expirationTime; };
|
void SetExpirationTime (uint64_t expirationTime) { m_ExpirationTime = expirationTime; };
|
||||||
@@ -173,6 +238,8 @@ namespace data
|
|||||||
{ return GetBufferLen () == other.GetBufferLen () && !memcmp (GetBuffer (), other.GetBuffer (), GetBufferLen ()); };
|
{ return GetBufferLen () == other.GetBufferLen () && !memcmp (GetBuffer (), other.GetBuffer (), GetBufferLen ()); };
|
||||||
|
|
||||||
virtual uint8_t GetStoreType () const { return NETDB_STORE_TYPE_LEASESET; };
|
virtual uint8_t GetStoreType () const { return NETDB_STORE_TYPE_LEASESET; };
|
||||||
|
virtual const IdentHash& GetStoreHash () const { return GetIdentHash (); }; // differ from ident hash for encrypted LeaseSet2
|
||||||
|
virtual std::shared_ptr<const LocalLeaseSet> GetInnerLeaseSet () const { return nullptr; }; // non-null for encrypted LeaseSet2
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@@ -186,9 +253,11 @@ namespace data
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
LocalLeaseSet2 (uint8_t storeType, std::shared_ptr<const IdentityEx> identity,
|
LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys,
|
||||||
uint16_t keyType, uint16_t keyLen, const uint8_t * encryptionPublicKey,
|
uint16_t keyType, uint16_t keyLen, const uint8_t * encryptionPublicKey,
|
||||||
std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels);
|
std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels);
|
||||||
|
LocalLeaseSet2 (uint8_t storeType, std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len); // from I2CP
|
||||||
|
|
||||||
virtual ~LocalLeaseSet2 () { delete[] m_Buffer; };
|
virtual ~LocalLeaseSet2 () { delete[] m_Buffer; };
|
||||||
|
|
||||||
uint8_t * GetBuffer () const { return m_Buffer + 1; };
|
uint8_t * GetBuffer () const { return m_Buffer + 1; };
|
||||||
@@ -196,11 +265,32 @@ namespace data
|
|||||||
|
|
||||||
uint8_t GetStoreType () const { return m_Buffer[0]; };
|
uint8_t GetStoreType () const { return m_Buffer[0]; };
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
|
|
||||||
|
LocalLeaseSet2 (std::shared_ptr<const IdentityEx> identity): LocalLeaseSet (identity, nullptr, 0), m_Buffer (nullptr), m_BufferLen(0) {}; // called from LocalEncryptedLeaseSet2
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
uint8_t * m_Buffer; // 1 byte store type + actual buffer
|
uint8_t * m_Buffer; // 1 byte store type + actual buffer
|
||||||
size_t m_BufferLen;
|
size_t m_BufferLen;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class LocalEncryptedLeaseSet2: public LocalLeaseSet2
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
LocalEncryptedLeaseSet2 (std::shared_ptr<const LocalLeaseSet2> ls, const i2p::data::PrivateKeys& keys, i2p::data::SigningKeyType blindedKeyType = i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519);
|
||||||
|
|
||||||
|
LocalEncryptedLeaseSet2 (std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len); // from I2CP
|
||||||
|
|
||||||
|
const IdentHash& GetStoreHash () const { return m_StoreHash; };
|
||||||
|
std::shared_ptr<const LocalLeaseSet> GetInnerLeaseSet () const { return m_InnerLeaseSet; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
IdentHash m_StoreHash;
|
||||||
|
std::shared_ptr<const LocalLeaseSet2> m_InnerLeaseSet;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -690,7 +690,7 @@ namespace transport
|
|||||||
}
|
}
|
||||||
if (memcmp (addr->ntcp2->staticKey, m_Establisher->m_RemoteStaticKey, 32))
|
if (memcmp (addr->ntcp2->staticKey, m_Establisher->m_RemoteStaticKey, 32))
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "NTCP2: Static key mistmatch in SessionConfirmed");
|
LogPrint (eLogError, "NTCP2: Static key mismatch in SessionConfirmed");
|
||||||
SendTerminationAndTerminate (eNTCP2IncorrectSParameter);
|
SendTerminationAndTerminate (eNTCP2IncorrectSParameter);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -783,7 +783,7 @@ namespace transport
|
|||||||
size_t moreBytes = m_Socket.available(ec);
|
size_t moreBytes = m_Socket.available(ec);
|
||||||
if (!ec && moreBytes >= m_NextReceivedLen)
|
if (!ec && moreBytes >= m_NextReceivedLen)
|
||||||
{
|
{
|
||||||
// read and process messsage immediately if avaliable
|
// read and process message immediately if available
|
||||||
moreBytes = boost::asio::read (m_Socket, boost::asio::buffer(m_NextReceivedBuffer, m_NextReceivedLen), boost::asio::transfer_all (), ec);
|
moreBytes = boost::asio::read (m_Socket, boost::asio::buffer(m_NextReceivedBuffer, m_NextReceivedLen), boost::asio::transfer_all (), ec);
|
||||||
HandleReceived (ec, moreBytes);
|
HandleReceived (ec, moreBytes);
|
||||||
}
|
}
|
||||||
@@ -887,7 +887,7 @@ namespace transport
|
|||||||
Terminate ();
|
Terminate ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogWarning, "NTCP2: Unexpected temination block size ", size);
|
LogPrint (eLogWarning, "NTCP2: Unexpected termination block size ", size);
|
||||||
break;
|
break;
|
||||||
case eNTCP2BlkPadding:
|
case eNTCP2BlkPadding:
|
||||||
LogPrint (eLogDebug, "NTCP2: padding");
|
LogPrint (eLogDebug, "NTCP2: padding");
|
||||||
@@ -935,7 +935,7 @@ namespace transport
|
|||||||
htobe16buf (buf + 1, len); // size
|
htobe16buf (buf + 1, len); // size
|
||||||
len += 3;
|
len += 3;
|
||||||
totalLen += len;
|
totalLen += len;
|
||||||
encryptBufs.push_back (std::make_pair (buf, len));
|
encryptBufs.push_back ( {buf, len} );
|
||||||
if (&it == &msgs.front ()) // first message
|
if (&it == &msgs.front ()) // first message
|
||||||
{
|
{
|
||||||
// allocate two bytes for length
|
// allocate two bytes for length
|
||||||
@@ -949,7 +949,7 @@ namespace transport
|
|||||||
auto paddingLen = CreatePaddingBlock (totalLen, buf + len, it->maxLen - it->len - 16);
|
auto paddingLen = CreatePaddingBlock (totalLen, buf + len, it->maxLen - it->len - 16);
|
||||||
if (paddingLen)
|
if (paddingLen)
|
||||||
{
|
{
|
||||||
encryptBufs.push_back (std::make_pair (buf + len, paddingLen));
|
encryptBufs.push_back ( {buf + len, paddingLen} );
|
||||||
len += paddingLen;
|
len += paddingLen;
|
||||||
totalLen += paddingLen;
|
totalLen += paddingLen;
|
||||||
}
|
}
|
||||||
@@ -969,7 +969,7 @@ namespace transport
|
|||||||
auto paddingLen = CreatePaddingBlock (totalLen, m_NextSendBuffer, 287 - 16);
|
auto paddingLen = CreatePaddingBlock (totalLen, m_NextSendBuffer, 287 - 16);
|
||||||
// and padding block to encrypt and send
|
// and padding block to encrypt and send
|
||||||
if (paddingLen)
|
if (paddingLen)
|
||||||
encryptBufs.push_back (std::make_pair (m_NextSendBuffer, paddingLen));
|
encryptBufs.push_back ( {m_NextSendBuffer, paddingLen} );
|
||||||
bufs.push_back (boost::asio::buffer (m_NextSendBuffer, paddingLen + 16));
|
bufs.push_back (boost::asio::buffer (m_NextSendBuffer, paddingLen + 16));
|
||||||
macBuf = m_NextSendBuffer + paddingLen;
|
macBuf = m_NextSendBuffer + paddingLen;
|
||||||
totalLen += paddingLen;
|
totalLen += paddingLen;
|
||||||
@@ -1001,7 +1001,7 @@ namespace transport
|
|||||||
// encrypt
|
// encrypt
|
||||||
uint8_t nonce[12];
|
uint8_t nonce[12];
|
||||||
CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++;
|
CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++;
|
||||||
i2p::crypto::AEADChaCha20Poly1305Encrypt ({std::make_pair (m_NextSendBuffer + 2, payloadLen)}, m_SendKey, nonce, m_NextSendBuffer + payloadLen + 2);
|
i2p::crypto::AEADChaCha20Poly1305Encrypt ({ {m_NextSendBuffer + 2, payloadLen} }, m_SendKey, nonce, m_NextSendBuffer + payloadLen + 2);
|
||||||
SetNextSentFrameLength (payloadLen + 16, m_NextSendBuffer);
|
SetNextSentFrameLength (payloadLen + 16, m_NextSendBuffer);
|
||||||
// send
|
// send
|
||||||
m_IsSending = true;
|
m_IsSending = true;
|
||||||
@@ -1180,6 +1180,7 @@ namespace transport
|
|||||||
{
|
{
|
||||||
m_NTCP2V6Acceptor->open (boost::asio::ip::tcp::v6());
|
m_NTCP2V6Acceptor->open (boost::asio::ip::tcp::v6());
|
||||||
m_NTCP2V6Acceptor->set_option (boost::asio::ip::v6_only (true));
|
m_NTCP2V6Acceptor->set_option (boost::asio::ip::v6_only (true));
|
||||||
|
m_NTCP2V6Acceptor->set_option (boost::asio::socket_base::reuse_address (true));
|
||||||
m_NTCP2V6Acceptor->bind (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address->port));
|
m_NTCP2V6Acceptor->bind (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address->port));
|
||||||
m_NTCP2V6Acceptor->listen ();
|
m_NTCP2V6Acceptor->listen ();
|
||||||
|
|
||||||
|
|||||||
@@ -843,6 +843,7 @@ namespace transport
|
|||||||
{
|
{
|
||||||
m_NTCPV6Acceptor->open (boost::asio::ip::tcp::v6());
|
m_NTCPV6Acceptor->open (boost::asio::ip::tcp::v6());
|
||||||
m_NTCPV6Acceptor->set_option (boost::asio::ip::v6_only (true));
|
m_NTCPV6Acceptor->set_option (boost::asio::ip::v6_only (true));
|
||||||
|
m_NTCPV6Acceptor->set_option (boost::asio::socket_base::reuse_address (true));
|
||||||
m_NTCPV6Acceptor->bind (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address->port));
|
m_NTCPV6Acceptor->bind (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address->port));
|
||||||
m_NTCPV6Acceptor->listen ();
|
m_NTCPV6Acceptor->listen ();
|
||||||
|
|
||||||
@@ -1286,7 +1287,7 @@ namespace transport
|
|||||||
if (it.second->IsTerminationTimeoutExpired (ts))
|
if (it.second->IsTerminationTimeoutExpired (ts))
|
||||||
{
|
{
|
||||||
auto session = it.second;
|
auto session = it.second;
|
||||||
// Termniate modifies m_NTCPSession, so we postpone it
|
// Terminate modifies m_NTCPSession, so we postpone it
|
||||||
m_Service.post ([session] {
|
m_Service.post ([session] {
|
||||||
LogPrint (eLogDebug, "NTCP: No activity for ", session->GetTerminationTimeout (), " seconds");
|
LogPrint (eLogDebug, "NTCP: No activity for ", session->GetTerminationTimeout (), " seconds");
|
||||||
session->Terminate ();
|
session->Terminate ();
|
||||||
|
|||||||
@@ -207,9 +207,18 @@ namespace data
|
|||||||
{
|
{
|
||||||
if (r->IsNewer (buf, len))
|
if (r->IsNewer (buf, len))
|
||||||
{
|
{
|
||||||
|
bool wasFloodfill = r->IsFloodfill ();
|
||||||
r->Update (buf, len);
|
r->Update (buf, len);
|
||||||
LogPrint (eLogInfo, "NetDb: RouterInfo updated: ", ident.ToBase64());
|
LogPrint (eLogInfo, "NetDb: RouterInfo updated: ", ident.ToBase64());
|
||||||
// TODO: check if floodfill has been changed
|
if (wasFloodfill != r->IsFloodfill ()) // if floodfill status updated
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "NetDb: RouterInfo floodfill status updated: ", ident.ToBase64());
|
||||||
|
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
|
||||||
|
if (wasFloodfill)
|
||||||
|
m_Floodfills.remove (r);
|
||||||
|
else
|
||||||
|
m_Floodfills.push_back (r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -220,7 +229,7 @@ namespace data
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
r = std::make_shared<RouterInfo> (buf, len);
|
r = std::make_shared<RouterInfo> (buf, len);
|
||||||
if (!r->IsUnreachable ())
|
if (!r->IsUnreachable () && r->HasValidAddresses ())
|
||||||
{
|
{
|
||||||
bool inserted = false;
|
bool inserted = false;
|
||||||
{
|
{
|
||||||
@@ -291,11 +300,23 @@ namespace data
|
|||||||
bool NetDb::AddLeaseSet2 (const IdentHash& ident, const uint8_t * buf, int len, uint8_t storeType)
|
bool NetDb::AddLeaseSet2 (const IdentHash& ident, const uint8_t * buf, int len, uint8_t storeType)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(m_LeaseSetsMutex);
|
std::unique_lock<std::mutex> lock(m_LeaseSetsMutex);
|
||||||
// always new LS2 for now. TODO: implement update
|
|
||||||
auto leaseSet = std::make_shared<LeaseSet2> (storeType, buf, len, false); // we don't need leases in netdb
|
auto leaseSet = std::make_shared<LeaseSet2> (storeType, buf, len, false); // we don't need leases in netdb
|
||||||
|
if (leaseSet->IsValid ())
|
||||||
|
{
|
||||||
|
auto it = m_LeaseSets.find(ident);
|
||||||
|
if (it == m_LeaseSets.end () || it->second->GetStoreType () != storeType ||
|
||||||
|
leaseSet->GetPublishedTimestamp () > it->second->GetPublishedTimestamp ())
|
||||||
|
{
|
||||||
|
// TODO: implement actual update
|
||||||
|
LogPrint (eLogInfo, "NetDb: LeaseSet2 updated: ", ident.ToBase32());
|
||||||
m_LeaseSets[ident] = leaseSet;
|
m_LeaseSets[ident] = leaseSet;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint (eLogError, "NetDb: new LeaseSet2 validation failed: ", ident.ToBase32());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<RouterInfo> NetDb::FindRouter (const IdentHash& ident) const
|
std::shared_ptr<RouterInfo> NetDb::FindRouter (const IdentHash& ident) const
|
||||||
{
|
{
|
||||||
@@ -319,6 +340,9 @@ namespace data
|
|||||||
|
|
||||||
std::shared_ptr<RouterProfile> NetDb::FindRouterProfile (const IdentHash& ident) const
|
std::shared_ptr<RouterProfile> NetDb::FindRouterProfile (const IdentHash& ident) const
|
||||||
{
|
{
|
||||||
|
if (!m_PersistProfiles)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
auto router = FindRouter (ident);
|
auto router = FindRouter (ident);
|
||||||
return router ? router->GetProfile () : nullptr;
|
return router ? router->GetProfile () : nullptr;
|
||||||
}
|
}
|
||||||
@@ -352,7 +376,7 @@ namespace data
|
|||||||
}
|
}
|
||||||
m_FloodfillBootstrap = ri;
|
m_FloodfillBootstrap = ri;
|
||||||
ReseedFromFloodfill(*ri);
|
ReseedFromFloodfill(*ri);
|
||||||
// don't try reseed servers if trying to boostrap from floodfill
|
// don't try reseed servers if trying to bootstrap from floodfill
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -418,7 +442,8 @@ namespace data
|
|||||||
|
|
||||||
void NetDb::VisitStoredRouterInfos(RouterInfoVisitor v)
|
void NetDb::VisitStoredRouterInfos(RouterInfoVisitor v)
|
||||||
{
|
{
|
||||||
m_Storage.Iterate([v] (const std::string & filename) {
|
m_Storage.Iterate([v] (const std::string & filename)
|
||||||
|
{
|
||||||
auto ri = std::make_shared<i2p::data::RouterInfo>(filename);
|
auto ri = std::make_shared<i2p::data::RouterInfo>(filename);
|
||||||
v(ri);
|
v(ri);
|
||||||
});
|
});
|
||||||
@@ -555,11 +580,11 @@ namespace data
|
|||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// clean up expired floodfiils
|
// clean up expired floodfills or not floodfills anymore
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
|
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
|
||||||
for (auto it = m_Floodfills.begin (); it != m_Floodfills.end ();)
|
for (auto it = m_Floodfills.begin (); it != m_Floodfills.end ();)
|
||||||
if ((*it)->IsUnreachable ())
|
if ((*it)->IsUnreachable () || !(*it)->IsFloodfill ())
|
||||||
it = m_Floodfills.erase (it);
|
it = m_Floodfills.erase (it);
|
||||||
else
|
else
|
||||||
++it;
|
++it;
|
||||||
@@ -1218,7 +1243,7 @@ namespace data
|
|||||||
{
|
{
|
||||||
if (!it->second->IsValid () || ts > it->second->GetExpirationTime () - LEASE_ENDDATE_THRESHOLD)
|
if (!it->second->IsValid () || ts > it->second->GetExpirationTime () - LEASE_ENDDATE_THRESHOLD)
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "NetDb: LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired or invalid");
|
LogPrint (eLogInfo, "NetDb: LeaseSet ", it->first.ToBase64 (), " expired or invalid");
|
||||||
it = m_LeaseSets.erase (it);
|
it = m_LeaseSets.erase (it);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -47,7 +47,10 @@ namespace i2p
|
|||||||
routerInfo.SetRouterIdentity (GetIdentity ());
|
routerInfo.SetRouterIdentity (GetIdentity ());
|
||||||
uint16_t port; i2p::config::GetOption("port", port);
|
uint16_t port; i2p::config::GetOption("port", port);
|
||||||
if (!port)
|
if (!port)
|
||||||
|
{
|
||||||
port = rand () % (30777 - 9111) + 9111; // I2P network ports range
|
port = rand () % (30777 - 9111) + 9111; // I2P network ports range
|
||||||
|
if (port == 9150) port = 9151; // Tor browser
|
||||||
|
}
|
||||||
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
|
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
|
||||||
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
|
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
|
||||||
bool ssu; i2p::config::GetOption("ssu", ssu);
|
bool ssu; i2p::config::GetOption("ssu", ssu);
|
||||||
@@ -76,7 +79,7 @@ namespace i2p
|
|||||||
}
|
}
|
||||||
if (ipv6)
|
if (ipv6)
|
||||||
{
|
{
|
||||||
std::string host = "::";
|
std::string host = "::1";
|
||||||
if (!i2p::config::IsDefault("host") && !ipv4) // override if v6 only
|
if (!i2p::config::IsDefault("host") && !ipv4) // override if v6 only
|
||||||
i2p::config::GetOption("host", host);
|
i2p::config::GetOption("host", host);
|
||||||
else if (!ifname.empty())
|
else if (!ifname.empty())
|
||||||
@@ -103,8 +106,13 @@ namespace i2p
|
|||||||
{
|
{
|
||||||
if (!m_NTCP2Keys) NewNTCP2Keys ();
|
if (!m_NTCP2Keys) NewNTCP2Keys ();
|
||||||
UpdateNTCP2Address (true);
|
UpdateNTCP2Address (true);
|
||||||
|
if (!ntcp) // NTCP2 should replace NTCP
|
||||||
|
{
|
||||||
|
bool published; i2p::config::GetOption("ntcp2.published", published);
|
||||||
|
if (published)
|
||||||
|
PublishNTCP2Address (port, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::UpdateRouterInfo ()
|
void RouterContext::UpdateRouterInfo ()
|
||||||
@@ -166,7 +174,10 @@ namespace i2p
|
|||||||
{
|
{
|
||||||
if (!m_NTCP2Keys) return;
|
if (!m_NTCP2Keys) return;
|
||||||
if (!port)
|
if (!port)
|
||||||
|
{
|
||||||
port = rand () % (30777 - 9111) + 9111; // I2P network ports range
|
port = rand () % (30777 - 9111) + 9111; // I2P network ports range
|
||||||
|
if (port == 9150) port = 9151; // Tor browser
|
||||||
|
}
|
||||||
bool updated = false;
|
bool updated = false;
|
||||||
for (auto& address : m_RouterInfo.GetAddresses ())
|
for (auto& address : m_RouterInfo.GetAddresses ())
|
||||||
{
|
{
|
||||||
@@ -332,6 +343,51 @@ namespace i2p
|
|||||||
return m_RouterInfo.GetCaps () & i2p::data::RouterInfo::eUnreachable;
|
return m_RouterInfo.GetCaps () & i2p::data::RouterInfo::eUnreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RouterContext::PublishNTCPAddress (bool publish, bool v4only)
|
||||||
|
{
|
||||||
|
auto& addresses = m_RouterInfo.GetAddresses ();
|
||||||
|
if (publish)
|
||||||
|
{
|
||||||
|
for (const auto& addr : addresses) // v4
|
||||||
|
{
|
||||||
|
if (addr->transportStyle == i2p::data::RouterInfo::eTransportSSU &&
|
||||||
|
addr->host.is_v4 ())
|
||||||
|
{
|
||||||
|
// insert NTCP address with host/port from SSU
|
||||||
|
m_RouterInfo.AddNTCPAddress (addr->host.to_string ().c_str (), addr->port);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!v4only)
|
||||||
|
{
|
||||||
|
for (const auto& addr : addresses) // v6
|
||||||
|
{
|
||||||
|
if (addr->transportStyle == i2p::data::RouterInfo::eTransportSSU &&
|
||||||
|
addr->host.is_v6 ())
|
||||||
|
{
|
||||||
|
// insert NTCP address with host/port from SSU
|
||||||
|
m_RouterInfo.AddNTCPAddress (addr->host.to_string ().c_str (), addr->port);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (auto it = addresses.begin (); it != addresses.end ();)
|
||||||
|
{
|
||||||
|
if ((*it)->transportStyle == i2p::data::RouterInfo::eTransportNTCP && !(*it)->IsNTCP2 () &&
|
||||||
|
(!v4only || (*it)->host.is_v4 ()))
|
||||||
|
{
|
||||||
|
it = addresses.erase (it);
|
||||||
|
if (v4only) break; // otherwise might be more than one address
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RouterContext::SetUnreachable ()
|
void RouterContext::SetUnreachable ()
|
||||||
{
|
{
|
||||||
// set caps
|
// set caps
|
||||||
@@ -341,22 +397,13 @@ namespace i2p
|
|||||||
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
|
caps &= ~i2p::data::RouterInfo::eSSUIntroducer; // can't be introducer
|
||||||
m_RouterInfo.SetCaps (caps);
|
m_RouterInfo.SetCaps (caps);
|
||||||
// remove NTCP address
|
// remove NTCP v4 address
|
||||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
PublishNTCPAddress (false);
|
||||||
for (auto it = addresses.begin (); it != addresses.end (); ++it)
|
|
||||||
{
|
|
||||||
if ((*it)->transportStyle == i2p::data::RouterInfo::eTransportNTCP && !(*it)->IsNTCP2 () &&
|
|
||||||
(*it)->host.is_v4 ())
|
|
||||||
{
|
|
||||||
addresses.erase (it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// delete previous introducers
|
// delete previous introducers
|
||||||
|
auto& addresses = m_RouterInfo.GetAddresses ();
|
||||||
for (auto& addr : addresses)
|
for (auto& addr : addresses)
|
||||||
if (addr->ssu)
|
if (addr->ssu)
|
||||||
addr->ssu->introducers.clear ();
|
addr->ssu->introducers.clear ();
|
||||||
|
|
||||||
// update
|
// update
|
||||||
UpdateRouterInfo ();
|
UpdateRouterInfo ();
|
||||||
}
|
}
|
||||||
@@ -371,27 +418,15 @@ namespace i2p
|
|||||||
if (m_IsFloodfill)
|
if (m_IsFloodfill)
|
||||||
caps |= i2p::data::RouterInfo::eFloodfill;
|
caps |= i2p::data::RouterInfo::eFloodfill;
|
||||||
m_RouterInfo.SetCaps (caps);
|
m_RouterInfo.SetCaps (caps);
|
||||||
|
|
||||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
|
||||||
// insert NTCP back
|
// insert NTCP back
|
||||||
bool ntcp; i2p::config::GetOption("ntcp", ntcp);
|
bool ntcp; i2p::config::GetOption("ntcp", ntcp);
|
||||||
if (ntcp) {
|
if (ntcp)
|
||||||
for (const auto& addr : addresses)
|
PublishNTCPAddress (true);
|
||||||
{
|
|
||||||
if (addr->transportStyle == i2p::data::RouterInfo::eTransportSSU &&
|
|
||||||
addr->host.is_v4 ())
|
|
||||||
{
|
|
||||||
// insert NTCP address with host/port from SSU
|
|
||||||
m_RouterInfo.AddNTCPAddress (addr->host.to_string ().c_str (), addr->port);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// delete previous introducers
|
// delete previous introducers
|
||||||
|
auto& addresses = m_RouterInfo.GetAddresses ();
|
||||||
for (auto& addr : addresses)
|
for (auto& addr : addresses)
|
||||||
if (addr->ssu)
|
if (addr->ssu)
|
||||||
addr->ssu->introducers.clear ();
|
addr->ssu->introducers.clear ();
|
||||||
|
|
||||||
// update
|
// update
|
||||||
UpdateRouterInfo ();
|
UpdateRouterInfo ();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ namespace i2p
|
|||||||
void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon
|
void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon
|
||||||
void PublishNTCP2Address (int port, bool publish = true);
|
void PublishNTCP2Address (int port, bool publish = true);
|
||||||
void UpdateNTCP2Address (bool enable);
|
void UpdateNTCP2Address (bool enable);
|
||||||
|
void PublishNTCPAddress (bool publish, bool v4only = true);
|
||||||
bool AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer);
|
bool AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer);
|
||||||
void RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
|
void RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
|
||||||
bool IsUnreachable () const;
|
bool IsUnreachable () const;
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ namespace data
|
|||||||
|
|
||||||
void RouterInfo::Update (const uint8_t * buf, int len)
|
void RouterInfo::Update (const uint8_t * buf, int len)
|
||||||
{
|
{
|
||||||
// verify signature since we have indentity already
|
// verify signature since we have identity already
|
||||||
int l = len - m_RouterIdentity->GetSignatureLen ();
|
int l = len - m_RouterIdentity->GetSignatureLen ();
|
||||||
if (m_RouterIdentity->Verify (buf, l, buf + l))
|
if (m_RouterIdentity->Verify (buf, l, buf + l))
|
||||||
{
|
{
|
||||||
@@ -208,20 +208,14 @@ namespace data
|
|||||||
{
|
{
|
||||||
boost::system::error_code ecode;
|
boost::system::error_code ecode;
|
||||||
address->host = boost::asio::ip::address::from_string (value, ecode);
|
address->host = boost::asio::ip::address::from_string (value, ecode);
|
||||||
if (ecode)
|
if (!ecode)
|
||||||
{
|
{
|
||||||
if (address->transportStyle == eTransportNTCP)
|
#if BOOST_VERSION >= 104900
|
||||||
{
|
if (!address->host.is_unspecified ()) // check if address is valid
|
||||||
supportedTransports |= eNTCPV4; // TODO:
|
#else
|
||||||
address->addressString = value;
|
address->host.to_string (ecode);
|
||||||
}
|
if (!ecode)
|
||||||
else
|
#endif
|
||||||
{
|
|
||||||
supportedTransports |= eSSUV4; // TODO:
|
|
||||||
address->addressString = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// add supported protocol
|
// add supported protocol
|
||||||
if (address->host.is_v4 ())
|
if (address->host.is_v4 ())
|
||||||
@@ -230,6 +224,7 @@ namespace data
|
|||||||
supportedTransports |= (address->transportStyle == eTransportNTCP) ? eNTCPV6 : eSSUV6;
|
supportedTransports |= (address->transportStyle == eTransportNTCP) ? eNTCPV6 : eSSUV6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (!strcmp (key, "port"))
|
else if (!strcmp (key, "port"))
|
||||||
address->port = boost::lexical_cast<int>(value);
|
address->port = boost::lexical_cast<int>(value);
|
||||||
else if (!strcmp (key, "mtu"))
|
else if (!strcmp (key, "mtu"))
|
||||||
@@ -888,7 +883,7 @@ namespace data
|
|||||||
template<typename Filter>
|
template<typename Filter>
|
||||||
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetAddress (Filter filter) const
|
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetAddress (Filter filter) const
|
||||||
{
|
{
|
||||||
// TODO: make it more gereric using comparator
|
// TODO: make it more generic using comparator
|
||||||
#if (BOOST_VERSION >= 105300)
|
#if (BOOST_VERSION >= 105300)
|
||||||
auto addresses = boost::atomic_load (&m_Addresses);
|
auto addresses = boost::atomic_load (&m_Addresses);
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -102,7 +102,6 @@ namespace data
|
|||||||
{
|
{
|
||||||
TransportStyle transportStyle;
|
TransportStyle transportStyle;
|
||||||
boost::asio::ip::address host;
|
boost::asio::ip::address host;
|
||||||
std::string addressString;
|
|
||||||
int port;
|
int port;
|
||||||
uint64_t date;
|
uint64_t date;
|
||||||
uint8_t cost;
|
uint8_t cost;
|
||||||
@@ -170,6 +169,7 @@ namespace data
|
|||||||
void EnableV4 ();
|
void EnableV4 ();
|
||||||
void DisableV4 ();
|
void DisableV4 ();
|
||||||
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 UsesIntroducer () const;
|
bool UsesIntroducer () const;
|
||||||
bool IsIntroducer () const { return m_Caps & eSSUIntroducer; };
|
bool IsIntroducer () const { return m_Caps & eSSUIntroducer; };
|
||||||
bool IsPeerTesting () const { return m_Caps & eSSUTesting; };
|
bool IsPeerTesting () const { return m_Caps & eSSUTesting; };
|
||||||
|
|||||||
@@ -328,7 +328,11 @@ namespace transport
|
|||||||
{
|
{
|
||||||
if (!session || session->GetRemoteEndpoint () != packet->from) // we received packet for other session than previous
|
if (!session || session->GetRemoteEndpoint () != packet->from) // we received packet for other session than previous
|
||||||
{
|
{
|
||||||
if (session) session->FlushData ();
|
if (session)
|
||||||
|
{
|
||||||
|
session->FlushData ();
|
||||||
|
session = nullptr;
|
||||||
|
}
|
||||||
auto it = sessions->find (packet->from);
|
auto it = sessions->find (packet->from);
|
||||||
if (it != sessions->end ())
|
if (it != sessions->end ())
|
||||||
session = it->second;
|
session = it->second;
|
||||||
@@ -750,6 +754,8 @@ namespace transport
|
|||||||
if (it.second->IsTerminationTimeoutExpired (ts))
|
if (it.second->IsTerminationTimeoutExpired (ts))
|
||||||
{
|
{
|
||||||
auto session = it.second;
|
auto session = it.second;
|
||||||
|
if (it.first != session->GetRemoteEndpoint ())
|
||||||
|
LogPrint (eLogWarning, "SSU: remote endpoint ", session->GetRemoteEndpoint (), " doesn't match key ", it.first, " adjusted");
|
||||||
m_Service.post ([session]
|
m_Service.post ([session]
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "SSU: no activity with ", session->GetRemoteEndpoint (), " for ", session->GetTerminationTimeout (), " seconds");
|
LogPrint (eLogWarning, "SSU: no activity with ", session->GetRemoteEndpoint (), " for ", session->GetTerminationTimeout (), " seconds");
|
||||||
@@ -776,6 +782,8 @@ namespace transport
|
|||||||
if (it.second->IsTerminationTimeoutExpired (ts))
|
if (it.second->IsTerminationTimeoutExpired (ts))
|
||||||
{
|
{
|
||||||
auto session = it.second;
|
auto session = it.second;
|
||||||
|
if (it.first != session->GetRemoteEndpoint ())
|
||||||
|
LogPrint (eLogWarning, "SSU: remote endpoint ", session->GetRemoteEndpoint (), " doesn't match key ", it.first);
|
||||||
m_ServiceV6.post ([session]
|
m_ServiceV6.post ([session]
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "SSU: no activity with ", session->GetRemoteEndpoint (), " for ", session->GetTerminationTimeout (), " seconds");
|
LogPrint (eLogWarning, "SSU: no activity with ", session->GetRemoteEndpoint (), " for ", session->GetTerminationTimeout (), " seconds");
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ namespace transport
|
|||||||
ProcessData (buf + headerSize, len - headerSize);
|
ProcessData (buf + headerSize, len - headerSize);
|
||||||
break;
|
break;
|
||||||
case PAYLOAD_TYPE_SESSION_REQUEST:
|
case PAYLOAD_TYPE_SESSION_REQUEST:
|
||||||
ProcessSessionRequest (buf, len, senderEndpoint); // buf with header
|
ProcessSessionRequest (buf, len); // buf with header
|
||||||
break;
|
break;
|
||||||
case PAYLOAD_TYPE_SESSION_CREATED:
|
case PAYLOAD_TYPE_SESSION_CREATED:
|
||||||
ProcessSessionCreated (buf, len); // buf with header
|
ProcessSessionCreated (buf, len); // buf with header
|
||||||
@@ -194,7 +194,7 @@ namespace transport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUSession::ProcessSessionRequest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
|
void SSUSession::ProcessSessionRequest (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "SSU message: session request");
|
LogPrint (eLogDebug, "SSU message: session request");
|
||||||
bool sendRelayTag = true;
|
bool sendRelayTag = true;
|
||||||
@@ -212,10 +212,9 @@ namespace transport
|
|||||||
}
|
}
|
||||||
if (headerSize >= len)
|
if (headerSize >= len)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "Session reaquest header size ", headerSize, " exceeds packet length ", len);
|
LogPrint (eLogError, "Session request header size ", headerSize, " exceeds packet length ", len);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_RemoteEndpoint = senderEndpoint;
|
|
||||||
if (!m_DHKeysPair)
|
if (!m_DHKeysPair)
|
||||||
m_DHKeysPair = transports.GetNextDHKeysPair ();
|
m_DHKeysPair = transports.GetNextDHKeysPair ();
|
||||||
CreateAESandMacKey (buf + headerSize);
|
CreateAESandMacKey (buf + headerSize);
|
||||||
@@ -1097,7 +1096,7 @@ namespace transport
|
|||||||
// intro key
|
// intro key
|
||||||
if (toAddress)
|
if (toAddress)
|
||||||
{
|
{
|
||||||
// send our intro key to address instead it's own
|
// send our intro key to address instead of its own
|
||||||
auto addr = i2p::context.GetRouterInfo ().GetSSUAddress ();
|
auto addr = i2p::context.GetRouterInfo ().GetSSUAddress ();
|
||||||
if (addr)
|
if (addr)
|
||||||
memcpy (payload, addr->ssu->key, 32); // intro key
|
memcpy (payload, addr->ssu->key, 32); // intro key
|
||||||
|
|||||||
@@ -80,7 +80,8 @@ namespace transport
|
|||||||
void Close ();
|
void Close ();
|
||||||
void Done ();
|
void Done ();
|
||||||
void Failed ();
|
void Failed ();
|
||||||
boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
|
const boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
|
||||||
|
|
||||||
bool IsV6 () const { return m_RemoteEndpoint.address ().is_v6 (); };
|
bool IsV6 () const { return m_RemoteEndpoint.address ().is_v6 (); };
|
||||||
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
|
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
|
||||||
void SendPeerTest (); // Alice
|
void SendPeerTest (); // Alice
|
||||||
@@ -103,7 +104,7 @@ namespace transport
|
|||||||
size_t GetSSUHeaderSize (const uint8_t * buf) const;
|
size_t GetSSUHeaderSize (const uint8_t * buf) const;
|
||||||
void PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs);
|
void PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs);
|
||||||
void ProcessMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); // call for established session
|
void ProcessMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); // call for established session
|
||||||
void ProcessSessionRequest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
|
void ProcessSessionRequest (const uint8_t * buf, size_t len);
|
||||||
void SendSessionRequest ();
|
void SendSessionRequest ();
|
||||||
void SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer, uint32_t nonce);
|
void SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer, uint32_t nonce);
|
||||||
void ProcessSessionCreated (uint8_t * buf, size_t len);
|
void ProcessSessionCreated (uint8_t * buf, size_t len);
|
||||||
@@ -139,7 +140,7 @@ namespace transport
|
|||||||
|
|
||||||
friend class SSUData; // TODO: change in later
|
friend class SSUData; // TODO: change in later
|
||||||
SSUServer& m_Server;
|
SSUServer& m_Server;
|
||||||
boost::asio::ip::udp::endpoint m_RemoteEndpoint;
|
const boost::asio::ip::udp::endpoint m_RemoteEndpoint;
|
||||||
boost::asio::deadline_timer m_ConnectTimer;
|
boost::asio::deadline_timer m_ConnectTimer;
|
||||||
bool m_IsPeerTest;
|
bool m_IsPeerTest;
|
||||||
SessionState m_State;
|
SessionState m_State;
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ namespace i2p
|
|||||||
namespace crypto
|
namespace crypto
|
||||||
{
|
{
|
||||||
#if OPENSSL_EDDSA
|
#if OPENSSL_EDDSA
|
||||||
EDDSA25519Verifier::EDDSA25519Verifier ()
|
EDDSA25519Verifier::EDDSA25519Verifier ():
|
||||||
|
m_Pkey (nullptr)
|
||||||
{
|
{
|
||||||
m_MDCtx = EVP_MD_CTX_create ();
|
m_MDCtx = EVP_MD_CTX_create ();
|
||||||
}
|
}
|
||||||
@@ -97,7 +98,7 @@ namespace crypto
|
|||||||
uint8_t publicKey[EDDSA25519_PUBLIC_KEY_LENGTH];
|
uint8_t publicKey[EDDSA25519_PUBLIC_KEY_LENGTH];
|
||||||
size_t len = EDDSA25519_PUBLIC_KEY_LENGTH;
|
size_t len = EDDSA25519_PUBLIC_KEY_LENGTH;
|
||||||
EVP_PKEY_get_raw_public_key (m_Pkey, publicKey, &len);
|
EVP_PKEY_get_raw_public_key (m_Pkey, publicKey, &len);
|
||||||
if (memcmp (publicKey, signingPublicKey, EDDSA25519_PUBLIC_KEY_LENGTH))
|
if (signingPublicKey && memcmp (publicKey, signingPublicKey, EDDSA25519_PUBLIC_KEY_LENGTH))
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "EdDSA public key mismatch. Fallback");
|
LogPrint (eLogWarning, "EdDSA public key mismatch. Fallback");
|
||||||
EVP_PKEY_free (m_Pkey);
|
EVP_PKEY_free (m_Pkey);
|
||||||
|
|||||||
@@ -487,6 +487,42 @@ namespace crypto
|
|||||||
typedef GOSTR3410Signer<GOSTR3411_256_Hash> GOSTR3410_256_Signer;
|
typedef GOSTR3410Signer<GOSTR3411_256_Hash> GOSTR3410_256_Signer;
|
||||||
typedef GOSTR3410Verifier<GOSTR3411_512_Hash> GOSTR3410_512_Verifier;
|
typedef GOSTR3410Verifier<GOSTR3411_512_Hash> GOSTR3410_512_Verifier;
|
||||||
typedef GOSTR3410Signer<GOSTR3411_512_Hash> GOSTR3410_512_Signer;
|
typedef GOSTR3410Signer<GOSTR3411_512_Hash> GOSTR3410_512_Signer;
|
||||||
|
|
||||||
|
// RedDSA
|
||||||
|
typedef EDDSA25519Verifier RedDSA25519Verifier;
|
||||||
|
class RedDSA25519Signer: public Signer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
RedDSA25519Signer (const uint8_t * signingPrivateKey)
|
||||||
|
{
|
||||||
|
memcpy (m_PrivateKey, signingPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH);
|
||||||
|
BN_CTX * ctx = BN_CTX_new ();
|
||||||
|
auto publicKey = GetEd25519 ()->GeneratePublicKey (m_PrivateKey, ctx);
|
||||||
|
GetEd25519 ()->EncodePublicKey (publicKey, m_PublicKeyEncoded, ctx);
|
||||||
|
BN_CTX_free (ctx);
|
||||||
|
}
|
||||||
|
~RedDSA25519Signer () {};
|
||||||
|
|
||||||
|
void Sign (const uint8_t * buf, int len, uint8_t * signature) const
|
||||||
|
{
|
||||||
|
GetEd25519 ()->SignRedDSA (m_PrivateKey, m_PublicKeyEncoded, buf, len, signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t * GetPublicKey () const { return m_PublicKeyEncoded; }; // for keys creation
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
uint8_t m_PrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH];
|
||||||
|
uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH];
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void CreateRedDSA25519RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
|
||||||
|
{
|
||||||
|
GetEd25519 ()->CreateRedDSAPrivateKey (signingPrivateKey);
|
||||||
|
RedDSA25519Signer signer (signingPrivateKey);
|
||||||
|
memcpy (signingPublicKey, signer.GetPublicKey (), EDDSA25519_PUBLIC_KEY_LENGTH);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -217,60 +217,16 @@ namespace stream
|
|||||||
|
|
||||||
void Stream::ProcessPacket (Packet * packet)
|
void Stream::ProcessPacket (Packet * packet)
|
||||||
{
|
{
|
||||||
// process flags
|
|
||||||
uint32_t receivedSeqn = packet->GetSeqn ();
|
uint32_t receivedSeqn = packet->GetSeqn ();
|
||||||
uint16_t flags = packet->GetFlags ();
|
uint16_t flags = packet->GetFlags ();
|
||||||
LogPrint (eLogDebug, "Streaming: Process seqn=", receivedSeqn, ", flags=", flags);
|
LogPrint (eLogDebug, "Streaming: Process seqn=", receivedSeqn, ", flags=", flags);
|
||||||
|
|
||||||
const uint8_t * optionData = packet->GetOptionData ();
|
if (!ProcessOptions (flags, packet))
|
||||||
|
|
||||||
if (flags & PACKET_FLAG_DELAY_REQUESTED)
|
|
||||||
optionData += 2;
|
|
||||||
|
|
||||||
if (flags & PACKET_FLAG_FROM_INCLUDED)
|
|
||||||
{
|
{
|
||||||
m_RemoteIdentity = std::make_shared<i2p::data::IdentityEx>(optionData, packet->GetOptionSize ());
|
|
||||||
if (m_RemoteIdentity->IsRSA ())
|
|
||||||
{
|
|
||||||
LogPrint (eLogInfo, "Streaming: Incoming stream from RSA destination ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), " Discarded");
|
|
||||||
m_LocalDestination.DeletePacket (packet);
|
m_LocalDestination.DeletePacket (packet);
|
||||||
Terminate ();
|
Terminate ();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
optionData += m_RemoteIdentity->GetFullLen ();
|
|
||||||
if (!m_RemoteLeaseSet)
|
|
||||||
LogPrint (eLogDebug, "Streaming: Incoming stream from ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), ", sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED)
|
|
||||||
{
|
|
||||||
uint16_t maxPacketSize = bufbe16toh (optionData);
|
|
||||||
LogPrint (eLogDebug, "Streaming: Max packet size ", maxPacketSize);
|
|
||||||
optionData += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & PACKET_FLAG_SIGNATURE_INCLUDED)
|
|
||||||
{
|
|
||||||
uint8_t signature[256];
|
|
||||||
auto signatureLen = m_RemoteIdentity->GetSignatureLen ();
|
|
||||||
if(signatureLen <= sizeof(signature))
|
|
||||||
{
|
|
||||||
memcpy (signature, optionData, signatureLen);
|
|
||||||
memset (const_cast<uint8_t *>(optionData), 0, signatureLen);
|
|
||||||
if (!m_RemoteIdentity->Verify (packet->GetBuffer (), packet->GetLength (), signature))
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "Streaming: Signature verification failed, sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID);
|
|
||||||
Close ();
|
|
||||||
flags |= PACKET_FLAG_CLOSE;
|
|
||||||
}
|
|
||||||
memcpy (const_cast<uint8_t *>(optionData), signature, signatureLen);
|
|
||||||
optionData += signatureLen;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LogPrint(eLogError, "Streaming: Signature too big, ", signatureLen, " bytes");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
packet->offset = packet->GetPayload () - packet->buf;
|
packet->offset = packet->GetPayload () - packet->buf;
|
||||||
if (packet->GetLength () > 0)
|
if (packet->GetLength () > 0)
|
||||||
@@ -298,6 +254,94 @@ namespace stream
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Stream::ProcessOptions (uint16_t flags, Packet * packet)
|
||||||
|
{
|
||||||
|
const uint8_t * optionData = packet->GetOptionData ();
|
||||||
|
size_t optionSize = packet->GetOptionSize ();
|
||||||
|
if (flags & PACKET_FLAG_DELAY_REQUESTED)
|
||||||
|
optionData += 2;
|
||||||
|
|
||||||
|
if (flags & PACKET_FLAG_FROM_INCLUDED)
|
||||||
|
{
|
||||||
|
if (m_RemoteLeaseSet) m_RemoteIdentity = m_RemoteLeaseSet->GetIdentity ();
|
||||||
|
if (!m_RemoteIdentity)
|
||||||
|
m_RemoteIdentity = std::make_shared<i2p::data::IdentityEx>(optionData, optionSize);
|
||||||
|
if (m_RemoteIdentity->IsRSA ())
|
||||||
|
{
|
||||||
|
LogPrint (eLogInfo, "Streaming: Incoming stream from RSA destination ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), " Discarded");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
optionData += m_RemoteIdentity->GetFullLen ();
|
||||||
|
if (!m_RemoteLeaseSet)
|
||||||
|
LogPrint (eLogDebug, "Streaming: Incoming stream from ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), ", sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED)
|
||||||
|
{
|
||||||
|
uint16_t maxPacketSize = bufbe16toh (optionData);
|
||||||
|
LogPrint (eLogDebug, "Streaming: Max packet size ", maxPacketSize);
|
||||||
|
optionData += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & PACKET_FLAG_OFFLINE_SIGNATURE)
|
||||||
|
{
|
||||||
|
if (!m_RemoteIdentity)
|
||||||
|
{
|
||||||
|
LogPrint (eLogInfo, "Streaming: offline signature without identity");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// if we have it in LeaseSet already we don't need to parse it again
|
||||||
|
if (m_RemoteLeaseSet) m_TransientVerifier = m_RemoteLeaseSet->GetTransientVerifier ();
|
||||||
|
if (m_TransientVerifier)
|
||||||
|
{
|
||||||
|
// skip option data
|
||||||
|
optionData += 6; // timestamp and key type
|
||||||
|
optionData += m_TransientVerifier->GetPublicKeyLen (); // public key
|
||||||
|
optionData += m_RemoteIdentity->GetSignatureLen (); // signature
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// transient key
|
||||||
|
size_t offset = 0;
|
||||||
|
m_TransientVerifier = i2p::data::ProcessOfflineSignature (m_RemoteIdentity, optionData, optionSize - (optionData - packet->GetOptionData ()), offset);
|
||||||
|
optionData += offset;
|
||||||
|
if (!m_TransientVerifier)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "Streaming: offline signature failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & PACKET_FLAG_SIGNATURE_INCLUDED)
|
||||||
|
{
|
||||||
|
uint8_t signature[256];
|
||||||
|
auto signatureLen = m_RemoteIdentity->GetSignatureLen ();
|
||||||
|
if(signatureLen <= sizeof(signature))
|
||||||
|
{
|
||||||
|
memcpy (signature, optionData, signatureLen);
|
||||||
|
memset (const_cast<uint8_t *>(optionData), 0, signatureLen);
|
||||||
|
bool verified = m_TransientVerifier ?
|
||||||
|
m_TransientVerifier->Verify (packet->GetBuffer (), packet->GetLength (), signature) :
|
||||||
|
m_RemoteIdentity->Verify (packet->GetBuffer (), packet->GetLength (), signature);
|
||||||
|
if (!verified)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "Streaming: Signature verification failed, sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID);
|
||||||
|
Close ();
|
||||||
|
flags |= PACKET_FLAG_CLOSE;
|
||||||
|
}
|
||||||
|
memcpy (const_cast<uint8_t *>(optionData), signature, signatureLen);
|
||||||
|
optionData += signatureLen;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "Streaming: Signature too big, ", signatureLen, " bytes");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void Stream::ProcessAck (Packet * packet)
|
void Stream::ProcessAck (Packet * packet)
|
||||||
{
|
{
|
||||||
bool acknowledged = false;
|
bool acknowledged = false;
|
||||||
@@ -438,19 +482,28 @@ namespace stream
|
|||||||
uint16_t flags = PACKET_FLAG_SYNCHRONIZE | PACKET_FLAG_FROM_INCLUDED |
|
uint16_t flags = PACKET_FLAG_SYNCHRONIZE | PACKET_FLAG_FROM_INCLUDED |
|
||||||
PACKET_FLAG_SIGNATURE_INCLUDED | PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED;
|
PACKET_FLAG_SIGNATURE_INCLUDED | PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED;
|
||||||
if (isNoAck) flags |= PACKET_FLAG_NO_ACK;
|
if (isNoAck) flags |= PACKET_FLAG_NO_ACK;
|
||||||
|
bool isOfflineSignature = m_LocalDestination.GetOwner ()->GetPrivateKeys ().IsOfflineSignature ();
|
||||||
|
if (isOfflineSignature) flags |= PACKET_FLAG_OFFLINE_SIGNATURE;
|
||||||
htobe16buf (packet + size, flags);
|
htobe16buf (packet + size, flags);
|
||||||
size += 2; // flags
|
size += 2; // flags
|
||||||
size_t identityLen = m_LocalDestination.GetOwner ()->GetIdentity ()->GetFullLen ();
|
size_t identityLen = m_LocalDestination.GetOwner ()->GetIdentity ()->GetFullLen ();
|
||||||
size_t signatureLen = m_LocalDestination.GetOwner ()->GetIdentity ()->GetSignatureLen ();
|
size_t signatureLen = m_LocalDestination.GetOwner ()->GetPrivateKeys ().GetSignatureLen ();
|
||||||
htobe16buf (packet + size, identityLen + signatureLen + 2); // identity + signature + packet size
|
uint8_t * optionsSize = packet + size; // set options size later
|
||||||
size += 2; // options size
|
size += 2; // options size
|
||||||
m_LocalDestination.GetOwner ()->GetIdentity ()->ToBuffer (packet + size, identityLen);
|
m_LocalDestination.GetOwner ()->GetIdentity ()->ToBuffer (packet + size, identityLen);
|
||||||
size += identityLen; // from
|
size += identityLen; // from
|
||||||
htobe16buf (packet + size, STREAMING_MTU);
|
htobe16buf (packet + size, STREAMING_MTU);
|
||||||
size += 2; // max packet size
|
size += 2; // max packet size
|
||||||
|
if (isOfflineSignature)
|
||||||
|
{
|
||||||
|
const auto& offlineSignature = m_LocalDestination.GetOwner ()->GetPrivateKeys ().GetOfflineSignature ();
|
||||||
|
memcpy (packet + size, offlineSignature.data (), offlineSignature.size ());
|
||||||
|
size += offlineSignature.size (); // offline signature
|
||||||
|
}
|
||||||
uint8_t * signature = packet + size; // set it later
|
uint8_t * signature = packet + size; // set it later
|
||||||
memset (signature, 0, signatureLen); // zeroes for now
|
memset (signature, 0, signatureLen); // zeroes for now
|
||||||
size += signatureLen; // signature
|
size += signatureLen; // signature
|
||||||
|
htobe16buf (optionsSize, packet + size - 2 - optionsSize); // actual options size
|
||||||
size += m_SendBuffer.Get (packet + size, STREAMING_MTU - size); // payload
|
size += m_SendBuffer.Get (packet + size, STREAMING_MTU - size); // payload
|
||||||
m_LocalDestination.GetOwner ()->Sign (packet, size, signature);
|
m_LocalDestination.GetOwner ()->Sign (packet, size, signature);
|
||||||
}
|
}
|
||||||
@@ -549,7 +602,7 @@ namespace stream
|
|||||||
size++; // NACK count
|
size++; // NACK count
|
||||||
}
|
}
|
||||||
size++; // resend delay
|
size++; // resend delay
|
||||||
htobuf16 (packet + size, 0); // nof flags set
|
htobuf16 (packet + size, 0); // no flags set
|
||||||
size += 2; // flags
|
size += 2; // flags
|
||||||
htobuf16 (packet + size, 0); // no options
|
htobuf16 (packet + size, 0); // no options
|
||||||
size += 2; // options size
|
size += 2; // options size
|
||||||
@@ -849,6 +902,12 @@ namespace stream
|
|||||||
LogPrint (eLogWarning, "Streaming: LeaseSet ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), " not found");
|
LogPrint (eLogWarning, "Streaming: LeaseSet ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), " not found");
|
||||||
m_LocalDestination.GetOwner ()->RequestDestination (m_RemoteIdentity->GetIdentHash ()); // try to request for a next attempt
|
m_LocalDestination.GetOwner ()->RequestDestination (m_RemoteIdentity->GetIdentHash ()); // try to request for a next attempt
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// LeaseSet updated
|
||||||
|
m_RemoteIdentity = m_RemoteLeaseSet->GetIdentity ();
|
||||||
|
m_TransientVerifier = m_RemoteLeaseSet->GetTransientVerifier ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (m_RemoteLeaseSet)
|
if (m_RemoteLeaseSet)
|
||||||
{
|
{
|
||||||
@@ -858,7 +917,12 @@ namespace stream
|
|||||||
if (leases.empty ())
|
if (leases.empty ())
|
||||||
{
|
{
|
||||||
expired = false;
|
expired = false;
|
||||||
m_LocalDestination.GetOwner ()->RequestDestination (m_RemoteIdentity->GetIdentHash ()); // time to request
|
// time to request
|
||||||
|
if (m_RemoteLeaseSet->GetOrigStoreType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
|
||||||
|
m_LocalDestination.GetOwner ()->RequestDestinationWithEncryptedLeaseSet (
|
||||||
|
std::make_shared<i2p::data::BlindedPublicKey>(m_RemoteIdentity));
|
||||||
|
else
|
||||||
|
m_LocalDestination.GetOwner ()->RequestDestination (m_RemoteIdentity->GetIdentHash ());
|
||||||
leases = m_RemoteLeaseSet->GetNonExpiredLeases (true); // then with threshold
|
leases = m_RemoteLeaseSet->GetNonExpiredLeases (true); // then with threshold
|
||||||
}
|
}
|
||||||
if (!leases.empty ())
|
if (!leases.empty ())
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ namespace stream
|
|||||||
const uint16_t PACKET_FLAG_PROFILE_INTERACTIVE = 0x0100;
|
const uint16_t PACKET_FLAG_PROFILE_INTERACTIVE = 0x0100;
|
||||||
const uint16_t PACKET_FLAG_ECHO = 0x0200;
|
const uint16_t PACKET_FLAG_ECHO = 0x0200;
|
||||||
const uint16_t PACKET_FLAG_NO_ACK = 0x0400;
|
const uint16_t PACKET_FLAG_NO_ACK = 0x0400;
|
||||||
|
const uint16_t PACKET_FLAG_OFFLINE_SIGNATURE = 0x0800;
|
||||||
|
|
||||||
const size_t STREAMING_MTU = 1730;
|
const size_t STREAMING_MTU = 1730;
|
||||||
const size_t MAX_PACKET_SIZE = 4096;
|
const size_t MAX_PACKET_SIZE = 4096;
|
||||||
@@ -195,6 +196,7 @@ namespace stream
|
|||||||
|
|
||||||
void SavePacket (Packet * packet);
|
void SavePacket (Packet * packet);
|
||||||
void ProcessPacket (Packet * packet);
|
void ProcessPacket (Packet * packet);
|
||||||
|
bool ProcessOptions (uint16_t flags, Packet * packet);
|
||||||
void ProcessAck (Packet * packet);
|
void ProcessAck (Packet * packet);
|
||||||
size_t ConcatenatePackets (uint8_t * buf, size_t len);
|
size_t ConcatenatePackets (uint8_t * buf, size_t len);
|
||||||
|
|
||||||
@@ -216,6 +218,7 @@ namespace stream
|
|||||||
bool m_IsAckSendScheduled;
|
bool m_IsAckSendScheduled;
|
||||||
StreamingDestination& m_LocalDestination;
|
StreamingDestination& m_LocalDestination;
|
||||||
std::shared_ptr<const i2p::data::IdentityEx> m_RemoteIdentity;
|
std::shared_ptr<const i2p::data::IdentityEx> m_RemoteIdentity;
|
||||||
|
std::shared_ptr<const i2p::crypto::Verifier> m_TransientVerifier; // in case of offline key
|
||||||
std::shared_ptr<const i2p::data::LeaseSet> m_RemoteLeaseSet;
|
std::shared_ptr<const i2p::data::LeaseSet> m_RemoteLeaseSet;
|
||||||
std::shared_ptr<i2p::garlic::GarlicRoutingSession> m_RoutingSession;
|
std::shared_ptr<i2p::garlic::GarlicRoutingSession> m_RoutingSession;
|
||||||
std::shared_ptr<const i2p::data::Lease> m_CurrentRemoteLease;
|
std::shared_ptr<const i2p::data::Lease> m_CurrentRemoteLease;
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#include <time.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
@@ -37,7 +39,6 @@ namespace util
|
|||||||
std::chrono::system_clock::now().time_since_epoch()).count ();
|
std::chrono::system_clock::now().time_since_epoch()).count ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int64_t g_TimeOffset = 0; // in seconds
|
static int64_t g_TimeOffset = 0; // in seconds
|
||||||
|
|
||||||
static void SyncTimeWithNTP (const std::string& address)
|
static void SyncTimeWithNTP (const std::string& address)
|
||||||
@@ -178,6 +179,25 @@ namespace util
|
|||||||
{
|
{
|
||||||
return GetLocalSecondsSinceEpoch () + g_TimeOffset;
|
return GetLocalSecondsSinceEpoch () + g_TimeOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GetCurrentDate (char * date)
|
||||||
|
{
|
||||||
|
GetDateString (GetSecondsSinceEpoch (), date);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetDateString (uint64_t timestamp, char * date)
|
||||||
|
{
|
||||||
|
using clock = std::chrono::system_clock;
|
||||||
|
auto t = clock::to_time_t (clock::time_point (std::chrono::seconds(timestamp)));
|
||||||
|
struct tm tm;
|
||||||
|
#ifdef _WIN32
|
||||||
|
gmtime_s(&tm, &t);
|
||||||
|
sprintf_s(date, 9, "%04i%02i%02i", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
|
||||||
|
#else
|
||||||
|
gmtime_r(&t, &tm);
|
||||||
|
sprintf(date, "%04i%02i%02i", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ namespace util
|
|||||||
uint32_t GetHoursSinceEpoch ();
|
uint32_t GetHoursSinceEpoch ();
|
||||||
uint64_t GetSecondsSinceEpoch ();
|
uint64_t GetSecondsSinceEpoch ();
|
||||||
|
|
||||||
|
void GetCurrentDate (char * date); // returns date as YYYYMMDD string, 9 bytes
|
||||||
|
void GetDateString (uint64_t timestamp, char * date); // timestap is seconds since epoch, returns date as YYYYMMDD string, 9 bytes
|
||||||
|
|
||||||
class NTPTimeSync
|
class NTPTimeSync
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -426,14 +426,6 @@ namespace transport
|
|||||||
auto address = peer.router->GetNTCPAddress (!context.SupportsV6 ());
|
auto address = peer.router->GetNTCPAddress (!context.SupportsV6 ());
|
||||||
if (address && m_NTCPServer)
|
if (address && m_NTCPServer)
|
||||||
{
|
{
|
||||||
#if BOOST_VERSION >= 104900
|
|
||||||
if (!address->host.is_unspecified ()) // we have address now
|
|
||||||
#else
|
|
||||||
boost::system::error_code ecode;
|
|
||||||
address->host.to_string (ecode);
|
|
||||||
if (!ecode)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
if (!peer.router->UsesIntroducer () && !peer.router->IsUnreachable ())
|
if (!peer.router->UsesIntroducer () && !peer.router->IsUnreachable ())
|
||||||
{
|
{
|
||||||
if(!m_NTCPServer->ShouldLimit())
|
if(!m_NTCPServer->ShouldLimit())
|
||||||
@@ -459,7 +451,6 @@ namespace transport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
else
|
||||||
LogPrint (eLogDebug, "Transports: NTCP address is not present for ", i2p::data::GetIdentHashAbbreviation (ident), ", trying SSU");
|
LogPrint (eLogDebug, "Transports: NTCP address is not present for ", i2p::data::GetIdentHashAbbreviation (ident), ", trying SSU");
|
||||||
}
|
}
|
||||||
@@ -469,19 +460,10 @@ namespace transport
|
|||||||
if (m_SSUServer && peer.router->IsSSU (!context.SupportsV6 ()))
|
if (m_SSUServer && peer.router->IsSSU (!context.SupportsV6 ()))
|
||||||
{
|
{
|
||||||
auto address = peer.router->GetSSUAddress (!context.SupportsV6 ());
|
auto address = peer.router->GetSSUAddress (!context.SupportsV6 ());
|
||||||
#if BOOST_VERSION >= 104900
|
|
||||||
if (!address->host.is_unspecified ()) // we have address now
|
|
||||||
#else
|
|
||||||
boost::system::error_code ecode;
|
|
||||||
address->host.to_string (ecode);
|
|
||||||
if (!ecode)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
m_SSUServer->CreateSession (peer.router, address->host, address->port);
|
m_SSUServer->CreateSession (peer.router, address->host, address->port);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
LogPrint (eLogInfo, "Transports: No NTCP or SSU addresses available");
|
LogPrint (eLogInfo, "Transports: No NTCP or SSU addresses available");
|
||||||
peer.Done ();
|
peer.Done ();
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||||
|
|||||||
@@ -51,6 +51,19 @@ namespace tunnel
|
|||||||
// create fragments
|
// create fragments
|
||||||
const std::shared_ptr<I2NPMessage> & msg = block.data;
|
const std::shared_ptr<I2NPMessage> & msg = block.data;
|
||||||
size_t fullMsgLen = diLen + msg->GetLength () + 2; // delivery instructions + payload + 2 bytes length
|
size_t fullMsgLen = diLen + msg->GetLength () + 2; // delivery instructions + payload + 2 bytes length
|
||||||
|
|
||||||
|
if (!messageCreated && fullMsgLen > m_RemainingSize) // check if we should complete previous message
|
||||||
|
{
|
||||||
|
size_t numFollowOnFragments = fullMsgLen / TUNNEL_DATA_MAX_PAYLOAD_SIZE;
|
||||||
|
// length of bytes doesn't fit full tunnel message
|
||||||
|
// every follow-on fragment adds 7 bytes
|
||||||
|
size_t nonFit = (fullMsgLen + numFollowOnFragments*7) % TUNNEL_DATA_MAX_PAYLOAD_SIZE;
|
||||||
|
if (!nonFit || nonFit > m_RemainingSize)
|
||||||
|
{
|
||||||
|
CompleteCurrentTunnelDataMessage ();
|
||||||
|
CreateCurrentTunnelDataMessage ();
|
||||||
|
}
|
||||||
|
}
|
||||||
if (fullMsgLen <= m_RemainingSize)
|
if (fullMsgLen <= m_RemainingSize)
|
||||||
{
|
{
|
||||||
// message fits. First and last fragment
|
// message fits. First and last fragment
|
||||||
@@ -65,18 +78,6 @@ namespace tunnel
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!messageCreated) // check if we should complete previous message
|
|
||||||
{
|
|
||||||
size_t numFollowOnFragments = fullMsgLen / TUNNEL_DATA_MAX_PAYLOAD_SIZE;
|
|
||||||
// length of bytes don't fit full tunnel message
|
|
||||||
// every follow-on fragment adds 7 bytes
|
|
||||||
size_t nonFit = (fullMsgLen + numFollowOnFragments*7) % TUNNEL_DATA_MAX_PAYLOAD_SIZE;
|
|
||||||
if (!nonFit || nonFit > m_RemainingSize)
|
|
||||||
{
|
|
||||||
CompleteCurrentTunnelDataMessage ();
|
|
||||||
CreateCurrentTunnelDataMessage ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (diLen + 6 <= m_RemainingSize)
|
if (diLen + 6 <= m_RemainingSize)
|
||||||
{
|
{
|
||||||
// delivery instructions fit
|
// delivery instructions fit
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <sysinfoapi.h>
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
#include <iphlpapi.h>
|
#include <iphlpapi.h>
|
||||||
@@ -21,9 +22,10 @@
|
|||||||
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
|
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
|
||||||
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
|
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
|
||||||
|
|
||||||
/* // No more needed. Exists in MinGW.
|
// inet_pton exists Windows since Vista, but XP haven't that function!
|
||||||
int inet_pton(int af, const char *src, void *dst)
|
// This function was written by Petar Korponai?. See http://stackoverflow.com/questions/15660203/inet-pton-identifier-not-found
|
||||||
{ // This function was written by Petar Korponai?. See http://stackoverflow.com/questions/15660203/inet-pton-identifier-not-found
|
int inet_pton_xp(int af, const char *src, void *dst)
|
||||||
|
{
|
||||||
struct sockaddr_storage ss;
|
struct sockaddr_storage ss;
|
||||||
int size = sizeof (ss);
|
int size = sizeof (ss);
|
||||||
char src_copy[INET6_ADDRSTRLEN + 1];
|
char src_copy[INET6_ADDRSTRLEN + 1];
|
||||||
@@ -45,7 +47,7 @@ int inet_pton(int af, const char *src, void *dst)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}*/
|
}
|
||||||
#else /* !WIN32 => UNIX */
|
#else /* !WIN32 => UNIX */
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <ifaddrs.h>
|
#include <ifaddrs.h>
|
||||||
@@ -58,6 +60,20 @@ namespace util
|
|||||||
namespace net
|
namespace net
|
||||||
{
|
{
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
|
bool IsWindowsXPorLater()
|
||||||
|
{
|
||||||
|
OSVERSIONINFO osvi;
|
||||||
|
|
||||||
|
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
|
||||||
|
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
||||||
|
GetVersionEx(&osvi);
|
||||||
|
|
||||||
|
if (osvi.dwMajorVersion <= 5)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int GetMTUWindowsIpv4(sockaddr_in inputAddress, int fallback)
|
int GetMTUWindowsIpv4(sockaddr_in inputAddress, int fallback)
|
||||||
{
|
{
|
||||||
ULONG outBufLen = 0;
|
ULONG outBufLen = 0;
|
||||||
@@ -65,9 +81,9 @@ namespace net
|
|||||||
PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr;
|
PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr;
|
||||||
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr;
|
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr;
|
||||||
|
|
||||||
|
|
||||||
if(GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen)
|
if(GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen)
|
||||||
== ERROR_BUFFER_OVERFLOW) {
|
== ERROR_BUFFER_OVERFLOW)
|
||||||
|
{
|
||||||
FREE(pAddresses);
|
FREE(pAddresses);
|
||||||
pAddresses = (IP_ADAPTER_ADDRESSES*) MALLOC(outBufLen);
|
pAddresses = (IP_ADAPTER_ADDRESSES*) MALLOC(outBufLen);
|
||||||
}
|
}
|
||||||
@@ -76,24 +92,28 @@ namespace net
|
|||||||
AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen
|
AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen
|
||||||
);
|
);
|
||||||
|
|
||||||
if(dwRetVal != NO_ERROR) {
|
if(dwRetVal != NO_ERROR)
|
||||||
|
{
|
||||||
LogPrint(eLogError, "NetIface: GetMTU(): enclosed GetAdaptersAddresses() call has failed");
|
LogPrint(eLogError, "NetIface: GetMTU(): enclosed GetAdaptersAddresses() call has failed");
|
||||||
FREE(pAddresses);
|
FREE(pAddresses);
|
||||||
return fallback;
|
return fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
pCurrAddresses = pAddresses;
|
pCurrAddresses = pAddresses;
|
||||||
while(pCurrAddresses) {
|
while(pCurrAddresses)
|
||||||
|
{
|
||||||
PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress;
|
PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress;
|
||||||
|
|
||||||
pUnicast = pCurrAddresses->FirstUnicastAddress;
|
pUnicast = pCurrAddresses->FirstUnicastAddress;
|
||||||
if(pUnicast == nullptr) {
|
if(pUnicast == nullptr)
|
||||||
LogPrint(eLogError, "NetIface: GetMTU(): not a unicast ipv4 address, this is not supported");
|
LogPrint(eLogError, "NetIface: GetMTU(): not a unicast ipv4 address, this is not supported");
|
||||||
}
|
|
||||||
for(int i = 0; pUnicast != nullptr; ++i) {
|
for(int i = 0; pUnicast != nullptr; ++i)
|
||||||
|
{
|
||||||
LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr;
|
LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr;
|
||||||
sockaddr_in* localInterfaceAddress = (sockaddr_in*) lpAddr;
|
sockaddr_in* localInterfaceAddress = (sockaddr_in*) lpAddr;
|
||||||
if(localInterfaceAddress->sin_addr.S_un.S_addr == inputAddress.sin_addr.S_un.S_addr) {
|
if(localInterfaceAddress->sin_addr.S_un.S_addr == inputAddress.sin_addr.S_un.S_addr)
|
||||||
|
{
|
||||||
auto result = pAddresses->Mtu;
|
auto result = pAddresses->Mtu;
|
||||||
FREE(pAddresses);
|
FREE(pAddresses);
|
||||||
return result;
|
return result;
|
||||||
@@ -116,7 +136,8 @@ namespace net
|
|||||||
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr;
|
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr;
|
||||||
|
|
||||||
if(GetAdaptersAddresses(AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen)
|
if(GetAdaptersAddresses(AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen)
|
||||||
== ERROR_BUFFER_OVERFLOW) {
|
== ERROR_BUFFER_OVERFLOW)
|
||||||
|
{
|
||||||
FREE(pAddresses);
|
FREE(pAddresses);
|
||||||
pAddresses = (IP_ADAPTER_ADDRESSES*) MALLOC(outBufLen);
|
pAddresses = (IP_ADAPTER_ADDRESSES*) MALLOC(outBufLen);
|
||||||
}
|
}
|
||||||
@@ -125,7 +146,8 @@ namespace net
|
|||||||
AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen
|
AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen
|
||||||
);
|
);
|
||||||
|
|
||||||
if(dwRetVal != NO_ERROR) {
|
if(dwRetVal != NO_ERROR)
|
||||||
|
{
|
||||||
LogPrint(eLogError, "NetIface: GetMTU(): enclosed GetAdaptersAddresses() call has failed");
|
LogPrint(eLogError, "NetIface: GetMTU(): enclosed GetAdaptersAddresses() call has failed");
|
||||||
FREE(pAddresses);
|
FREE(pAddresses);
|
||||||
return fallback;
|
return fallback;
|
||||||
@@ -133,23 +155,28 @@ namespace net
|
|||||||
|
|
||||||
bool found_address = false;
|
bool found_address = false;
|
||||||
pCurrAddresses = pAddresses;
|
pCurrAddresses = pAddresses;
|
||||||
while(pCurrAddresses) {
|
while(pCurrAddresses)
|
||||||
|
{
|
||||||
PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress;
|
PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress;
|
||||||
pUnicast = pCurrAddresses->FirstUnicastAddress;
|
pUnicast = pCurrAddresses->FirstUnicastAddress;
|
||||||
if(pUnicast == nullptr) {
|
if(pUnicast == nullptr)
|
||||||
LogPrint(eLogError, "NetIface: GetMTU(): not a unicast ipv6 address, this is not supported");
|
LogPrint(eLogError, "NetIface: GetMTU(): not a unicast ipv6 address, this is not supported");
|
||||||
}
|
|
||||||
for(int i = 0; pUnicast != nullptr; ++i) {
|
for(int i = 0; pUnicast != nullptr; ++i)
|
||||||
|
{
|
||||||
LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr;
|
LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr;
|
||||||
sockaddr_in6 *localInterfaceAddress = (sockaddr_in6*) lpAddr;
|
sockaddr_in6 *localInterfaceAddress = (sockaddr_in6*) lpAddr;
|
||||||
|
|
||||||
for (int j = 0; j != 8; ++j) {
|
for (int j = 0; j != 8; ++j)
|
||||||
if (localInterfaceAddress->sin6_addr.u.Word[j] != inputAddress.sin6_addr.u.Word[j]) {
|
{
|
||||||
|
if (localInterfaceAddress->sin6_addr.u.Word[j] != inputAddress.sin6_addr.u.Word[j])
|
||||||
break;
|
break;
|
||||||
} else {
|
else
|
||||||
found_address = true;
|
found_address = true;
|
||||||
}
|
}
|
||||||
} if (found_address) {
|
|
||||||
|
if (found_address)
|
||||||
|
{
|
||||||
auto result = pAddresses->Mtu;
|
auto result = pAddresses->Mtu;
|
||||||
FREE(pAddresses);
|
FREE(pAddresses);
|
||||||
pAddresses = nullptr;
|
pAddresses = nullptr;
|
||||||
@@ -175,11 +202,19 @@ namespace net
|
|||||||
std::string localAddressUniversal = localAddress.to_string();
|
std::string localAddressUniversal = localAddress.to_string();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(localAddress.is_v4()) {
|
if (IsWindowsXPorLater())
|
||||||
|
{
|
||||||
|
#define inet_pton inet_pton_xp
|
||||||
|
}
|
||||||
|
|
||||||
|
if(localAddress.is_v4())
|
||||||
|
{
|
||||||
sockaddr_in inputAddress;
|
sockaddr_in inputAddress;
|
||||||
inet_pton(AF_INET, localAddressUniversal.c_str(), &(inputAddress.sin_addr));
|
inet_pton(AF_INET, localAddressUniversal.c_str(), &(inputAddress.sin_addr));
|
||||||
return GetMTUWindowsIpv4(inputAddress, fallback);
|
return GetMTUWindowsIpv4(inputAddress, fallback);
|
||||||
} else if(localAddress.is_v6()) {
|
}
|
||||||
|
else if(localAddress.is_v6())
|
||||||
|
{
|
||||||
sockaddr_in6 inputAddress;
|
sockaddr_in6 inputAddress;
|
||||||
inet_pton(AF_INET6, localAddressUniversal.c_str(), &(inputAddress.sin6_addr));
|
inet_pton(AF_INET6, localAddressUniversal.c_str(), &(inputAddress.sin6_addr));
|
||||||
return GetMTUWindowsIpv6(inputAddress, fallback);
|
return GetMTUWindowsIpv6(inputAddress, fallback);
|
||||||
@@ -187,7 +222,6 @@ namespace net
|
|||||||
LogPrint(eLogError, "NetIface: GetMTU(): address family is not supported");
|
LogPrint(eLogError, "NetIface: GetMTU(): address family is not supported");
|
||||||
return fallback;
|
return fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
#else // assume unix
|
#else // assume unix
|
||||||
int GetMTUUnix(const boost::asio::ip::address& localAddress, int fallback)
|
int GetMTUUnix(const boost::asio::ip::address& localAddress, int fallback)
|
||||||
@@ -261,6 +295,9 @@ namespace net
|
|||||||
{
|
{
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
LogPrint(eLogError, "NetIface: cannot get address by interface name, not implemented on WIN32");
|
LogPrint(eLogError, "NetIface: cannot get address by interface name, not implemented on WIN32");
|
||||||
|
if(ipv6)
|
||||||
|
return boost::asio::ip::address::from_string("::1");
|
||||||
|
else
|
||||||
return boost::asio::ip::address::from_string("127.0.0.1");
|
return boost::asio::ip::address::from_string("127.0.0.1");
|
||||||
#else
|
#else
|
||||||
int af = (ipv6 ? AF_INET6 : AF_INET);
|
int af = (ipv6 ? AF_INET6 : AF_INET);
|
||||||
@@ -291,8 +328,9 @@ namespace net
|
|||||||
}
|
}
|
||||||
if(addrs) freeifaddrs(addrs);
|
if(addrs) freeifaddrs(addrs);
|
||||||
std::string fallback;
|
std::string fallback;
|
||||||
if(ipv6) {
|
if(ipv6)
|
||||||
fallback = "::";
|
{
|
||||||
|
fallback = "::1";
|
||||||
LogPrint(eLogWarning, "NetIface: cannot find ipv6 address for interface ", ifname);
|
LogPrint(eLogWarning, "NetIface: cannot find ipv6 address for interface ", ifname);
|
||||||
} else {
|
} else {
|
||||||
fallback = "127.0.0.1";
|
fallback = "127.0.0.1";
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c)
|
#define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c)
|
||||||
|
|
||||||
#define I2PD_VERSION_MAJOR 2
|
#define I2PD_VERSION_MAJOR 2
|
||||||
#define I2PD_VERSION_MINOR 23
|
#define I2PD_VERSION_MINOR 25
|
||||||
#define I2PD_VERSION_MICRO 0
|
#define I2PD_VERSION_MICRO 0
|
||||||
#define I2PD_VERSION_PATCH 0
|
#define I2PD_VERSION_PATCH 0
|
||||||
#define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO)
|
#define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO)
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
#define I2P_VERSION_MAJOR 0
|
#define I2P_VERSION_MAJOR 0
|
||||||
#define I2P_VERSION_MINOR 9
|
#define I2P_VERSION_MINOR 9
|
||||||
#define I2P_VERSION_MICRO 38
|
#define I2P_VERSION_MICRO 40
|
||||||
#define I2P_VERSION_PATCH 0
|
#define I2P_VERSION_PATCH 0
|
||||||
#define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
|
#define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
#include "Base.h"
|
#include "Base.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "Identity.h"
|
#include "Identity.h"
|
||||||
@@ -30,23 +31,30 @@ namespace client
|
|||||||
std::string etagsPath, indexPath, localPath;
|
std::string etagsPath, indexPath, localPath;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AddressBookFilesystemStorage (): storage("addressbook", "b", "", "b32") {};
|
AddressBookFilesystemStorage (): storage("addressbook", "b", "", "b32")
|
||||||
|
{
|
||||||
|
i2p::config::GetOption("persist.addressbook", m_IsPersist);
|
||||||
|
}
|
||||||
std::shared_ptr<const i2p::data::IdentityEx> GetAddress (const i2p::data::IdentHash& ident) const;
|
std::shared_ptr<const i2p::data::IdentityEx> GetAddress (const i2p::data::IdentHash& ident) const;
|
||||||
void AddAddress (std::shared_ptr<const i2p::data::IdentityEx> address);
|
void AddAddress (std::shared_ptr<const i2p::data::IdentityEx> address);
|
||||||
void RemoveAddress (const i2p::data::IdentHash& ident);
|
void RemoveAddress (const i2p::data::IdentHash& ident);
|
||||||
|
|
||||||
bool Init ();
|
bool Init ();
|
||||||
int Load (std::map<std::string, i2p::data::IdentHash>& addresses);
|
int Load (std::map<std::string, std::shared_ptr<Address> > & addresses);
|
||||||
int LoadLocal (std::map<std::string, i2p::data::IdentHash>& addresses);
|
int LoadLocal (std::map<std::string, std::shared_ptr<Address> >& addresses);
|
||||||
int Save (const std::map<std::string, i2p::data::IdentHash>& addresses);
|
int Save (const std::map<std::string, std::shared_ptr<Address> >& addresses);
|
||||||
|
|
||||||
void SaveEtag (const i2p::data::IdentHash& subsciption, const std::string& etag, const std::string& lastModified);
|
void SaveEtag (const i2p::data::IdentHash& subsciption, const std::string& etag, const std::string& lastModified);
|
||||||
bool GetEtag (const i2p::data::IdentHash& subscription, std::string& etag, std::string& lastModified);
|
bool GetEtag (const i2p::data::IdentHash& subscription, std::string& etag, std::string& lastModified);
|
||||||
|
void ResetEtags ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
int LoadFromFile (const std::string& filename, std::map<std::string, i2p::data::IdentHash>& addresses); // returns -1 if can't open file, otherwise number of records
|
int LoadFromFile (const std::string& filename, std::map<std::string, std::shared_ptr<Address> >& addresses); // returns -1 if can't open file, otherwise number of records
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
bool m_IsPersist;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool AddressBookFilesystemStorage::Init()
|
bool AddressBookFilesystemStorage::Init()
|
||||||
@@ -69,6 +77,11 @@ namespace client
|
|||||||
|
|
||||||
std::shared_ptr<const i2p::data::IdentityEx> AddressBookFilesystemStorage::GetAddress (const i2p::data::IdentHash& ident) const
|
std::shared_ptr<const i2p::data::IdentityEx> AddressBookFilesystemStorage::GetAddress (const i2p::data::IdentHash& ident) const
|
||||||
{
|
{
|
||||||
|
if (!m_IsPersist)
|
||||||
|
{
|
||||||
|
LogPrint(eLogDebug, "Addressbook: Persistence is disabled");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
std::string filename = storage.Path(ident.ToBase32());
|
std::string filename = storage.Path(ident.ToBase32());
|
||||||
std::ifstream f(filename, std::ifstream::binary);
|
std::ifstream f(filename, std::ifstream::binary);
|
||||||
if (!f.is_open ()) {
|
if (!f.is_open ()) {
|
||||||
@@ -92,6 +105,7 @@ namespace client
|
|||||||
|
|
||||||
void AddressBookFilesystemStorage::AddAddress (std::shared_ptr<const i2p::data::IdentityEx> address)
|
void AddressBookFilesystemStorage::AddAddress (std::shared_ptr<const i2p::data::IdentityEx> address)
|
||||||
{
|
{
|
||||||
|
if (!m_IsPersist) return;
|
||||||
std::string path = storage.Path( address->GetIdentHash().ToBase32() );
|
std::string path = storage.Path( address->GetIdentHash().ToBase32() );
|
||||||
std::ofstream f (path, std::ofstream::binary | std::ofstream::out);
|
std::ofstream f (path, std::ofstream::binary | std::ofstream::out);
|
||||||
if (!f.is_open ()) {
|
if (!f.is_open ()) {
|
||||||
@@ -107,10 +121,11 @@ namespace client
|
|||||||
|
|
||||||
void AddressBookFilesystemStorage::RemoveAddress (const i2p::data::IdentHash& ident)
|
void AddressBookFilesystemStorage::RemoveAddress (const i2p::data::IdentHash& ident)
|
||||||
{
|
{
|
||||||
|
if (!m_IsPersist) return;
|
||||||
storage.Remove( ident.ToBase32() );
|
storage.Remove( ident.ToBase32() );
|
||||||
}
|
}
|
||||||
|
|
||||||
int AddressBookFilesystemStorage::LoadFromFile (const std::string& filename, std::map<std::string, i2p::data::IdentHash>& addresses)
|
int AddressBookFilesystemStorage::LoadFromFile (const std::string& filename, std::map<std::string, std::shared_ptr<Address> >& addresses)
|
||||||
{
|
{
|
||||||
int num = 0;
|
int num = 0;
|
||||||
std::ifstream f (filename, std::ifstream::in); // in text mode
|
std::ifstream f (filename, std::ifstream::in); // in text mode
|
||||||
@@ -129,16 +144,14 @@ namespace client
|
|||||||
std::string name = s.substr(0, pos++);
|
std::string name = s.substr(0, pos++);
|
||||||
std::string addr = s.substr(pos);
|
std::string addr = s.substr(pos);
|
||||||
|
|
||||||
i2p::data::IdentHash ident;
|
addresses[name] = std::make_shared<Address>(addr);
|
||||||
ident.FromBase32 (addr);
|
|
||||||
addresses[name] = ident;
|
|
||||||
num++;
|
num++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AddressBookFilesystemStorage::Load (std::map<std::string, i2p::data::IdentHash>& addresses)
|
int AddressBookFilesystemStorage::Load (std::map<std::string, std::shared_ptr<Address> >& addresses)
|
||||||
{
|
{
|
||||||
int num = LoadFromFile (indexPath, addresses);
|
int num = LoadFromFile (indexPath, addresses);
|
||||||
if (num < 0)
|
if (num < 0)
|
||||||
@@ -152,7 +165,7 @@ namespace client
|
|||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AddressBookFilesystemStorage::LoadLocal (std::map<std::string, i2p::data::IdentHash>& addresses)
|
int AddressBookFilesystemStorage::LoadLocal (std::map<std::string, std::shared_ptr<Address> >& addresses)
|
||||||
{
|
{
|
||||||
int num = LoadFromFile (localPath, addresses);
|
int num = LoadFromFile (localPath, addresses);
|
||||||
if (num < 0) return 0;
|
if (num < 0) return 0;
|
||||||
@@ -160,7 +173,7 @@ namespace client
|
|||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AddressBookFilesystemStorage::Save (const std::map<std::string, i2p::data::IdentHash>& addresses)
|
int AddressBookFilesystemStorage::Save (const std::map<std::string, std::shared_ptr<Address> >& addresses)
|
||||||
{
|
{
|
||||||
if (addresses.empty()) {
|
if (addresses.empty()) {
|
||||||
LogPrint(eLogWarning, "Addressbook: not saving empty addressbook");
|
LogPrint(eLogWarning, "Addressbook: not saving empty addressbook");
|
||||||
@@ -175,8 +188,14 @@ namespace client
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& it: addresses) {
|
for (const auto& it: addresses)
|
||||||
f << it.first << "," << it.second.ToBase32 () << std::endl;
|
{
|
||||||
|
f << it.first << ",";
|
||||||
|
if (it.second->IsIdentHash ())
|
||||||
|
f << it.second->identHash.ToBase32 ();
|
||||||
|
else
|
||||||
|
f << it.second->blindedPublicKey->ToB33 ();
|
||||||
|
f << std::endl;
|
||||||
num++;
|
num++;
|
||||||
}
|
}
|
||||||
LogPrint (eLogInfo, "Addressbook: ", num, " addresses saved");
|
LogPrint (eLogInfo, "Addressbook: ", num, " addresses saved");
|
||||||
@@ -205,7 +224,39 @@ namespace client
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AddressBookFilesystemStorage::ResetEtags ()
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "Addressbook: resetting eTags");
|
||||||
|
for (boost::filesystem::directory_iterator it (etagsPath); it != boost::filesystem::directory_iterator (); ++it)
|
||||||
|
{
|
||||||
|
if (!boost::filesystem::is_regular_file (it->status ()))
|
||||||
|
continue;
|
||||||
|
boost::filesystem::remove (it->path ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
|
Address::Address (const std::string& b32)
|
||||||
|
{
|
||||||
|
if (b32.length () <= B33_ADDRESS_THRESHOLD)
|
||||||
|
{
|
||||||
|
addressType = eAddressIndentHash;
|
||||||
|
identHash.FromBase32 (b32);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
addressType = eAddressBlindedPublicKey;
|
||||||
|
blindedPublicKey = std::make_shared<i2p::data::BlindedPublicKey>(b32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Address::Address (const i2p::data::IdentHash& hash)
|
||||||
|
{
|
||||||
|
addressType = eAddressIndentHash;
|
||||||
|
identHash = hash;
|
||||||
|
}
|
||||||
|
|
||||||
AddressBook::AddressBook (): m_Storage(nullptr), m_IsLoaded (false), m_IsDownloading (false),
|
AddressBook::AddressBook (): m_Storage(nullptr), m_IsLoaded (false), m_IsDownloading (false),
|
||||||
m_NumRetries (0), m_DefaultSubscription (nullptr), m_SubscriptionsUpdateTimer (nullptr)
|
m_NumRetries (0), m_DefaultSubscription (nullptr), m_SubscriptionsUpdateTimer (nullptr)
|
||||||
{
|
{
|
||||||
@@ -242,7 +293,7 @@ namespace client
|
|||||||
}
|
}
|
||||||
if (m_IsDownloading)
|
if (m_IsDownloading)
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "Addressbook: subscriptions is downloading, abort");
|
LogPrint (eLogInfo, "Addressbook: subscriptions are downloading, abort");
|
||||||
for (int i = 0; i < 30; i++)
|
for (int i = 0; i < 30; i++)
|
||||||
{
|
{
|
||||||
if (!m_IsDownloading)
|
if (!m_IsDownloading)
|
||||||
@@ -265,67 +316,70 @@ namespace client
|
|||||||
m_Subscriptions.clear ();
|
m_Subscriptions.clear ();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AddressBook::GetIdentHash (const std::string& address, i2p::data::IdentHash& ident)
|
std::shared_ptr<const Address> AddressBook::GetAddress (const std::string& address)
|
||||||
{
|
{
|
||||||
auto pos = address.find(".b32.i2p");
|
auto pos = address.find(".b32.i2p");
|
||||||
if (pos != std::string::npos)
|
if (pos != std::string::npos)
|
||||||
{
|
return std::make_shared<const Address>(address.substr (0, pos));
|
||||||
Base32ToByteStream (address.c_str(), pos, ident, 32);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pos = address.find (".i2p");
|
pos = address.find (".i2p");
|
||||||
if (pos != std::string::npos)
|
if (pos != std::string::npos)
|
||||||
{
|
{
|
||||||
auto identHash = FindAddress (address);
|
auto addr = FindAddress (address);
|
||||||
if (identHash)
|
if (!addr)
|
||||||
{
|
|
||||||
ident = *identHash;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LookupAddress (address); // TODO:
|
LookupAddress (address); // TODO:
|
||||||
return false;
|
return addr;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if not .b32 we assume full base64 address
|
// if not .b32 we assume full base64 address
|
||||||
i2p::data::IdentityEx dest;
|
i2p::data::IdentityEx dest;
|
||||||
if (!dest.FromBase64 (address))
|
if (!dest.FromBase64 (address))
|
||||||
return false;
|
return nullptr;
|
||||||
ident = dest.GetIdentHash ();
|
return std::make_shared<const Address>(dest.GetIdentHash ());
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const i2p::data::IdentHash * AddressBook::FindAddress (const std::string& address)
|
std::shared_ptr<const Address> AddressBook::FindAddress (const std::string& address)
|
||||||
{
|
{
|
||||||
auto it = m_Addresses.find (address);
|
auto it = m_Addresses.find (address);
|
||||||
if (it != m_Addresses.end ())
|
if (it != m_Addresses.end ())
|
||||||
return &it->second;
|
return it->second;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddressBook::InsertAddress (const std::string& address, const std::string& base64)
|
void AddressBook::InsertAddress (const std::string& address, const std::string& jump)
|
||||||
{
|
{
|
||||||
|
auto pos = jump.find(".b32.i2p");
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
{
|
||||||
|
m_Addresses[address] = std::make_shared<Address>(jump.substr (0, pos));
|
||||||
|
LogPrint (eLogInfo, "Addressbook: added ", address," -> ", jump);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// assume base64
|
||||||
auto ident = std::make_shared<i2p::data::IdentityEx>();
|
auto ident = std::make_shared<i2p::data::IdentityEx>();
|
||||||
ident->FromBase64 (base64);
|
if (ident->FromBase64 (jump))
|
||||||
|
{
|
||||||
m_Storage->AddAddress (ident);
|
m_Storage->AddAddress (ident);
|
||||||
m_Addresses[address] = ident->GetIdentHash ();
|
m_Addresses[address] = std::make_shared<Address>(ident->GetIdentHash ());
|
||||||
LogPrint (eLogInfo, "Addressbook: added ", address," -> ", ToAddress(ident->GetIdentHash ()));
|
LogPrint (eLogInfo, "Addressbook: added ", address," -> ", ToAddress(ident->GetIdentHash ()));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
LogPrint (eLogError, "Addressbook: malformed address ", jump);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AddressBook::InsertAddress (std::shared_ptr<const i2p::data::IdentityEx> address)
|
void AddressBook::InsertFullAddress (std::shared_ptr<const i2p::data::IdentityEx> address)
|
||||||
{
|
{
|
||||||
m_Storage->AddAddress (address);
|
m_Storage->AddAddress (address);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const i2p::data::IdentityEx> AddressBook::GetAddress (const std::string& address)
|
std::shared_ptr<const i2p::data::IdentityEx> AddressBook::GetFullAddress (const std::string& address)
|
||||||
{
|
{
|
||||||
i2p::data::IdentHash ident;
|
auto addr = GetAddress (address);
|
||||||
if (!GetIdentHash (address, ident)) return nullptr;
|
if (!addr || !addr->IsIdentHash ()) return nullptr;
|
||||||
return m_Storage->GetAddress (ident);
|
return m_Storage->GetAddress (addr->identHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddressBook::LoadHosts ()
|
void AddressBook::LoadHosts ()
|
||||||
@@ -343,6 +397,9 @@ namespace client
|
|||||||
LoadHostsFromStream (f, false);
|
LoadHostsFromStream (f, false);
|
||||||
m_IsLoaded = true;
|
m_IsLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reset eTags, because we don’t know how old hosts.txt is or can't load addressbook
|
||||||
|
m_Storage->ResetEtags ();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AddressBook::LoadHostsFromStream (std::istream& f, bool is_update)
|
bool AddressBook::LoadHostsFromStream (std::istream& f, bool is_update)
|
||||||
@@ -379,16 +436,17 @@ namespace client
|
|||||||
auto it = m_Addresses.find (name);
|
auto it = m_Addresses.find (name);
|
||||||
if (it != m_Addresses.end ()) // already exists ?
|
if (it != m_Addresses.end ()) // already exists ?
|
||||||
{
|
{
|
||||||
if (it->second != ident->GetIdentHash ()) // address changed?
|
if (it->second->IsIdentHash () && it->second->identHash != ident->GetIdentHash ()) // address changed?
|
||||||
{
|
{
|
||||||
it->second = ident->GetIdentHash ();
|
it->second->identHash = ident->GetIdentHash ();
|
||||||
m_Storage->AddAddress (ident);
|
m_Storage->AddAddress (ident);
|
||||||
LogPrint (eLogInfo, "Addressbook: updated host: ", name);
|
LogPrint (eLogInfo, "Addressbook: updated host: ", name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_Addresses.insert (std::make_pair (name, ident->GetIdentHash ()));
|
//m_Addresses.emplace (name, std::make_shared<Address>(ident->GetIdentHash ()));
|
||||||
|
m_Addresses[name] = std::make_shared<Address>(ident->GetIdentHash ()); // for gcc 4.7
|
||||||
m_Storage->AddAddress (ident);
|
m_Storage->AddAddress (ident);
|
||||||
if (is_update)
|
if (is_update)
|
||||||
LogPrint (eLogInfo, "Addressbook: added new host: ", name);
|
LogPrint (eLogInfo, "Addressbook: added new host: ", name);
|
||||||
@@ -443,32 +501,33 @@ namespace client
|
|||||||
|
|
||||||
void AddressBook::LoadLocal ()
|
void AddressBook::LoadLocal ()
|
||||||
{
|
{
|
||||||
std::map<std::string, i2p::data::IdentHash> localAddresses;
|
std::map<std::string, std::shared_ptr<Address>> localAddresses;
|
||||||
m_Storage->LoadLocal (localAddresses);
|
m_Storage->LoadLocal (localAddresses);
|
||||||
for (const auto& it: localAddresses)
|
for (const auto& it: localAddresses)
|
||||||
{
|
{
|
||||||
|
if (!it.second->IsIdentHash ()) continue; // skip blinded for now
|
||||||
auto dot = it.first.find ('.');
|
auto dot = it.first.find ('.');
|
||||||
if (dot != std::string::npos)
|
if (dot != std::string::npos)
|
||||||
{
|
{
|
||||||
auto domain = it.first.substr (dot + 1);
|
auto domain = it.first.substr (dot + 1);
|
||||||
auto it1 = m_Addresses.find (domain); // find domain in our addressbook
|
auto it1 = m_Addresses.find (domain); // find domain in our addressbook
|
||||||
if (it1 != m_Addresses.end ())
|
if (it1 != m_Addresses.end () && it1->second->IsIdentHash ())
|
||||||
{
|
{
|
||||||
auto dest = context.FindLocalDestination (it1->second);
|
auto dest = context.FindLocalDestination (it1->second->identHash);
|
||||||
if (dest)
|
if (dest)
|
||||||
{
|
{
|
||||||
// address is ours
|
// address is ours
|
||||||
std::shared_ptr<AddressResolver> resolver;
|
std::shared_ptr<AddressResolver> resolver;
|
||||||
auto it2 = m_Resolvers.find (it1->second);
|
auto it2 = m_Resolvers.find (it1->second->identHash);
|
||||||
if (it2 != m_Resolvers.end ())
|
if (it2 != m_Resolvers.end ())
|
||||||
resolver = it2->second; // resolver exists
|
resolver = it2->second; // resolver exists
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// create new resolver
|
// create new resolver
|
||||||
resolver = std::make_shared<AddressResolver>(dest);
|
resolver = std::make_shared<AddressResolver>(dest);
|
||||||
m_Resolvers.insert (std::make_pair(it1->second, resolver));
|
m_Resolvers.insert (std::make_pair(it1->second->identHash, resolver));
|
||||||
}
|
}
|
||||||
resolver->AddAddress (it.first, it.second);
|
resolver->AddAddress (it.first, it.second->identHash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -598,11 +657,11 @@ namespace client
|
|||||||
|
|
||||||
void AddressBook::LookupAddress (const std::string& address)
|
void AddressBook::LookupAddress (const std::string& address)
|
||||||
{
|
{
|
||||||
const i2p::data::IdentHash * ident = nullptr;
|
std::shared_ptr<const Address> addr;
|
||||||
auto dot = address.find ('.');
|
auto dot = address.find ('.');
|
||||||
if (dot != std::string::npos)
|
if (dot != std::string::npos)
|
||||||
ident = FindAddress (address.substr (dot + 1));
|
addr = FindAddress (address.substr (dot + 1));
|
||||||
if (!ident)
|
if (!addr || !addr->IsIdentHash ()) // TODO:
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "Addressbook: Can't find domain for ", address);
|
LogPrint (eLogError, "Addressbook: Can't find domain for ", address);
|
||||||
return;
|
return;
|
||||||
@@ -620,14 +679,14 @@ namespace client
|
|||||||
std::unique_lock<std::mutex> l(m_LookupsMutex);
|
std::unique_lock<std::mutex> l(m_LookupsMutex);
|
||||||
m_Lookups[nonce] = address;
|
m_Lookups[nonce] = address;
|
||||||
}
|
}
|
||||||
LogPrint (eLogDebug, "Addressbook: Lookup of ", address, " to ", ident->ToBase32 (), " nonce=", nonce);
|
LogPrint (eLogDebug, "Addressbook: Lookup of ", address, " to ", addr->identHash.ToBase32 (), " nonce=", nonce);
|
||||||
size_t len = address.length () + 9;
|
size_t len = address.length () + 9;
|
||||||
uint8_t * buf = new uint8_t[len];
|
uint8_t * buf = new uint8_t[len];
|
||||||
memset (buf, 0, 4);
|
memset (buf, 0, 4);
|
||||||
htobe32buf (buf + 4, nonce);
|
htobe32buf (buf + 4, nonce);
|
||||||
buf[8] = address.length ();
|
buf[8] = address.length ();
|
||||||
memcpy (buf + 9, address.c_str (), address.length ());
|
memcpy (buf + 9, address.c_str (), address.length ());
|
||||||
datagram->SendDatagramTo (buf, len, *ident, ADDRESS_RESPONSE_DATAGRAM_PORT, ADDRESS_RESOLVER_DATAGRAM_PORT);
|
datagram->SendDatagramTo (buf, len, addr->identHash, ADDRESS_RESPONSE_DATAGRAM_PORT, ADDRESS_RESOLVER_DATAGRAM_PORT);
|
||||||
delete[] buf;
|
delete[] buf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -657,7 +716,7 @@ namespace client
|
|||||||
// TODO: verify from
|
// TODO: verify from
|
||||||
i2p::data::IdentHash hash(buf + 8);
|
i2p::data::IdentHash hash(buf + 8);
|
||||||
if (!hash.IsZero ())
|
if (!hash.IsZero ())
|
||||||
m_Addresses[address] = hash;
|
m_Addresses[address] = std::make_shared<Address>(hash);
|
||||||
else
|
else
|
||||||
LogPrint (eLogInfo, "AddressBook: Lookup response: ", address, " not found");
|
LogPrint (eLogInfo, "AddressBook: Lookup response: ", address, " not found");
|
||||||
}
|
}
|
||||||
@@ -679,14 +738,19 @@ namespace client
|
|||||||
i2p::http::URL url;
|
i2p::http::URL url;
|
||||||
// must be run in separate thread
|
// must be run in separate thread
|
||||||
LogPrint (eLogInfo, "Addressbook: Downloading hosts database from ", m_Link);
|
LogPrint (eLogInfo, "Addressbook: Downloading hosts database from ", m_Link);
|
||||||
if (!url.parse(m_Link)) {
|
if (!url.parse(m_Link))
|
||||||
|
{
|
||||||
LogPrint(eLogError, "Addressbook: failed to parse url: ", m_Link);
|
LogPrint(eLogError, "Addressbook: failed to parse url: ", m_Link);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!m_Book.GetIdentHash (url.host, m_Ident)) {
|
auto addr = m_Book.GetAddress (url.host);
|
||||||
|
if (!addr || !addr->IsIdentHash ())
|
||||||
|
{
|
||||||
LogPrint (eLogError, "Addressbook: Can't resolve ", url.host);
|
LogPrint (eLogError, "Addressbook: Can't resolve ", url.host);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
m_Ident = addr->identHash;
|
||||||
/* this code block still needs some love */
|
/* this code block still needs some love */
|
||||||
std::condition_variable newDataReceived;
|
std::condition_variable newDataReceived;
|
||||||
std::mutex newDataReceivedMutex;
|
std::mutex newDataReceivedMutex;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "Identity.h"
|
#include "Identity.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Destination.h"
|
#include "Destination.h"
|
||||||
|
#include "LeaseSet.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
@@ -28,6 +29,19 @@ namespace client
|
|||||||
const uint16_t ADDRESS_RESOLVER_DATAGRAM_PORT = 53;
|
const uint16_t ADDRESS_RESOLVER_DATAGRAM_PORT = 53;
|
||||||
const uint16_t ADDRESS_RESPONSE_DATAGRAM_PORT = 54;
|
const uint16_t ADDRESS_RESPONSE_DATAGRAM_PORT = 54;
|
||||||
|
|
||||||
|
const size_t B33_ADDRESS_THRESHOLD = 52; // characters
|
||||||
|
|
||||||
|
struct Address
|
||||||
|
{
|
||||||
|
enum { eAddressIndentHash, eAddressBlindedPublicKey } addressType;
|
||||||
|
i2p::data::IdentHash identHash;
|
||||||
|
std::shared_ptr<i2p::data::BlindedPublicKey> blindedPublicKey;
|
||||||
|
|
||||||
|
Address (const std::string& b32);
|
||||||
|
Address (const i2p::data::IdentHash& hash);
|
||||||
|
bool IsIdentHash () const { return addressType == eAddressIndentHash; };
|
||||||
|
};
|
||||||
|
|
||||||
inline std::string GetB32Address(const i2p::data::IdentHash& ident) { return ident.ToBase32().append(".b32.i2p"); }
|
inline std::string GetB32Address(const i2p::data::IdentHash& ident) { return ident.ToBase32().append(".b32.i2p"); }
|
||||||
|
|
||||||
class AddressBookStorage // interface for storage
|
class AddressBookStorage // interface for storage
|
||||||
@@ -40,12 +54,13 @@ namespace client
|
|||||||
virtual void RemoveAddress (const i2p::data::IdentHash& ident) = 0;
|
virtual void RemoveAddress (const i2p::data::IdentHash& ident) = 0;
|
||||||
|
|
||||||
virtual bool Init () = 0;
|
virtual bool Init () = 0;
|
||||||
virtual int Load (std::map<std::string, i2p::data::IdentHash>& addresses) = 0;
|
virtual int Load (std::map<std::string, std::shared_ptr<Address> >& addresses) = 0;
|
||||||
virtual int LoadLocal (std::map<std::string, i2p::data::IdentHash>& addresses) = 0;
|
virtual int LoadLocal (std::map<std::string, std::shared_ptr<Address> >& addresses) = 0;
|
||||||
virtual int Save (const std::map<std::string, i2p::data::IdentHash>& addresses) = 0;
|
virtual int Save (const std::map<std::string, std::shared_ptr<Address> >& addresses) = 0;
|
||||||
|
|
||||||
virtual void SaveEtag (const i2p::data::IdentHash& subscription, const std::string& etag, const std::string& lastModified) = 0;
|
virtual void SaveEtag (const i2p::data::IdentHash& subscription, const std::string& etag, const std::string& lastModified) = 0;
|
||||||
virtual bool GetEtag (const i2p::data::IdentHash& subscription, std::string& etag, std::string& lastModified) = 0;
|
virtual bool GetEtag (const i2p::data::IdentHash& subscription, std::string& etag, std::string& lastModified) = 0;
|
||||||
|
virtual void ResetEtags () = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AddressBookSubscription;
|
class AddressBookSubscription;
|
||||||
@@ -59,12 +74,12 @@ namespace client
|
|||||||
void Start ();
|
void Start ();
|
||||||
void StartResolvers ();
|
void StartResolvers ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
bool GetIdentHash (const std::string& address, i2p::data::IdentHash& ident);
|
std::shared_ptr<const Address> GetAddress (const std::string& address);
|
||||||
std::shared_ptr<const i2p::data::IdentityEx> GetAddress (const std::string& address);
|
std::shared_ptr<const i2p::data::IdentityEx> GetFullAddress (const std::string& address);
|
||||||
const i2p::data::IdentHash * FindAddress (const std::string& address);
|
std::shared_ptr<const Address> FindAddress (const std::string& address);
|
||||||
void LookupAddress (const std::string& address);
|
void LookupAddress (const std::string& address);
|
||||||
void InsertAddress (const std::string& address, const std::string& base64); // for jump service
|
void InsertAddress (const std::string& address, const std::string& jump); // for jump links
|
||||||
void InsertAddress (std::shared_ptr<const i2p::data::IdentityEx> address);
|
void InsertFullAddress (std::shared_ptr<const i2p::data::IdentityEx> address);
|
||||||
|
|
||||||
bool LoadHostsFromStream (std::istream& f, bool is_update);
|
bool LoadHostsFromStream (std::istream& f, bool is_update);
|
||||||
void DownloadComplete (bool success, const i2p::data::IdentHash& subscription, const std::string& etag, const std::string& lastModified);
|
void DownloadComplete (bool success, const i2p::data::IdentHash& subscription, const std::string& etag, const std::string& lastModified);
|
||||||
@@ -92,7 +107,7 @@ namespace client
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
std::mutex m_AddressBookMutex;
|
std::mutex m_AddressBookMutex;
|
||||||
std::map<std::string, i2p::data::IdentHash> m_Addresses;
|
std::map<std::string, std::shared_ptr<Address> > m_Addresses;
|
||||||
std::map<i2p::data::IdentHash, std::shared_ptr<AddressResolver> > m_Resolvers; // local destination->resolver
|
std::map<i2p::data::IdentHash, std::shared_ptr<AddressResolver> > m_Resolvers; // local destination->resolver
|
||||||
std::mutex m_LookupsMutex;
|
std::mutex m_LookupsMutex;
|
||||||
std::map<uint32_t, std::string> m_Lookups; // nonce -> address
|
std::map<uint32_t, std::string> m_Lookups; // nonce -> address
|
||||||
|
|||||||
@@ -72,17 +72,24 @@ namespace client
|
|||||||
if (eol != receiver->buffer && eol[-1] == '\r') eol[-1] = 0; // workaround for Transmission, it sends '\r\n' terminated address
|
if (eol != receiver->buffer && eol[-1] == '\r') eol[-1] = 0; // workaround for Transmission, it sends '\r\n' terminated address
|
||||||
receiver->data = (uint8_t *)eol + 1;
|
receiver->data = (uint8_t *)eol + 1;
|
||||||
receiver->dataLen = receiver->bufferOffset - (eol - receiver->buffer + 1);
|
receiver->dataLen = receiver->bufferOffset - (eol - receiver->buffer + 1);
|
||||||
i2p::data::IdentHash ident;
|
auto addr = context.GetAddressBook ().GetAddress (receiver->buffer);
|
||||||
if (!context.GetAddressBook ().GetIdentHash (receiver->buffer, ident))
|
if (!addr)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "BOB: address ", receiver->buffer, " not found");
|
LogPrint (eLogError, "BOB: address ", receiver->buffer, " not found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto leaseSet = GetLocalDestination ()->FindLeaseSet (ident);
|
if (addr->IsIdentHash ())
|
||||||
|
{
|
||||||
|
auto leaseSet = GetLocalDestination ()->FindLeaseSet (addr->identHash);
|
||||||
if (leaseSet)
|
if (leaseSet)
|
||||||
CreateConnection (receiver, leaseSet);
|
CreateConnection (receiver, leaseSet);
|
||||||
else
|
else
|
||||||
GetLocalDestination ()->RequestDestination (ident,
|
GetLocalDestination ()->RequestDestination (addr->identHash,
|
||||||
|
std::bind (&BOBI2PInboundTunnel::HandleDestinationRequestComplete,
|
||||||
|
this, std::placeholders::_1, receiver));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
GetLocalDestination ()->RequestDestinationWithEncryptedLeaseSet (addr->blindedPublicKey,
|
||||||
std::bind (&BOBI2PInboundTunnel::HandleDestinationRequestComplete,
|
std::bind (&BOBI2PInboundTunnel::HandleDestinationRequestComplete,
|
||||||
this, std::placeholders::_1, receiver));
|
this, std::placeholders::_1, receiver));
|
||||||
}
|
}
|
||||||
@@ -540,29 +547,37 @@ namespace client
|
|||||||
void BOBCommandSession::LookupCommandHandler (const char * operand, size_t len)
|
void BOBCommandSession::LookupCommandHandler (const char * operand, size_t len)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "BOB: lookup ", operand);
|
LogPrint (eLogDebug, "BOB: lookup ", operand);
|
||||||
i2p::data::IdentHash ident;
|
auto addr = context.GetAddressBook ().GetAddress (operand);
|
||||||
if (!context.GetAddressBook ().GetIdentHash (operand, ident))
|
if (!addr)
|
||||||
{
|
{
|
||||||
SendReplyError ("Address Not found");
|
SendReplyError ("Address Not found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto localDestination = m_CurrentDestination ? m_CurrentDestination->GetLocalDestination () : i2p::client::context.GetSharedLocalDestination ();
|
auto localDestination = m_CurrentDestination ? m_CurrentDestination->GetLocalDestination () : i2p::client::context.GetSharedLocalDestination ();
|
||||||
auto leaseSet = localDestination->FindLeaseSet (ident);
|
if (addr->IsIdentHash ())
|
||||||
if (leaseSet)
|
|
||||||
SendReplyOK (leaseSet->GetIdentity ()->ToBase64 ().c_str ());
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
|
// we might have leaseset already
|
||||||
|
auto leaseSet = localDestination->FindLeaseSet (addr->identHash);
|
||||||
|
if (leaseSet)
|
||||||
|
{
|
||||||
|
SendReplyOK (leaseSet->GetIdentity ()->ToBase64 ().c_str ());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// trying to request
|
||||||
auto s = shared_from_this ();
|
auto s = shared_from_this ();
|
||||||
localDestination->RequestDestination (ident,
|
auto requstCallback =
|
||||||
[s](std::shared_ptr<i2p::data::LeaseSet> ls)
|
[s](std::shared_ptr<i2p::data::LeaseSet> ls)
|
||||||
{
|
{
|
||||||
if (ls)
|
if (ls)
|
||||||
s->SendReplyOK (ls->GetIdentity ()->ToBase64 ().c_str ());
|
s->SendReplyOK (ls->GetIdentity ()->ToBase64 ().c_str ());
|
||||||
else
|
else
|
||||||
s->SendReplyError ("LeaseSet Not found");
|
s->SendReplyError ("LeaseSet Not found");
|
||||||
}
|
};
|
||||||
);
|
if (addr->IsIdentHash ())
|
||||||
}
|
localDestination->RequestDestination (addr->identHash, requstCallback);
|
||||||
|
else
|
||||||
|
localDestination->RequestDestinationWithEncryptedLeaseSet (addr->blindedPublicKey, requstCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BOBCommandSession::ClearCommandHandler (const char * operand, size_t len)
|
void BOBCommandSession::ClearCommandHandler (const char * operand, size_t len)
|
||||||
|
|||||||
@@ -540,7 +540,8 @@ namespace client
|
|||||||
{
|
{
|
||||||
// http proxy
|
// http proxy
|
||||||
std::string outproxy = section.second.get("outproxy", "");
|
std::string outproxy = section.second.get("outproxy", "");
|
||||||
auto tun = std::make_shared<i2p::proxy::HTTPProxy>(name, address, port, outproxy, localDestination);
|
bool addresshelper = section.second.get("addresshelper", true);
|
||||||
|
auto tun = std::make_shared<i2p::proxy::HTTPProxy>(name, address, port, outproxy, addresshelper, localDestination);
|
||||||
clientTunnel = tun;
|
clientTunnel = tun;
|
||||||
clientEndpoint = tun->GetLocalEndpoint ();
|
clientEndpoint = tun->GetLocalEndpoint ();
|
||||||
}
|
}
|
||||||
@@ -716,6 +717,7 @@ namespace client
|
|||||||
uint16_t httpProxyPort; i2p::config::GetOption("httpproxy.port", httpProxyPort);
|
uint16_t httpProxyPort; i2p::config::GetOption("httpproxy.port", httpProxyPort);
|
||||||
i2p::data::SigningKeyType sigType; i2p::config::GetOption("httpproxy.signaturetype", sigType);
|
i2p::data::SigningKeyType sigType; i2p::config::GetOption("httpproxy.signaturetype", sigType);
|
||||||
std::string httpOutProxyURL; i2p::config::GetOption("httpproxy.outproxy", httpOutProxyURL);
|
std::string httpOutProxyURL; i2p::config::GetOption("httpproxy.outproxy", httpOutProxyURL);
|
||||||
|
bool httpAddresshelper; i2p::config::GetOption("httpproxy.addresshelper", httpAddresshelper);
|
||||||
LogPrint(eLogInfo, "Clients: starting HTTP Proxy at ", httpProxyAddr, ":", httpProxyPort);
|
LogPrint(eLogInfo, "Clients: starting HTTP Proxy at ", httpProxyAddr, ":", httpProxyPort);
|
||||||
if (httpProxyKeys.length () > 0)
|
if (httpProxyKeys.length () > 0)
|
||||||
{
|
{
|
||||||
@@ -732,7 +734,7 @@ namespace client
|
|||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_HttpProxy = new i2p::proxy::HTTPProxy("HTTP Proxy", httpProxyAddr, httpProxyPort, httpOutProxyURL, localDestination);
|
m_HttpProxy = new i2p::proxy::HTTPProxy("HTTP Proxy", httpProxyAddr, httpProxyPort, httpOutProxyURL, httpAddresshelper, localDestination);
|
||||||
m_HttpProxy->Start();
|
m_HttpProxy->Start();
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ namespace proxy {
|
|||||||
std::shared_ptr<boost::asio::ip::tcp::socket> m_proxysock;
|
std::shared_ptr<boost::asio::ip::tcp::socket> m_proxysock;
|
||||||
boost::asio::ip::tcp::resolver m_proxy_resolver;
|
boost::asio::ip::tcp::resolver m_proxy_resolver;
|
||||||
std::string m_OutproxyUrl;
|
std::string m_OutproxyUrl;
|
||||||
|
bool m_Addresshelper;
|
||||||
i2p::http::URL m_ProxyURL;
|
i2p::http::URL m_ProxyURL;
|
||||||
i2p::http::URL m_RequestURL;
|
i2p::http::URL m_RequestURL;
|
||||||
uint8_t m_socks_buf[255+8]; // for socks request/response
|
uint8_t m_socks_buf[255+8]; // for socks request/response
|
||||||
@@ -95,13 +96,15 @@ namespace proxy {
|
|||||||
i2p::http::HTTPReq m_ClientRequest;
|
i2p::http::HTTPReq m_ClientRequest;
|
||||||
i2p::http::HTTPRes m_ClientResponse;
|
i2p::http::HTTPRes m_ClientResponse;
|
||||||
std::stringstream m_ClientRequestBuffer;
|
std::stringstream m_ClientRequestBuffer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
HTTPReqHandler(HTTPProxy * parent, std::shared_ptr<boost::asio::ip::tcp::socket> sock) :
|
HTTPReqHandler(HTTPProxy * parent, std::shared_ptr<boost::asio::ip::tcp::socket> sock) :
|
||||||
I2PServiceHandler(parent), m_sock(sock),
|
I2PServiceHandler(parent), m_sock(sock),
|
||||||
m_proxysock(std::make_shared<boost::asio::ip::tcp::socket>(parent->GetService())),
|
m_proxysock(std::make_shared<boost::asio::ip::tcp::socket>(parent->GetService())),
|
||||||
m_proxy_resolver(parent->GetService()),
|
m_proxy_resolver(parent->GetService()),
|
||||||
m_OutproxyUrl(parent->GetOutproxyURL()) {}
|
m_OutproxyUrl(parent->GetOutproxyURL()),
|
||||||
|
m_Addresshelper(parent->GetHelperSupport()) {}
|
||||||
~HTTPReqHandler() { Terminate(); }
|
~HTTPReqHandler() { Terminate(); }
|
||||||
void Handle () { AsyncSockRead(); } /* overload */
|
void Handle () { AsyncSockRead(); } /* overload */
|
||||||
};
|
};
|
||||||
@@ -208,7 +211,7 @@ namespace proxy {
|
|||||||
void HTTPReqHandler::SanitizeHTTPRequest(i2p::http::HTTPReq & req)
|
void HTTPReqHandler::SanitizeHTTPRequest(i2p::http::HTTPReq & req)
|
||||||
{
|
{
|
||||||
/* drop common headers */
|
/* drop common headers */
|
||||||
req.RemoveHeader("Referer");
|
req.RemoveHeader("Referrer");
|
||||||
req.RemoveHeader("Via");
|
req.RemoveHeader("Via");
|
||||||
req.RemoveHeader("From");
|
req.RemoveHeader("From");
|
||||||
req.RemoveHeader("Forwarded");
|
req.RemoveHeader("Forwarded");
|
||||||
@@ -219,7 +222,11 @@ namespace proxy {
|
|||||||
/* replace headers */
|
/* replace headers */
|
||||||
req.UpdateHeader("User-Agent", "MYOB/6.66 (AN/ON)");
|
req.UpdateHeader("User-Agent", "MYOB/6.66 (AN/ON)");
|
||||||
/* add headers */
|
/* add headers */
|
||||||
req.UpdateHeader("Connection", "close"); /* keep-alive conns not supported yet */
|
/* close connection, if not Connection: (U|u)pgrade (for websocket) */
|
||||||
|
auto h = req.GetHeader ("Connection");
|
||||||
|
auto x = h.find("pgrade");
|
||||||
|
if (!(x != std::string::npos && std::tolower(h[x - 1]) == 'u'))
|
||||||
|
req.UpdateHeader("Connection", "close");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -230,8 +237,6 @@ namespace proxy {
|
|||||||
*/
|
*/
|
||||||
bool HTTPReqHandler::HandleRequest()
|
bool HTTPReqHandler::HandleRequest()
|
||||||
{
|
{
|
||||||
std::string b64;
|
|
||||||
|
|
||||||
m_req_len = m_ClientRequest.parse(m_recv_buf);
|
m_req_len = m_ClientRequest.parse(m_recv_buf);
|
||||||
|
|
||||||
if (m_req_len == 0)
|
if (m_req_len == 0)
|
||||||
@@ -248,10 +253,10 @@ namespace proxy {
|
|||||||
m_RequestURL.parse(m_ClientRequest.uri);
|
m_RequestURL.parse(m_ClientRequest.uri);
|
||||||
bool m_Confirm;
|
bool m_Confirm;
|
||||||
|
|
||||||
if (ExtractAddressHelper(m_RequestURL, b64, m_Confirm))
|
std::string jump;
|
||||||
|
if (ExtractAddressHelper(m_RequestURL, jump, m_Confirm))
|
||||||
{
|
{
|
||||||
bool addresshelper; i2p::config::GetOption("httpproxy.addresshelper", addresshelper);
|
if (!m_Addresshelper)
|
||||||
if (!addresshelper)
|
|
||||||
{
|
{
|
||||||
LogPrint(eLogWarning, "HTTPProxy: addresshelper request rejected");
|
LogPrint(eLogWarning, "HTTPProxy: addresshelper request rejected");
|
||||||
GenericProxyError("Invalid request", "addresshelper is not supported");
|
GenericProxyError("Invalid request", "addresshelper is not supported");
|
||||||
@@ -259,8 +264,8 @@ namespace proxy {
|
|||||||
}
|
}
|
||||||
if (!i2p::client::context.GetAddressBook ().FindAddress (m_RequestURL.host) || m_Confirm)
|
if (!i2p::client::context.GetAddressBook ().FindAddress (m_RequestURL.host) || m_Confirm)
|
||||||
{
|
{
|
||||||
i2p::client::context.GetAddressBook ().InsertAddress (m_RequestURL.host, b64);
|
i2p::client::context.GetAddressBook ().InsertAddress (m_RequestURL.host, jump);
|
||||||
LogPrint (eLogInfo, "HTTPProxy: added b64 from addresshelper for ", m_RequestURL.host);
|
LogPrint (eLogInfo, "HTTPProxy: added address from addresshelper for ", m_RequestURL.host);
|
||||||
std::string full_url = m_RequestURL.to_string();
|
std::string full_url = m_RequestURL.to_string();
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Host " << m_RequestURL.host << " added to router's addressbook from helper. "
|
ss << "Host " << m_RequestURL.host << " added to router's addressbook from helper. "
|
||||||
@@ -272,7 +277,7 @@ namespace proxy {
|
|||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Host " << m_RequestURL.host << " <font color=red>already in router's addressbook</font>. "
|
ss << "Host " << m_RequestURL.host << " <font color=red>already in router's addressbook</font>. "
|
||||||
<< "Click <a href=\"" << m_RequestURL.query << "?i2paddresshelper=" << b64 << "&update=true\">here</a> to update record.";
|
<< "Click <a href=\"" << m_RequestURL.query << "?i2paddresshelper=" << jump << "&update=true\">here</a> to update record.";
|
||||||
GenericProxyInfo("Addresshelper found", ss.str().c_str());
|
GenericProxyInfo("Addresshelper found", ss.str().c_str());
|
||||||
return true; /* request processed */
|
return true; /* request processed */
|
||||||
}
|
}
|
||||||
@@ -335,9 +340,8 @@ namespace proxy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* check dest_host really exists and inside I2P network */
|
/* check dest_host really exists and inside I2P network */
|
||||||
i2p::data::IdentHash identHash;
|
|
||||||
if (str_rmatch(dest_host, ".i2p")) {
|
if (str_rmatch(dest_host, ".i2p")) {
|
||||||
if (!i2p::client::context.GetAddressBook ().GetIdentHash (dest_host, identHash)) {
|
if (!i2p::client::context.GetAddressBook ().GetAddress (dest_host)) {
|
||||||
HostNotFound(dest_host);
|
HostNotFound(dest_host);
|
||||||
return true; /* request processed */
|
return true; /* request processed */
|
||||||
}
|
}
|
||||||
@@ -349,7 +353,7 @@ namespace proxy {
|
|||||||
else
|
else
|
||||||
GenericProxyError("Outproxy failure", "bad outproxy settings");
|
GenericProxyError("Outproxy failure", "bad outproxy settings");
|
||||||
} else {
|
} else {
|
||||||
LogPrint (eLogWarning, "HTTPProxy: outproxy failure for ", dest_host, ": no outprxy enabled");
|
LogPrint (eLogWarning, "HTTPProxy: outproxy failure for ", dest_host, ": no outproxy enabled");
|
||||||
std::string message = "Host " + dest_host + " not inside I2P network, but outproxy is not enabled";
|
std::string message = "Host " + dest_host + " not inside I2P network, but outproxy is not enabled";
|
||||||
GenericProxyError("Outproxy failure", message.c_str());
|
GenericProxyError("Outproxy failure", message.c_str());
|
||||||
}
|
}
|
||||||
@@ -392,7 +396,7 @@ namespace proxy {
|
|||||||
|
|
||||||
// update User-Agent to ESR version of Firefox, same as Tor Browser below version 8, for non-HTTPS connections
|
// update User-Agent to ESR version of Firefox, same as Tor Browser below version 8, for non-HTTPS connections
|
||||||
if(m_ClientRequest.method != "CONNECT")
|
if(m_ClientRequest.method != "CONNECT")
|
||||||
m_ClientRequest.UpdateHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; rv:52.0) Gecko/20100101 Firefox/52.0");
|
m_ClientRequest.UpdateHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; rv:60.0) Gecko/20100101 Firefox/60.0");
|
||||||
|
|
||||||
m_ClientRequest.write(m_ClientRequestBuffer);
|
m_ClientRequest.write(m_ClientRequestBuffer);
|
||||||
m_ClientRequestBuffer << m_recv_buf.substr(m_req_len);
|
m_ClientRequestBuffer << m_recv_buf.substr(m_req_len);
|
||||||
@@ -619,9 +623,9 @@ namespace proxy {
|
|||||||
Done (shared_from_this());
|
Done (shared_from_this());
|
||||||
}
|
}
|
||||||
|
|
||||||
HTTPProxy::HTTPProxy(const std::string& name, const std::string& address, int port, const std::string & outproxy, std::shared_ptr<i2p::client::ClientDestination> localDestination):
|
HTTPProxy::HTTPProxy(const std::string& name, const std::string& address, int port, const std::string & outproxy, bool addresshelper, std::shared_ptr<i2p::client::ClientDestination> localDestination):
|
||||||
TCPIPAcceptor (address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ()),
|
TCPIPAcceptor (address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ()),
|
||||||
m_Name (name), m_OutproxyUrl(outproxy)
|
m_Name (name), m_OutproxyUrl (outproxy), m_Addresshelper (addresshelper)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,13 @@ namespace proxy {
|
|||||||
class HTTPProxy: public i2p::client::TCPIPAcceptor
|
class HTTPProxy: public i2p::client::TCPIPAcceptor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HTTPProxy(const std::string& name, const std::string& address, int port, const std::string & outproxy, std::shared_ptr<i2p::client::ClientDestination> localDestination);
|
HTTPProxy(const std::string& name, const std::string& address, int port, const std::string & outproxy, bool addresshelper, std::shared_ptr<i2p::client::ClientDestination> localDestination);
|
||||||
HTTPProxy(const std::string& name, const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr) :
|
HTTPProxy(const std::string& name, const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr) :
|
||||||
HTTPProxy(name, address, port, "", localDestination) {} ;
|
HTTPProxy(name, address, port, "", true, localDestination) {} ;
|
||||||
~HTTPProxy() {};
|
~HTTPProxy() {};
|
||||||
|
|
||||||
std::string GetOutproxyURL() const { return m_OutproxyUrl; }
|
std::string GetOutproxyURL() const { return m_OutproxyUrl; }
|
||||||
|
bool GetHelperSupport() { return m_Addresshelper; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Implements TCPIPAcceptor
|
// Implements TCPIPAcceptor
|
||||||
@@ -21,6 +22,7 @@ namespace proxy {
|
|||||||
private:
|
private:
|
||||||
std::string m_Name;
|
std::string m_Name;
|
||||||
std::string m_OutproxyUrl;
|
std::string m_OutproxyUrl;
|
||||||
|
bool m_Addresshelper;
|
||||||
};
|
};
|
||||||
} // http
|
} // http
|
||||||
} // i2p
|
} // i2p
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2016, The PurpleI2P Project
|
* Copyright (c) 2013-2019, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@@ -63,7 +63,16 @@ namespace client
|
|||||||
|
|
||||||
void I2CPDestination::LeaseSetCreated (const uint8_t * buf, size_t len)
|
void I2CPDestination::LeaseSetCreated (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
auto ls = new i2p::data::LocalLeaseSet (m_Identity, buf, len);
|
auto ls = std::make_shared<i2p::data::LocalLeaseSet> (m_Identity, buf, len);
|
||||||
|
ls->SetExpirationTime (m_LeaseSetExpirationTime);
|
||||||
|
SetLeaseSet (ls);
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2CPDestination::LeaseSet2Created (uint8_t storeType, const uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
auto ls = (storeType == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) ?
|
||||||
|
std::make_shared<i2p::data::LocalEncryptedLeaseSet2> (m_Identity, buf, len):
|
||||||
|
std::make_shared<i2p::data::LocalLeaseSet2> (storeType, m_Identity, buf, len);
|
||||||
ls->SetExpirationTime (m_LeaseSetExpirationTime);
|
ls->SetExpirationTime (m_LeaseSetExpirationTime);
|
||||||
SetLeaseSet (ls);
|
SetLeaseSet (ls);
|
||||||
}
|
}
|
||||||
@@ -361,7 +370,7 @@ namespace client
|
|||||||
size_t offset = identity->FromBuffer (buf, len);
|
size_t offset = identity->FromBuffer (buf, len);
|
||||||
if (!offset)
|
if (!offset)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "I2CP: create session maformed identity");
|
LogPrint (eLogError, "I2CP: create session malformed identity");
|
||||||
SendSessionStatusMessage (3); // invalid
|
SendSessionStatusMessage (3); // invalid
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -512,6 +521,50 @@ namespace client
|
|||||||
LogPrint (eLogError, "I2CP: unexpected sessionID ", sessionID);
|
LogPrint (eLogError, "I2CP: unexpected sessionID ", sessionID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void I2CPSession::CreateLeaseSet2MessageHandler (const uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
uint16_t sessionID = bufbe16toh (buf);
|
||||||
|
if (sessionID == m_SessionID)
|
||||||
|
{
|
||||||
|
size_t offset = 2;
|
||||||
|
if (m_Destination)
|
||||||
|
{
|
||||||
|
uint8_t storeType = buf[offset]; offset++; // store type
|
||||||
|
i2p::data::LeaseSet2 ls (storeType, buf + offset, len - offset); // outer layer only for encrypted
|
||||||
|
if (!ls.IsValid ())
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "I2CP: invalid LeaseSet2 of type ", storeType);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
offset += ls.GetBufferLen ();
|
||||||
|
// private keys
|
||||||
|
int numPrivateKeys = buf[offset]; offset++;
|
||||||
|
uint16_t currentKeyType = 0;
|
||||||
|
const uint8_t * currentKey = nullptr;
|
||||||
|
for (int i = 0; i < numPrivateKeys; i++)
|
||||||
|
{
|
||||||
|
if (offset + 4 > len) return;
|
||||||
|
uint16_t keyType = bufbe16toh (buf + offset); offset += 2; // encryption type
|
||||||
|
uint16_t keyLen = bufbe16toh (buf + offset); offset += 2; // private key length
|
||||||
|
if (offset + keyLen > len) return;
|
||||||
|
if (keyType > currentKeyType)
|
||||||
|
{
|
||||||
|
currentKeyType = keyType;
|
||||||
|
currentKey = buf + offset;
|
||||||
|
}
|
||||||
|
offset += keyLen;
|
||||||
|
}
|
||||||
|
// TODO: support multiple keys
|
||||||
|
if (currentKey)
|
||||||
|
m_Destination->SetEncryptionPrivateKey (currentKey);
|
||||||
|
|
||||||
|
m_Destination->LeaseSet2Created (storeType, ls.GetBuffer (), ls.GetBufferLen ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint (eLogError, "I2CP: unexpected sessionID ", sessionID);
|
||||||
|
}
|
||||||
|
|
||||||
void I2CPSession::SendMessageMessageHandler (const uint8_t * buf, size_t len)
|
void I2CPSession::SendMessageMessageHandler (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
uint16_t sessionID = bufbe16toh (buf);
|
uint16_t sessionID = bufbe16toh (buf);
|
||||||
@@ -566,12 +619,16 @@ namespace client
|
|||||||
case 1: // address
|
case 1: // address
|
||||||
{
|
{
|
||||||
auto name = ExtractString (buf + 11, len - 11);
|
auto name = ExtractString (buf + 11, len - 11);
|
||||||
if (!i2p::client::context.GetAddressBook ().GetIdentHash (name, ident))
|
auto addr = i2p::client::context.GetAddressBook ().GetAddress (name);
|
||||||
|
if (!addr || !addr->IsIdentHash ())
|
||||||
{
|
{
|
||||||
|
// TODO: handle blinded addresses
|
||||||
LogPrint (eLogError, "I2CP: address ", name, " not found");
|
LogPrint (eLogError, "I2CP: address ", name, " not found");
|
||||||
SendHostReplyMessage (requestID, nullptr);
|
SendHostReplyMessage (requestID, nullptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
ident = addr->identHash;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -704,6 +761,7 @@ namespace client
|
|||||||
m_MessagesHandlers[I2CP_DESTROY_SESSION_MESSAGE] = &I2CPSession::DestroySessionMessageHandler;
|
m_MessagesHandlers[I2CP_DESTROY_SESSION_MESSAGE] = &I2CPSession::DestroySessionMessageHandler;
|
||||||
m_MessagesHandlers[I2CP_RECONFIGURE_SESSION_MESSAGE] = &I2CPSession::ReconfigureSessionMessageHandler;
|
m_MessagesHandlers[I2CP_RECONFIGURE_SESSION_MESSAGE] = &I2CPSession::ReconfigureSessionMessageHandler;
|
||||||
m_MessagesHandlers[I2CP_CREATE_LEASESET_MESSAGE] = &I2CPSession::CreateLeaseSetMessageHandler;
|
m_MessagesHandlers[I2CP_CREATE_LEASESET_MESSAGE] = &I2CPSession::CreateLeaseSetMessageHandler;
|
||||||
|
m_MessagesHandlers[I2CP_CREATE_LEASESET2_MESSAGE] = &I2CPSession::CreateLeaseSet2MessageHandler;
|
||||||
m_MessagesHandlers[I2CP_SEND_MESSAGE_MESSAGE] = &I2CPSession::SendMessageMessageHandler;
|
m_MessagesHandlers[I2CP_SEND_MESSAGE_MESSAGE] = &I2CPSession::SendMessageMessageHandler;
|
||||||
m_MessagesHandlers[I2CP_SEND_MESSAGE_EXPIRES_MESSAGE] = &I2CPSession::SendMessageExpiresMessageHandler;
|
m_MessagesHandlers[I2CP_SEND_MESSAGE_EXPIRES_MESSAGE] = &I2CPSession::SendMessageExpiresMessageHandler;
|
||||||
m_MessagesHandlers[I2CP_HOST_LOOKUP_MESSAGE] = &I2CPSession::HostLookupMessageHandler;
|
m_MessagesHandlers[I2CP_HOST_LOOKUP_MESSAGE] = &I2CPSession::HostLookupMessageHandler;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2016, The PurpleI2P Project
|
* Copyright (c) 2013-2019, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@@ -36,6 +36,7 @@ namespace client
|
|||||||
const uint8_t I2CP_DESTROY_SESSION_MESSAGE = 3;
|
const uint8_t I2CP_DESTROY_SESSION_MESSAGE = 3;
|
||||||
const uint8_t I2CP_REQUEST_VARIABLE_LEASESET_MESSAGE = 37;
|
const uint8_t I2CP_REQUEST_VARIABLE_LEASESET_MESSAGE = 37;
|
||||||
const uint8_t I2CP_CREATE_LEASESET_MESSAGE = 4;
|
const uint8_t I2CP_CREATE_LEASESET_MESSAGE = 4;
|
||||||
|
const uint8_t I2CP_CREATE_LEASESET2_MESSAGE = 41;
|
||||||
const uint8_t I2CP_SEND_MESSAGE_MESSAGE = 5;
|
const uint8_t I2CP_SEND_MESSAGE_MESSAGE = 5;
|
||||||
const uint8_t I2CP_SEND_MESSAGE_EXPIRES_MESSAGE = 36;
|
const uint8_t I2CP_SEND_MESSAGE_EXPIRES_MESSAGE = 36;
|
||||||
const uint8_t I2CP_MESSAGE_PAYLOAD_MESSAGE = 31;
|
const uint8_t I2CP_MESSAGE_PAYLOAD_MESSAGE = 31;
|
||||||
@@ -68,6 +69,7 @@ namespace client
|
|||||||
|
|
||||||
void SetEncryptionPrivateKey (const uint8_t * key);
|
void SetEncryptionPrivateKey (const uint8_t * key);
|
||||||
void LeaseSetCreated (const uint8_t * buf, size_t len); // called from I2CPSession
|
void LeaseSetCreated (const uint8_t * buf, size_t len); // called from I2CPSession
|
||||||
|
void LeaseSet2Created (uint8_t storeType, const uint8_t * buf, size_t len); // called from I2CPSession
|
||||||
void SendMsgTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint32_t nonce); // called from I2CPSession
|
void SendMsgTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint32_t nonce); // called from I2CPSession
|
||||||
|
|
||||||
// implements LocalDestination
|
// implements LocalDestination
|
||||||
@@ -126,6 +128,7 @@ namespace client
|
|||||||
void DestroySessionMessageHandler (const uint8_t * buf, size_t len);
|
void DestroySessionMessageHandler (const uint8_t * buf, size_t len);
|
||||||
void ReconfigureSessionMessageHandler (const uint8_t * buf, size_t len);
|
void ReconfigureSessionMessageHandler (const uint8_t * buf, size_t len);
|
||||||
void CreateLeaseSetMessageHandler (const uint8_t * buf, size_t len);
|
void CreateLeaseSetMessageHandler (const uint8_t * buf, size_t len);
|
||||||
|
void CreateLeaseSet2MessageHandler (const uint8_t * buf, size_t len);
|
||||||
void SendMessageMessageHandler (const uint8_t * buf, size_t len);
|
void SendMessageMessageHandler (const uint8_t * buf, size_t len);
|
||||||
void SendMessageExpiresMessageHandler (const uint8_t * buf, size_t len);
|
void SendMessageExpiresMessageHandler (const uint8_t * buf, size_t len);
|
||||||
void HostLookupMessageHandler (const uint8_t * buf, size_t len);
|
void HostLookupMessageHandler (const uint8_t * buf, size_t len);
|
||||||
|
|||||||
@@ -101,9 +101,9 @@ namespace client
|
|||||||
|
|
||||||
void I2PService::CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, int port) {
|
void I2PService::CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, int port) {
|
||||||
assert(streamRequestComplete);
|
assert(streamRequestComplete);
|
||||||
i2p::data::IdentHash identHash;
|
auto address = i2p::client::context.GetAddressBook ().GetAddress (dest);
|
||||||
if (i2p::client::context.GetAddressBook ().GetIdentHash (dest, identHash))
|
if (address)
|
||||||
CreateStream(streamRequestComplete, identHash, port);
|
CreateStream(streamRequestComplete, address, port);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "I2PService: Remote destination not found: ", dest);
|
LogPrint (eLogWarning, "I2PService: Remote destination not found: ", dest);
|
||||||
@@ -111,27 +111,31 @@ namespace client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PService::CreateStream(StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash & identHash, int port)
|
void I2PService::CreateStream(StreamRequestComplete streamRequestComplete, std::shared_ptr<const Address> address, int port)
|
||||||
{
|
{
|
||||||
if(m_ConnectTimeout)
|
if(m_ConnectTimeout && !m_LocalDestination->IsReady())
|
||||||
{
|
{
|
||||||
if(m_LocalDestination->IsReady())
|
AddReadyCallback([this, streamRequestComplete, address, port] (const boost::system::error_code & ec) {
|
||||||
m_LocalDestination->CreateStream (streamRequestComplete, identHash, port);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AddReadyCallback([this, streamRequestComplete, identHash, port] (const boost::system::error_code & ec) {
|
|
||||||
if(ec)
|
if(ec)
|
||||||
{
|
{
|
||||||
LogPrint(eLogWarning, "I2PService::CeateStream() ", ec.message());
|
LogPrint(eLogWarning, "I2PService::CeateStream() ", ec.message());
|
||||||
streamRequestComplete(nullptr);
|
streamRequestComplete(nullptr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
this->m_LocalDestination->CreateStream(streamRequestComplete, identHash, port);
|
{ if (address->IsIdentHash ())
|
||||||
|
this->m_LocalDestination->CreateStream(streamRequestComplete, address->identHash, port);
|
||||||
|
else
|
||||||
|
this->m_LocalDestination->CreateStream (streamRequestComplete, address->blindedPublicKey, port);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
else
|
||||||
m_LocalDestination->CreateStream(streamRequestComplete, identHash, port);
|
{
|
||||||
|
if (address->IsIdentHash ())
|
||||||
|
m_LocalDestination->CreateStream (streamRequestComplete, address->identHash, port);
|
||||||
|
else
|
||||||
|
m_LocalDestination->CreateStream (streamRequestComplete, address->blindedPublicKey, port);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TCPIPPipe::TCPIPPipe(I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> upstream, std::shared_ptr<boost::asio::ip::tcp::socket> downstream) : I2PServiceHandler(owner), m_up(upstream), m_down(downstream)
|
TCPIPPipe::TCPIPPipe(I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> upstream, std::shared_ptr<boost::asio::ip::tcp::socket> downstream) : I2PServiceHandler(owner), m_up(upstream), m_down(downstream)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include "Destination.h"
|
#include "Destination.h"
|
||||||
#include "Identity.h"
|
#include "Identity.h"
|
||||||
|
#include "AddressBook.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
@@ -49,7 +50,7 @@ namespace client
|
|||||||
m_LocalDestination = dest;
|
m_LocalDestination = dest;
|
||||||
}
|
}
|
||||||
void CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, int port = 0);
|
void CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, int port = 0);
|
||||||
void CreateStream(StreamRequestComplete complete, const i2p::data::IdentHash & ident, int port);
|
void CreateStream(StreamRequestComplete complete, std::shared_ptr<const Address> address, int port);
|
||||||
inline boost::asio::io_service& GetService () { return m_LocalDestination->GetService (); }
|
inline boost::asio::io_service& GetService () { return m_LocalDestination->GetService (); }
|
||||||
|
|
||||||
virtual void Start () = 0;
|
virtual void Start () = 0;
|
||||||
|
|||||||
@@ -256,7 +256,13 @@ namespace client
|
|||||||
{
|
{
|
||||||
if (!m_ConnectionSent && !line.compare(0, 10, "Connection"))
|
if (!m_ConnectionSent && !line.compare(0, 10, "Connection"))
|
||||||
{
|
{
|
||||||
|
/* close connection, if not Connection: (U|u)pgrade (for websocket) */
|
||||||
|
auto x = line.find("pgrade");
|
||||||
|
if (x != std::string::npos && std::tolower(line[x - 1]) == 'u')
|
||||||
|
m_OutHeader << line << "\r\n";
|
||||||
|
else
|
||||||
m_OutHeader << "Connection: close\r\n";
|
m_OutHeader << "Connection: close\r\n";
|
||||||
|
|
||||||
m_ConnectionSent = true;
|
m_ConnectionSent = true;
|
||||||
}
|
}
|
||||||
else if (!m_ProxyConnectionSent && !line.compare(0, 16, "Proxy-Connection"))
|
else if (!m_ProxyConnectionSent && !line.compare(0, 16, "Proxy-Connection"))
|
||||||
@@ -387,15 +393,15 @@ namespace client
|
|||||||
class I2PClientTunnelHandler: public I2PServiceHandler, public std::enable_shared_from_this<I2PClientTunnelHandler>
|
class I2PClientTunnelHandler: public I2PServiceHandler, public std::enable_shared_from_this<I2PClientTunnelHandler>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
I2PClientTunnelHandler (I2PClientTunnel * parent, i2p::data::IdentHash destination,
|
I2PClientTunnelHandler (I2PClientTunnel * parent, std::shared_ptr<const Address> address,
|
||||||
int destinationPort, std::shared_ptr<boost::asio::ip::tcp::socket> socket):
|
int destinationPort, std::shared_ptr<boost::asio::ip::tcp::socket> socket):
|
||||||
I2PServiceHandler(parent), m_DestinationIdentHash(destination),
|
I2PServiceHandler(parent), m_Address(address),
|
||||||
m_DestinationPort (destinationPort), m_Socket(socket) {};
|
m_DestinationPort (destinationPort), m_Socket(socket) {};
|
||||||
void Handle();
|
void Handle();
|
||||||
void Terminate();
|
void Terminate();
|
||||||
private:
|
private:
|
||||||
void HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream);
|
void HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream);
|
||||||
i2p::data::IdentHash m_DestinationIdentHash;
|
std::shared_ptr<const Address> m_Address;
|
||||||
int m_DestinationPort;
|
int m_DestinationPort;
|
||||||
std::shared_ptr<boost::asio::ip::tcp::socket> m_Socket;
|
std::shared_ptr<boost::asio::ip::tcp::socket> m_Socket;
|
||||||
};
|
};
|
||||||
@@ -404,7 +410,7 @@ namespace client
|
|||||||
{
|
{
|
||||||
GetOwner()->CreateStream (
|
GetOwner()->CreateStream (
|
||||||
std::bind (&I2PClientTunnelHandler::HandleStreamRequestComplete, shared_from_this(), std::placeholders::_1),
|
std::bind (&I2PClientTunnelHandler::HandleStreamRequestComplete, shared_from_this(), std::placeholders::_1),
|
||||||
m_DestinationIdentHash, m_DestinationPort);
|
m_Address, m_DestinationPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PClientTunnelHandler::HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream)
|
void I2PClientTunnelHandler::HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream)
|
||||||
@@ -439,43 +445,39 @@ namespace client
|
|||||||
I2PClientTunnel::I2PClientTunnel (const std::string& name, const std::string& destination,
|
I2PClientTunnel::I2PClientTunnel (const std::string& name, const std::string& destination,
|
||||||
const std::string& address, int port, std::shared_ptr<ClientDestination> localDestination, int destinationPort):
|
const std::string& address, int port, std::shared_ptr<ClientDestination> localDestination, int destinationPort):
|
||||||
TCPIPAcceptor (address, port, localDestination), m_Name (name), m_Destination (destination),
|
TCPIPAcceptor (address, port, localDestination), m_Name (name), m_Destination (destination),
|
||||||
m_DestinationIdentHash (nullptr), m_DestinationPort (destinationPort)
|
m_DestinationPort (destinationPort)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PClientTunnel::Start ()
|
void I2PClientTunnel::Start ()
|
||||||
{
|
{
|
||||||
TCPIPAcceptor::Start ();
|
TCPIPAcceptor::Start ();
|
||||||
GetIdentHash();
|
GetAddress ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PClientTunnel::Stop ()
|
void I2PClientTunnel::Stop ()
|
||||||
{
|
{
|
||||||
TCPIPAcceptor::Stop();
|
TCPIPAcceptor::Stop();
|
||||||
auto *originalIdentHash = m_DestinationIdentHash;
|
m_Address = nullptr;
|
||||||
m_DestinationIdentHash = nullptr;
|
|
||||||
delete originalIdentHash;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* HACK: maybe we should create a caching IdentHash provider in AddressBook */
|
/* HACK: maybe we should create a caching IdentHash provider in AddressBook */
|
||||||
const i2p::data::IdentHash * I2PClientTunnel::GetIdentHash ()
|
std::shared_ptr<const Address> I2PClientTunnel::GetAddress ()
|
||||||
{
|
{
|
||||||
if (!m_DestinationIdentHash)
|
if (!m_Address)
|
||||||
{
|
{
|
||||||
i2p::data::IdentHash identHash;
|
m_Address = i2p::client::context.GetAddressBook ().GetAddress (m_Destination);
|
||||||
if (i2p::client::context.GetAddressBook ().GetIdentHash (m_Destination, identHash))
|
if (!m_Address)
|
||||||
m_DestinationIdentHash = new i2p::data::IdentHash (identHash);
|
|
||||||
else
|
|
||||||
LogPrint (eLogWarning, "I2PTunnel: Remote destination ", m_Destination, " not found");
|
LogPrint (eLogWarning, "I2PTunnel: Remote destination ", m_Destination, " not found");
|
||||||
}
|
}
|
||||||
return m_DestinationIdentHash;
|
return m_Address;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<I2PServiceHandler> I2PClientTunnel::CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket)
|
std::shared_ptr<I2PServiceHandler> I2PClientTunnel::CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket)
|
||||||
{
|
{
|
||||||
const i2p::data::IdentHash *identHash = GetIdentHash();
|
auto address = GetAddress ();
|
||||||
if (identHash)
|
if (address)
|
||||||
return std::make_shared<I2PClientTunnelHandler>(this, *identHash, m_DestinationPort, socket);
|
return std::make_shared<I2PClientTunnelHandler>(this, address, m_DestinationPort, socket);
|
||||||
else
|
else
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -808,9 +810,9 @@ namespace client
|
|||||||
|
|
||||||
void I2PUDPClientTunnel::TryResolving() {
|
void I2PUDPClientTunnel::TryResolving() {
|
||||||
LogPrint(eLogInfo, "UDP Tunnel: Trying to resolve ", m_RemoteDest);
|
LogPrint(eLogInfo, "UDP Tunnel: Trying to resolve ", m_RemoteDest);
|
||||||
i2p::data::IdentHash * h = new i2p::data::IdentHash;
|
|
||||||
|
|
||||||
while(!context.GetAddressBook().GetIdentHash(m_RemoteDest, *h) && !m_cancel_resolve)
|
std::shared_ptr<const Address> addr;
|
||||||
|
while(!(addr = context.GetAddressBook().GetAddress(m_RemoteDest)) && !m_cancel_resolve)
|
||||||
{
|
{
|
||||||
LogPrint(eLogWarning, "UDP Tunnel: failed to lookup ", m_RemoteDest);
|
LogPrint(eLogWarning, "UDP Tunnel: failed to lookup ", m_RemoteDest);
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
@@ -820,7 +822,13 @@ namespace client
|
|||||||
LogPrint(eLogError, "UDP Tunnel: lookup of ", m_RemoteDest, " was cancelled");
|
LogPrint(eLogError, "UDP Tunnel: lookup of ", m_RemoteDest, " was cancelled");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_RemoteIdent = h;
|
if (!addr || !addr->IsIdentHash ())
|
||||||
|
{
|
||||||
|
LogPrint(eLogError, "UDP Tunnel: ", m_RemoteDest, " not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_RemoteIdent = new i2p::data::IdentHash;
|
||||||
|
*m_RemoteIdent = addr->identHash;
|
||||||
LogPrint(eLogInfo, "UDP Tunnel: resolved ", m_RemoteDest, " to ", m_RemoteIdent->ToBase32());
|
LogPrint(eLogInfo, "UDP Tunnel: resolved ", m_RemoteDest, " to ", m_RemoteIdent->ToBase32());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "Datagram.h"
|
#include "Datagram.h"
|
||||||
#include "Streaming.h"
|
#include "Streaming.h"
|
||||||
#include "I2PService.h"
|
#include "I2PService.h"
|
||||||
|
#include "AddressBook.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
@@ -129,11 +130,11 @@ namespace client
|
|||||||
const char* GetName() { return m_Name.c_str (); }
|
const char* GetName() { return m_Name.c_str (); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const i2p::data::IdentHash * GetIdentHash ();
|
std::shared_ptr<const Address> GetAddress ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_Name, m_Destination;
|
std::string m_Name, m_Destination;
|
||||||
const i2p::data::IdentHash * m_DestinationIdentHash;
|
std::shared_ptr<const Address> m_Address;
|
||||||
int m_DestinationPort;
|
int m_DestinationPort;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -14,13 +14,13 @@ namespace client
|
|||||||
|
|
||||||
void MatchedTunnelDestination::ResolveCurrentLeaseSet()
|
void MatchedTunnelDestination::ResolveCurrentLeaseSet()
|
||||||
{
|
{
|
||||||
if(i2p::client::context.GetAddressBook().GetIdentHash(m_RemoteName, m_RemoteIdent))
|
auto addr = i2p::client::context.GetAddressBook().GetAddress (m_RemoteName);
|
||||||
|
if(addr && addr->IsIdentHash ())
|
||||||
{
|
{
|
||||||
|
m_RemoteIdent = addr->identHash;
|
||||||
auto ls = FindLeaseSet(m_RemoteIdent);
|
auto ls = FindLeaseSet(m_RemoteIdent);
|
||||||
if(ls)
|
if(ls)
|
||||||
{
|
|
||||||
HandleFoundCurrentLeaseSet(ls);
|
HandleFoundCurrentLeaseSet(ls);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
RequestDestination(m_RemoteIdent, std::bind(&MatchedTunnelDestination::HandleFoundCurrentLeaseSet, this, std::placeholders::_1));
|
RequestDestination(m_RemoteIdent, std::bind(&MatchedTunnelDestination::HandleFoundCurrentLeaseSet, this, std::placeholders::_1));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -360,6 +360,24 @@ namespace client
|
|||||||
forward = std::make_shared<boost::asio::ip::udp::endpoint>(addr, port);
|
forward = std::make_shared<boost::asio::ip::udp::endpoint>(addr, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//ensure we actually received a destination
|
||||||
|
if (destination.empty())
|
||||||
|
{
|
||||||
|
SendMessageReply (SAM_SESSION_STATUS_INVALID_KEY, strlen(SAM_SESSION_STATUS_INVALID_KEY), true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (destination != SAM_VALUE_TRANSIENT)
|
||||||
|
{
|
||||||
|
//ensure it's a base64 string
|
||||||
|
i2p::data::PrivateKeys keys;
|
||||||
|
if (!keys.FromBase64(destination))
|
||||||
|
{
|
||||||
|
SendMessageReply(SAM_SESSION_STATUS_INVALID_KEY, strlen(SAM_SESSION_STATUS_INVALID_KEY), true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// create destination
|
// create destination
|
||||||
auto session = m_Owner.CreateSession (id, destination == SAM_VALUE_TRANSIENT ? "" : destination, ¶ms);
|
auto session = m_Owner.CreateSession (id, destination == SAM_VALUE_TRANSIENT ? "" : destination, ¶ms);
|
||||||
if (session)
|
if (session)
|
||||||
@@ -449,7 +467,7 @@ namespace client
|
|||||||
size_t l = dest->FromBase64(destination);
|
size_t l = dest->FromBase64(destination);
|
||||||
if (l > 0)
|
if (l > 0)
|
||||||
{
|
{
|
||||||
context.GetAddressBook().InsertAddress(dest);
|
context.GetAddressBook().InsertFullAddress(dest);
|
||||||
auto leaseSet = session->localDestination->FindLeaseSet(dest->GetIdentHash());
|
auto leaseSet = session->localDestination->FindLeaseSet(dest->GetIdentHash());
|
||||||
if (leaseSet)
|
if (leaseSet)
|
||||||
Connect(leaseSet);
|
Connect(leaseSet);
|
||||||
@@ -461,7 +479,7 @@ namespace client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
SendMessageReply(SAM_SESSION_STATUS_INVALID_KEY, strlen(SAM_SESSION_STATUS_INVALID_KEY), true);
|
SendMessageReply (SAM_STREAM_STATUS_INVALID_KEY, strlen(SAM_STREAM_STATUS_INVALID_KEY), true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true);
|
SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true);
|
||||||
@@ -558,11 +576,22 @@ namespace client
|
|||||||
i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL;
|
i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL;
|
||||||
auto it = params.find (SAM_PARAM_SIGNATURE_TYPE);
|
auto it = params.find (SAM_PARAM_SIGNATURE_TYPE);
|
||||||
if (it != params.end ())
|
if (it != params.end ())
|
||||||
// TODO: extract string values
|
{
|
||||||
signatureType = std::stoi(it->second);
|
if (!m_Owner.ResolveSignatureType (it->second, signatureType))
|
||||||
|
LogPrint (eLogWarning, "SAM: ", SAM_PARAM_SIGNATURE_TYPE, " is invalid ", it->second);
|
||||||
|
}
|
||||||
it = params.find (SAM_PARAM_CRYPTO_TYPE);
|
it = params.find (SAM_PARAM_CRYPTO_TYPE);
|
||||||
if (it != params.end ())
|
if (it != params.end ())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
cryptoType = std::stoi(it->second);
|
cryptoType = std::stoi(it->second);
|
||||||
|
}
|
||||||
|
catch (const std::exception& ex)
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "SAM: ", SAM_PARAM_CRYPTO_TYPE, "error: ", ex.what ());
|
||||||
|
}
|
||||||
|
}
|
||||||
auto keys = i2p::data::PrivateKeys::CreateRandomKeys (signatureType, cryptoType);
|
auto keys = i2p::data::PrivateKeys::CreateRandomKeys (signatureType, cryptoType);
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
size_t l = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY,
|
size_t l = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY,
|
||||||
@@ -581,22 +610,29 @@ namespace client
|
|||||||
ExtractParams (buf, params);
|
ExtractParams (buf, params);
|
||||||
std::string& name = params[SAM_PARAM_NAME];
|
std::string& name = params[SAM_PARAM_NAME];
|
||||||
std::shared_ptr<const i2p::data::IdentityEx> identity;
|
std::shared_ptr<const i2p::data::IdentityEx> identity;
|
||||||
i2p::data::IdentHash ident;
|
std::shared_ptr<const Address> addr;
|
||||||
auto session = m_Owner.FindSession(m_ID);
|
auto session = m_Owner.FindSession(m_ID);
|
||||||
auto dest = session == nullptr ? context.GetSharedLocalDestination() : session->localDestination;
|
auto dest = session == nullptr ? context.GetSharedLocalDestination() : session->localDestination;
|
||||||
if (name == "ME")
|
if (name == "ME")
|
||||||
SendNamingLookupReply (dest->GetIdentity ());
|
SendNamingLookupReply (dest->GetIdentity ());
|
||||||
else if ((identity = context.GetAddressBook ().GetAddress (name)) != nullptr)
|
else if ((identity = context.GetAddressBook ().GetFullAddress (name)) != nullptr)
|
||||||
SendNamingLookupReply (identity);
|
SendNamingLookupReply (identity);
|
||||||
else if (context.GetAddressBook ().GetIdentHash (name, ident))
|
else if ((addr = context.GetAddressBook ().GetAddress (name)))
|
||||||
{
|
{
|
||||||
auto leaseSet = dest->FindLeaseSet (ident);
|
if (addr->IsIdentHash ())
|
||||||
|
{
|
||||||
|
auto leaseSet = dest->FindLeaseSet (addr->identHash);
|
||||||
if (leaseSet)
|
if (leaseSet)
|
||||||
SendNamingLookupReply (leaseSet->GetIdentity ());
|
SendNamingLookupReply (leaseSet->GetIdentity ());
|
||||||
else
|
else
|
||||||
dest->RequestDestination (ident,
|
dest->RequestDestination (addr->identHash,
|
||||||
std::bind (&SAMSocket::HandleNamingLookupLeaseSetRequestComplete,
|
std::bind (&SAMSocket::HandleNamingLookupLeaseSetRequestComplete,
|
||||||
shared_from_this (), std::placeholders::_1, ident));
|
shared_from_this (), std::placeholders::_1, name));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
dest->RequestDestinationWithEncryptedLeaseSet (addr->blindedPublicKey,
|
||||||
|
std::bind (&SAMSocket::HandleNamingLookupLeaseSetRequestComplete,
|
||||||
|
shared_from_this (), std::placeholders::_1, name));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -621,22 +657,20 @@ namespace client
|
|||||||
SendMessageReply (m_Buffer, len, true);
|
SendMessageReply (m_Buffer, len, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SAMSocket::HandleNamingLookupLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, i2p::data::IdentHash ident)
|
void SAMSocket::HandleNamingLookupLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, std::string name)
|
||||||
{
|
{
|
||||||
if (leaseSet)
|
if (leaseSet)
|
||||||
{
|
{
|
||||||
context.GetAddressBook ().InsertAddress (leaseSet->GetIdentity ());
|
context.GetAddressBook ().InsertFullAddress (leaseSet->GetIdentity ());
|
||||||
SendNamingLookupReply (leaseSet->GetIdentity ());
|
SendNamingLookupReply (leaseSet->GetIdentity ());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "SAM: naming lookup failed. LeaseSet for ", ident.ToBase32 (), " not found");
|
LogPrint (eLogError, "SAM: naming lookup failed. LeaseSet for ", name, " not found");
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY_INVALID_KEY,
|
size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY_INVALID_KEY, name.c_str());
|
||||||
context.GetAddressBook ().ToAddress (ident).c_str());
|
|
||||||
#else
|
#else
|
||||||
size_t len = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY_INVALID_KEY,
|
size_t len = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY_INVALID_KEY, name.c_str());
|
||||||
context.GetAddressBook ().ToAddress (ident).c_str());
|
|
||||||
#endif
|
#endif
|
||||||
SendMessageReply (m_Buffer, len, false);
|
SendMessageReply (m_Buffer, len, false);
|
||||||
}
|
}
|
||||||
@@ -815,7 +849,7 @@ namespace client
|
|||||||
m_SocketType = eSAMSocketTypeStream;
|
m_SocketType = eSAMSocketTypeStream;
|
||||||
m_IsAccepting = false;
|
m_IsAccepting = false;
|
||||||
m_Stream = stream;
|
m_Stream = stream;
|
||||||
context.GetAddressBook ().InsertAddress (stream->GetRemoteIdentity ());
|
context.GetAddressBook ().InsertFullAddress (stream->GetRemoteIdentity ());
|
||||||
auto session = m_Owner.FindSession (m_ID);
|
auto session = m_Owner.FindSession (m_ID);
|
||||||
if (session)
|
if (session)
|
||||||
{
|
{
|
||||||
@@ -921,7 +955,17 @@ namespace client
|
|||||||
SAMBridge::SAMBridge (const std::string& address, int port):
|
SAMBridge::SAMBridge (const std::string& address, int port):
|
||||||
m_IsRunning (false), m_Thread (nullptr),
|
m_IsRunning (false), m_Thread (nullptr),
|
||||||
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port)),
|
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port)),
|
||||||
m_DatagramEndpoint (boost::asio::ip::address::from_string(address), port-1), m_DatagramSocket (m_Service, m_DatagramEndpoint)
|
m_DatagramEndpoint (boost::asio::ip::address::from_string(address), port-1), m_DatagramSocket (m_Service, m_DatagramEndpoint),
|
||||||
|
m_SignatureTypes
|
||||||
|
{
|
||||||
|
{"DSA_SHA1", i2p::data::SIGNING_KEY_TYPE_DSA_SHA1},
|
||||||
|
{"ECDSA_SHA256_P256", i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256},
|
||||||
|
{"ECDSA_SHA256_P384", i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA384_P384},
|
||||||
|
{"ECDSA_SHA256_P521", i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA512_P521},
|
||||||
|
{"EdDSA_SHA512_Ed25519", i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519},
|
||||||
|
{"GOST_GOSTR3411256_GOSTR3410CRYPTOPROA", i2p::data::SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256},
|
||||||
|
{"GOST_GOSTR3411512_GOSTR3410TC26A512", i2p::data::SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512}
|
||||||
|
}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -942,7 +986,16 @@ namespace client
|
|||||||
void SAMBridge::Stop ()
|
void SAMBridge::Stop ()
|
||||||
{
|
{
|
||||||
m_IsRunning = false;
|
m_IsRunning = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
m_Acceptor.cancel ();
|
m_Acceptor.cancel ();
|
||||||
|
}
|
||||||
|
catch (const std::exception& ex)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "SAM: runtime exception: ", ex.what ());
|
||||||
|
}
|
||||||
|
|
||||||
for (auto& it: m_Sessions)
|
for (auto& it: m_Sessions)
|
||||||
it.second->CloseStreams ();
|
it.second->CloseStreams ();
|
||||||
m_Sessions.clear ();
|
m_Sessions.clear ();
|
||||||
@@ -1028,15 +1081,8 @@ namespace client
|
|||||||
auto it = params->find (SAM_PARAM_SIGNATURE_TYPE);
|
auto it = params->find (SAM_PARAM_SIGNATURE_TYPE);
|
||||||
if (it != params->end ())
|
if (it != params->end ())
|
||||||
{
|
{
|
||||||
// TODO: extract string values
|
if (!ResolveSignatureType (it->second, signatureType))
|
||||||
try
|
LogPrint (eLogWarning, "SAM: ", SAM_PARAM_SIGNATURE_TYPE, " is invalid ", it->second);
|
||||||
{
|
|
||||||
signatureType = std::stoi(it->second);
|
|
||||||
}
|
|
||||||
catch (const std::exception& ex)
|
|
||||||
{
|
|
||||||
LogPrint (eLogWarning, "SAM: ", SAM_PARAM_SIGNATURE_TYPE, "error: ", ex.what ());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
it = params->find (SAM_PARAM_CRYPTO_TYPE);
|
it = params->find (SAM_PARAM_CRYPTO_TYPE);
|
||||||
if (it != params->end ())
|
if (it != params->end ())
|
||||||
@@ -1166,5 +1212,28 @@ namespace client
|
|||||||
else
|
else
|
||||||
LogPrint (eLogError, "SAM: datagram receive error: ", ecode.message ());
|
LogPrint (eLogError, "SAM: datagram receive error: ", ecode.message ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SAMBridge::ResolveSignatureType (const std::string& name, i2p::data::SigningKeyType& type) const
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
type = std::stoi (name);
|
||||||
|
}
|
||||||
|
catch (const std::invalid_argument& ex)
|
||||||
|
{
|
||||||
|
// name is not numeric, resolving
|
||||||
|
auto it = m_SignatureTypes.find (name);
|
||||||
|
if (it != m_SignatureTypes.end ())
|
||||||
|
type = it->second;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (const std::exception& ex)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// name has been resolved
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ namespace client
|
|||||||
const char SAM_STREAM_CONNECT[] = "STREAM CONNECT";
|
const char SAM_STREAM_CONNECT[] = "STREAM CONNECT";
|
||||||
const char SAM_STREAM_STATUS_OK[] = "STREAM STATUS RESULT=OK\n";
|
const char SAM_STREAM_STATUS_OK[] = "STREAM STATUS RESULT=OK\n";
|
||||||
const char SAM_STREAM_STATUS_INVALID_ID[] = "STREAM STATUS RESULT=INVALID_ID\n";
|
const char SAM_STREAM_STATUS_INVALID_ID[] = "STREAM STATUS RESULT=INVALID_ID\n";
|
||||||
|
const char SAM_STREAM_STATUS_INVALID_KEY[] = "STREAM STATUS RESULT=INVALID_KEY\n";
|
||||||
const char SAM_STREAM_STATUS_CANT_REACH_PEER[] = "STREAM STATUS RESULT=CANT_REACH_PEER\n";
|
const char SAM_STREAM_STATUS_CANT_REACH_PEER[] = "STREAM STATUS RESULT=CANT_REACH_PEER\n";
|
||||||
const char SAM_STREAM_STATUS_I2P_ERROR[] = "STREAM STATUS RESULT=I2P_ERROR\n";
|
const char SAM_STREAM_STATUS_I2P_ERROR[] = "STREAM STATUS RESULT=I2P_ERROR\n";
|
||||||
const char SAM_STREAM_ACCEPT[] = "STREAM ACCEPT";
|
const char SAM_STREAM_ACCEPT[] = "STREAM ACCEPT";
|
||||||
@@ -123,7 +124,7 @@ namespace client
|
|||||||
void Connect (std::shared_ptr<const i2p::data::LeaseSet> remote);
|
void Connect (std::shared_ptr<const i2p::data::LeaseSet> remote);
|
||||||
void HandleConnectLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet);
|
void HandleConnectLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet);
|
||||||
void SendNamingLookupReply (std::shared_ptr<const i2p::data::IdentityEx> identity);
|
void SendNamingLookupReply (std::shared_ptr<const i2p::data::IdentityEx> identity);
|
||||||
void HandleNamingLookupLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, i2p::data::IdentHash ident);
|
void HandleNamingLookupLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, std::string name);
|
||||||
void HandleSessionReadinessCheckTimer (const boost::system::error_code& ecode);
|
void HandleSessionReadinessCheckTimer (const boost::system::error_code& ecode);
|
||||||
void SendSessionCreateReplyOk ();
|
void SendSessionCreateReplyOk ();
|
||||||
|
|
||||||
@@ -184,6 +185,8 @@ namespace client
|
|||||||
|
|
||||||
void RemoveSocket(const std::shared_ptr<SAMSocket> & socket);
|
void RemoveSocket(const std::shared_ptr<SAMSocket> & socket);
|
||||||
|
|
||||||
|
bool ResolveSignatureType (const std::string& name, i2p::data::SigningKeyType& type) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Run ();
|
void Run ();
|
||||||
@@ -207,6 +210,7 @@ namespace client
|
|||||||
mutable std::mutex m_OpenSocketsMutex;
|
mutable std::mutex m_OpenSocketsMutex;
|
||||||
std::list<std::shared_ptr<SAMSocket> > m_OpenSockets;
|
std::list<std::shared_ptr<SAMSocket> > m_OpenSockets;
|
||||||
uint8_t m_DatagramReceiveBuffer[i2p::datagram::MAX_DATAGRAM_SIZE+1];
|
uint8_t m_DatagramReceiveBuffer[i2p::datagram::MAX_DATAGRAM_SIZE+1];
|
||||||
|
std::map<std::string, i2p::data::SigningKeyType> m_SignatureTypes;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,8 @@
|
|||||||
<translation type="qt" />
|
<translation type="qt" />
|
||||||
|
|
||||||
<releases>
|
<releases>
|
||||||
|
<release version="2.25.0" date="2019-05-09" />
|
||||||
|
<release version="2.24.0" date="2019-03-21" />
|
||||||
<release version="2.23.0" date="2019-01-21" />
|
<release version="2.23.0" date="2019-01-21" />
|
||||||
<release version="2.22.0" date="2018-11-09" />
|
<release version="2.22.0" date="2018-11-09" />
|
||||||
<release version="2.21.1" date="2018-10-22" />
|
<release version="2.21.1" date="2018-10-22" />
|
||||||
|
|||||||
Reference in New Issue
Block a user