Compare commits

..

221 Commits
2.1.0 ... 2.3.0

Author SHA1 Message Date
orignal
cae9ccfda1 version 2.3.0 2016-01-12 10:14:22 -05:00
orignal
248ae7d4d5 do nothing upon SIGHUP for now 2016-01-12 10:12:55 -05:00
orignal
7f08bbe938 handle -pidfile parameter correctly 2016-01-12 10:00:17 -05:00
orignal
81b2f2114d purplei2p webconsole style(by sha-db) 2016-01-12 09:36:01 -05:00
orignal
5eee430be3 fixed typo 2016-01-12 09:34:46 -05:00
orignal
870e84a700 new webconsole layout (by nda) 2016-01-11 22:05:10 -05:00
orignal
8d4fae24ea fixed misalignment 2016-01-11 19:03:04 -05:00
orignal
7a84daf3f7 temporary disable openssl mutexes 2016-01-11 17:37:20 -05:00
orignal
7968279bc2 send X-I2P-DestHash 2016-01-11 13:48:18 -05:00
orignal
258be40285 notransit parameter added 2016-01-11 11:08:06 -05:00
hagen
b2ae30eba1 * fix cmake output library name (#315) 2016-01-11 11:31:55 +00:00
hagen
daaba1dbc0 * prevent zero-division exception when running offline 2016-01-11 11:31:02 +00:00
hagen
a3c6ed4dd2 * fix warnings from -Wunused-result 2016-01-11 11:31:02 +00:00
hagen
e4255ed712 + add --pidfile cmdline option 2016-01-11 11:31:02 +00:00
hagen
5d510f1cf4 * DaemonLinux : set umask to 0027 instead 0000 2016-01-11 10:55:50 +00:00
hagen
1819bd910a * add log message when fork failed 2016-01-11 10:55:18 +00:00
hagen
43eecdbb3f * update default tunnels.cfg 2016-01-11 02:55:21 +00:00
hagen
108c1bcac4 * update docs/configuration.md 2016-01-11 02:52:16 +00:00
hagen
4b7e5864d4 * cleanup default config file 2016-01-11 02:52:00 +00:00
hagen
fb1d2abbfa * cleanup manpage 2016-01-11 02:51:35 +00:00
orignal
0c290e65ef removed deprecated parameters 2016-01-10 21:39:29 -05:00
orignal
5487fad2ce fixed race conditin 2016-01-10 18:55:00 -05:00
orignal
d41f930f69 fixed unintialized reply key 2016-01-10 16:40:28 -05:00
orignal
595b2619fd fixed misalignment for timestamp 2016-01-09 19:24:52 -05:00
orignal
26d305d866 fixed misalignment of certificate length 2016-01-09 17:26:17 -05:00
orignal
c9d95ff161 eliminate one extra multipilication 2016-01-08 10:21:43 -05:00
orignal
9cc592b564 correct buffer size for deflate 2016-01-05 14:50:45 -05:00
orignal
ff48422ec0 check I2NP message buffer size 2016-01-05 14:29:18 -05:00
orignal
a26c5f85c3 ignore LeaseSets coming from transit tunnels 2016-01-04 19:56:46 -05:00
orignal
727436e1cf specify signature type for I2P tunnels 2016-01-03 21:43:43 -05:00
orignal
d1c57a1872 New bandwidth values 2016-01-03 19:15:12 -05:00
orignal
b7c021af8c clear extra bandwidth bit 2016-01-03 09:54:03 -05:00
orignal
7149b509d7 extra bandwidth caps 2016-01-02 22:17:04 -05:00
orignal
45e7111dda publish stats for floodfill 2016-01-02 17:23:20 -05:00
orignal
9fc69db9eb reserve extra 16 bytes for padding 2016-01-01 17:39:12 -05:00
orignal
2ba314d9d9 count checksum and padding for buffer size 2016-01-01 15:41:18 -05:00
orignal
f35660c8e2 fixed windows build 2016-01-01 08:30:38 -05:00
orignal
68b1fe8631 use TUNNEL_DATA_ENCRYPTED_SIZE for tunnel encryption 2015-12-31 19:46:14 -05:00
orignal
4242c86d40 check for buffer overflow during flood 2015-12-31 17:09:04 -05:00
orignal
ef4dc3cbc9 fixed race condition of openssl calls 2015-12-31 16:02:10 -05:00
orignal
8daa7561fa pass ident hash by values to RequestComplete 2015-12-31 11:21:01 -05:00
orignal
2cc3dfc2ce fixed windows build 2015-12-28 12:26:10 -05:00
orignal
459800568a fixed windows build 2015-12-28 11:55:55 -05:00
orignal
3a35b84b03 fixed FreeBSD build 2015-12-28 10:52:02 -05:00
orignal
79cfa52bf9 fixed windows build 2015-12-28 08:30:40 -05:00
hagen
a0e8fe5848 * implement --loglevel option 2015-12-28 10:54:00 +00:00
hagen
2dae5bccb2 * util.cpp : reorder defines 2015-12-28 10:54:00 +00:00
hagen
8e867ab0c0 * util.cpp : reorder defines 2015-12-28 10:54:00 +00:00
hagen
1b2c88fe38 * drop i2p::util::config::GetCharArg 2015-12-28 10:54:00 +00:00
hagen
f3bee5ff3f * log message fix 2015-12-28 10:53:48 +00:00
orignal
196d7e8f72 send correct RouterInfo statistics 2015-12-26 09:41:12 -05:00
orignal
16596c18fb log max packet size 2015-12-23 20:47:44 -05:00
hagen
7ea3a87bfc * missing initializer for member ‘i2p::transport::Peer::delayedMessages‘ 2015-12-24 00:55:53 +00:00
hagen
a57905b6cd * merged branch 'sane-log-messages' 2015-12-24 00:46:32 +00:00
orignal
f9c592ca22 static link against libgcc, libstdc++ and libwinpthread 2015-12-23 10:24:10 -05:00
hagen
aecac0ef85 * bump version in debian/changelog 2015-12-23 01:32:01 +00:00
orignal
ca315c51a0 version 2.2.0 2015-12-21 20:49:27 -05:00
orignal
45c8858140 persist temporary keys 2015-12-21 10:17:00 -05:00
orignal
06e45bff24 removed unused parameter 2015-12-21 09:33:09 -05:00
Mikhail Titov
2635a658d0 Fix missing cached openssl in appveyor 2015-12-20 22:57:55 -06:00
hagen
f48a98f691 * disable AESNI by default for .deb package (#312) 2015-12-21 03:48:35 +00:00
hagen
3badda95c1 * reseed now https only 2015-12-21 03:46:35 +00:00
hagen
364ccc05d5 * Log.h: drop unused template 2015-12-21 03:00:12 +00:00
hagen
d09fedf208 * sane log messages: TransitTunnel.cpp 2015-12-21 03:00:12 +00:00
hagen
7936f8730f * sane log messages: Reseed.cpp 2015-12-21 03:00:12 +00:00
hagen
6c0dfc4356 * sane log messages: Log.cpp 2015-12-21 03:00:12 +00:00
hagen
d9af8c31a2 * sane log messages: LeaseSet.cpp 2015-12-21 03:00:12 +00:00
hagen
ca375314f0 * sane log messages: Identity.cpp 2015-12-21 03:00:12 +00:00
hagen
5266d4d79c * sane log messages: RouterInfo.cpp 2015-12-21 03:00:12 +00:00
hagen
1cb0826de0 * sane log messages: SSUData.cpp 2015-12-21 03:00:12 +00:00
hagen
89e3178ea3 * sane log messages: HTTPServer.cpp 2015-12-21 03:00:12 +00:00
hagen
3b5d9d6cee * sane log messages: RouterContext.cpp 2015-12-21 03:00:12 +00:00
hagen
ce4ed19029 * sane log messages: SSU.cpp 2015-12-21 03:00:11 +00:00
hagen
01a502339c * sane log messages: api.cpp 2015-12-21 03:00:11 +00:00
hagen
642d0e6f74 * sane log messages: Streaming.cpp 2015-12-21 03:00:11 +00:00
hagen
d9e659deb0 * sane log messages: Destination.cpp 2015-12-21 03:00:11 +00:00
hagen
830fe7f9b8 * sane log messages: Transports.cpp 2015-12-21 03:00:11 +00:00
hagen
3e8c247c05 * sane log messages: ClientContext.cpp 2015-12-21 03:00:11 +00:00
hagen
16880074fa * sane log messages: DaemonWin32.cpp 2015-12-21 03:00:11 +00:00
hagen
19c74ce9fa * sane log messages: DaemonLinux.cpp 2015-12-21 03:00:11 +00:00
hagen
56ef0dad9c * sane log messages: Daemon.cpp 2015-12-21 03:00:11 +00:00
hagen
8d99808821 * sane log messages: I2PTunnel.cpp 2015-12-21 03:00:11 +00:00
hagen
1cb08fdecc * sane log messages: util.cpp 2015-12-21 03:00:11 +00:00
hagen
e8952d7e02 * sane log messages: TunnelPool.cpp 2015-12-21 03:00:11 +00:00
hagen
18fad9c9d9 * sane log messages: Garlic.cpp 2015-12-21 03:00:11 +00:00
hagen
89a0a94f3e * sane log messages: SAM.cpp 2015-12-21 03:00:11 +00:00
hagen
0859cf30f8 * sane log messages: UPnP.cpp 2015-12-21 03:00:11 +00:00
hagen
a0fe02a560 * sane log messages: BOB.cpp 2015-12-21 03:00:11 +00:00
hagen
3156f7dacd * sane log messages: Tunnel.cpp 2015-12-21 03:00:11 +00:00
hagen
c3958bf042 * sane log messages: NTCPSession.cpp 2015-12-21 03:00:11 +00:00
hagen
facc5f8aa7 * sane log messages: SSUSession.cpp 2015-12-21 03:00:11 +00:00
hagen
8170257c26 * sane log messages: AddressBook.cpp 2015-12-21 03:00:11 +00:00
hagen
489e37b2a1 * sane log messages: NetDb.cpp 2015-12-21 03:00:11 +00:00
hagen
4899e0d2d5 * sane log messages: I2NPProtocol.cpp 2015-12-21 03:00:11 +00:00
Mikhail Titov
762f9c4b23 Merge pull request #308 from mlt/openssl-cmake
Cleaned up appveyor CI along with MSVC & mingw builds
2015-12-20 13:38:12 -06:00
Mikhail Titov
6d3dac0ec1 Windows build status badge update in README.md 2015-12-19 22:19:06 -06:00
Mikhail Titov
f684815272 Build miniupnpc.dll on Appveyor 2015-12-19 22:19:05 -06:00
Mikhail Titov
8e04218c95 Install optional miniupnpc.dll if exist 2015-12-19 22:19:04 -06:00
Mikhail Titov
23cb45454b Set default install folder for CMake based NSIS 2015-12-19 22:19:02 -06:00
Mikhail Titov
7fc9a161b1 Default NSIS template from CMake 2015-12-19 22:19:01 -06:00
Mikhail Titov
95a5473051 Initial CMake based packaging 2015-12-19 22:19:00 -06:00
Mikhail Titov
66ceb573dc Update Windows build docs 2015-12-19 22:18:59 -06:00
Mikhail Titov
5f8223ebb5 Patch for 64-bit zlib build with MSVC assembly 2015-12-19 22:18:58 -06:00
Mikhail Titov
51146d4152 MSVC optimization & hardening 2015-12-19 22:18:57 -06:00
Mikhail Titov
3334281949 Search for patch tool with CMake
This is to enable static build of "bundled" zlib with MSVC
2015-12-19 00:03:32 -06:00
Mikhail Titov
8e85d9ac00 Sync Windows VERSIONINFO resource with version.h 2015-12-19 00:03:31 -06:00
Mikhail Titov
e1c69a6250 Transparency in icon 2015-12-19 00:03:30 -06:00
Mikhail Titov
edd9a18257 Cleanup some CMake msys specifics
* Exclude MSYS from -z relro
* WIN32_LEAN_AND_MEAN
2015-12-19 00:03:28 -06:00
Mikhail Titov
65f993677f Remove unnecessary thread & chrono Boost libs
Prevent boost thread auto-link erroneous attempts with MSVC
2015-12-19 00:03:27 -06:00
Mikhail Titov
bc775140bb appveyor.yml 2015-12-19 00:03:26 -06:00
Mikhail Titov
4b2bd6e18f Include dir for precompiled headers with gcc 2015-12-19 00:03:24 -06:00
orignal
c36a810bcb ignore extended options for SessionCreated and SessionConfirmed 2015-12-18 11:52:44 -05:00
orignal
a994bbc36b call CryptoConstants from Crypto.cpp only 2015-12-18 10:09:25 -05:00
hagen
c3238f4d0b * fix warnings of type mismatch (#298) 2015-12-17 08:10:17 +00:00
hagen
632d26e398 * update maintainer scripts 2015-12-17 07:16:26 +00:00
hagen
214cc8b810 * install reseed certs 2015-12-17 05:00:03 +00:00
hagen
8f218141f4 * add 'i2pd' user (#313) 2015-12-17 04:39:08 +00:00
hagen
3676304751 * provide default subscriptions.txt 2015-12-17 04:39:08 +00:00
hagen
c605fd57aa * AddressBook.cpp : mistype in log message 2015-12-17 04:39:08 +00:00
orignal
4599f6919c shared_ptr for local destination in TunnelPool 2015-12-16 14:52:48 -05:00
hagen
8ad20c0db3 * allow parallel builds (#310) 2015-12-16 01:12:14 +00:00
hagen
638a69e5f0 * fix comments in default config (#311) 2015-12-16 00:19:52 +00:00
orignal
9fa6b1ebe1 keep pending incoming streams if acceptor is not set 2015-12-14 22:36:23 -05:00
orignal
5930e2d221 keep pending incoming streams if acceptor is not set 2015-12-14 22:23:28 -05:00
orignal
fdd96975fb cancel destination request 2015-12-13 14:40:43 -05:00
orignal
de6dd77046 use shared_ptr for LeaseSet request 2015-12-13 10:51:43 -05:00
orignal
1b6ad8413e spread addresses between subdirectories 2015-12-11 15:48:33 -05:00
orignal
6096d572f3 handle RelayResponse 2015-12-09 22:17:43 -05:00
orignal
badcd64b62 print full tunnel path 2015-12-09 19:07:12 -05:00
orignal
a7b8b52dbd fixed crash 2015-12-09 18:01:42 -05:00
orignal
d89f0f51df show full tunnel path 2015-12-09 10:35:04 -05:00
orignal
be358f3f2e enable RI catch for OBEP back 2015-12-09 10:03:51 -05:00
orignal
f122da1485 change and save I2PControl password 2015-12-08 10:40:43 -05:00
hagen
0dda4728b6 * update README 2015-12-08 12:18:25 +00:00
hagen
45fd95e02b * update default/i2pd and traditional init script 2015-12-08 11:38:28 +00:00
hagen
91aa2d7f6f + add example config files 2015-12-08 11:38:28 +00:00
hagen
a96b7d2a80 * drop patch not needed anymore 2015-12-08 11:38:28 +00:00
hagen
8f9cea54c5 * rename main binary 2015-12-08 11:38:28 +00:00
orignal
045558bede correct path to openssl 2015-12-06 22:48:08 -05:00
hagen
58124ebaab * update debian/docs 2015-12-05 11:55:27 +00:00
hagen
0c87dd5624 * added debian/logrotate (thanks to kytv) 2015-12-05 11:55:27 +00:00
hagen
b87f986a49 * added manpage (thanks to kytv) 2015-12-05 11:55:27 +00:00
hagen
c6a6035bb9 * debian/control : compat level -> 9 2015-12-05 07:56:51 +00:00
orignal
1ef12f0645 updated reseeders list 2015-12-04 14:59:31 -05:00
orignal
ef3ec33ba3 create all subdirectories for non-case sensitive systems 2015-12-04 14:06:37 -05:00
orignal
c82ef1ee8f link against openssl for Mac OS X 2015-12-04 13:19:08 -05:00
Mikhail Titov
23b8a60242 Appveyor status badge 2015-12-03 23:39:09 -06:00
Mikhail Titov
ac9511165e Merge pull request #307 from mlt/openssl-cmake
Better CMake support for MSVC builds
2015-12-03 23:35:14 -06:00
Mikhail Titov
9d70851eb9 Respect static for zlib with CMake 2015-12-03 23:23:26 -06:00
Mikhail Titov
759dfb28ce Increase PCH heap limit for MSVC 2015-12-03 23:07:31 -06:00
Mikhail Titov
ff356b1f21 Use assembly language when building zlib for MSVC++ 2015-12-03 23:07:30 -06:00
Mikhail Titov
b2a6c1bc68 fixup! read Content-Length from http header
MSVC++ complains on ssize_t
2015-12-03 23:07:29 -06:00
Mikhail Titov
76549d0a4a Fix win32 resource compilation with msys
squash! Fix win32 resource

winres.h is missing for mingw
2015-12-03 23:07:27 -06:00
Mikhail Titov
e5c72cae83 Fix CMake stuff for msys2 2015-12-03 23:07:26 -06:00
orignal
bf47df46c9 allow DNS names for SSU 2015-12-03 15:45:01 -05:00
orignal
0ef42870e5 try SSU if NTCP address is not presented 2015-12-02 12:48:10 -05:00
orignal
da8a6a4c2b make sure to use ipv4 introducers only 2015-12-01 09:21:02 -05:00
orignal
988007a8c9 pass correct pointer to sessions table 2015-11-30 19:45:57 -05:00
hagen
710439e83c * cleanup README
* move all docs to single dir
2015-12-01 00:06:00 +00:00
hagen
80a0a3d4fb * BUILD_NOTES.md : add hints for building deb 2015-12-01 00:02:59 +00:00
hagen
43299aea10 * BUILD_NOTES.md : update 2015-12-01 00:02:59 +00:00
hagen
f5aea766a7 * move 'Requirements' sections to BUILD_NOTES.md 2015-12-01 00:02:59 +00:00
orignal
c5308e3f2f separate SSU sessions lists for V4 and V6 2015-11-30 15:53:07 -05:00
orignal
2b8e662f81 connect through introducer in v4 thread 2015-11-30 14:59:32 -05:00
orignal
0a6d849435 pass shared_ptr to SendRelayIntro 2015-11-30 10:23:05 -05:00
orignal
a0106fe5d8 Merge pull request #306 from erlend1/openssl
Configurable addresses from master
2015-11-30 10:20:19 -05:00
erlend1
cee1b8a64a Configurable addresses from master 2015-11-30 16:44:32 +02:00
orignal
4e2ba71d59 more introducers 2015-11-29 17:25:42 -05:00
orignal
fb2bdfb9ee create SSU session in SSU thread 2015-11-29 09:10:49 -05:00
orignal
72785f6740 eliminate some unnecessary calculations 2015-11-27 22:16:10 -05:00
orignal
a94a05fac9 replaced radix-16 to radix-256 2015-11-27 19:02:54 -05:00
orignal
430368de97 temporary disable Ed25519 per thread 2015-11-27 15:46:30 -05:00
orignal
7bfb499549 reduce number of precalculated points 2015-11-27 13:19:45 -05:00
hagen
9bc477e1b6 * use stricter linker options for .deb packages 2015-11-27 14:02:19 +00:00
hagen
f84ac18472 * set defaults to *FLAGS instead redefining them 2015-11-27 14:01:15 +00:00
hagen
cd515a2e54 * fix Depends: for i2pd-dbg 2015-11-27 14:01:15 +00:00
hagen
c73c8fdc47 * fix building of empty -dbg package 2015-11-27 13:35:24 +00:00
hagen
e755a32b23 * take some enchancements for debian/ dir from kytv (#1) 2015-11-27 12:09:31 +00:00
hagen
d4d1768575 * Makefile.* : fix build with gcc 4.7.2 (#299) 2015-11-27 11:42:44 +00:00
orignal
0a5745c559 Update README.md 2015-11-26 21:04:19 -05:00
orignal
b24959205b Update README.md 2015-11-26 21:03:58 -05:00
orignal
d69f297c05 split between CreateSession and CreateSessionThrough Introducer 2015-11-26 16:20:24 -05:00
orignal
3c8e331809 Ed25519 per thread 2015-11-26 14:00:40 -05:00
orignal
d169471e8c copy constructor for Ed22519 2015-11-26 13:31:30 -05:00
orignal
56453f6b5c moved BN_CTX creation to curve's Verify and Sign 2015-11-26 10:25:51 -05:00
orignal
dac2e8c79e use left sift instead multipilication by 2 2015-11-26 09:48:06 -05:00
orignal
ccc96bc610 Merge pull request #304 from hagen-i2p/fixes
Misc fixes
2015-11-26 07:05:46 -05:00
hagen
654371cb6a fix debian/ directory 2015-11-26 11:24:28 +00:00
hagen
1af8d873bb delete build/cmake_modules/FindCryptoPP.cmake (now using openssl) 2015-11-26 11:24:02 +00:00
hagen
b7a0e23309 fix BUILD_NOTES: url, md-format, crypto++ reference 2015-11-26 11:23:32 +00:00
hagen
4a0f868941 fix Dockerfile : drop crypto++, add openssl 2015-11-26 11:23:30 +00:00
hagen
448073cdd6 format '%lu' expects argument of type 'long unsigned int', but argument 5 has type 'size_t {aka unsigned int} 2015-11-26 11:23:27 +00:00
orignal
ad79ec7b1f async handshake 2015-11-25 13:11:02 -05:00
orignal
e194854c6d replace GetSession to CreateSession 2015-11-25 12:51:35 -05:00
orignal
d01d033209 eliminate session creation collision 2015-11-25 11:51:35 -05:00
orignal
06c4aca490 always use shared_ptr for I2NPMessage 2015-11-24 13:09:12 -05:00
orignal
885d57138a read Content-Length from http header 2015-11-23 19:47:08 -05:00
orignal
9e2a770a26 read complete request 2015-11-23 16:40:06 -05:00
orignal
942b699bb9 fixed few SSL errors 2015-11-23 14:48:56 -05:00
orignal
c9d03a8094 I2PControl through SSL 2015-11-23 13:22:02 -05:00
orignal
d015538bb4 create certificate for https 2015-11-23 11:56:00 -05:00
orignal
90d6c5c5bb fixed race condition 2015-11-23 09:26:32 -05:00
orignal
387ce4b6fa fixed access to eepsites from webconsole 2015-11-22 21:02:02 -05:00
orignal
7943b13891 use shared_ptr for sockets 2015-11-22 17:01:37 -05:00
orignal
50a7cd19b4 Update README.md 2015-11-22 16:48:38 -05:00
orignal
53e9335bb0 Update README.md 2015-11-22 16:47:55 -05:00
orignal
e5cb70972e moved status_string to reply structure 2015-11-22 10:58:57 -05:00
orignal
0d84871037 backport of 'make http server http/1.1 compliant' 2015-11-21 17:26:12 -05:00
orignal
1d37745c0c more separation between api and executable builds 2015-11-21 17:04:40 -05:00
orignal
ad9ade7849 reduce number of transient BIGNUM allocations 2015-11-20 21:27:16 -05:00
orignal
c1e2ee32b4 fixed mingw build error 2015-11-20 12:34:53 -05:00
orignal
1588d2734c use path.string () instead path.c_str () 2015-11-20 12:30:20 -05:00
orignal
50dda4263f fixed mingw build error 2015-11-20 11:42:38 -05:00
orignal
a8f2239495 backport GetMTU 2015-11-20 10:36:04 -05:00
orignal
c42636b0ee check for zero-length 2015-11-20 10:10:13 -05:00
orignal
54b2c8bd7e backport fix build for clang 2015-11-20 10:02:54 -05:00
orignal
d01a21a867 backport openbsd support 2015-11-20 09:55:34 -05:00
orignal
5d43052c05 Merge pull request #296 from edwtjo/make-tunnelscfg-configurable-again
Make tunnels.cfg configurable
2015-11-20 09:08:26 -05:00
Edward Tjörnhammar
4109ab1590 Make tunnels.cfg configurable 2015-11-20 13:59:00 +01:00
orignal
f6eabd695b don't store B explicitly 2015-11-19 22:38:18 -05:00
orignal
24d9dacfd9 fixed mingw build 2015-11-19 21:02:55 -05:00
124 changed files with 4383 additions and 2363 deletions

View File

@@ -34,8 +34,15 @@ namespace client
private:
boost::filesystem::path GetPath () const { return i2p::util::filesystem::GetDefaultDataDir() / "addressbook"; };
boost::filesystem::path GetPath () const
{
return i2p::util::filesystem::GetDefaultDataDir() / "addressbook";
}
boost::filesystem::path GetAddressPath (const i2p::data::IdentHash& ident) const
{
auto b32 = ident.ToBase32();
return GetPath () / (std::string ("b") + b32[0]) / (b32 + ".b32");
}
};
AddressBookFilesystemStorage::AddressBookFilesystemStorage ()
@@ -47,12 +54,28 @@ namespace client
if (!boost::filesystem::create_directory (path))
LogPrint (eLogError, "Failed to create addressbook directory");
}
}
std::shared_ptr<const i2p::data::IdentityEx> AddressBookFilesystemStorage::GetAddress (const i2p::data::IdentHash& ident) const
{
auto filename = GetPath () / (ident.ToBase32() + ".b32");
std::ifstream f(filename.c_str (), std::ifstream::binary);
auto filename = GetAddressPath (ident);
if (!boost::filesystem::exists (filename))
{
boost::filesystem::create_directory (filename.parent_path ());
// try to find in main folder
auto filename1 = GetPath () / (ident.ToBase32 () + ".b32");
if (!boost::filesystem::exists (filename1))
{
boost::system::error_code ec;
boost::filesystem::rename (filename1, filename, ec);
if (ec)
LogPrint (eLogError, "Couldn't move file ", ec.message ());
}
else
return nullptr; // address doesn't exist
}
std::ifstream f(filename.string (), std::ifstream::binary);
if (f.is_open ())
{
f.seekg (0,std::ios::end);
@@ -75,8 +98,14 @@ namespace client
void AddressBookFilesystemStorage::AddAddress (std::shared_ptr<const i2p::data::IdentityEx> address)
{
auto filename = GetPath () / (address->GetIdentHash ().ToBase32() + ".b32");
std::ofstream f (filename.c_str (), std::ofstream::binary | std::ofstream::out);
auto filename = GetAddressPath (address->GetIdentHash ());
std::ofstream f (filename.string (), std::ofstream::binary | std::ofstream::out);
if (!f.is_open ())
{
// create subdirectory
if (boost::filesystem::create_directory (filename.parent_path ()))
f.open (filename.string (), std::ofstream::binary | std::ofstream::out); // and try to open again
}
if (f.is_open ())
{
size_t len = address->GetFullLen ();
@@ -91,7 +120,7 @@ namespace client
void AddressBookFilesystemStorage::RemoveAddress (const i2p::data::IdentHash& ident)
{
auto filename = GetPath () / (ident.ToBase32() + ".b32");
auto filename = GetAddressPath (ident);
if (boost::filesystem::exists (filename))
boost::filesystem::remove (filename);
}
@@ -100,7 +129,7 @@ namespace client
{
int num = 0;
auto filename = GetPath () / "addresses.csv";
std::ifstream f (filename.c_str (), std::ofstream::in); // in text mode
std::ifstream f (filename.string (), std::ofstream::in); // in text mode
if (f.is_open ())
{
addresses.clear ();
@@ -123,10 +152,10 @@ namespace client
num++;
}
}
LogPrint (eLogInfo, num, " addresses loaded");
LogPrint (eLogInfo, "Addressbook: ", num, " addresses loaded");
}
else
LogPrint (eLogWarning, filename, " not found");
LogPrint (eLogWarning, "Addressbook: ", filename, " not found");
return num;
}
@@ -134,7 +163,7 @@ namespace client
{
int num = 0;
auto filename = GetPath () / "addresses.csv";
std::ofstream f (filename.c_str (), std::ofstream::out); // in text mode
std::ofstream f (filename.string (), std::ofstream::out); // in text mode
if (f.is_open ())
{
for (auto it: addresses)
@@ -142,7 +171,7 @@ namespace client
f << it.first << "," << it.second.ToBase32 () << std::endl;
num++;
}
LogPrint (eLogInfo, num, " addresses saved");
LogPrint (eLogInfo, "Addressbook: ", num, " addresses saved");
}
else
LogPrint (eLogError, "Can't open file ", filename);
@@ -261,7 +290,7 @@ namespace client
m_Storage = CreateStorage ();
m_Storage->AddAddress (ident);
m_Addresses[address] = ident->GetIdentHash ();
LogPrint (address,"->", ToAddress(ident->GetIdentHash ()), " added");
LogPrint (eLogInfo, "Addressbook: ", address,"->", ToAddress(ident->GetIdentHash ()), " added");
}
void AddressBook::InsertAddress (std::shared_ptr<const i2p::data::IdentityEx> address)
@@ -447,7 +476,7 @@ namespace client
void AddressBookSubscription::Request ()
{
// must be run in separate thread
LogPrint (eLogInfo, "Downloading hosts from ", m_Link, " ETag: ", m_Etag, " Last-Modified: ", m_LastModified);
LogPrint (eLogInfo, "Downloading hosts database from ", m_Link, " ETag: ", m_Etag, " Last-Modified: ", m_LastModified);
bool success = false;
i2p::util::http::url u (m_Link);
i2p::data::IdentHash ident;
@@ -466,7 +495,10 @@ namespace client
newDataReceived.notify_all ();
});
if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT)) == std::cv_status::timeout)
LogPrint (eLogError, "Subscription LeseseSet request timeout expired");
{
LogPrint (eLogError, "Subscription LeaseSet request timeout expired");
i2p::client::context.GetSharedLocalDestination ()->CancelDestinationRequest (ident);
}
}
if (leaseSet)
{
@@ -559,7 +591,10 @@ namespace client
}
else
LogPrint (eLogError, "Can't resolve ", u.host_);
LogPrint (eLogInfo, "Download complete ", success ? "Success" : "Failed");
if (!success)
LogPrint (eLogError, "Addressbook download failed");
m_Book.DownloadComplete (success);
}
}

30
BOB.cpp
View File

@@ -61,7 +61,7 @@ namespace client
std::shared_ptr<AddressReceiver> receiver)
{
if (ecode)
LogPrint ("BOB inbound tunnel read error: ", ecode.message ());
LogPrint (eLogError, "BOB: inbound tunnel read error: ", ecode.message ());
else
{
receiver->bufferOffset += bytes_transferred;
@@ -76,7 +76,7 @@ namespace client
i2p::data::IdentHash ident;
if (!context.GetAddressBook ().GetIdentHash (receiver->buffer, ident))
{
LogPrint (eLogError, "BOB address ", receiver->buffer, " not found");
LogPrint (eLogError, "BOB: address ", receiver->buffer, " not found");
return;
}
auto leaseSet = GetLocalDestination ()->FindLeaseSet (ident);
@@ -92,7 +92,7 @@ namespace client
if (receiver->bufferOffset < BOB_COMMAND_BUFFER_SIZE)
ReceiveAddress (receiver);
else
LogPrint ("BOB missing inbound address ");
LogPrint (eLogError, "BOB: missing inbound address");
}
}
}
@@ -102,12 +102,12 @@ namespace client
if (leaseSet)
CreateConnection (receiver, leaseSet);
else
LogPrint ("LeaseSet for BOB inbound destination not found");
LogPrint (eLogError, "BOB: LeaseSet for inbound destination not found");
}
void BOBI2PInboundTunnel::CreateConnection (std::shared_ptr<AddressReceiver> receiver, std::shared_ptr<const i2p::data::LeaseSet> leaseSet)
{
LogPrint ("New BOB inbound connection");
LogPrint (eLogDebug, "BOB: New inbound connection");
auto connection = std::make_shared<I2PTunnelConnection>(this, receiver->socket, leaseSet);
AddHandler (connection);
connection->I2PConnect (receiver->data, receiver->dataLen);
@@ -135,7 +135,7 @@ namespace client
if (localDestination)
localDestination->AcceptStreams (std::bind (&BOBI2POutboundTunnel::HandleAccept, this, std::placeholders::_1));
else
LogPrint ("Local destination not set for server tunnel");
LogPrint (eLogError, "BOB: Local destination not set for server tunnel");
}
void BOBI2POutboundTunnel::HandleAccept (std::shared_ptr<i2p::stream::Stream> stream)
@@ -229,7 +229,7 @@ namespace client
{
if (ecode)
{
LogPrint ("BOB command channel read error: ", ecode.message ());
LogPrint (eLogError, "BOB: command channel read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
@@ -256,7 +256,7 @@ namespace client
(this->*(it->second))(operand, eol - operand);
else
{
LogPrint (eLogError, "BOB unknown command ", m_ReceiveBuffer);
LogPrint (eLogError, "BOB: unknown command ", m_ReceiveBuffer);
SendReplyError ("unknown command");
}
@@ -269,7 +269,7 @@ namespace client
m_ReceiveBufferOffset = size;
else
{
LogPrint (eLogError, "Malformed input of the BOB command channel");
LogPrint (eLogError, "BOB: Malformed input of the command channel");
Terminate ();
}
}
@@ -288,7 +288,7 @@ namespace client
{
if (ecode)
{
LogPrint ("BOB command channel send error: ", ecode.message ());
LogPrint (eLogError, "BOB: command channel send error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
@@ -524,9 +524,9 @@ namespace client
SendReplyError ("malformed");
}
BOBCommandChannel::BOBCommandChannel (int port):
BOBCommandChannel::BOBCommandChannel (const std::string& address, int port):
m_IsRunning (false), m_Thread (nullptr),
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port))
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port))
{
// command -> handler
m_CommandHandlers[BOB_COMMAND_ZAP] = &BOBCommandSession::ZapCommandHandler;
@@ -589,7 +589,7 @@ namespace client
}
catch (std::exception& ex)
{
LogPrint (eLogError, "BOB: ", ex.what ());
LogPrint (eLogError, "BOB: runtime exception: ", ex.what ());
}
}
}
@@ -632,11 +632,11 @@ namespace client
if (!ecode)
{
LogPrint (eLogInfo, "New BOB command connection from ", session->GetSocket ().remote_endpoint ());
LogPrint (eLogInfo, "BOB: New command connection from ", session->GetSocket ().remote_endpoint ());
session->SendVersion ();
}
else
LogPrint (eLogError, "BOB accept error: ", ecode.message ());
LogPrint (eLogError, "BOB: accept error: ", ecode.message ());
}
}
}

2
BOB.h
View File

@@ -199,7 +199,7 @@ namespace client
{
public:
BOBCommandChannel (int port);
BOBCommandChannel (const std::string& address, int port);
~BOBCommandChannel ();
void Start ();

View File

@@ -154,7 +154,7 @@ namespace data
if (isFirstTime) iT64Build();
n = InCount/4;
m = InCount%4;
if (!m)
if (InCount && !m)
outCount = 3*n;
else {
outCount = 0;

View File

@@ -41,55 +41,32 @@ namespace client
std::string proxyKeys = i2p::util::config::GetArg("-proxykeys", "");
if (proxyKeys.length () > 0)
localDestination = LoadLocalDestination (proxyKeys, false);
m_HttpProxy = new i2p::proxy::HTTPProxy(i2p::util::config::GetArg("-httpproxyport", 4446), localDestination);
LogPrint(eLogInfo, "Clients: starting HTTP Proxy");
m_HttpProxy = new i2p::proxy::HTTPProxy(i2p::util::config::GetArg("-httpproxyaddress", "127.0.0.1"), i2p::util::config::GetArg("-httpproxyport", 4446), localDestination);
m_HttpProxy->Start();
LogPrint("HTTP Proxy started");
m_SocksProxy = new i2p::proxy::SOCKSProxy(i2p::util::config::GetArg("-socksproxyport", 4447), localDestination);
LogPrint(eLogInfo, "Clients: starting SOCKS Proxy");
m_SocksProxy = new i2p::proxy::SOCKSProxy(i2p::util::config::GetArg("-socksproxyaddress", "127.0.0.1"), i2p::util::config::GetArg("-socksproxyport", 4447), localDestination);
m_SocksProxy->Start();
LogPrint("SOCKS Proxy Started");
// I2P tunnels
std::string ircDestination = i2p::util::config::GetArg("-ircdest", "");
if (ircDestination.length () > 0) // ircdest is presented
{
localDestination = nullptr;
std::string ircKeys = i2p::util::config::GetArg("-irckeys", "");
if (ircKeys.length () > 0)
localDestination = LoadLocalDestination (ircKeys, false);
auto ircPort = i2p::util::config::GetArg("-ircport", 6668);
auto ircTunnel = new I2PClientTunnel (ircDestination, ircPort, localDestination);
ircTunnel->Start ();
m_ClientTunnels.insert (std::make_pair(ircPort, std::unique_ptr<I2PClientTunnel>(ircTunnel)));
LogPrint("IRC tunnel started");
}
std::string eepKeys = i2p::util::config::GetArg("-eepkeys", "");
if (eepKeys.length () > 0) // eepkeys file is presented
{
localDestination = LoadLocalDestination (eepKeys, true);
auto serverTunnel = new I2PServerTunnel (i2p::util::config::GetArg("-eephost", "127.0.0.1"),
i2p::util::config::GetArg("-eepport", 80), localDestination);
serverTunnel->Start ();
m_ServerTunnels.insert (std::make_pair(localDestination->GetIdentHash (), std::unique_ptr<I2PServerTunnel>(serverTunnel)));
LogPrint("Server tunnel started");
}
ReadTunnels ();
// SAM
int samPort = i2p::util::config::GetArg("-samport", 0);
if (samPort)
{
m_SamBridge = new SAMBridge (samPort);
LogPrint(eLogInfo, "Clients: starting SAM bridge");
m_SamBridge = new SAMBridge (i2p::util::config::GetArg("-samaddress", "127.0.0.1"), samPort);
m_SamBridge->Start ();
LogPrint("SAM bridge started");
}
// BOB
int bobPort = i2p::util::config::GetArg("-bobport", 0);
if (bobPort)
{
m_BOBCommandChannel = new BOBCommandChannel (bobPort);
LogPrint(eLogInfo, "Clients: starting BOB command channel");
m_BOBCommandChannel = new BOBCommandChannel (i2p::util::config::GetArg("-bobaddress", "127.0.0.1"), bobPort);
m_BOBCommandChannel->Start ();
LogPrint("BOB command channel started");
}
m_AddressBook.Start ();
@@ -97,40 +74,47 @@ namespace client
void ClientContext::Stop ()
{
LogPrint(eLogInfo, "Clients: stopping HTTP Proxy");
m_HttpProxy->Stop();
delete m_HttpProxy;
m_HttpProxy = nullptr;
LogPrint("HTTP Proxy stopped");
LogPrint(eLogInfo, "Clients: stopping SOCKS Proxy");
m_SocksProxy->Stop();
delete m_SocksProxy;
m_SocksProxy = nullptr;
LogPrint("SOCKS Proxy stopped");
for (auto& it: m_ClientTunnels)
{
LogPrint(eLogInfo, "Clients: stopping I2P client tunnel on port ", it.first);
it.second->Stop ();
LogPrint("I2P client tunnel on port ", it.first, " stopped");
}
m_ClientTunnels.clear ();
for (auto& it: m_ServerTunnels)
{
LogPrint(eLogInfo, "Clients: stopping I2P server tunnel");
it.second->Stop ();
LogPrint("I2P server tunnel stopped");
}
m_ServerTunnels.clear ();
if (m_SamBridge)
{
LogPrint(eLogInfo, "Clients: stopping SAM bridge");
m_SamBridge->Stop ();
delete m_SamBridge;
m_SamBridge = nullptr;
LogPrint("SAM brdige stopped");
}
if (m_BOBCommandChannel)
{
LogPrint(eLogInfo, "Clients: stopping BOB command channel");
m_BOBCommandChannel->Stop ();
delete m_BOBCommandChannel;
m_BOBCommandChannel = nullptr;
LogPrint("BOB command channel stopped");
}
}
LogPrint(eLogInfo, "Clients: stopping AddressBook");
m_AddressBook.Stop ();
for (auto it: m_Destinations)
it.second->Stop ();
@@ -138,7 +122,8 @@ namespace client
m_SharedLocalDestination = nullptr;
}
std::shared_ptr<ClientDestination> ClientContext::LoadLocalDestination (const std::string& filename, bool isPublic)
std::shared_ptr<ClientDestination> ClientContext::LoadLocalDestination (const std::string& filename,
bool isPublic, i2p::data::SigningKeyType sigType)
{
i2p::data::PrivateKeys keys;
std::string fullPath = i2p::util::filesystem::GetFullPath (filename);
@@ -152,12 +137,12 @@ namespace client
s.read ((char *)buf, len);
keys.FromBuffer (buf, len);
delete[] buf;
LogPrint ("Local address ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " loaded");
LogPrint (eLogInfo, "Clients: Local address ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " loaded");
}
else
{
LogPrint ("Can't open file ", fullPath, " Creating new one");
keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256);
LogPrint (eLogError, "Clients: can't open file ", fullPath, " Creating new one with signature type ", sigType);
keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType);
std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
size_t len = keys.GetFullLen ();
uint8_t * buf = new uint8_t[len];
@@ -165,7 +150,7 @@ namespace client
f.write ((char *)buf, len);
delete[] buf;
LogPrint ("New private keys file ", fullPath, " for ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " created");
LogPrint (eLogInfo, "Clients: New private keys file ", fullPath, " for ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " created");
}
std::shared_ptr<ClientDestination> localDestination = nullptr;
@@ -173,7 +158,7 @@ namespace client
auto it = m_Destinations.find (keys.GetPublic ()->GetIdentHash ());
if (it != m_Destinations.end ())
{
LogPrint (eLogWarning, "Local destination ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " alreday exists");
LogPrint (eLogWarning, "Clients: Local destination ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " already exists");
localDestination = it->second;
}
else
@@ -217,7 +202,7 @@ namespace client
auto it = m_Destinations.find (keys.GetPublic ()->GetIdentHash ());
if (it != m_Destinations.end ())
{
LogPrint ("Local destination ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " exists");
LogPrint (eLogWarning, "Clients: Local destination ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " exists");
if (!it->second->IsRunning ())
{
it->second->Start ();
@@ -240,16 +225,18 @@ namespace client
return nullptr;
}
// should be moved in i2p::utils::fs
void ClientContext::ReadTunnels ()
{
boost::property_tree::ptree pt;
std::string pathTunnelsConfigFile = i2p::util::filesystem::GetTunnelsConfigFile().string();
try
{
boost::property_tree::read_ini (i2p::util::filesystem::GetFullPath (TUNNELS_CONFIG_FILENAME), pt);
boost::property_tree::read_ini (pathTunnelsConfigFile, pt);
}
catch (std::exception& ex)
{
LogPrint (eLogWarning, "Can't read ", TUNNELS_CONFIG_FILENAME, ": ", ex.what ());
LogPrint (eLogWarning, "Clients: Can't read ", pathTunnelsConfigFile, ": ", ex.what ());
return;
}
@@ -267,16 +254,18 @@ namespace client
int port = section.second.get<int> (I2P_CLIENT_TUNNEL_PORT);
// optional params
std::string keys = section.second.get (I2P_CLIENT_TUNNEL_KEYS, "");
std::string address = section.second.get (I2P_CLIENT_TUNNEL_ADDRESS, "127.0.0.1");
int destinationPort = section.second.get (I2P_CLIENT_TUNNEL_DESTINATION_PORT, 0);
i2p::data::SigningKeyType sigType = section.second.get (I2P_CLIENT_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256);
std::shared_ptr<ClientDestination> localDestination = nullptr;
if (keys.length () > 0)
localDestination = LoadLocalDestination (keys, false);
auto clientTunnel = new I2PClientTunnel (dest, port, localDestination, destinationPort);
localDestination = LoadLocalDestination (keys, false, sigType);
auto clientTunnel = new I2PClientTunnel (dest, address, port, localDestination, destinationPort);
if (m_ClientTunnels.insert (std::make_pair (port, std::unique_ptr<I2PClientTunnel>(clientTunnel))).second)
clientTunnel->Start ();
else
LogPrint (eLogError, "I2P client tunnel with port ", port, " already exists");
LogPrint (eLogError, "Clients: I2P client tunnel with port ", port, " already exists");
numClientTunnels++;
}
else if (type == I2P_TUNNELS_SECTION_TYPE_SERVER || type == I2P_TUNNELS_SECTION_TYPE_HTTP)
@@ -288,8 +277,9 @@ namespace client
// optional params
int inPort = section.second.get (I2P_SERVER_TUNNEL_INPORT, 0);
std::string accessList = section.second.get (I2P_SERVER_TUNNEL_ACCESS_LIST, "");
auto localDestination = LoadLocalDestination (keys, true);
i2p::data::SigningKeyType sigType = section.second.get (I2P_SERVER_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256);
auto localDestination = LoadLocalDestination (keys, true, sigType);
I2PServerTunnel * serverTunnel = (type == I2P_TUNNELS_SECTION_TYPE_HTTP) ? new I2PServerTunnelHTTP (host, port, localDestination, inPort) : new I2PServerTunnel (host, port, localDestination, inPort);
if (accessList.length () > 0)
{
@@ -309,20 +299,20 @@ namespace client
if (m_ServerTunnels.insert (std::make_pair (localDestination->GetIdentHash (), std::unique_ptr<I2PServerTunnel>(serverTunnel))).second)
serverTunnel->Start ();
else
LogPrint (eLogError, "I2P server tunnel for destination ", m_AddressBook.ToAddress(localDestination->GetIdentHash ()), " already exists");
LogPrint (eLogError, "Clients: I2P server tunnel for destination ", m_AddressBook.ToAddress(localDestination->GetIdentHash ()), " already exists");
numServerTunnels++;
}
else
LogPrint (eLogWarning, "Unknown section type=", type, " of ", name, " in ", TUNNELS_CONFIG_FILENAME);
LogPrint (eLogWarning, "Clients: Unknown section type=", type, " of ", name, " in ", pathTunnelsConfigFile);
}
catch (std::exception& ex)
{
LogPrint (eLogError, "Can't read tunnel ", name, " params: ", ex.what ());
LogPrint (eLogError, "Clients: Can't read tunnel ", name, " params: ", ex.what ());
}
}
LogPrint (eLogInfo, numClientTunnels, " I2P client tunnels created");
LogPrint (eLogInfo, numServerTunnels, " I2P server tunnels created");
LogPrint (eLogInfo, "Clients: ", numClientTunnels, " I2P client tunnels created");
LogPrint (eLogInfo, "Clients: ", numServerTunnels, " I2P server tunnels created");
}
}
}

View File

@@ -21,15 +21,17 @@ namespace client
const char I2P_TUNNELS_SECTION_TYPE_SERVER[] = "server";
const char I2P_TUNNELS_SECTION_TYPE_HTTP[] = "http";
const char I2P_CLIENT_TUNNEL_PORT[] = "port";
const char I2P_CLIENT_TUNNEL_ADDRESS[] = "address";
const char I2P_CLIENT_TUNNEL_DESTINATION[] = "destination";
const char I2P_CLIENT_TUNNEL_KEYS[] = "keys";
const char I2P_CLIENT_TUNNEL_SIGNATURE_TYPE[] = "signaturetype";
const char I2P_CLIENT_TUNNEL_DESTINATION_PORT[] = "destinationport";
const char I2P_SERVER_TUNNEL_HOST[] = "host";
const char I2P_SERVER_TUNNEL_PORT[] = "port";
const char I2P_SERVER_TUNNEL_KEYS[] = "keys";
const char I2P_SERVER_TUNNEL_SIGNATURE_TYPE[] = "signaturetype";
const char I2P_SERVER_TUNNEL_INPORT[] = "inport";
const char I2P_SERVER_TUNNEL_ACCESS_LIST[] = "accesslist";
const char TUNNELS_CONFIG_FILENAME[] = "tunnels.cfg";
class ClientContext
{
@@ -48,7 +50,8 @@ namespace client
const std::map<std::string, std::string> * params = nullptr);
void DeleteLocalDestination (std::shared_ptr<ClientDestination> destination);
std::shared_ptr<ClientDestination> FindLocalDestination (const i2p::data::IdentHash& destination) const;
std::shared_ptr<ClientDestination> LoadLocalDestination (const std::string& filename, bool isPublic);
std::shared_ptr<ClientDestination> LoadLocalDestination (const std::string& filename, bool isPublic,
i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256);
AddressBook& GetAddressBook () { return m_AddressBook; };
const SAMBridge * GetSAMBridge () const { return m_SamBridge; };

View File

@@ -1,11 +1,16 @@
#include <string.h>
#include <string>
#include <vector>
#include <mutex>
#include <memory>
#include <openssl/sha.h>
#include <openssl/dh.h>
#include <openssl/md5.h>
#include <openssl/rand.h>
#include <openssl/crypto.h>
#include "TunnelBase.h"
#include <openssl/ssl.h>
#include "Log.h"
//#include "TunnelBase.h"
#include "Crypto.h"
namespace i2p
@@ -66,7 +71,44 @@ namespace crypto
const int rsae_ = 65537;
const CryptoConstants& GetCryptoConstants ()
struct CryptoConstants
{
// DH/ElGamal
BIGNUM * elgp;
BIGNUM * elgg;
// DSA
BIGNUM * dsap;
BIGNUM * dsaq;
BIGNUM * dsag;
// RSA
BIGNUM * rsae;
CryptoConstants (const uint8_t * elgp_, int elgg_, const uint8_t * dsap_,
const uint8_t * dsaq_, const uint8_t * dsag_, int rsae_)
{
elgp = BN_new ();
BN_bin2bn (elgp_, 256, elgp);
elgg = BN_new ();
BN_set_word (elgg, elgg_);
dsap = BN_new ();
BN_bin2bn (dsap_, 128, dsap);
dsaq = BN_new ();
BN_bin2bn (dsaq_, 20, dsaq);
dsag = BN_new ();
BN_bin2bn (dsag_, 128, dsag);
rsae = BN_new ();
BN_set_word (rsae, rsae_);
}
~CryptoConstants ()
{
BN_free (elgp); BN_free (elgg); BN_free (dsap); BN_free (dsaq); BN_free (dsag); BN_free (rsae);
}
};
static const CryptoConstants& GetCryptoConstants ()
{
static CryptoConstants cryptoConstants (elgp_, elgg_, dsap_, dsaq_, dsag_, rsae_);
return cryptoConstants;
@@ -81,6 +123,32 @@ namespace crypto
return true;
}
// RSA
#define rsae GetCryptoConstants ().rsae
const BIGNUM * GetRSAE ()
{
return rsae;
}
// DSA
#define dsap GetCryptoConstants ().dsap
#define dsaq GetCryptoConstants ().dsaq
#define dsag GetCryptoConstants ().dsag
DSA * CreateDSA ()
{
DSA * dsa = DSA_new ();
dsa->p = BN_dup (dsap);
dsa->q = BN_dup (dsaq);
dsa->g = BN_dup (dsag);
dsa->priv_key = NULL;
dsa->pub_key = NULL;
return dsa;
}
// DH/ElGamal
#define elgp GetCryptoConstants ().elgp
#define elgg GetCryptoConstants ().elgg
// DH
DHKeys::DHKeys (): m_IsUpdated (true)
@@ -573,7 +641,7 @@ namespace crypto
#else
m_IVEncryption.Encrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv
m_LayerEncryption.SetIV (out);
m_LayerEncryption.Encrypt (in + 16, /*i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE*/1008, out + 16); // data
m_LayerEncryption.Encrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data
m_IVEncryption.Encrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv
#endif
}
@@ -610,10 +678,37 @@ namespace crypto
#else
m_IVDecryption.Decrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv
m_LayerDecryption.SetIV (out);
m_LayerDecryption.Decrypt (in + 16, /*i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE*/1008, out + 16); // data
m_LayerDecryption.Decrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data
m_IVDecryption.Decrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv
#endif
}
/* std::vector <std::unique_ptr<std::mutex> > m_OpenSSLMutexes;
static void OpensslLockingCallback(int mode, int type, const char * file, int line)
{
if (type > 0 && (size_t)type < m_OpenSSLMutexes.size ())
{
if (mode & CRYPTO_LOCK)
m_OpenSSLMutexes[type]->lock ();
else
m_OpenSSLMutexes[type]->unlock ();
}
}*/
void InitCrypto ()
{
SSL_library_init ();
/* auto numLocks = CRYPTO_num_locks();
for (int i = 0; i < numLocks; i++)
m_OpenSSLMutexes.emplace_back (new std::mutex);
CRYPTO_set_locking_callback (OpensslLockingCallback);*/
}
void TerminateCrypto ()
{
/* CRYPTO_set_locking_callback (nullptr);
m_OpenSSLMutexes.clear ();*/
}
}
}

View File

@@ -6,64 +6,20 @@
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/aes.h>
#include <openssl/dsa.h>
#include "Base.h"
namespace i2p
{
namespace crypto
{
struct CryptoConstants
{
// DH/ElGamal
BIGNUM * elgp;
BIGNUM * elgg;
// DSA
BIGNUM * dsap;
BIGNUM * dsaq;
BIGNUM * dsag;
// RSA
BIGNUM * rsae;
CryptoConstants (const uint8_t * elgp_, int elgg_, const uint8_t * dsap_,
const uint8_t * dsaq_, const uint8_t * dsag_, int rsae_)
{
elgp = BN_new ();
BN_bin2bn (elgp_, 256, elgp);
elgg = BN_new ();
BN_set_word (elgg, elgg_);
dsap = BN_new ();
BN_bin2bn (dsap_, 128, dsap);
dsaq = BN_new ();
BN_bin2bn (dsaq_, 20, dsaq);
dsag = BN_new ();
BN_bin2bn (dsag_, 128, dsag);
rsae = BN_new ();
BN_set_word (rsae, rsae_);
}
~CryptoConstants ()
{
BN_free (elgp); BN_free (elgg); BN_free (dsap); BN_free (dsaq); BN_free (dsag); BN_free (rsae);
}
};
const CryptoConstants& GetCryptoConstants ();
// DH/ElGamal
#define elgp GetCryptoConstants ().elgp
#define elgg GetCryptoConstants ().elgg
bool bn2buf (const BIGNUM * bn, uint8_t * buf, size_t len);
// DSA
#define dsap GetCryptoConstants ().dsap
#define dsaq GetCryptoConstants ().dsaq
#define dsag GetCryptoConstants ().dsag
DSA * CreateDSA ();
// RSA
#define rsae GetCryptoConstants ().rsae
bool bn2buf (const BIGNUM * bn, uint8_t * buf, size_t len);
const BIGNUM * GetRSAE ();
// DH
class DHKeys
@@ -316,6 +272,9 @@ namespace crypto
CBCDecryption m_LayerDecryption;
#endif
};
void InitCrypto ();
void TerminateCrypto ();
}
}

View File

@@ -19,8 +19,7 @@
#include "HTTPServer.h"
#include "I2PControl.h"
#include "ClientContext.h"
// ssl.h somehow pulls Windows.h stuff that has to go after asio
#include <openssl/ssl.h>
#include "Crypto.h"
#ifdef USE_UPNP
#include "UPnP.h"
@@ -60,13 +59,12 @@ namespace i2p
bool Daemon_Singleton::init(int argc, char* argv[])
{
SSL_library_init ();
i2p::crypto::InitCrypto ();
i2p::util::config::OptionParser(argc, argv);
i2p::context.Init ();
LogPrint("\n\n\n\ni2pd starting\n");
LogPrint("Version ", VERSION);
LogPrint("data directory: ", i2p::util::filesystem::GetDataDir().string());
LogPrint(eLogInfo, "\n\n\n\ni2pd v", VERSION, " starting\n");
LogPrint(eLogDebug, "data directory: ", i2p::util::filesystem::GetDataDir().string());
i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs);
isDaemon = i2p::util::config::GetArg("-daemon", 0);
@@ -75,24 +73,29 @@ namespace i2p
int port = i2p::util::config::GetArg("-port", 0);
if (port)
i2p::context.UpdatePort (port);
const char * host = i2p::util::config::GetCharArg("-host", "");
if (host && host[0])
std::string host = i2p::util::config::GetArg("-host", "");
if (host != "")
i2p::context.UpdateAddress (boost::asio::ip::address::from_string (host));
i2p::context.SetSupportsV6 (i2p::util::config::GetArg("-v6", 0));
i2p::context.SetFloodfill (i2p::util::config::GetArg("-floodfill", 0));
i2p::context.SetAcceptsTunnels (!i2p::util::config::GetArg("-notransit", 0));
bool isFloodfill = i2p::util::config::GetArg("-floodfill", 0);
i2p::context.SetFloodfill (isFloodfill);
auto bandwidth = i2p::util::config::GetArg("-bandwidth", "");
if (bandwidth.length () > 0)
{
if (bandwidth[0] > 'L')
if (bandwidth[0] > 'O')
i2p::context.SetExtraBandwidth ();
else if (bandwidth[0] > 'L')
i2p::context.SetHighBandwidth ();
else
i2p::context.SetLowBandwidth ();
}
LogPrint("CMD parameters:");
else if (isFloodfill)
i2p::context.SetExtraBandwidth ();
LogPrint(eLogDebug, "Daemon: CMD parameters:");
for (int i = 0; i < argc; ++i)
LogPrint(i, " ", argv[i]);
LogPrint(eLogDebug, i, ": ", argv[i]);
return true;
}
@@ -111,61 +114,68 @@ namespace i2p
logfile_path.append("\\i2pd.log");
#endif
StartLog (logfile_path);
}
else
} else {
StartLog (""); // write to stdout
}
g_Log->SetLogLevel(i2p::util::config::GetArg("-loglevel", "info"));
}
d.httpServer = std::unique_ptr<i2p::util::HTTPServer>(new i2p::util::HTTPServer(i2p::util::config::GetArg("-httpport", 7070)));
LogPrint(eLogInfo, "Daemon: staring HTTP Server");
d.httpServer = std::unique_ptr<i2p::util::HTTPServer>(new i2p::util::HTTPServer(i2p::util::config::GetArg("-httpaddress", "127.0.0.1"), i2p::util::config::GetArg("-httpport", 7070)));
d.httpServer->Start();
LogPrint("HTTP Server started");
LogPrint(eLogInfo, "Daemon: starting NetDB");
i2p::data::netdb.Start();
LogPrint("NetDB started");
#ifdef USE_UPNP
LogPrint(eLogInfo, "Daemon: starting UPnP");
d.m_UPnP.Start ();
LogPrint(eLogInfo, "UPnP started");
#endif
LogPrint(eLogInfo, "Daemon: starting Transports");
i2p::transport::transports.Start();
LogPrint("Transports started");
LogPrint(eLogInfo, "Daemon: starting Tunnels");
i2p::tunnel::tunnels.Start();
LogPrint("Tunnels started");
LogPrint(eLogInfo, "Daemon: starting Client");
i2p::client::context.Start ();
LogPrint("Client started");
// I2P Control
int i2pcontrolPort = i2p::util::config::GetArg("-i2pcontrolport", 0);
if (i2pcontrolPort)
{
d.m_I2PControlService = std::unique_ptr<i2p::client::I2PControlService>(new i2p::client::I2PControlService (i2pcontrolPort));
LogPrint(eLogInfo, "Daemon: starting I2PControl");
d.m_I2PControlService = std::unique_ptr<i2p::client::I2PControlService>(new i2p::client::I2PControlService (i2p::util::config::GetArg("-i2pcontroladdress", "127.0.0.1"), i2pcontrolPort));
d.m_I2PControlService->Start ();
LogPrint("I2PControl started");
}
return true;
}
bool Daemon_Singleton::stop()
{
LogPrint("Shutdown started.");
LogPrint(eLogInfo, "Daemon: shutting down");
LogPrint(eLogInfo, "Daemon: stopping Client");
i2p::client::context.Stop();
LogPrint("Client stopped");
LogPrint(eLogInfo, "Daemon: stopping Tunnels");
i2p::tunnel::tunnels.Stop();
LogPrint("Tunnels stopped");
#ifdef USE_UPNP
LogPrint(eLogInfo, "Daemon: stopping UPnP");
d.m_UPnP.Stop ();
LogPrint(eLogInfo, "UPnP stopped");
#endif
LogPrint(eLogInfo, "Daemon: stopping Transports");
i2p::transport::transports.Stop();
LogPrint("Transports stopped");
LogPrint(eLogInfo, "Daemon: stopping NetDB");
i2p::data::netdb.Stop();
LogPrint("NetDB stopped");
LogPrint(eLogInfo, "Daemon: stopping HTTP Server");
d.httpServer->Stop();
d.httpServer = nullptr;
LogPrint("HTTP Server stopped");
if (d.m_I2PControlService)
{
LogPrint(eLogInfo, "Daemon: stopping I2PControl");
d.m_I2PControlService->Stop ();
d.m_I2PControlService = nullptr;
LogPrint("I2PControl stopped");
}
i2p::crypto::TerminateCrypto ();
StopLog ();
return true;

View File

@@ -63,7 +63,7 @@ namespace i2p
virtual bool stop();
private:
std::string pidfile;
int pidFilehandle;
int pidFH;
};
#endif

View File

@@ -17,17 +17,8 @@ void handle_signal(int sig)
switch (sig)
{
case SIGHUP:
if (i2p::util::config::GetArg("daemon", 0) == 1)
{
static bool first=true;
if (first)
{
first=false;
return;
}
}
LogPrint("Reloading config.");
i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs);
LogPrint(eLogInfo, "Daemon: Got SIGHUP, doing nothing");
// TODO:
break;
case SIGABRT:
case SIGTERM:
@@ -52,18 +43,25 @@ namespace i2p
::exit (EXIT_SUCCESS);
if (pid < 0) // error
{
LogPrint(eLogError, "Daemon: could not fork: ", strerror(errno));
return false;
}
// child
umask(0);
umask(S_IWGRP | S_IRWXO); // 0027
int sid = setsid();
if (sid < 0)
{
LogPrint("Error, could not create process group.");
LogPrint(eLogError, "Daemon: could not create process group.");
return false;
}
std::string d(i2p::util::filesystem::GetDataDir().string ()); // make a copy
chdir(d.c_str());
if (chdir(d.c_str()) != 0)
{
LogPrint(eLogError, "Daemon: could not chdir: ", strerror(errno));
return false;
}
// close stdin/stdout/stderr descriptors
::close (0);
@@ -75,22 +73,29 @@ namespace i2p
}
// Pidfile
pidfile = IsService () ? "/var/run" : i2p::util::filesystem::GetDataDir().string();
pidfile.append("/i2pd.pid");
pidFilehandle = open(pidfile.c_str(), O_RDWR | O_CREAT, 0600);
if (pidFilehandle == -1)
{
LogPrint("Error, could not create pid file (", pidfile, ")\nIs an instance already running?");
return false;
// this code is c-styled and a bit ugly, but we need fd for locking pidfile
pidfile = i2p::util::config::GetArg("-pidfile", "");
if (pidfile != "") {
pidFH = open(pidfile.c_str(), O_RDWR | O_CREAT, 0600);
if (pidFH < 0)
{
LogPrint(eLogError, "Daemon: could not create pid file ", pidfile, ": ", strerror(errno));
return false;
}
if (lockf(pidFH, F_TLOCK, 0) != 0)
{
LogPrint(eLogError, "Daemon: could not lock pid file ", pidfile, ": ", strerror(errno));
return false;
}
char pid[10];
sprintf(pid, "%d\n", getpid());
ftruncate(pidFH, 0);
if (write(pidFH, pid, strlen(pid)) < 0)
{
LogPrint(eLogError, "Daemon: could not write pidfile: ", strerror(errno));
return false;
}
}
if (lockf(pidFilehandle, F_TLOCK, 0) == -1)
{
LogPrint("Error, could not lock pid file (", pidfile, ")\nIs an instance already running?");
return false;
}
char pid[10];
sprintf(pid, "%d\n", getpid());
write(pidFilehandle, pid, strlen(pid));
// Signal handler
struct sigaction sa;
@@ -107,7 +112,6 @@ namespace i2p
bool DaemonLinux::stop()
{
close(pidFilehandle);
unlink(pidfile.c_str());
return Daemon_Singleton::stop();

View File

@@ -49,17 +49,17 @@ namespace i2p
if (isDaemon == 1)
{
LogPrint("Service session");
LogPrint(eLogDebug, "Daemon: running as service");
I2PService service(SERVICE_NAME);
if (!I2PService::Run(service))
{
LogPrint("Service failed to run w/err 0x%08lx\n", GetLastError());
LogPrint(eLogError, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError());
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
else
LogPrint("User session");
LogPrint(eLogDebug, "Daemon: running as user");
return true;
}
@@ -80,4 +80,4 @@ namespace i2p
}
}
#endif
#endif

View File

@@ -48,15 +48,13 @@ namespace datagram
m_Owner->RequestDestination (ident, std::bind (&DatagramDestination::HandleLeaseSetRequestComplete, this, std::placeholders::_1, msg));
}
void DatagramDestination::HandleLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> remote, I2NPMessage * msg)
void DatagramDestination::HandleLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> remote, std::shared_ptr<I2NPMessage> msg)
{
if (remote)
SendMsg (msg, remote);
else
DeleteI2NPMessage (msg);
}
void DatagramDestination::SendMsg (I2NPMessage * msg, std::shared_ptr<const i2p::data::LeaseSet> remote)
void DatagramDestination::SendMsg (std::shared_ptr<I2NPMessage> msg, std::shared_ptr<const i2p::data::LeaseSet> remote)
{
auto outboundTunnel = m_Owner->GetTunnelPool ()->GetNextOutboundTunnel ();
auto leases = remote->GetNonExpiredLeases ();
@@ -64,7 +62,7 @@ namespace datagram
{
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
uint32_t i = rand () % leases.size ();
auto garlic = m_Owner->WrapMessage (remote, ToSharedI2NPMessage (msg), true);
auto garlic = m_Owner->WrapMessage (remote, msg, true);
msgs.push_back (i2p::tunnel::TunnelMessageBlock
{
i2p::tunnel::eDeliveryTypeTunnel,
@@ -79,7 +77,6 @@ namespace datagram
LogPrint (eLogWarning, "Failed to send datagram. All leases expired");
else
LogPrint (eLogWarning, "Failed to send datagram. No outbound tunnels");
DeleteI2NPMessage (msg);
}
}
@@ -123,9 +120,9 @@ namespace datagram
HandleDatagram (fromPort, toPort, uncompressed, uncompressedLen);
}
I2NPMessage * DatagramDestination::CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort)
std::shared_ptr<I2NPMessage> DatagramDestination::CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort)
{
I2NPMessage * msg = NewI2NPMessage ();
auto msg = NewI2NPMessage ();
uint8_t * buf = msg->GetPayload ();
buf += 4; // reserve for length
size_t size = m_Deflator.Deflate (payload, len, buf, msg->maxLen - msg->len);
@@ -139,10 +136,7 @@ namespace datagram
msg->FillI2NPMessageHeader (eI2NPData);
}
else
{
DeleteI2NPMessage (msg);
msg = nullptr;
}
return msg;
}
}

View File

@@ -39,10 +39,10 @@ namespace datagram
private:
void HandleLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, I2NPMessage * msg);
void HandleLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, std::shared_ptr<I2NPMessage> msg);
I2NPMessage * CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort);
void SendMsg (I2NPMessage * msg, std::shared_ptr<const i2p::data::LeaseSet> remote);
std::shared_ptr<I2NPMessage> CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort);
void SendMsg (std::shared_ptr<I2NPMessage> msg, std::shared_ptr<const i2p::data::LeaseSet> remote);
void HandleDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
private:

View File

@@ -19,7 +19,10 @@ namespace client
m_Keys (keys), m_IsPublic (isPublic), m_PublishReplyToken (0),
m_DatagramDestination (nullptr), m_PublishConfirmationTimer (m_Service), m_CleanupTimer (m_Service)
{
i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey);
if (m_IsPublic)
PersistTemporaryKeys ();
else
i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey);
int inboundTunnelLen = DEFAULT_INBOUND_TUNNEL_LENGTH;
int outboundTunnelLen = DEFAULT_OUTBOUND_TUNNEL_LENGTH;
int inboundTunnelsQuantity = DEFAULT_INBOUND_TUNNELS_QUANTITY;
@@ -34,7 +37,7 @@ namespace client
if (len > 0)
{
inboundTunnelLen = len;
LogPrint (eLogInfo, "Inbound tunnel length set to ", len);
LogPrint (eLogInfo, "Destination: Inbound tunnel length set to ", len);
}
}
it = params->find (I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH);
@@ -44,7 +47,7 @@ namespace client
if (len > 0)
{
outboundTunnelLen = len;
LogPrint (eLogInfo, "Outbound tunnel length set to ", len);
LogPrint (eLogInfo, "Destination: Outbound tunnel length set to ", len);
}
}
it = params->find (I2CP_PARAM_INBOUND_TUNNELS_QUANTITY);
@@ -54,7 +57,7 @@ namespace client
if (quantity > 0)
{
inboundTunnelsQuantity = quantity;
LogPrint (eLogInfo, "Inbound tunnels quantity set to ", quantity);
LogPrint (eLogInfo, "Destination: Inbound tunnels quantity set to ", quantity);
}
}
it = params->find (I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY);
@@ -64,7 +67,7 @@ namespace client
if (quantity > 0)
{
outboundTunnelsQuantity = quantity;
LogPrint (eLogInfo, "Outbound tunnels quantity set to ", quantity);
LogPrint (eLogInfo, "Destination: Outbound tunnels quantity set to ", quantity);
}
}
it = params->find (I2CP_PARAM_EXPLICIT_PEERS);
@@ -79,14 +82,14 @@ namespace client
ident.FromBase64 (b64);
explicitPeers->push_back (ident);
}
LogPrint (eLogInfo, "Explicit peers set to ", it->second);
LogPrint (eLogInfo, "Destination: Explicit peers set to ", it->second);
}
}
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (this, inboundTunnelLen, outboundTunnelLen, inboundTunnelsQuantity, outboundTunnelsQuantity);
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (inboundTunnelLen, outboundTunnelLen, inboundTunnelsQuantity, outboundTunnelsQuantity);
if (explicitPeers)
m_Pool->SetExplicitPeers (explicitPeers);
if (m_IsPublic)
LogPrint (eLogInfo, "Local address ", GetIdentHash().ToBase32 (), " created");
LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created");
}
ClientDestination::~ClientDestination ()
@@ -94,7 +97,8 @@ namespace client
if (m_IsRunning)
Stop ();
for (auto it: m_LeaseSetRequests)
delete it.second;
if (it.second->requestComplete) it.second->requestComplete (nullptr);
m_LeaseSetRequests.clear ();
if (m_Pool)
i2p::tunnel::tunnels.DeleteTunnelPool (m_Pool);
if (m_DatagramDestination)
@@ -111,7 +115,7 @@ namespace client
}
catch (std::exception& ex)
{
LogPrint ("Destination: ", ex.what ());
LogPrint (eLogError, "Destination: runtime exception: ", ex.what ());
}
}
}
@@ -121,7 +125,7 @@ namespace client
if (!m_IsRunning)
{
m_IsRunning = true;
m_Pool->SetLocalDestination (this);
m_Pool->SetLocalDestination (shared_from_this ());
m_Pool->SetActive (true);
m_Thread = new std::thread (std::bind (&ClientDestination::Run, this));
m_StreamingDestination = std::make_shared<i2p::stream::StreamingDestination> (shared_from_this ()); // TODO:
@@ -174,7 +178,7 @@ namespace client
if (it->second->HasNonExpiredLeases ())
return it->second;
else
LogPrint ("All leases of remote LeaseSet expired");
LogPrint (eLogWarning, "Destination: All leases of remote LeaseSet expired");
}
else
{
@@ -198,7 +202,7 @@ namespace client
void ClientDestination::UpdateLeaseSet ()
{
m_LeaseSet.reset (new i2p::data::LeaseSet (*m_Pool));
m_LeaseSet.reset (new i2p::data::LeaseSet (m_Pool));
}
bool ClientDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag)
@@ -255,7 +259,7 @@ namespace client
size_t offset = DATABASE_STORE_HEADER_SIZE;
if (replyToken)
{
LogPrint (eLogInfo, "Reply token is ignored for DatabaseStore");
LogPrint (eLogInfo, "Destination: Reply token is ignored for DatabaseStore");
offset += 36;
}
std::shared_ptr<i2p::data::LeaseSet> leaseSet;
@@ -292,14 +296,13 @@ namespace client
}
}
else
LogPrint (eLogError, "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 (buf + DATABASE_STORE_KEY_OFFSET);
if (it1 != m_LeaseSetRequests.end ())
{
it1->second->requestTimeoutTimer.cancel ();
if (it1->second->requestComplete) it1->second->requestComplete (leaseSet);
delete it1->second;
m_LeaseSetRequests.erase (it1);
}
}
@@ -308,11 +311,11 @@ namespace client
{
i2p::data::IdentHash key (buf);
int num = buf[32]; // num
LogPrint ("DatabaseSearchReply for ", key.ToBase64 (), " num=", num);
LogPrint (eLogDebug, "Destination: DatabaseSearchReply for ", key.ToBase64 (), " num=", num);
auto it = m_LeaseSetRequests.find (key);
if (it != m_LeaseSetRequests.end ())
{
LeaseSetRequest * request = it->second;
auto request = it->second;
bool found = false;
if (request->excluded.size () < MAX_NUM_FLOODFILLS_PER_REQUEST)
{
@@ -322,30 +325,29 @@ namespace client
auto floodfill = i2p::data::netdb.FindRouter (peerHash);
if (floodfill)
{
LogPrint (eLogInfo, "Requesting ", key.ToBase64 (), " at ", peerHash.ToBase64 ());
LogPrint (eLogInfo, "Destination: Requesting ", key.ToBase64 (), " at ", peerHash.ToBase64 ());
if (SendLeaseSetRequest (key, floodfill, request))
found = true;
}
else
{
LogPrint (eLogInfo, "Found new floodfill. Request it");
LogPrint (eLogInfo, "Destination: Found new floodfill, request it"); // TODO: recheck this message
i2p::data::netdb.RequestDestination (peerHash);
}
}
if (!found)
LogPrint (eLogError, "Suggested floodfills are not presented in netDb");
LogPrint (eLogError, "Destination: Suggested floodfills are not presented in netDb");
}
else
LogPrint (eLogInfo, key.ToBase64 (), " was not found on ", MAX_NUM_FLOODFILLS_PER_REQUEST," floodfills");
LogPrint (eLogInfo, "Destination: ", key.ToBase64 (), " was not found on ", MAX_NUM_FLOODFILLS_PER_REQUEST, " floodfills");
if (!found)
{
if (request->requestComplete) request->requestComplete (nullptr);
delete request;
m_LeaseSetRequests.erase (key);
}
}
else
LogPrint ("Request for ", key.ToBase64 (), " not found");
LogPrint (eLogWarning, "Destination: Request for ", key.ToBase64 (), " not found");
}
void ClientDestination::HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
@@ -353,7 +355,7 @@ namespace client
uint32_t msgID = bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET);
if (msgID == m_PublishReplyToken)
{
LogPrint (eLogDebug, "Publishing confirmed");
LogPrint (eLogDebug, "Destination: Publishing LeaseSet confirmed");
m_ExcludedFloodfills.clear ();
m_PublishReplyToken = 0;
}
@@ -373,30 +375,30 @@ namespace client
{
if (!m_LeaseSet || !m_Pool)
{
LogPrint (eLogError, "Can't publish non-existing LeaseSet");
LogPrint (eLogError, "Destination: Can't publish non-existing LeaseSet");
return;
}
if (m_PublishReplyToken)
{
LogPrint (eLogInfo, "Publishing is pending");
LogPrint (eLogDebug, "Destination: Publishing LeaseSet is pending");
return;
}
auto outbound = m_Pool->GetNextOutboundTunnel ();
if (!outbound)
{
LogPrint ("Can't publish LeaseSet. No outbound tunnels");
LogPrint (eLogError, "Destination: Can't publish LeaseSet. No outbound tunnels");
return;
}
std::set<i2p::data::IdentHash> excluded;
auto floodfill = i2p::data::netdb.GetClosestFloodfill (m_LeaseSet->GetIdentHash (), m_ExcludedFloodfills);
if (!floodfill)
{
LogPrint ("Can't publish LeaseSet. No more floodfills found");
LogPrint (eLogError, "Destination: Can't publish LeaseSet, no more floodfills found");
m_ExcludedFloodfills.clear ();
return;
}
m_ExcludedFloodfills.insert (floodfill->GetIdentHash ());
LogPrint (eLogDebug, "Publish LeaseSet of ", GetIdentHash ().ToBase32 ());
LogPrint (eLogDebug, "Destination: Publish LeaseSet of ", GetIdentHash ().ToBase32 ());
RAND_bytes ((uint8_t *)&m_PublishReplyToken, 4);
auto msg = WrapMessage (floodfill, i2p::CreateDatabaseStoreMsg (m_LeaseSet, m_PublishReplyToken));
m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT));
@@ -411,7 +413,7 @@ namespace client
{
if (m_PublishReplyToken)
{
LogPrint (eLogWarning, "Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, "seconds. Try again");
LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds, will try again");
m_PublishReplyToken = 0;
Publish ();
}
@@ -434,7 +436,7 @@ namespace client
if (dest)
dest->HandleDataMessagePayload (buf, length);
else
LogPrint ("Missing streaming destination");
LogPrint (eLogError, "Destination: Missing streaming destination");
}
break;
case PROTOCOL_TYPE_DATAGRAM:
@@ -442,10 +444,10 @@ namespace client
if (m_DatagramDestination)
m_DatagramDestination->HandleDataMessagePayload (fromPort, toPort, buf, length);
else
LogPrint ("Missing streaming destination");
LogPrint (eLogError, "Destination: Missing datagram destination");
break;
default:
LogPrint ("Data: unexpected protocol ", buf[9]);
LogPrint (eLogError, "Destination: Data: unexpected protocol ", buf[9]);
}
}
@@ -527,52 +529,61 @@ namespace client
{
if (!m_Pool || !IsReady ())
{
if (requestComplete) requestComplete (false);
if (requestComplete) requestComplete (nullptr);
return false;
}
m_Service.post (std::bind (&ClientDestination::RequestLeaseSet, shared_from_this (), dest, requestComplete));
return true;
}
void ClientDestination::CancelDestinationRequest (const i2p::data::IdentHash& dest)
{
auto s = shared_from_this ();
m_Service.post ([dest, s](void)
{
auto it = s->m_LeaseSetRequests.find (dest);
if (it != s->m_LeaseSetRequests.end ())
s->m_LeaseSetRequests.erase (it);
});
}
void ClientDestination::RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete)
{
std::set<i2p::data::IdentHash> excluded;
auto floodfill = i2p::data::netdb.GetClosestFloodfill (dest, excluded);
if (floodfill)
{
LeaseSetRequest * request = new LeaseSetRequest (m_Service);
auto request = std::make_shared<LeaseSetRequest> (m_Service);
request->requestComplete = requestComplete;
auto ret = m_LeaseSetRequests.insert (std::pair<i2p::data::IdentHash, LeaseSetRequest *>(dest,request));
auto ret = m_LeaseSetRequests.insert (std::pair<i2p::data::IdentHash, std::shared_ptr<LeaseSetRequest> >(dest,request));
if (ret.second) // inserted
{
if (!SendLeaseSetRequest (dest, floodfill, request))
{
// request failed
if (request->requestComplete) request->requestComplete (nullptr);
delete request;
m_LeaseSetRequests.erase (dest);
}
}
else // duplicate
{
LogPrint (eLogError, "Request of ", dest.ToBase64 (), " is pending already");
LogPrint (eLogWarning, "Destination: Request of LeaseSet ", dest.ToBase64 (), " is pending already");
// TODO: queue up requests
if (request->requestComplete) request->requestComplete (nullptr);
delete request;
}
}
else
LogPrint (eLogError, "No floodfills found");
LogPrint (eLogError, "Destination: Can't request LeaseSet, no floodfills found");
}
bool ClientDestination::SendLeaseSetRequest (const i2p::data::IdentHash& dest,
std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, LeaseSetRequest * request)
std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request)
{
auto replyTunnel = m_Pool->GetNextInboundTunnel ();
if (!replyTunnel) LogPrint (eLogError, "No inbound tunnels found");
if (!replyTunnel) LogPrint (eLogError, "Destination: Can't send LeaseSet request, no inbound tunnels found");
auto outboundTunnel = m_Pool->GetNextOutboundTunnel ();
if (!outboundTunnel) LogPrint (eLogError, "No outbound tunnels found");
if (!outboundTunnel) LogPrint (eLogError, "Destination: Can't send LeaseSet request, no outbound tunnels found");
if (replyTunnel && outboundTunnel)
{
@@ -624,14 +635,13 @@ namespace client
}
else
{
LogPrint (eLogInfo, dest.ToBase64 (), " was not found within ", MAX_LEASESET_REQUEST_TIMEOUT, " seconds");
LogPrint (eLogWarning, "Destination: ", dest.ToBase64 (), " was not found within ", MAX_LEASESET_REQUEST_TIMEOUT, " seconds");
done = true;
}
if (done)
{
if (it->second->requestComplete) it->second->requestComplete (false);
delete it->second;
if (it->second->requestComplete) it->second->requestComplete (nullptr);
m_LeaseSetRequests.erase (it);
}
}
@@ -656,12 +666,40 @@ namespace client
{
if (!it->second->HasNonExpiredLeases ()) // all leases expired
{
LogPrint ("Remote LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired");
LogPrint (eLogWarning, "Destination: Remote LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired");
it = m_RemoteLeaseSets.erase (it);
}
else
it++;
}
}
void ClientDestination::PersistTemporaryKeys ()
{
auto path = i2p::util::filesystem::GetDefaultDataDir() / "destinations";
auto filename = path / (GetIdentHash ().ToBase32 () + ".dat");
std::ifstream f(filename.string (), std::ifstream::binary);
if (f)
{
f.read ((char *)m_EncryptionPublicKey, 256);
f.read ((char *)m_EncryptionPrivateKey, 256);
}
if (!f)
{
LogPrint (eLogInfo, "Creating new temporary keys for address ", GetIdentHash ().ToBase32 ());
i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey);
if (!boost::filesystem::exists (path))
{
if (!boost::filesystem::create_directory (path))
LogPrint (eLogError, "Failed to create destinations directory");
}
std::ofstream f1 (filename.string (), std::ofstream::binary | std::ofstream::out);
if (f1)
{
f1.write ((char *)m_EncryptionPublicKey, 256);
f1.write ((char *)m_EncryptionPrivateKey, 256);
}
}
}
}
}

View File

@@ -28,8 +28,8 @@ namespace client
const int PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds
const int LEASESET_REQUEST_TIMEOUT = 5; // in seconds
const int MAX_LEASESET_REQUEST_TIMEOUT = 40; // in seconds
const int MAX_NUM_FLOODFILLS_PER_REQUEST = 7;
const int DESTINATION_CLEANUP_TIMEOUT = 20; // in minutes
const unsigned int MAX_NUM_FLOODFILLS_PER_REQUEST = 7;
// I2CP
const char I2CP_PARAM_INBOUND_TUNNEL_LENGTH[] = "inbound.length";
@@ -73,6 +73,7 @@ namespace client
bool IsReady () const { return m_LeaseSet && m_LeaseSet->HasNonExpiredLeases () && m_Pool->GetOutboundTunnels ().size () > 0; };
std::shared_ptr<const i2p::data::LeaseSet> FindLeaseSet (const i2p::data::IdentHash& ident);
bool RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete = nullptr);
void CancelDestinationRequest (const i2p::data::IdentHash& dest);
// streaming
std::shared_ptr<i2p::stream::StreamingDestination> CreateStreamingDestination (int port); // additional
@@ -118,11 +119,12 @@ namespace client
void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
void RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete);
bool SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, 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 HandleCleanupTimer (const boost::system::error_code& ecode);
void CleanupRemoteLeaseSets ();
void PersistTemporaryKeys ();
private:
volatile bool m_IsRunning;
@@ -132,7 +134,7 @@ namespace client
i2p::data::PrivateKeys m_Keys;
uint8_t m_EncryptionPublicKey[256], m_EncryptionPrivateKey[256];
std::map<i2p::data::IdentHash, std::shared_ptr<i2p::data::LeaseSet> > m_RemoteLeaseSets;
std::map<i2p::data::IdentHash, LeaseSetRequest *> m_LeaseSetRequests;
std::map<i2p::data::IdentHash, std::shared_ptr<LeaseSetRequest> > m_LeaseSetRequests;
std::shared_ptr<i2p::tunnel::TunnelPool> m_Pool;
std::shared_ptr<i2p::data::LeaseSet> m_LeaseSet;

View File

@@ -61,7 +61,7 @@ namespace garlic
if (msgID == m_LeaseSetUpdateMsgID)
{
m_LeaseSetUpdateStatus = eLeaseSetUpToDate;
LogPrint (eLogInfo, "LeaseSet update confirmed");
LogPrint (eLogInfo, "Garlic: LeaseSet update confirmed");
}
else
CleanupExpiredTags ();
@@ -112,7 +112,7 @@ namespace garlic
std::shared_ptr<I2NPMessage> GarlicRoutingSession::WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg)
{
auto m = ToSharedI2NPMessage(NewI2NPMessage ());
auto m = NewI2NPMessage ();
m->Align (12); // in order to get buf aligned to 16 (12 + 4)
size_t len = 0;
uint8_t * buf = m->GetPayload () + 4; // 4 bytes for length
@@ -139,10 +139,10 @@ namespace garlic
// create message
if (!tagFound) // new session
{
LogPrint ("No garlic tags available. Use ElGamal");
LogPrint (eLogWarning, "Garlic: No tags available. Use ElGamal");
if (!m_Destination)
{
LogPrint ("Can't use ElGamal for unknown destination");
LogPrint (eLogError, "Garlic: Can't use ElGamal for unknown destination");
return nullptr;
}
// create ElGamal block
@@ -237,7 +237,7 @@ namespace garlic
m_Owner->DeliveryStatusSent (shared_from_this (), msgID);
}
else
LogPrint ("DeliveryStatus clove was not created");
LogPrint (eLogWarning, "Garlic: DeliveryStatus clove was not created");
}
// attach LeaseSet
if (m_LeaseSetUpdateStatus == eLeaseSetUpdated)
@@ -337,10 +337,10 @@ namespace garlic
size += 3;
}
else
LogPrint (eLogError, "No inbound tunnels in the pool for DeliveryStatus");
LogPrint (eLogError, "Garlic: No inbound tunnels in the pool for DeliveryStatus");
}
else
LogPrint ("Missing local LeaseSet");
LogPrint (eLogWarning, "Garlic: Missing local LeaseSet");
return size;
}
@@ -372,7 +372,7 @@ namespace garlic
uint32_t length = bufbe32toh (buf);
if (length > msg->GetLength ())
{
LogPrint (eLogError, "Garlic message length ", length, " exceeds I2NP message length ", msg->GetLength ());
LogPrint (eLogWarning, "Garlic: message length ", length, " exceeds I2NP message length ", msg->GetLength ());
return;
}
buf += 4; // length
@@ -389,7 +389,7 @@ namespace garlic
HandleAESBlock (buf + 32, length - 32, it->second, msg->from);
}
else
LogPrint (eLogError, "Garlic message length ", length, " is less than 32 bytes");
LogPrint (eLogWarning, "Garlic: message length ", length, " is less than 32 bytes");
m_Tags.erase (it); // tag might be used only once
}
else
@@ -407,7 +407,7 @@ namespace garlic
HandleAESBlock (buf + 514, length - 514, decryption, msg->from);
}
else
LogPrint (eLogError, "Failed to decrypt garlic");
LogPrint (eLogError, "Garlic: Failed to decrypt message");
}
// cleanup expired tags
@@ -427,7 +427,7 @@ namespace garlic
else
it++;
}
LogPrint (numExpiredTags, " tags expired for ", GetIdentHash().ToBase64 ());
LogPrint (eLogDebug, "Garlic: ", numExpiredTags, " tags expired for ", GetIdentHash().ToBase64 ());
}
m_LastTagsCleanupTime = ts;
}
@@ -442,7 +442,7 @@ namespace garlic
{
if (tagCount*32 > len)
{
LogPrint (eLogError, "Tag count ", tagCount, " exceeds length ", len);
LogPrint (eLogError, "Garlic: Tag count ", tagCount, " exceeds length ", len);
return ;
}
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
@@ -454,7 +454,7 @@ namespace garlic
uint32_t payloadSize = bufbe32toh (buf);
if (payloadSize > len)
{
LogPrint (eLogError, "Unexpected payload size ", payloadSize);
LogPrint (eLogError, "Garlic: Unexpected payload size ", payloadSize);
return;
}
buf += 4;
@@ -469,7 +469,7 @@ namespace garlic
SHA256 (buf, payloadSize, digest);
if (memcmp (payloadHash, digest, 32)) // payload hash doesn't match
{
LogPrint ("Wrong payload hash");
LogPrint (eLogError, "Garlic: wrong payload hash");
return;
}
HandleGarlicPayload (buf, payloadSize, from);
@@ -479,7 +479,7 @@ namespace garlic
{
const uint8_t * buf1 = buf;
int numCloves = buf[0];
LogPrint (numCloves," cloves");
LogPrint (eLogDebug, "Garlic: ", numCloves," cloves");
buf++;
for (int i = 0; i < numCloves; i++)
{
@@ -489,24 +489,24 @@ namespace garlic
if (flag & 0x80) // encrypted?
{
// TODO: implement
LogPrint ("Clove encrypted");
LogPrint (eLogWarning, "Garlic: clove encrypted");
buf += 32;
}
GarlicDeliveryType deliveryType = (GarlicDeliveryType)((flag >> 5) & 0x03);
switch (deliveryType)
{
case eGarlicDeliveryTypeLocal:
LogPrint ("Garlic type local");
LogPrint (eLogDebug, "Garlic: type local");
HandleI2NPMessage (buf, len, from);
break;
case eGarlicDeliveryTypeDestination:
LogPrint ("Garlic type destination");
LogPrint (eLogDebug, "Garlic: type destination");
buf += 32; // destination. check it later or for multiple destinations
HandleI2NPMessage (buf, len, from);
break;
case eGarlicDeliveryTypeTunnel:
{
LogPrint ("Garlic type tunnel");
LogPrint (eLogDebug, "Garlic: type tunnel");
// gwHash and gwTunnel sequence is reverted
uint8_t * gwHash = buf;
buf += 32;
@@ -521,15 +521,15 @@ namespace garlic
tunnel->SendTunnelDataMsg (gwHash, gwTunnel, msg);
}
else
LogPrint ("No outbound tunnels available for garlic clove");
LogPrint (eLogWarning, "Garlic: No outbound tunnels available for garlic clove");
break;
}
case eGarlicDeliveryTypeRouter:
LogPrint ("Garlic type router not supported");
LogPrint (eLogWarning, "Garlic: type router not supported");
buf += 32;
break;
default:
LogPrint ("Unknow garlic delivery type ", (int)deliveryType);
LogPrint (eLogWarning, "Garlic: unknown delivery type ", (int)deliveryType);
}
buf += GetI2NPMessageLength (buf); // I2NP
buf += 4; // CloveID
@@ -537,7 +537,7 @@ namespace garlic
buf += 3; // Certificate
if (buf - buf1 > (int)len)
{
LogPrint (eLogError, "Garlic clove is too long");
LogPrint (eLogError, "Garlic: clove is too long");
break;
}
}
@@ -601,7 +601,7 @@ namespace garlic
{
it->second->MessageConfirmed (msgID);
m_CreatedSessions.erase (it);
LogPrint (eLogInfo, "Garlic message ", msgID, " acknowledged");
LogPrint (eLogDebug, "Garlic: message ", msgID, " acknowledged");
}
}
}

View File

@@ -285,8 +285,8 @@ namespace proxy
}
}
HTTPProxyServer::HTTPProxyServer(int port, std::shared_ptr<i2p::client::ClientDestination> localDestination):
TCPIPAcceptor(port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ())
HTTPProxyServer::HTTPProxyServer(const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination):
TCPIPAcceptor(address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ())
{
}

View File

@@ -16,7 +16,7 @@ namespace proxy
{
public:
HTTPProxyServer(int port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr);
HTTPProxyServer(const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr);
~HTTPProxyServer() {};
protected:

View File

@@ -1,3 +1,5 @@
#include <ctime>
#include <iomanip>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
@@ -174,293 +176,7 @@ namespace util
const std::string HTTPConnection::itoopieFavicon =
"data:image/vnd.microsoft.icon;base64,"
"AAABAAEAQEAAAAEAIAAoQgAAFgAAACgAAABAAAAAgAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAABsAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgQAAAIMAAACEAAAAg"
"wAAAIAAAACCAAAASQAAACUAAAAmAAAAOwAAAFIAAABgAAAAVAAAACcAAAAVAAAADQAAAAcAAAADAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACjAAAA/wAAAP4AAAD+AAAA/gAAAP4AAAD+A"
"AAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/"
"AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAACbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAP8AA"
"AD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4A"
"AAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/wAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAKQAAAAAAAAAAAAAAAADbAAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP8AAAD/AAAA/gAA"
"AP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAIA/gAAAPwAAAD/AAAA/gAAAP4AAAD+AAAA/gA"
"AAP4AAAD+AAAA/wAAAFkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApAAAAAAAAAAAAHAAAAP8AAAD+AAAA/gAAAPwACwD9ABEA"
"/QASAPgAFgD4ABUA+AATAP0ADQD8AAIA/AAAAP8AAAD+AAAA/gAAAP8ADQD7ACMA/QAlAP8AJwD/ACI"
"A/QATAPwAAAD8AAAA/gAAAP4AAAD+AAAA/gAAAKIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADe"
"AAAA/gAAAPwAJAD+AAwA+wAAAP8AAAD/AAAA/wAEAPwAEgD8ACQA/gAmAP8AHAD8AAEA/gAAAP4ACwD"
"8ACUA/wAkAP8AFwD8AAkA/AAQAP0AIwD+ACQA/wANAPsAAAD+AAAA/gAAAP8AAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAEAAABNAAAA/wAAAP8AGAD8AAAA/QAYAPMARQDyAFEA9wBOAPIAPAD0ABEA8QAAAP8"
"AGgD7ACMA/wAVAP0AAAD9ACMA/QAkAP8ADwD9AAgA+ABBAPUALADyAAAA/AAUAPwAJgD/ABgA/AAAAP"
"0AAAD/AAAAdgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+AAAAP4ADQD8AAgA/wAqAPAAcAD/AGoA/wB"
"qAP8AagD/AGoA/wBvAP8ATwDvAAAA/QAbAP0AEwD8AAYA/QAkAP8AGAD8AAsA9wBuAPgAagD/AGsA/w"
"BjAPkADAD3AAQA/QAiAP4AGgD9AAAA/gAAAP8AAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZgAAAP8AAAD+ABY"
"A+wAQAPQAcQD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBTAPEAAAD/AAcA/AAMAPwAIQD9AA"
"AA+gBoAPgAagD/AGoA/wBqAP8AagD/AHAA/gAuAO0AAAD/AB8A/QAPAPwAAAD+AAAA+AAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAANIAAAD+AAwA+QAAAP0AZQD1AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8Abg"
"D/ABcA8QAAAP4ACAD9AAAA+QBeAPkAagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AbQD/ADkA7wAAAP8AJ"
"AD9AAAA/gAAAP8AAAAfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAALi8AAAAAAAAAAAAAAAD/AAAA/QAAAP8AKwD1AGsA/wBqAP8AagD/AGoA/wBqAP"
"8AagD/AGoA/wBqAP8AagD/AGoA/wA9APUAAAD/AAAA/wBKAPMAagD/AGoA/wBqAP8AagD/AGoA/wBqA"
"P8AagD/AGoA/wBxAP8ADgD1ABMA/AAHAPsAAAD/AAAARQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzPAIAAAAgAAAA/wAAAPwAAAD/AGQA9A"
"BqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8ASQD1AAAA/wASAPMAcAD/AGoA/"
"wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AawD/ACsA+QAOAP4ADQD8AAAA/wAAAEUAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7gAAAAAAAADgwAQAYLwAA//8AAA"
"ICIwAAAP8AAAD+AAYA8wBwAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/A"
"EIA9QAAAP8AMADvAGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGsA/wApAP0AEQD8"
"AAIA/QAAAP8AAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAVgEAAA"
"AAACJ5AQA2ygAAND8BAHV+AgAAAAAAAAH/AAAA/gAcAPQAbAD/AGoA/wBqAP8AagD/AGoA/wBqAP8Aa"
"gD/AGoA/wBqAP8AagD/AGsA/wApAPYAAAD+AB4A+gBsAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8A"
"agD/AGoA/wBrAP8ALADxAAAA/AAAAP4AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAABYAhQAfAE8ABgBWAQAAAAAAIoABAAAAAAA5UgEAAAAAAAAA+AAAAP4AJQD2AGsA/wBqA"
"P8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBsAPgAAAD6AAAA/gANAPAAbgD/AGoA/wBq"
"AP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/ADsA+QAAAP8AAAD+AAAA4AAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtQAAAAAAAABYABgAZgEGAIMBAAAAAAA+fgEAAAAAAAAAA"
"AACA8wAAAH+ACkA9wBgAPgARQDwADoA9gA5APYASgD0AHAA9wBrAP8AagD/AGoA/wBxAP0AFQD0AAAA"
"/gAAAP4AAAD5AHMA/QBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBvAP0ATgDxAEwA9AA1AOkAAAD/AAA"
"A/gAAAP8AAAB3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAvAAzAKcBAADXAAAAAAAcAFYBF"
"gB4ASAAZwEAXT8BADpdAgAAAAAAAQG+AAEB/gAAAf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAPsAJAD1"
"AEQA9ABEAPMACQD3AAAA/wAAAP4AAAD+AAAA/wAiAPMASAD4AE8A9gBuAPgAbQD/AGoA/wBvAP8AFQD"
"yAAAA/wAAAP8AAAD/AAAA/gAAAP4AAAD+AAAA/wAAABoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAABgCuAQAAAAAAAAAAAAAAACEAkQIWAJMBGQBXAQCWlAIAAAAAAAAA7gABAf4AAQD+AAAA/wAAAP8A"
"AAD0AAAA/gAAAP8AAAD/AAAA/gAAAP8AAAD/AAAA/gAAAP4IAAn9JwAs/TsARP5CAEz+PQBG/ioAMP4"
"EAAX6ABkA9gBAAPUAUwDrAAAA/wADEfUAFXztAA5U9wAAAPcAAAD/AAAA/gAAAP4AAACYAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAABcAugAkALIAAAAAAAAAAAAJABQAHwCaAR8AhwMNKUwCAAMDRgAB"
"Af8AAAD+AAAA+QAbn/MAK/zwACz//wAs//cAIMDkAAAA+QAAAP4AAAD+CAAK/V0Aav6TAKn+nQC0/5c"
"Arf+VAKv/lACq/5QAq/+WAK3/nwC3/4IAlv5FAE/+AAAA/wAAAP8AHKnzACnx/wAq9v8ALP/5AAo+9A"
"AAAP4AAAD+AAAA7QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACtAQAAAAAAAKoACABt"
"AQwAYwAAAAAAAQAERQAAAP8AAAD+AAAA/wAfuPEAKfL/ACnz/wAq+v8AIsrwAAEH9gAAAP4AAAD+JAA"
"p/ZoAsf+TAKj/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/lACq/0sAVv4AAAD/AC"
"PQ8gAp8/8AKfP/ACny/wAYke4AAAD/AAAA/gAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAgAAAAK0AAAAAAGsA/wAAAAAAAAACSgAAAf8AAQH+AAAA/gAAAP8AGZHnACfm+AAdqvIACjz"
"tAAAA/wAAAP4AAAD+CgAL/ZwAtP+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAK"
"n/kwCp/5IAqP9OAFn+AAAA/wAetPMAKfP/ACny/wAq+PcAAQfyAAAA/gAAAP4AAAD/AAAAEgAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKkAAAAAAAUAFwAAAAAAAAABeQAAAP8AAAH+AAAA/wMBBf0"
"AAAH+AAAA/wAAAP8AAAD/AAEB/gAAAP4AAAD9AAAB/k4AWv6SAKj/kwCp/5MAqf+TAKn/kwCp/5MAqf"
"+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/ZwB2/gAAAP4ACC32ACHC9AAZk/AAAQX3AAAA/gAAA"
"P4AAAD+AAAA/wAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUAYQEAAAAAAAAAwAA"
"AAP8BAAH+EwAV/YkAnfJ6AIzzBQAH/QAAAP4AAAD+AAEB/gARF/0Aa5P9AMb//gACAv4oAC7+lwCu/5"
"MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5oAsv8YABv9AAAA/"
"gAAAP8AAAD/AAAA/ksAVv0SABX9AAAA/gAAAP8AAABmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAEAAAATAAAA6AAAAP0AAAD+IgAo+5oAsfCSAKnxlQCr8RYAGvwAAQH+AAAA/gAAAP4AQFf9AL"
"r//wC3/P8AXn79AAAA/o8ApP6TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/k"
"wCp/5MAqf+TAKn/mgCx/0QATv4AAAD+AAAA/gAAAP2gALj/WQBn/gAAAP4AAAD+AAAAtwAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAAAA9gAAAP0AAAD+HwAk+5wAs/CSAKnxkwCp8VEAXfcAAA"
"D+AAAB/gAAAP4AAQH+AAAA/QDD//8At/v/ALDz/gAAAP5aAGf+kwCo/5MAqf+TAKn/kwCp/5MAqf+TA"
"Kn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf9sAHz+AAAA/gAAAP4AAAD9nwC3/5YArf8A"
"AAD+AAAA/gAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2AAAAP0AAAD+AAAA/pgAr/"
"CTAKnxkwCp8ZIAqPGHAJvyAAAA/wAAAP4AAAD+AAEB/gAAAP4Ae6X9ALb7/wC+//8AJjX9KgAw/ZcAr"
"f+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/mQCv/wAA"
"AP4AAAD+AAAA/Z8Atv+YAK//HwAk/QAAAP4AAAD/AAAAZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHA"
"AAAP8AAAD+AAAA/gAAAP+RAKbxkgCo8ZMAqfGTAKnxkgCo8XYAiPQEAAX+AAAA/yUAK/sBAAH+ACg3/"
"QC+//8Atvr/AG6W/QAAAP6YAK//kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp"
"/5MAqf+TAKn/kwCp/5MAqf9oAHf+AAAA/kAASf6UAKv/kwCp/0cAUv4AAAD+AAAA/gAAAMkAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAACRAAAA/wAAAP4AAAD+BQAG/nsAjfOUAKrxkwCp8ZMAqfGTAKjxn"
"QC08JcArvCYAK/xSQBU9wAAAP4Aqen+ALf7/wC3+v4AAAD+WwBo/pMAqf+TAKn/kwCp/5MAqf+TAKn/"
"kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5wAs/6ZAK//kwCp/5MAqf9bAGj"
"+AAAA/gAAAP4AAAD/AAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE0AAAD7AAAA/QAAAP4AA"
"AD/TABY+J0AtPCTAKnxkwCp8ZMAqfGTAKnxkwCp8Y4ApPEAAAD/AFRx/QC4/P8Avf//AC0+/RQAGP2c"
"ALP/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+"
"TAKn/kwCp/5MAqf+TAKn/YQBv/wAAAP4AAAD+AAAA/wAAAG0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAABAAAAAAAAALgAAAD/AAAA/gABAP4bAB78jwCk8pMAqfGTAKnxkwCp8ZMAqfGXAK3xKwAy+wAC"
"BP0Axv//ALb6/wBvlf0AAAD+dwCJ/p8Atv+dALT+lgCt/p4Atv6eALb/lwCu/5MAqf+TAKn/kwCp/5M"
"Aqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCo/1IAXv0AAAD+AAAA/gAAAP4AAACRAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATgAAAP8AAAD9AAAB/gAAAP5ZAGf2ngC1"
"8JMAqfGTAKnxkwCp8WAAb/UAAAD+AJLH/gC3+/8As/X+AAAA/gsADP0AAAD9AAAA/gAAAP4AAAD+AQA"
"C/SMAKP1NAFj+gQCU/pwAs/+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5sAsv8cACH9AA"
"AA/gAAAP4AAAD/AAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO"
"AAAA1QAAAP8AAAD+AAAA/hMAFfxzAIT0nQC08JMAqfF5AIrzAAAA/gA6T/0Au///ALn//wBkh/4AERj"
"9ACs7/QBFX/0AT2z9AElk/gAxQ/0AAgT9AAAA/gAAAP4UABf9bwCA/pcArv+TAKn/kwCp/5MAqf+TAK"
"n/kwCp/5MAqv9rAHr+AAAA/gAAAP4AAAD/AAAAhgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB+AAAA/wAAAP4AAAD+AAAA/hQAF/xJAFP4GwAf/AAAAP4"
"ABgn9AMP//wC3+/8Auf7/AML//wC8//8Auf7/ALj9/wC5/v8AvP//AMb//wCj4P0AWnj9AAAA/QAAAP"
"42AD/9mgCx/5MAqP+TAKn/lACq/54Atv9YAGX+AAAA/gAAAP4AAAD/AAAArAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAh4AAADVAAAA/gA"
"AAP4AAAD+AAAA/gAAAP4AEhr9AJ3V/gC3+v8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/w"
"C3+/8At/v/ALf8/wDB//8AYYT9AAAA/ggACv1cAGn+bAB9/UEAS/4CAAL+AAAA/gAAAP4AAAD/AAAAl"
"gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAABAAEBFAAAAP8AAAD+AAAA/gAAAP4AUGz9AML//wC2+/8At/v/ALf7/wC3+/8At/v/AL"
"f7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf8/wCq5v4AERj+AAEA/gAAAP4AAAD+A"
"AAA/gAAAP4AAAD/AAAAdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOgAAAD+AAAA/gAAAP4Aeqf9ALz//wC3+/8At/"
"v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At"
"/r/ALz//gAcJvwAAQH+AAAA/gAAAP4AAAD/AAAAfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI0AAAD/AAAA/gAAAP"
"4Ac579ALn+/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+"
"/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8Avf/+ABcg/QAAAf4AAAD+AAAA/wAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAABIAAAD/AAAA/gAAAP4AP1X9AL7//wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/"
"wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wCy8v4AAAD+AAAA"
"/gAAAP8AAACKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAACoAAAA/QAAAP4ABAb9AL7//wC3+/8At/v/ALf7/wC3+/8At/v/A"
"Lf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/"
"ALf7/wC3+/8Atvr/AHmm/QAAAP4AAAD+AAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAA/wAAAP4AAAD+AHWh/QC2+v8At"
"/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8A"
"t/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wDD//8AGSP9AAAA/gAAAP8AAABuAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbQAAA"
"P8AAAD+AAUH/QDE//8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3"
"+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8Atvv/AH+s/gA"
"AAP4AAAD+AAAA2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAALMAAAD+AAAA/gBZd/0At/z/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7"
"/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf"
"7/wC3+/8At/v/ALf7/wDF//8AAAD9AAAA/gAAAP8AAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwAAAA/gAAAP4Al9D9ALf7/wC3+/8At/v/"
"ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v"
"/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8Auf7/AERe/QAAAP4AAAD/AAAAUQAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP4A"
"AAD9AMb//gC3+/8At/v/ALf7/wC3+/8Auf7/AMb//gC2+f4AwP/+AMT//wC4/f8At/v/ALf7/wC3+/8"
"At/v/ALf7/wC3+/8At/v/ALf7/wC8//8Avf//ALn+/wC3+/8At/v/ALf7/wC3+/8At/v/ALb7/wBvlf"
"4AAAD+AAAA/gAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAACgAAAP8AAAD+ABgg/QDA//8At/v/ALf7/wC2+v8AuPz+AEVe/QAAAP0AAAD+AAAA/gA"
"EBv0AU2/9ALz//wC3+/8At/v/ALf7/wC3+/8Atvr/AL7//wBmi/0ALj/9ACQx/QBJZP0Ai739AMD//w"
"C3+/8At/v/ALf7/wC3+/8Aksj+AAAA/gAAAP4AAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABcAAAD/AAAA/gAtPf4AvP//ALf7/wC3+/8As/T+AAo"
"O/QAAAP0SEhLtAAAA/gAAAP4AAAD+AAAA/gAWH/0Av///ALf7/wC3+/8At/v/ALHx/gANEv0AAAD+AA"
"AA/gAAAP4AAAD/AAAA/wAuP/0Avv//ALf7/wC3+/8At/v/AKjm/QAAAP4AAAD+AAAApwAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATAAAA/wAAAP4AL0H"
"+ALz//wC3+/8AvP//ADJE/QAAAPfc3Nz1TExM6wAAAP4AAAD+AAAA/gAAAP8AAAD+AGeN/gC3+/8At/"
"v/AML//wAeKf0AAAH/AAAA/gAAAP4AAAD+cXFx3YSEhOoAAAD9AEVe/QC6//8At/v/ALf7/wCs7P8AA"
"AD+AAAA/gAAAKEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAP8AAAD+ACAt/QC+//8At/v/ALP1/gAAAP95eXns/////2FhYeoBAQH/AAAA/gEBAf"
"9eXl7lDQ0N9gAgLP0Av///ALf7/wCNwf4AAAD/NDQ03AAAAP8AAAD+AAAA/6Ojo+b/////eXl55AAAA"
"P8AtPf+ALf7/wC3+/8AoNv9AAAA/gAAAP4AAACHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/gAAAP0Ax///ALf7/wCIu/0AAAD/ysrK6/"
"/////8/Pz6Hx8f6wAAAP8kJCTm/f39/WVlZe4ABAX8AMT//wC3/P8AV3X9ERER7/////9MTEzrAAAA6"
"ElJSeb///////////X19e8AAAD/AHuo/QC3+/8At/v/AIW2/gAAAP4AAAD/AAAAZAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0wAAAP4AAAD+AK"
"fl/gC3+/8AjcH+AAAA/83Nze/////////////////////w//////////9gYGDsAA8V/QDC//8Auv//A"
"EJa/UFBQeb////////////////////////////////////vAAAA/wBvlfwAt/v/ALf7/wBdff0AAAD+"
"AAAA/wAAAC0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAI4AAAD+AAAA/gBnjP0At/v/ALz//gAAAP+CgoLx/////////////////////////////"
"///CAkJ8QBCXP4Auf7/ALj8/wBScf0DAwPw////////////////////////////////tra26AAAAP8A"
"hrf+ALf7/wDA//8AHCf9AAAA/gAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3AAAA/wAAAP4AEBb9AMT//wC6//8AQVn+AAAA9+Pj4"
"/L/////////////////////cnJy1gAAAP8AlMr9ALf7/wC3+/8AhLT+AAAA/5mZmeL/////////////"
"/////////////R0dHesAAAD9AL///gC3+/8ApuX+AAAA/gAAAP4AAAC1AAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMAAAD+AAAA/"
"gCGtv0Atvr/ALn+/wARF/0AAAD3cHBw7bGxseqioqLuOjo67QAAAP8ARFz9ALz//wC3+/8At/v/AML/"
"/wAbJf0AAAD/jo6O5v////b//////f397zw8PPEAAAD/AGCC/QC4/P8Auv//AEJb/QAAAP4AAAD/AAA"
"AUQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAABpAAAA/wAAAP4AERf9AMP//wC3+/8Auv/+AEVf/AAAAP8AAAD/AAAA/wAAAP0AWnn9"
"AMH//wC3+/8At/v/ALf7/wC3+/8AtPf+ABsm/QAAAP8AAADwDg4O+QAAAPwAAAD+AD1T/QDB//8At/v"
"/AKLd/gAAAP4AAAD+AAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPIAAAD+AAAA/gBfgP0Auf7/ALf7/wC5/v8A"
"wv//AJnS/gCWzv4Awf//ALj9/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wDC//8Ahbb+AFBt/QA3TP0"
"ATGn9AI/D/gC+//8At/v/AMD//wATGv0AAAD+AAAA/wAAAE4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAA9AAAA/wAA"
"AP4AAAD+AJPJ/QC2+v8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC"
"3+/8At/v/ALf7/wC4/f8Au///ALj9/wC3+/8At/v/AML//wA0SP0AAAD+AAAA/QAAAMMAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAJYAAAD/AAAA/gAAAP4Andj9ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf"
"7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/AML//wA+Vf0AAAD+AA"
"AA/gAAAPYAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwwAAAP4AAAD+AAAA/gCGt/0AvP/"
"/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8Atv"
"r/ALr//gAoNv0AAAD+AAAA/gAAAP8AAAAeAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAC9AAAA/wAAAP4AAAD+AEFY/QC6/f4At/z/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/"
"8At/v/ALf7/wC2+v8Aw///AICv/gAEBv0AAAH+AAAA/QAAAP8AAAAiAAAAAQAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIMAAAD/AAAA/gAAAP4AAAD9AFl3/QCt7/4AwP//ALj9/w"
"C2+/8At/v/ALf7/wC3+/8At/v/ALz//wDB//4AeKP+ABki/QAAAP4AAAD+AAAA/wAAAOEAAAASAAAAA"
"QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALAAAAOUAAAD/AA"
"AA/gAAAP4AAAD+ABcg/QBQbv0AbJD9AH2s/gCBsP0Ac5v+AFt6/QAtPv0AAAD9AAAA/gAAAP4AAAD+A"
"AAA/wAAAIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAWgAAAOIAAAD/AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AA"
"AD+AAAA/gAAAP8AAAD/AAAAmQAAAAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAIgAAADRAAAA/wAAA"
"P8AAAD/AAAA/wAAAP8AAAD/AAAA5QAAAJoAAABWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAHAAAAIAAAACQAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///gAf///////4AAAAD/////wAAAAP////"
"/AAAAB/////+AAAAH/////4AAAA//////gAAAD/////8AAAAH/////wAAAAP////+AAAAA/////4AAA"
"AD/////gAAAAP////+AAAAA/////4AAAAD/////gAAAAP////+AAAAA/////4AAAAB/////gAAAAD//"
"//+AAAAAP////wAAAAA////+AAAAAD////wAAAAAP///8AAAAAA////gAAAAAB///8AAAAAAH///gAA"
"AAAAf//+AAAAAAA///4AAAAAAD///4AAAAAAP///wAAAAAAf///wAAAAAD////gAAAAAP////gAAAAB"
"/////AAAAAP////+AAAAD/////wAAAAf////+AAAAB/////4AAAAD/////AAAAAP////8AAAAA/////"
"wAAAAB////+AAAAAH////4AAAAAf////gAAAAA////+AAAAAD////4AAAAAP////gAAAAA////+AAAA"
"AD////4AAAAAf////gAAAAB////+AAAAAH////8AAAAAf////wAAAAD/////gAAAAP////+AAAAB///"
"//8AAAAH/////wAAAA//////gAAAH//////AAAA//////+AAAH//////+AAA///////+AAP///////+"
"AH//////////////8=";
"";
const char HTTP_COMMAND_TUNNELS[] = "tunnels";
const char HTTP_COMMAND_TRANSIT_TUNNELS[] = "transit_tunnels";
@@ -488,21 +204,25 @@ namespace util
std::vector<boost::asio::const_buffer> buffers;
if (headers.size () > 0)
{
status_string = "HTTP/1.1 ";
status_string += std::to_string (status);
status_string += " ";
switch (status)
{
case 105: buffers.push_back(boost::asio::buffer("HTTP/1.1 105 Name Not Resolved\r\n")); break;
case 200: buffers.push_back(boost::asio::buffer("HTTP/1.1 200 OK\r\n")); break;
case 400: buffers.push_back(boost::asio::buffer("HTTP/1.1 400 Bad Request\r\n")); break;
case 404: buffers.push_back(boost::asio::buffer("HTTP/1.1 404 Not Found\r\n")); break;
case 408: buffers.push_back(boost::asio::buffer("HTTP/1.1 408 Request Timeout\r\n")); break;
case 500: buffers.push_back(boost::asio::buffer("HTTP/1.1 500 Internal Server Error\r\n")); break;
case 502: buffers.push_back(boost::asio::buffer("HTTP/1.1 502 Bad Gateway\r\n")); break;
case 503: buffers.push_back(boost::asio::buffer("HTTP/1.1 503 Not Implemented\r\n")); break;
case 504: buffers.push_back(boost::asio::buffer("HTTP/1.1 504 Gateway Timeout\r\n")); break;
default:
buffers.push_back(boost::asio::buffer("HTTP/1.1 200 OK\r\n"));
case 105: status_string += "Name Not Resolved"; break;
case 200: status_string += "OK"; break;
case 400: status_string += "Bad Request"; break;
case 404: status_string += "Not Found"; break;
case 408: status_string += "Request Timeout"; break;
case 500: status_string += "Internal Server Error"; break;
case 502: status_string += "Bad Gateway"; break;
case 503: status_string += "Not Implemented"; break;
case 504: status_string += "Gateway Timeout"; break;
default: status_string += "WTF";
}
buffers.push_back(boost::asio::buffer(status_string, status_string.size()));
buffers.push_back(boost::asio::buffer(misc_strings::crlf));
for (std::size_t i = 0; i < headers.size(); ++i)
{
header& h = headers[i];
@@ -520,14 +240,9 @@ namespace util
void HTTPConnection::Terminate ()
{
if (!m_Stream) return;
m_Socket->close ();
m_Stream->Close ();
m_Socket->get_io_service ().post ([=](void)
{
m_Stream.reset ();
m_Stream = nullptr;
});
m_Stream = nullptr;
m_Socket->close ();
}
void HTTPConnection::Receive ()
@@ -596,7 +311,7 @@ namespace util
{
end = str.find ('&', pos);
std::string param = str.substr (pos, end - pos);
LogPrint (param);
LogPrint (eLogDebug, "HTTPServer: extracted parameters: ", param);
size_t e = param.find ('=');
if (e != std::string::npos)
params[param.substr(0, e)] = param.substr(e+1);
@@ -631,10 +346,20 @@ namespace util
std::stringstream s;
// Html5 head start
s << "<!DOCTYPE html>\n<html lang=\"en\">"; // TODO: Add support for locale.
s << "<head><meta charset=\"utf-8\" />"; // TODO: Find something to parse html/template system. This is horrible.
s << "<link rel='shortcut icon' href='";
s << itoopieFavicon;
s << "' /><title>Purple I2P " << VERSION " Webconsole</title></head>";
s << "<head><meta charset=\"utf-8\">"; // TODO: Find something to parse html/template system. This is horrible.
// s << "<link rel='shortcut icon' href='";
// s << itoopieFavicon;
// s << "' />";
s << "<title>Purple I2P " << VERSION " Webconsole</title>";
s << "<style>";
s << "body {font: 100%/1.5em sans-serif; margin: 0; padding: 0; background: #FAFAFA;}";
s << "a {text-decoration: none;}";
s << "body, a {color: #103456}";
s << ".header {font-size: 2.5em; text-align: center; margin: 1.5em 0; color: #894C84;}";
s << ".wrapper {margin: 0 auto; padding: 1em; max-width: 48em;}";
s << ".left {width: 28em; float:left;}";
s << "</style>";
s << "</head>";
// Head end
if (address.length () > 1)
HandleCommand (address.substr (2), s);
@@ -646,7 +371,9 @@ namespace util
void HTTPConnection::FillContent (std::stringstream& s)
{
s << "<h2>Welcome to the Webconsole!</h2><br>";
s << "<div class=header><b>i2pd </b>webconsole</div>";
s << "<div class=wrapper>";
s << "<div class=left>";
s << "<b>Uptime:</b> " << boost::posix_time::to_simple_string (
boost::posix_time::time_duration (boost::posix_time::seconds (
i2p::context.GetUptime ()))) << "<br>";
@@ -687,25 +414,22 @@ namespace util
}
s << address.host.to_string() << ":" << address.port << "<br>";
}
s << "<br><b>Routers:</b> <i>" << i2p::data::netdb.GetNumRouters () << "</i> ";
s << "<b>Floodfills:</b> <i>" << i2p::data::netdb.GetNumFloodfills () << "</i> ";
s << "<b>LeaseSets:</b> <i>" << i2p::data::netdb.GetNumLeaseSets () << "</i><br>";
s << "<br><b><a href=/?" << HTTP_COMMAND_LOCAL_DESTINATIONS << ">Local destinations</a></b>";
s << "<br><b><a href=/?" << HTTP_COMMAND_TUNNELS << ">Tunnels</a></b>";
s << "<br><b><a href=/?" << HTTP_COMMAND_TRANSIT_TUNNELS << ">Transit tunnels</a></b>";
s << "<br><b><a href=/?" << HTTP_COMMAND_TRANSPORTS << ">Transports</a></b>";
s << "<br><b>Routers:</b> " << i2p::data::netdb.GetNumRouters () << " ";
s << "<b>Floodfills:</b> " << i2p::data::netdb.GetNumFloodfills () << " ";
s << "<b>LeaseSets:</b> " << i2p::data::netdb.GetNumLeaseSets () << "<br>";
s << "</div><div>";
s << "[ <a href=/?" << HTTP_COMMAND_LOCAL_DESTINATIONS << ">Local destinations</a> ]<br>";
s << "[ <a href=/?" << HTTP_COMMAND_TUNNELS << ">Tunnels</a> ]<br>";
s << "[ <a href=/?" << HTTP_COMMAND_TRANSIT_TUNNELS << ">Transit tunnels</a> ]<br>";
s << "[ <a href=/?" << HTTP_COMMAND_TRANSPORTS << ">Transports</a> ]<br>";
if (i2p::client::context.GetSAMBridge ())
s << "<br><b><a href=/?" << HTTP_COMMAND_SAM_SESSIONS << ">SAM sessions</a></b>";
s << "<br>";
s << "[ <a href=/?" << HTTP_COMMAND_SAM_SESSIONS << ">SAM sessions</a> ]<br><br>";
if (i2p::context.AcceptsTunnels ())
s << "<br><b><a href=/?" << HTTP_COMMAND_STOP_ACCEPTING_TUNNELS << ">Stop accepting tunnels</a></b><br>";
s << "[ <a href=/?" << HTTP_COMMAND_STOP_ACCEPTING_TUNNELS << ">Stop accepting tunnels</a> ]<br><br>";
else
s << "<br><b><a href=/?" << HTTP_COMMAND_START_ACCEPTING_TUNNELS << ">Start accepting tunnels</a></b><br>";
s << "<br><b><a href=/?" << HTTP_COMMAND_RUN_PEER_TEST << ">Run peer test</a></b><br>";
s << "<p><a href=\"zmw2cyw2vj7f6obx3msmdvdepdhnw2ctc4okza2zjxlukkdfckhq.b32.i2p\">Flibusta</a></p>";
s << "[ <a href=/?" << HTTP_COMMAND_START_ACCEPTING_TUNNELS << ">Start accepting tunnels</a> ]<br><br>";
s << "[ <a href=/?" << HTTP_COMMAND_RUN_PEER_TEST << ">Run peer test</a> ]<br><br>";
s << "</div></div></body>";
}
void HTTPConnection::HandleCommand (const std::string& command, std::stringstream& s)
@@ -771,7 +495,6 @@ namespace util
s << "<br>SSU<br>";
for (auto it: ssuServer->GetSessions ())
{
// incoming connections don't have remote router
auto endpoint = it.second->GetRemoteEndpoint ();
if (it.second->IsOutgoing ()) s << "-->";
s << endpoint.address ().to_string () << ":" << endpoint.port ();
@@ -779,8 +502,17 @@ namespace util
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
if (it.second->GetRelayTag ())
s << " [itag:" << it.second->GetRelayTag () << "]";
s << "<br>";
s << std::endl;
s << "<br>" << std::endl;
}
s << "<br>SSU6<br>";
for (auto it: ssuServer->GetSessionsV6 ())
{
auto endpoint = it.second->GetRemoteEndpoint ();
if (it.second->IsOutgoing ()) s << "-->";
s << endpoint.address ().to_string () << ":" << endpoint.port ();
if (!it.second->IsOutgoing ()) s << "-->";
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
s << "<br>" << std::endl;
}
}
}
@@ -958,8 +690,8 @@ namespace util
void HTTPConnection::HandleDestinationRequest (const std::string& address, const std::string& uri)
{
std::string request = "GET " + uri + " HTTP/1.1\r\nHost:" + address + "\r\n";
LogPrint("HTTP Client Request: ", request);
std::string request = "GET " + uri + " HTTP/1.1\r\nHost:" + address + "\r\n\r\n";
LogPrint(eLogDebug, "HTTPServer: client request: ", request);
SendToAddress (address, 80, request.c_str (), request.size ());
}
@@ -968,7 +700,7 @@ namespace util
i2p::data::IdentHash destination;
if (!i2p::client::context.GetAddressBook ().GetIdentHash (address, destination))
{
LogPrint ("Unknown address ", address);
LogPrint (eLogWarning, "HTTPServer: Unknown address ", address);
SendReply ("<html>" + itoopieImage + "<br>Unknown address " + address + "</html>", 404);
return;
}
@@ -1040,22 +772,28 @@ namespace util
void HTTPConnection::SendReply (const std::string& content, int status)
{
m_Reply.content = content;
m_Reply.headers.resize(2);
m_Reply.headers[0].name = "Content-Length";
m_Reply.headers[0].value = boost::lexical_cast<std::string>(m_Reply.content.size());
m_Reply.headers[1].name = "Content-Type";
m_Reply.headers[1].value = "text/html";
m_Reply.headers.resize(3);
// we need the date header to be complaint with http 1.1
std::time_t time_now = std::time(nullptr);
char time_buff[128];
if (std::strftime(time_buff, sizeof(time_buff), "%a, %d %b %Y %H:%M:%S GMT", std::gmtime(&time_now)))
{
m_Reply.headers[0].name = "Date";
m_Reply.headers[0].value = std::string(time_buff);
m_Reply.headers[1].name = "Content-Length";
m_Reply.headers[1].value = boost::lexical_cast<std::string>(m_Reply.content.size());
m_Reply.headers[2].name = "Content-Type";
m_Reply.headers[2].value = "text/html";
}
boost::asio::async_write (*m_Socket, m_Reply.to_buffers(status),
std::bind (&HTTPConnection::HandleWriteReply, shared_from_this (), std::placeholders::_1));
}
HTTPServer::HTTPServer (int port):
HTTPServer::HTTPServer (const std::string& address, int port):
m_Thread (nullptr), m_Work (m_Service),
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4 (), port)),
m_NewSocket (nullptr)
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string(address), port))
{
}
HTTPServer::~HTTPServer ()
@@ -1065,7 +803,7 @@ namespace util
void HTTPServer::Start ()
{
m_Thread = new std::thread (std::bind (&HTTPServer::Run, this));
m_Thread = std::unique_ptr<std::thread>(new std::thread (std::bind (&HTTPServer::Run, this)));
m_Acceptor.listen ();
Accept ();
}
@@ -1077,7 +815,6 @@ namespace util
if (m_Thread)
{
m_Thread->join ();
delete m_Thread;
m_Thread = nullptr;
}
}
@@ -1089,25 +826,27 @@ namespace util
void HTTPServer::Accept ()
{
m_NewSocket = new boost::asio::ip::tcp::socket (m_Service);
m_Acceptor.async_accept (*m_NewSocket, boost::bind (&HTTPServer::HandleAccept, this,
boost::asio::placeholders::error));
auto newSocket = std::make_shared<boost::asio::ip::tcp::socket> (m_Service);
m_Acceptor.async_accept (*newSocket, boost::bind (&HTTPServer::HandleAccept, this,
boost::asio::placeholders::error, newSocket));
}
void HTTPServer::HandleAccept(const boost::system::error_code& ecode)
void HTTPServer::HandleAccept(const boost::system::error_code& ecode,
std::shared_ptr<boost::asio::ip::tcp::socket> newSocket)
{
if (!ecode)
{
CreateConnection(m_NewSocket);
CreateConnection(newSocket);
Accept ();
}
}
void HTTPServer::CreateConnection(boost::asio::ip::tcp::socket * m_NewSocket)
void HTTPServer::CreateConnection(std::shared_ptr<boost::asio::ip::tcp::socket> newSocket)
{
auto conn = std::make_shared<HTTPConnection> (m_NewSocket);
auto conn = std::make_shared<HTTPConnection> (newSocket);
conn->Receive ();
}
}
}

View File

@@ -39,17 +39,15 @@ namespace util
struct reply
{
std::vector<header> headers;
std::string content;
std::string status_string, content;
std::vector<boost::asio::const_buffer> to_buffers (int status);
};
public:
HTTPConnection (boost::asio::ip::tcp::socket * socket):
HTTPConnection (std::shared_ptr<boost::asio::ip::tcp::socket> socket):
m_Socket (socket), m_Timer (socket->get_io_service ()),
m_Stream (nullptr), m_BufferLen (0) {};
~HTTPConnection() { delete m_Socket; }
void Receive ();
private:
@@ -81,7 +79,7 @@ namespace util
protected:
boost::asio::ip::tcp::socket * m_Socket;
std::shared_ptr<boost::asio::ip::tcp::socket> m_Socket;
boost::asio::deadline_timer m_Timer;
std::shared_ptr<i2p::stream::Stream> m_Stream;
char m_Buffer[HTTP_CONNECTION_BUFFER_SIZE + 1], m_StreamBuffer[HTTP_CONNECTION_BUFFER_SIZE + 1];
@@ -108,7 +106,7 @@ namespace util
{
public:
HTTPServer (int port);
HTTPServer (const std::string& address, int port);
virtual ~HTTPServer ();
void Start ();
@@ -118,18 +116,18 @@ namespace util
void Run ();
void Accept ();
void HandleAccept(const boost::system::error_code& ecode);
void HandleAccept(const boost::system::error_code& ecode,
std::shared_ptr<boost::asio::ip::tcp::socket> newSocket);
private:
std::thread * m_Thread;
std::unique_ptr<std::thread> m_Thread;
boost::asio::io_service m_Service;
boost::asio::io_service::work m_Work;
boost::asio::ip::tcp::acceptor m_Acceptor;
boost::asio::ip::tcp::socket * m_NewSocket;
protected:
virtual void CreateConnection(boost::asio::ip::tcp::socket * m_NewSocket);
virtual void CreateConnection(std::shared_ptr<boost::asio::ip::tcp::socket> newSocket);
};
}
}

View File

@@ -18,30 +18,20 @@ using namespace i2p::transport;
namespace i2p
{
I2NPMessage * NewI2NPMessage ()
std::shared_ptr<I2NPMessage> NewI2NPMessage ()
{
return new I2NPMessageBuffer<I2NP_MAX_MESSAGE_SIZE>();
return std::make_shared<I2NPMessageBuffer<I2NP_MAX_MESSAGE_SIZE> >();
}
I2NPMessage * NewI2NPShortMessage ()
std::shared_ptr<I2NPMessage> NewI2NPShortMessage ()
{
return new I2NPMessageBuffer<I2NP_MAX_SHORT_MESSAGE_SIZE>();
return std::make_shared<I2NPMessageBuffer<I2NP_MAX_SHORT_MESSAGE_SIZE> >();
}
I2NPMessage * NewI2NPMessage (size_t len)
std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len)
{
return (len < I2NP_MAX_SHORT_MESSAGE_SIZE/2) ? NewI2NPShortMessage () : NewI2NPMessage ();
}
void DeleteI2NPMessage (I2NPMessage * msg)
{
delete msg;
}
std::shared_ptr<I2NPMessage> ToSharedI2NPMessage (I2NPMessage * msg)
{
return std::shared_ptr<I2NPMessage>(msg, DeleteI2NPMessage);
}
void I2NPMessage::FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID)
{
@@ -61,23 +51,18 @@ namespace i2p
SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + 5000);
}
I2NPMessage * CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, int len, uint32_t replyMsgID)
std::shared_ptr<I2NPMessage> CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, size_t len, uint32_t replyMsgID)
{
I2NPMessage * msg = NewI2NPMessage (len);
if (msg->len + len < msg->maxLen)
{
memcpy (msg->GetPayload (), buf, len);
msg->len += len;
}
else
LogPrint (eLogError, "I2NP message length ", len, " exceeds max length");
auto msg = NewI2NPMessage (len);
if (msg->Concat (buf, len) < len)
LogPrint (eLogError, "I2NP: message length ", len, " exceeds max length ", msg->maxLen);
msg->FillI2NPMessageHeader (msgType, replyMsgID);
return msg;
}
std::shared_ptr<I2NPMessage> CreateI2NPMessage (const uint8_t * buf, int len, std::shared_ptr<i2p::tunnel::InboundTunnel> from)
std::shared_ptr<I2NPMessage> CreateI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from)
{
I2NPMessage * msg = NewI2NPMessage ();
auto msg = NewI2NPMessage ();
if (msg->offset + len < msg->maxLen)
{
memcpy (msg->GetBuffer (), buf, len);
@@ -85,13 +70,13 @@ namespace i2p
msg->from = from;
}
else
LogPrint (eLogError, "I2NP message length ", len, " exceeds max length");
return ToSharedI2NPMessage(msg);
LogPrint (eLogError, "I2NP: message length ", len, " exceeds max length");
return msg;
}
std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID)
{
I2NPMessage * m = NewI2NPShortMessage ();
auto m = NewI2NPShortMessage ();
uint8_t * buf = m->GetPayload ();
if (msgID)
{
@@ -106,13 +91,13 @@ namespace i2p
}
m->len += DELIVERY_STATUS_SIZE;
m->FillI2NPMessageHeader (eI2NPDeliveryStatus);
return ToSharedI2NPMessage (m);
return m;
}
std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
uint32_t replyTunnelID, bool exploratory, std::set<i2p::data::IdentHash> * excludedPeers)
{
auto m = ToSharedI2NPMessage (excludedPeers ? NewI2NPMessage () : NewI2NPShortMessage ());
auto m = excludedPeers ? NewI2NPMessage () : NewI2NPShortMessage ();
uint8_t * buf = m->GetPayload ();
memcpy (buf, key, 32); // key
buf += 32;
@@ -159,7 +144,7 @@ namespace i2p
const i2p::tunnel::InboundTunnel * replyTunnel, const uint8_t * replyKey, const uint8_t * replyTag)
{
int cnt = excludedFloodfills.size ();
auto m = ToSharedI2NPMessage (cnt > 0 ? NewI2NPMessage () : NewI2NPShortMessage ());
auto m = cnt > 0 ? NewI2NPMessage () : NewI2NPShortMessage ();
uint8_t * buf = m->GetPayload ();
memcpy (buf, dest, 32); // key
buf += 32;
@@ -194,7 +179,7 @@ namespace i2p
std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident,
std::vector<i2p::data::IdentHash> routers)
{
auto m = ToSharedI2NPMessage (NewI2NPShortMessage ());
auto m = NewI2NPShortMessage ();
uint8_t * buf = m->GetPayload ();
size_t len = 0;
memcpy (buf, ident, 32);
@@ -218,7 +203,7 @@ namespace i2p
if (!router) // we send own RouterInfo
router = context.GetSharedRouterInfo ();
auto m = ToSharedI2NPMessage (NewI2NPShortMessage ());
auto m = NewI2NPShortMessage ();
uint8_t * payload = m->GetPayload ();
memcpy (payload + DATABASE_STORE_KEY_OFFSET, router->GetIdentHash (), 32);
@@ -253,7 +238,7 @@ namespace i2p
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LeaseSet> leaseSet, uint32_t replyToken)
{
if (!leaseSet) return nullptr;
auto m = ToSharedI2NPMessage (NewI2NPShortMessage ());
auto m = NewI2NPShortMessage ();
uint8_t * payload = m->GetPayload ();
memcpy (payload + DATABASE_STORE_KEY_OFFSET, leaseSet->GetIdentHash (), 32);
payload[DATABASE_STORE_TYPE_OFFSET] = 1; // LeaseSet
@@ -278,6 +263,12 @@ namespace i2p
m->FillI2NPMessageHeader (eI2NPDatabaseStore);
return m;
}
bool IsRouterInfoMsg (std::shared_ptr<I2NPMessage> msg)
{
if (!msg || msg->GetTypeID () != eI2NPDatabaseStore) return false;
return !msg->GetPayload ()[DATABASE_STORE_TYPE_OFFSET]; // 0- RouterInfo
}
bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText)
{
@@ -286,7 +277,7 @@ namespace i2p
uint8_t * record = records + i*TUNNEL_BUILD_RECORD_SIZE;
if (!memcmp (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)i2p::context.GetRouterInfo ().GetIdentHash (), 16))
{
LogPrint ("Record ",i," is ours");
LogPrint (eLogDebug, "I2NP: Build request record ", i, " is ours");
i2p::crypto::ElGamalDecrypt (i2p::context.GetEncryptionPrivateKey (), record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText);
// replace record to reply
@@ -330,22 +321,22 @@ namespace i2p
void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len)
{
int num = buf[0];
LogPrint ("VariableTunnelBuild ", num, " records");
LogPrint (eLogDebug, "I2NP: VariableTunnelBuild ", num, " records");
auto tunnel = i2p::tunnel::tunnels.GetPendingInboundTunnel (replyMsgID);
if (tunnel)
{
// endpoint of inbound tunnel
LogPrint ("VariableTunnelBuild reply for tunnel ", tunnel->GetTunnelID ());
LogPrint (eLogDebug, "I2NP: VariableTunnelBuild reply for tunnel ", tunnel->GetTunnelID ());
if (tunnel->HandleTunnelBuildResponse (buf, len))
{
LogPrint ("Inbound tunnel ", tunnel->GetTunnelID (), " has been created");
LogPrint (eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID (), " has been created");
tunnel->SetState (i2p::tunnel::eTunnelStateEstablished);
i2p::tunnel::tunnels.AddInboundTunnel (tunnel);
}
else
{
LogPrint ("Inbound tunnel ", tunnel->GetTunnelID (), " has been declined");
LogPrint (eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID (), " has been declined");
tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed);
}
}
@@ -358,14 +349,14 @@ namespace i2p
{
// so we send it to reply tunnel
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
ToSharedI2NPMessage (CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
eI2NPVariableTunnelBuildReply, buf, len,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))));
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
}
else
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
ToSharedI2NPMessage (CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))));
CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
}
}
}
@@ -379,75 +370,75 @@ namespace i2p
{
// so we send it to reply tunnel
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
ToSharedI2NPMessage (CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
eI2NPTunnelBuildReply, buf, len,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))));
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
}
else
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
ToSharedI2NPMessage (CreateI2NPMessage (eI2NPTunnelBuild, buf, len,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))));
CreateI2NPMessage (eI2NPTunnelBuild, buf, len,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
}
}
void HandleVariableTunnelBuildReplyMsg (uint32_t replyMsgID, uint8_t * buf, size_t len)
{
LogPrint ("VariableTunnelBuildReplyMsg replyMsgID=", replyMsgID);
LogPrint (eLogDebug, "I2NP: VariableTunnelBuildReplyMsg replyMsgID=", replyMsgID);
auto tunnel = i2p::tunnel::tunnels.GetPendingOutboundTunnel (replyMsgID);
if (tunnel)
{
// reply for outbound tunnel
if (tunnel->HandleTunnelBuildResponse (buf, len))
{
LogPrint ("Outbound tunnel ", tunnel->GetTunnelID (), " has been created");
LogPrint (eLogInfo, "I2NP: Outbound tunnel ", tunnel->GetTunnelID (), " has been created");
tunnel->SetState (i2p::tunnel::eTunnelStateEstablished);
i2p::tunnel::tunnels.AddOutboundTunnel (tunnel);
}
else
{
LogPrint ("Outbound tunnel ", tunnel->GetTunnelID (), " has been declined");
LogPrint (eLogInfo, "I2NP: Outbound tunnel ", tunnel->GetTunnelID (), " has been declined");
tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed);
}
}
else
LogPrint ("Pending tunnel for message ", replyMsgID, " not found");
LogPrint (eLogWarning, "I2NP: Pending tunnel for message ", replyMsgID, " not found");
}
I2NPMessage * CreateTunnelDataMsg (const uint8_t * buf)
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (const uint8_t * buf)
{
I2NPMessage * msg = NewI2NPShortMessage ();
memcpy (msg->GetPayload (), buf, i2p::tunnel::TUNNEL_DATA_MSG_SIZE);
msg->len += i2p::tunnel::TUNNEL_DATA_MSG_SIZE;
auto msg = NewI2NPShortMessage ();
msg->Concat (buf, i2p::tunnel::TUNNEL_DATA_MSG_SIZE);
msg->FillI2NPMessageHeader (eI2NPTunnelData);
return msg;
}
I2NPMessage * CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload)
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload)
{
I2NPMessage * msg = NewI2NPShortMessage ();
memcpy (msg->GetPayload () + 4, payload, i2p::tunnel::TUNNEL_DATA_MSG_SIZE - 4);
auto msg = NewI2NPShortMessage ();
htobe32buf (msg->GetPayload (), tunnelID);
msg->len += i2p::tunnel::TUNNEL_DATA_MSG_SIZE;
msg->len += 4; // tunnelID
msg->Concat (payload, i2p::tunnel::TUNNEL_DATA_MSG_SIZE - 4);
msg->FillI2NPMessageHeader (eI2NPTunnelData);
return msg;
}
std::shared_ptr<I2NPMessage> CreateEmptyTunnelDataMsg ()
{
I2NPMessage * msg = NewI2NPShortMessage ();
auto msg = NewI2NPShortMessage ();
msg->len += i2p::tunnel::TUNNEL_DATA_MSG_SIZE;
return ToSharedI2NPMessage (msg);
return msg;
}
I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len)
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len)
{
I2NPMessage * msg = NewI2NPMessage (len);
auto msg = NewI2NPMessage (len);
uint8_t * payload = msg->GetPayload ();
htobe32buf (payload + TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET, tunnelID);
htobe16buf (payload + TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET, len);
memcpy (payload + TUNNEL_GATEWAY_HEADER_SIZE, buf, len);
msg->len += TUNNEL_GATEWAY_HEADER_SIZE + len;
msg->len += TUNNEL_GATEWAY_HEADER_SIZE;
if (msg->Concat (buf, len) < len)
LogPrint (eLogError, "I2NP: tunnel gateway buffer overflow ", msg->maxLen);
msg->FillI2NPMessageHeader (eI2NPTunnelGateway);
return msg;
}
@@ -467,21 +458,18 @@ namespace i2p
return msg;
}
else
{
I2NPMessage * msg1 = CreateTunnelGatewayMsg (tunnelID, msg->GetBuffer (), msg->GetLength ());
return ToSharedI2NPMessage (msg1);
}
return CreateTunnelGatewayMsg (tunnelID, msg->GetBuffer (), msg->GetLength ());
}
I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType,
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType,
const uint8_t * buf, size_t len, uint32_t replyMsgID)
{
I2NPMessage * msg = NewI2NPMessage (len);
auto msg = NewI2NPMessage (len);
size_t gatewayMsgOffset = I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE;
msg->offset += gatewayMsgOffset;
msg->len += gatewayMsgOffset;
memcpy (msg->GetPayload (), buf, len);
msg->len += len;
if (msg->Concat (buf, len) < len)
LogPrint (eLogError, "I2NP: tunnel gateway buffer overflow ", msg->maxLen);
msg->FillI2NPMessageHeader (msgType, replyMsgID); // create content message
len = msg->GetLength ();
msg->offset -= gatewayMsgOffset;
@@ -501,30 +489,26 @@ namespace i2p
{
uint8_t typeID = msg[I2NP_HEADER_TYPEID_OFFSET];
uint32_t msgID = bufbe32toh (msg + I2NP_HEADER_MSGID_OFFSET);
LogPrint ("I2NP msg received len=", len,", type=", (int)typeID, ", msgID=", (unsigned int)msgID);
LogPrint (eLogDebug, "I2NP: msg received len=", len,", type=", (int)typeID, ", msgID=", (unsigned int)msgID);
uint8_t * buf = msg + I2NP_HEADER_SIZE;
int size = bufbe16toh (msg + I2NP_HEADER_SIZE_OFFSET);
switch (typeID)
{
case eI2NPVariableTunnelBuild:
LogPrint ("VariableTunnelBuild");
HandleVariableTunnelBuildMsg (msgID, buf, size);
break;
case eI2NPVariableTunnelBuildReply:
LogPrint ("VariableTunnelBuildReply");
HandleVariableTunnelBuildReplyMsg (msgID, buf, size);
break;
case eI2NPTunnelBuild:
LogPrint ("TunnelBuild");
HandleTunnelBuildMsg (buf, size);
break;
case eI2NPTunnelBuildReply:
LogPrint ("TunnelBuildReply");
// TODO:
break;
default:
LogPrint ("Unexpected message ", (int)typeID);
LogPrint (eLogWarning, "I2NP: Unexpected message ", (int)typeID);
}
}
@@ -532,25 +516,24 @@ namespace i2p
{
if (msg)
{
switch (msg->GetTypeID ())
uint8_t typeID = msg->GetTypeID ();
LogPrint (eLogDebug, "I2NP: Handling message with type ", (int)typeID);
switch (typeID)
{
case eI2NPTunnelData:
LogPrint ("TunnelData");
i2p::tunnel::tunnels.PostTunnelData (msg);
break;
case eI2NPTunnelGateway:
LogPrint ("TunnelGateway");
i2p::tunnel::tunnels.PostTunnelData (msg);
break;
case eI2NPGarlic:
{
LogPrint ("Garlic");
if (msg->from)
{
if (msg->from->GetTunnelPool ())
msg->from->GetTunnelPool ()->ProcessGarlicMessage (msg);
else
LogPrint (eLogInfo, "Local destination for garlic doesn't exist anymore");
LogPrint (eLogInfo, "I2NP: Local destination for garlic doesn't exist anymore");
}
else
i2p::context.ProcessGarlicMessage (msg);
@@ -564,7 +547,6 @@ namespace i2p
break;
case eI2NPDeliveryStatus:
{
LogPrint ("DeliveryStatus");
if (msg->from && msg->from->GetTunnelPool ())
msg->from->GetTunnelPool ()->ProcessDeliveryStatus (msg);
else

View File

@@ -97,7 +97,7 @@ namespace i2p
const uint8_t DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP = 0x08; // 1000
const uint8_t DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP = 0x0C; // 1100
const int MAX_NUM_TRANSIT_TUNNELS = 2500;
const unsigned int MAX_NUM_TRANSIT_TUNNELS = 2500;
namespace tunnel
{
@@ -155,6 +155,15 @@ namespace tunnel
}
}
size_t Concat (const uint8_t * buf1, size_t len1)
{
// make sure with don't write beyond maxLen
if (len + len1 > maxLen) len1 = maxLen - len;
memcpy (buf + len, buf1, len1);
len += len1;
return len1;
}
I2NPMessage& operator=(const I2NPMessage& other)
{
memcpy (buf + offset, other.buf + other.offset, other.GetLength ());
@@ -193,17 +202,15 @@ namespace tunnel
struct I2NPMessageBuffer: public I2NPMessage
{
I2NPMessageBuffer () { buf = m_Buffer; maxLen = sz; };
uint8_t m_Buffer[sz + 16];
uint8_t m_Buffer[sz + 32]; // 16 alignment + 16 padding
};
I2NPMessage * NewI2NPMessage ();
I2NPMessage * NewI2NPShortMessage ();
I2NPMessage * NewI2NPMessage (size_t len);
void DeleteI2NPMessage (I2NPMessage * msg);
std::shared_ptr<I2NPMessage> ToSharedI2NPMessage (I2NPMessage * msg);
std::shared_ptr<I2NPMessage> NewI2NPMessage ();
std::shared_ptr<I2NPMessage> NewI2NPShortMessage ();
std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len);
I2NPMessage * CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, int len, uint32_t replyMsgID = 0);
std::shared_ptr<I2NPMessage> CreateI2NPMessage (const uint8_t * buf, int len, std::shared_ptr<i2p::tunnel::InboundTunnel> from = nullptr);
std::shared_ptr<I2NPMessage> CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, size_t len, uint32_t replyMsgID = 0);
std::shared_ptr<I2NPMessage> CreateI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from = nullptr);
std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID);
std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
@@ -215,18 +222,19 @@ namespace tunnel
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router = nullptr, uint32_t replyToken = 0);
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LeaseSet> leaseSet, uint32_t replyToken = 0);
bool IsRouterInfoMsg (std::shared_ptr<I2NPMessage> msg);
bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText);
void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len);
void HandleVariableTunnelBuildReplyMsg (uint32_t replyMsgID, uint8_t * buf, size_t len);
void HandleTunnelBuildMsg (uint8_t * buf, size_t len);
I2NPMessage * CreateTunnelDataMsg (const uint8_t * buf);
I2NPMessage * CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload);
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (const uint8_t * buf);
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload);
std::shared_ptr<I2NPMessage> CreateEmptyTunnelDataMsg ();
I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len);
I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType,
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len);
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType,
const uint8_t * buf, size_t len, uint32_t replyMsgID = 0);
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg);

View File

@@ -1,11 +1,13 @@
// There is bug in boost 1.49 with gcc 4.7 coming with Debian Wheezy
#define GCC47_BOOST149 ((BOOST_VERSION == 104900) && (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7))
#include "I2PControl.h"
#include <stdio.h>
#include <sstream>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <boost/lexical_cast.hpp>
#include <boost/date_time/local_time/local_time.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/property_tree/ini_parser.hpp>
#if !GCC47_BOOST149
#include <boost/property_tree/json_parser.hpp>
#endif
@@ -17,16 +19,38 @@
#include "Timestamp.h"
#include "Transports.h"
#include "version.h"
#include "I2PControl.h"
namespace i2p
{
namespace client
{
I2PControlService::I2PControlService (int port):
I2PControlService::I2PControlService (const std::string& address, int port):
m_Password (I2P_CONTROL_DEFAULT_PASSWORD), m_IsRunning (false), m_Thread (nullptr),
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)),
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port)),
m_SSLContext (m_Service, boost::asio::ssl::context::sslv23),
m_ShutdownTimer (m_Service)
{
LoadConfig ();
// certificate
auto path = GetPath ();
if (!boost::filesystem::exists (path))
{
if (!boost::filesystem::create_directory (path))
LogPrint (eLogError, "Failed to create i2pcontrol directory");
}
if (!boost::filesystem::exists (path / I2P_CONTROL_KEY_FILE) ||
!boost::filesystem::exists (path / I2P_CONTROL_CERT_FILE))
{
// create new certificate
CreateCertificate ();
LogPrint (eLogInfo, "I2PControl certificates created");
}
m_SSLContext.set_options (boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::single_dh_use);
m_SSLContext.use_certificate_file ((path / I2P_CONTROL_CERT_FILE).string (), boost::asio::ssl::context::pem);
m_SSLContext.use_private_key_file ((path / I2P_CONTROL_KEY_FILE).string (), boost::asio::ssl::context::pem);
// handlers
m_MethodHandlers[I2P_CONTROL_METHOD_AUTHENTICATE] = &I2PControlService::AuthenticateHandler;
m_MethodHandlers[I2P_CONTROL_METHOD_ECHO] = &I2PControlService::EchoHandler;
m_MethodHandlers[I2P_CONTROL_METHOD_I2PCONTROL] = &I2PControlService::I2PControlHandler;
@@ -34,6 +58,9 @@ namespace client
m_MethodHandlers[I2P_CONTROL_METHOD_ROUTER_MANAGER] = &I2PControlService::RouterManagerHandler;
m_MethodHandlers[I2P_CONTROL_METHOD_NETWORK_SETTING] = &I2PControlService::NetworkSettingHandler;
// I2PControl
m_I2PControlHandlers[I2P_CONTROL_I2PCONTROL_PASSWORD] = &I2PControlService::PasswordHandler;
// RouterInfo
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_UPTIME] = &I2PControlService::UptimeHandler;
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_VERSION] = &I2PControlService::VersionHandler;
@@ -56,6 +83,49 @@ namespace client
Stop ();
}
void I2PControlService::LoadConfig ()
{
auto path = GetPath ();
if (!boost::filesystem::exists (path))
{
if (!boost::filesystem::create_directory (path))
LogPrint (eLogError, "Failed to create i2pcontrol directory");
}
boost::property_tree::ptree pt;
auto filename = path / I2P_CONTROL_CONFIG_FILE;
bool isNew = true;
if (boost::filesystem::exists (filename))
{
try
{
boost::property_tree::read_ini (filename.string (), pt);
isNew = false;
}
catch (std::exception& ex)
{
LogPrint (eLogError, "Can't read ", filename, ": ", ex.what ());
}
}
m_Password = pt.get (I2P_CONTROL_I2PCONTROL_PASSWORD, I2P_CONTROL_DEFAULT_PASSWORD);
if (isNew) SaveConfig ();
}
void I2PControlService::SaveConfig ()
{
boost::property_tree::ptree pt;
pt.put (I2P_CONTROL_I2PCONTROL_PASSWORD, m_Password);
auto filename = GetPath () / I2P_CONTROL_CONFIG_FILE;
// we take care about directory in LoadConfig
try
{
boost::property_tree::write_ini (filename.string (), pt);
}
catch (std::exception& ex)
{
LogPrint (eLogError, "Can't write ", filename, ": ", ex.what ());
}
}
void I2PControlService::Start ()
{
if (!m_IsRunning)
@@ -99,27 +169,43 @@ namespace client
void I2PControlService::Accept ()
{
auto newSocket = std::make_shared<boost::asio::ip::tcp::socket> (m_Service);
m_Acceptor.async_accept (*newSocket, std::bind (&I2PControlService::HandleAccept, this,
auto newSocket = std::make_shared<ssl_socket> (m_Service, m_SSLContext);
m_Acceptor.async_accept (newSocket->lowest_layer(), std::bind (&I2PControlService::HandleAccept, this,
std::placeholders::_1, newSocket));
}
void I2PControlService::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket)
void I2PControlService::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<ssl_socket> socket)
{
if (ecode != boost::asio::error::operation_aborted)
Accept ();
if (!ecode)
{
LogPrint (eLogInfo, "New I2PControl request from ", socket->remote_endpoint ());
std::this_thread::sleep_for (std::chrono::milliseconds(5));
ReadRequest (socket);
LogPrint (eLogInfo, "New I2PControl request from ", socket->lowest_layer ().remote_endpoint ());
Handshake (socket);
}
else
LogPrint (eLogError, "I2PControl accept error: ", ecode.message ());
}
void I2PControlService::ReadRequest (std::shared_ptr<boost::asio::ip::tcp::socket> socket)
void I2PControlService::Handshake (std::shared_ptr<ssl_socket> socket)
{
socket->async_handshake(boost::asio::ssl::stream_base::server,
std::bind( &I2PControlService::HandleHandshake, this, std::placeholders::_1, socket));
}
void I2PControlService::HandleHandshake (const boost::system::error_code& ecode, std::shared_ptr<ssl_socket> socket)
{
if (!ecode)
{
//std::this_thread::sleep_for (std::chrono::milliseconds(5));
ReadRequest (socket);
}
else
LogPrint (eLogError, "I2PControl handshake error: ", ecode.message ());
}
void I2PControlService::ReadRequest (std::shared_ptr<ssl_socket> socket)
{
auto request = std::make_shared<I2PControlBuffer>();
socket->async_read_some (
@@ -133,7 +219,7 @@ namespace client
}
void I2PControlService::HandleRequestReceived (const boost::system::error_code& ecode,
size_t bytes_transferred, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
size_t bytes_transferred, std::shared_ptr<ssl_socket> socket,
std::shared_ptr<I2PControlBuffer> buf)
{
if (ecode)
@@ -150,13 +236,25 @@ namespace client
if (isHtml)
{
std::string header;
size_t contentLength = 0;
while (!ss.eof () && header != "\r")
{
std::getline(ss, header);
auto colon = header.find (':');
if (colon != std::string::npos && header.substr (0, colon) == "Content-Length")
contentLength = std::stoi (header.substr (colon + 1));
}
if (ss.eof ())
{
LogPrint (eLogError, "Malformed I2PControl request. HTTP header expected");
return; // TODO:
}
std::streamoff rem = contentLength + ss.tellg () - bytes_transferred; // more bytes to read
if (rem > 0)
{
bytes_transferred = boost::asio::read (*socket, boost::asio::buffer (buf->data (), rem));
ss.write (buf->data (), bytes_transferred);
}
}
#if GCC47_BOOST149
LogPrint (eLogError, "json_read is not supported due bug in boost 1.49 with gcc 4.7");
@@ -209,7 +307,7 @@ namespace client
ss << "\"" << name << "\":" << std::fixed << std::setprecision(2) << value;
}
void I2PControlService::SendResponse (std::shared_ptr<boost::asio::ip::tcp::socket> socket,
void I2PControlService::SendResponse (std::shared_ptr<ssl_socket> socket,
std::shared_ptr<I2PControlBuffer> buf, std::ostringstream& response, bool isHtml)
{
size_t len = response.str ().length (), offset = 0;
@@ -236,11 +334,10 @@ namespace client
}
void I2PControlService::HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred,
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<I2PControlBuffer> buf)
std::shared_ptr<ssl_socket> socket, std::shared_ptr<I2PControlBuffer> buf)
{
if (ecode)
LogPrint (eLogError, "I2PControl write error: ", ecode.message ());
socket->close ();
}
// handlers
@@ -277,12 +374,23 @@ namespace client
LogPrint (eLogDebug, it.first);
auto it1 = m_I2PControlHandlers.find (it.first);
if (it1 != m_I2PControlHandlers.end ())
{
(this->*(it1->second))(it.second.data ());
InsertParam (results, it.first, "");
}
else
LogPrint (eLogError, "I2PControl NetworkSetting unknown request ", it.first);
LogPrint (eLogError, "I2PControl I2PControl unknown request ", it.first);
}
}
void I2PControlService::PasswordHandler (const std::string& value)
{
LogPrint (eLogDebug, "I2PControl new password=", value);
m_Password = value;
m_Tokens.clear ();
SaveConfig ();
}
// RouterInfo
void I2PControlService::RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
@@ -290,11 +398,13 @@ namespace client
LogPrint (eLogDebug, "I2PControl RouterInfo");
for (auto it = params.begin (); it != params.end (); it++)
{
if (it != params.begin ()) results << ",";
LogPrint (eLogDebug, it->first);
auto it1 = m_RouterInfoHandlers.find (it->first);
if (it1 != m_RouterInfoHandlers.end ())
{
if (it != params.begin ()) results << ",";
(this->*(it1->second))(results);
}
else
LogPrint (eLogError, "I2PControl RouterInfo unknown request ", it->first);
}
@@ -412,5 +522,56 @@ namespace client
}
}
// certificate
void I2PControlService::CreateCertificate ()
{
EVP_PKEY * pkey = EVP_PKEY_new ();
RSA * rsa = RSA_new ();
BIGNUM * e = BN_dup (i2p::crypto::GetRSAE ());
RSA_generate_key_ex (rsa, 4096, e, NULL);
BN_free (e);
if (rsa)
{
EVP_PKEY_assign_RSA (pkey, rsa);
X509 * x509 = X509_new ();
ASN1_INTEGER_set (X509_get_serialNumber (x509), 1);
X509_gmtime_adj (X509_get_notBefore (x509), 0);
X509_gmtime_adj (X509_get_notAfter (x509), I2P_CONTROL_CERTIFICATE_VALIDITY*24*60*60); // expiration
X509_set_pubkey (x509, pkey); // public key
X509_NAME * name = X509_get_subject_name (x509);
X509_NAME_add_entry_by_txt (name, "C", MBSTRING_ASC, (unsigned char *)"RU", -1, -1, 0); // country (Russia by default)
X509_NAME_add_entry_by_txt (name, "O", MBSTRING_ASC, (unsigned char *)I2P_CONTROL_CERTIFICATE_ORGANIZATION, -1, -1, 0); // organization
X509_NAME_add_entry_by_txt (name, "CN", MBSTRING_ASC, (unsigned char *)I2P_CONTROL_CERTIFICATE_COMMON_NAME, -1, -1, 0); // common name
X509_set_issuer_name (x509, name); // set issuer to ourselves
X509_sign (x509, pkey, EVP_sha1 ()); // sign
// save key and certificate
// keys
auto filename = GetPath () / I2P_CONTROL_KEY_FILE;
FILE * f= fopen (filename.string ().c_str (), "wb");
if (f)
{
PEM_write_PrivateKey (f, pkey, NULL, NULL, 0, NULL, NULL);
fclose (f);
}
else
LogPrint (eLogError, "Can't open file ", filename);
// certificate
filename = GetPath () / I2P_CONTROL_CERT_FILE;
f= fopen (filename.string ().c_str (), "wb");
if (f)
{
PEM_write_X509 (f, x509);
fclose (f);
}
else
LogPrint (eLogError, "Can't open file ", filename);
X509_free (x509);
}
else
LogPrint (eLogError, "Couldn't create RSA key for certificate");
EVP_PKEY_free (pkey);
}
}
}

View File

@@ -10,7 +10,10 @@
#include <map>
#include <set>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/filesystem.hpp>
#include "util.h"
namespace i2p
{
@@ -19,6 +22,10 @@ namespace client
const size_t I2P_CONTROL_MAX_REQUEST_SIZE = 1024;
typedef std::array<char, I2P_CONTROL_MAX_REQUEST_SIZE> I2PControlBuffer;
const char I2P_CONTROL_PATH[] = "ipcontrol";
const char I2P_CONTROL_KEY_FILE[] = "key.pem";
const char I2P_CONTROL_CERT_FILE[] = "cert.pem";
const char I2P_CONTROL_CONFIG_FILE[] = "i2pcontrol.conf";
const char I2P_CONTROL_DEFAULT_PASSWORD[] = "itoopie";
const char I2P_CONTROL_PROPERTY_ID[] = "id";
@@ -62,11 +69,17 @@ namespace client
const char I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL[] = "ShutdownGraceful";
const char I2P_CONTROL_ROUTER_MANAGER_RESEED[] = "Reseed";
// Certificate
const long I2P_CONTROL_CERTIFICATE_VALIDITY = 365*10; // 10 years
const char I2P_CONTROL_CERTIFICATE_COMMON_NAME[] = "i2pd.i2pcontrol";
const char I2P_CONTROL_CERTIFICATE_ORGANIZATION[] = "Purple I2P";
class I2PControlService
{
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket;
public:
I2PControlService (int port);
I2PControlService (const std::string& address, int port);
~I2PControlService ();
void Start ();
@@ -74,16 +87,25 @@ namespace client
private:
void LoadConfig ();
void SaveConfig ();
void Run ();
void Accept ();
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket);
void ReadRequest (std::shared_ptr<boost::asio::ip::tcp::socket> socket);
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<ssl_socket> socket);
void Handshake (std::shared_ptr<ssl_socket> socket);
void HandleHandshake (const boost::system::error_code& ecode, std::shared_ptr<ssl_socket> socket);
void ReadRequest (std::shared_ptr<ssl_socket> socket);
void HandleRequestReceived (const boost::system::error_code& ecode, size_t bytes_transferred,
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<I2PControlBuffer> buf);
void SendResponse (std::shared_ptr<boost::asio::ip::tcp::socket> socket,
std::shared_ptr<ssl_socket> socket, std::shared_ptr<I2PControlBuffer> buf);
void SendResponse (std::shared_ptr<ssl_socket> socket,
std::shared_ptr<I2PControlBuffer> buf, std::ostringstream& response, bool isHtml);
void HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred,
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<I2PControlBuffer> buf);
std::shared_ptr<ssl_socket> socket, std::shared_ptr<I2PControlBuffer> buf);
boost::filesystem::path GetPath () const { return i2p::util::filesystem::GetDefaultDataDir() / I2P_CONTROL_PATH; };
void CreateCertificate ();
private:
@@ -103,6 +125,7 @@ namespace client
// I2PControl
typedef void (I2PControlService::*I2PControlRequestHandler)(const std::string& value);
void PasswordHandler (const std::string& value);
// RouterInfo
typedef void (I2PControlService::*RouterInfoRequestHandler)(std::ostringstream& results);
@@ -133,6 +156,7 @@ namespace client
boost::asio::io_service m_Service;
boost::asio::ip::tcp::acceptor m_Acceptor;
boost::asio::ssl::context m_SSLContext;
boost::asio::deadline_timer m_ShutdownTimer;
std::set<std::string> m_Tokens;

View File

@@ -3,7 +3,7 @@
#include <inttypes.h>
#include <string.h>
#if defined(__linux__) || defined(__FreeBSD_kernel__)
#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)
#include <endian.h>
#elif __FreeBSD__
#include <sys/endian.h>

View File

@@ -81,13 +81,13 @@ namespace client
class TCPIPAcceptor: public I2PService
{
public:
TCPIPAcceptor (int port, std::shared_ptr<ClientDestination> localDestination = nullptr) :
TCPIPAcceptor (const std::string& address, int port, std::shared_ptr<ClientDestination> localDestination = nullptr) :
I2PService(localDestination),
m_Acceptor (GetService (), boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4 (), port)),
m_Acceptor (GetService (), boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string(address), port)),
m_Timer (GetService ()) {}
TCPIPAcceptor (int port, i2p::data::SigningKeyType kt) :
TCPIPAcceptor (const std::string& address, int port, i2p::data::SigningKeyType kt) :
I2PService(kt),
m_Acceptor (GetService (), boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4 (), port)),
m_Acceptor (GetService (), boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string(address), port)),
m_Timer (GetService ()) {}
virtual ~TCPIPAcceptor () { TCPIPAcceptor::Stop(); }
//If you override this make sure you call it from the children

View File

@@ -78,7 +78,7 @@ namespace client
{
if (ecode)
{
LogPrint ("I2PTunnel read error: ", ecode.message ());
LogPrint (eLogError, "I2PTunnel: read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
@@ -103,7 +103,7 @@ namespace client
{
if (ecode)
{
LogPrint ("I2PTunnel write error: ", ecode.message ());
LogPrint (eLogError, "I2PTunnel: write error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
@@ -124,7 +124,7 @@ namespace client
{
if (ecode)
{
LogPrint ("I2PTunnel stream read error: ", ecode.message ());
LogPrint (eLogError, "I2PTunnel: stream read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
@@ -142,12 +142,12 @@ namespace client
{
if (ecode)
{
LogPrint ("I2PTunnel connect error: ", ecode.message ());
LogPrint (eLogError, "I2PTunnel: connect error: ", ecode.message ());
Terminate ();
}
else
{
LogPrint ("I2PTunnel connected");
LogPrint (eLogDebug, "I2PTunnel: connected");
if (m_IsQuiet)
StreamReceive ();
else
@@ -165,7 +165,7 @@ namespace client
I2PTunnelConnectionHTTP::I2PTunnelConnectionHTTP (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
std::shared_ptr<boost::asio::ip::tcp::socket> socket,
const boost::asio::ip::tcp::endpoint& target, const std::string& host):
I2PTunnelConnection (owner, stream, socket, target), m_Host (host), m_HeaderSent (false)
I2PTunnelConnection (owner, stream, socket, target), m_Host (host), m_HeaderSent (false), m_From (stream->GetRemoteIdentity ())
{
}
@@ -193,6 +193,12 @@ namespace client
else
break;
}
// add X-I2P fields
if (m_From)
{
m_OutHeader << X_I2P_DEST_HASH << ": " << m_From->GetIdentHash ().ToBase64 () << "\r\n";
// m_OutHeader << X_I2P_DEST_B64 << ": " << m_From->ToBase64 () << "\r\n";
}
if (endOfHeader)
{
@@ -232,7 +238,7 @@ namespace client
if (stream)
{
if (Kill()) return;
LogPrint (eLogInfo,"New I2PTunnel connection");
LogPrint (eLogDebug, "I2PTunnel: new connection");
auto connection = std::make_shared<I2PTunnelConnection>(GetOwner(), m_Socket, stream);
GetOwner()->AddHandler (connection);
connection->I2PConnect ();
@@ -240,7 +246,7 @@ namespace client
}
else
{
LogPrint (eLogError,"I2P Client Tunnel Issue when creating the stream, check the previous warnings for more info.");
LogPrint (eLogError, "I2PTunnel: Client Tunnel Issue when creating the stream, check the previous warnings for more info.");
Terminate();
}
}
@@ -256,9 +262,8 @@ namespace client
Done(shared_from_this());
}
I2PClientTunnel::I2PClientTunnel (const std::string& destination, int port, std::shared_ptr<ClientDestination> localDestination, int destinationPort):
TCPIPAcceptor (port,localDestination), m_Destination (destination), m_DestinationIdentHash (nullptr), m_DestinationPort (destinationPort)
{}
I2PClientTunnel::I2PClientTunnel (const std::string& destination, const std::string& address, int port, std::shared_ptr<ClientDestination> localDestination, int destinationPort):
TCPIPAcceptor (address, port, localDestination), m_Destination (destination), m_DestinationIdentHash (nullptr), m_DestinationPort (destinationPort) {}
void I2PClientTunnel::Start ()
{
@@ -283,7 +288,7 @@ namespace client
if (i2p::client::context.GetAddressBook ().GetIdentHash (m_Destination, identHash))
m_DestinationIdentHash = new i2p::data::IdentHash (identHash);
else
LogPrint (eLogWarning,"Remote destination ", m_Destination, " not found");
LogPrint (eLogWarning, "I2PTunnel: Remote destination ", m_Destination, " not found");
}
return m_DestinationIdentHash;
}
@@ -334,12 +339,12 @@ namespace client
if (!ecode)
{
auto addr = (*it).endpoint ().address ();
LogPrint (eLogInfo, "server tunnel ", (*it).host_name (), " has been resolved to ", addr);
LogPrint (eLogInfo, "I2PTunnel: server tunnel ", (*it).host_name (), " has been resolved to ", addr);
m_Endpoint.address (addr);
Accept ();
}
else
LogPrint (eLogError, "Unable to resolve server tunnel address: ", ecode.message ());
LogPrint (eLogError, "I2PTunnel: Unable to resolve server tunnel address: ", ecode.message ());
}
void I2PServerTunnel::SetAccessList (const std::set<i2p::data::IdentHash>& accessList)
@@ -360,7 +365,7 @@ namespace client
localDestination->AcceptStreams (std::bind (&I2PServerTunnel::HandleAccept, this, std::placeholders::_1));
}
else
LogPrint ("Local destination not set for server tunnel");
LogPrint (eLogError, "I2PTunnel: Local destination not set for server tunnel");
}
void I2PServerTunnel::HandleAccept (std::shared_ptr<i2p::stream::Stream> stream)
@@ -371,7 +376,7 @@ namespace client
{
if (!m_AccessList.count (stream->GetRemoteIdentity ()->GetIdentHash ()))
{
LogPrint (eLogWarning, "Address ", stream->GetRemoteIdentity ()->GetIdentHash ().ToBase32 (), " is not in white list. Incoming connection dropped");
LogPrint (eLogWarning, "I2PTunnel: Address ", stream->GetRemoteIdentity ()->GetIdentHash ().ToBase32 (), " is not in white list. Incoming connection dropped");
stream->Close ();
return;
}

View File

@@ -19,7 +19,10 @@ namespace client
const size_t I2P_TUNNEL_CONNECTION_BUFFER_SIZE = 8192;
const int I2P_TUNNEL_CONNECTION_MAX_IDLE = 3600; // in seconds
const int I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds
// for HTTP tunnels
const char X_I2P_DEST_HASH[] = "X-I2P-DestHash"; // hash in base64
//const char X_I2P_DEST_B64[] = "X-I2P-DestB64"; // full address in base64
//const char X_I2P_DEST_B32[] = "X-I2P-DestB32"; // full address in base32
class I2PTunnelConnection: public I2PServiceHandler, public std::enable_shared_from_this<I2PTunnelConnection>
{
@@ -74,6 +77,7 @@ namespace client
std::string m_Host;
std::stringstream m_InHeader, m_OutHeader;
bool m_HeaderSent;
std::shared_ptr<const i2p::data::IdentityEx> m_From;
};
class I2PClientTunnel: public TCPIPAcceptor
@@ -86,7 +90,7 @@ namespace client
public:
I2PClientTunnel (const std::string& destination, int port, std::shared_ptr<ClientDestination> localDestination, int destinationPort = 0);
I2PClientTunnel (const std::string& destination, const std::string& address, int port, std::shared_ptr<ClientDestination> localDestination, int destinationPort = 0);
~I2PClientTunnel () {}
void Start ();

View File

@@ -16,7 +16,7 @@ namespace data
{
// copy public and signing keys together
memcpy (publicKey, keys.publicKey, sizeof (publicKey) + sizeof (signingKey));
memset (&certificate, 0, sizeof (certificate));
memset (certificate, 0, sizeof (certificate));
return *this;
}
@@ -101,12 +101,12 @@ namespace data
break;
}
default:
LogPrint ("Signing key type ", (int)type, " is not supported");
LogPrint (eLogError, "Identity: Signing key type ", (int)type, " is not supported");
}
m_ExtendedLen = 4 + excessLen; // 4 bytes extra + excess length
// fill certificate
m_StandardIdentity.certificate.type = CERTIFICATE_TYPE_KEY;
m_StandardIdentity.certificate.length = htobe16 (m_ExtendedLen);
m_StandardIdentity.certificate[0] = CERTIFICATE_TYPE_KEY;
htobe16buf (m_StandardIdentity.certificate + 1, m_ExtendedLen);
// fill extended buffer
m_ExtendedBuffer = new uint8_t[m_ExtendedLen];
htobe16buf (m_ExtendedBuffer, type);
@@ -125,7 +125,7 @@ namespace data
else // DSA-SHA1
{
memcpy (m_StandardIdentity.signingKey, signingKey, sizeof (m_StandardIdentity.signingKey));
memset (&m_StandardIdentity.certificate, 0, sizeof (m_StandardIdentity.certificate));
memset (m_StandardIdentity.certificate, 0, sizeof (m_StandardIdentity.certificate));
m_IdentHash = m_StandardIdentity.Hash ();
m_ExtendedLen = 0;
m_ExtendedBuffer = nullptr;
@@ -194,15 +194,15 @@ namespace data
{
if (len < DEFAULT_IDENTITY_SIZE)
{
LogPrint (eLogError, "Identity buffer length ", len, " is too small");
LogPrint (eLogError, "Identity: buffer length ", len, " is too small");
return 0;
}
memcpy (&m_StandardIdentity, buf, DEFAULT_IDENTITY_SIZE);
delete[] m_ExtendedBuffer;
if (m_StandardIdentity.certificate.length)
m_ExtendedLen = bufbe16toh (m_StandardIdentity.certificate + 1);
if (m_ExtendedLen)
{
m_ExtendedLen = be16toh (m_StandardIdentity.certificate.length);
if (m_ExtendedLen + DEFAULT_IDENTITY_SIZE <= len)
{
m_ExtendedBuffer = new uint8_t[m_ExtendedLen];
@@ -210,7 +210,7 @@ namespace data
}
else
{
LogPrint (eLogError, "Certificate length ", m_ExtendedLen, " exceeds buffer length ", len - DEFAULT_IDENTITY_SIZE);
LogPrint (eLogError, "Identity: Certificate length ", m_ExtendedLen, " exceeds buffer length ", len - DEFAULT_IDENTITY_SIZE);
return 0;
}
}
@@ -272,7 +272,7 @@ namespace data
if (!m_Verifier) CreateVerifier ();
if (m_Verifier)
return m_Verifier->GetSignatureLen ();
return 40;
return i2p::crypto::DSA_SIGNATURE_LENGTH;
}
bool IdentityEx::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
{
@@ -284,14 +284,14 @@ namespace data
SigningKeyType IdentityEx::GetSigningKeyType () const
{
if (m_StandardIdentity.certificate.type == CERTIFICATE_TYPE_KEY && m_ExtendedBuffer)
if (m_StandardIdentity.certificate[0] == CERTIFICATE_TYPE_KEY && m_ExtendedBuffer)
return bufbe16toh (m_ExtendedBuffer); // signing key
return SIGNING_KEY_TYPE_DSA_SHA1;
}
CryptoKeyType IdentityEx::GetCryptoKeyType () const
{
if (m_StandardIdentity.certificate.type == CERTIFICATE_TYPE_KEY && m_ExtendedBuffer)
if (m_StandardIdentity.certificate[0] == CERTIFICATE_TYPE_KEY && m_ExtendedBuffer)
return bufbe16toh (m_ExtendedBuffer + 2); // crypto key
return CRYPTO_KEY_TYPE_ELGAMAL;
}
@@ -359,12 +359,13 @@ namespace data
break;
}
default:
LogPrint ("Signing key type ", (int)keyType, " is not supported");
LogPrint (eLogError, "Identity: Signing key type ", (int)keyType, " is not supported");
}
}
void IdentityEx::DropVerifier () const
{
// TODO: potential race condition with Verify
m_Verifier = nullptr;
}
@@ -470,7 +471,7 @@ namespace data
m_Signer.reset (new i2p::crypto::EDDSA25519Signer (m_SigningPrivateKey));
break;
default:
LogPrint ("Signing key type ", (int)m_Public->GetSigningKeyType (), " is not supported");
LogPrint (eLogError, "Identity: Signing key type ", (int)m_Public->GetSigningKeyType (), " is not supported");
}
}
@@ -505,7 +506,7 @@ namespace data
i2p::crypto::CreateEDDSA25519RandomKeys (keys.m_SigningPrivateKey, signingPublicKey);
break;
default:
LogPrint ("Signing key type ", (int)type, " is not supported. Create DSA-SHA1");
LogPrint (eLogError, "Identity: Signing key type ", (int)type, " is not supported. Create DSA-SHA1");
return PrivateKeys (i2p::data::CreateRandomKeys ()); // DSA-SHA1
}
// encryption

View File

@@ -18,7 +18,6 @@ namespace data
return ident.ToBase64 ().substr (0, 4);
}
#pragma pack(1)
struct Keys
{
uint8_t privateKey[256];
@@ -38,11 +37,7 @@ namespace data
{
uint8_t publicKey[256];
uint8_t signingKey[128];
struct
{
uint8_t type;
uint16_t length;
} certificate;
uint8_t certificate[3]; // byte 1 - type, bytes 2-3 - length
Identity () = default;
Identity (const Keys& keys) { *this = keys; };
@@ -50,7 +45,7 @@ namespace data
size_t FromBuffer (const uint8_t * buf, size_t len);
IdentHash Hash () const;
};
#pragma pack()
Keys CreateRandomKeys ();
const size_t DEFAULT_IDENTITY_SIZE = sizeof (Identity); // 387 bytes

View File

@@ -21,17 +21,18 @@ namespace data
ReadFromBuffer ();
}
LeaseSet::LeaseSet (const i2p::tunnel::TunnelPool& pool):
LeaseSet::LeaseSet (std::shared_ptr<const i2p::tunnel::TunnelPool> pool):
m_IsValid (true)
{
if (!pool) return;
// header
const i2p::data::LocalDestination * localDestination = pool.GetLocalDestination ();
auto localDestination = pool->GetLocalDestination ();
if (!localDestination)
{
m_Buffer = nullptr;
m_BufferLen = 0;
m_IsValid = false;
LogPrint (eLogError, "Destination for local LeaseSet doesn't exist");
LogPrint (eLogError, "LeaseSet: Destination for local LeaseSet doesn't exist");
return;
}
m_Buffer = new uint8_t[MAX_LS_BUFFER_SIZE];
@@ -41,7 +42,7 @@ namespace data
auto signingKeyLen = localDestination->GetIdentity ()->GetSigningPublicKeyLen ();
memset (m_Buffer + m_BufferLen, 0, signingKeyLen);
m_BufferLen += signingKeyLen;
auto tunnels = pool.GetInboundTunnels (5); // 5 tunnels maximum
auto tunnels = pool->GetInboundTunnels (5); // 5 tunnels maximum
m_Buffer[m_BufferLen] = tunnels.size (); // num leases
m_BufferLen++;
// leases
@@ -60,7 +61,7 @@ namespace data
// signature
localDestination->Sign (m_Buffer, m_BufferLen, m_Buffer + m_BufferLen);
m_BufferLen += localDestination->GetIdentity ()->GetSignatureLen ();
LogPrint ("Local LeaseSet of ", tunnels.size (), " leases created");
LogPrint (eLogDebug, "LeaseSet: Local LeaseSet of ", tunnels.size (), " leases created");
ReadFromBuffer ();
}
@@ -89,7 +90,7 @@ namespace data
size += m_Identity->GetSigningPublicKeyLen (); // unused signing key
uint8_t num = m_Buffer[size];
size++; // num
LogPrint ("LeaseSet num=", (int)num);
LogPrint (eLogDebug, "LeaseSet: read num=", (int)num);
if (!num) m_IsValid = false;
// process leases
@@ -109,7 +110,7 @@ namespace data
if (!netdb.FindRouter (lease.tunnelGateway))
{
// if not found request it
LogPrint (eLogInfo, "Lease's tunnel gateway not found. Requested");
LogPrint (eLogInfo, "LeaseSet: Lease's tunnel gateway not found, requesting");
netdb.RequestDestination (lease.tunnelGateway);
}
}
@@ -117,7 +118,7 @@ namespace data
// verify
if (!m_Identity->Verify (m_Buffer, leases - m_Buffer, leases))
{
LogPrint (eLogWarning, "LeaseSet verification failed");
LogPrint (eLogWarning, "LeaseSet: verification failed");
m_IsValid = false;
}
}

View File

@@ -37,7 +37,7 @@ namespace data
public:
LeaseSet (const uint8_t * buf, size_t len);
LeaseSet (const i2p::tunnel::TunnelPool& pool);
LeaseSet (std::shared_ptr<const i2p::tunnel::TunnelPool> pool);
~LeaseSet () { delete[] m_Buffer; };
void Update (const uint8_t * buf, size_t len);
std::shared_ptr<const IdentityEx> GetIdentity () const { return m_Identity; };

17
Log.cpp
View File

@@ -24,7 +24,7 @@ void LogMsg::Process()
const std::string& Log::GetTimestamp ()
{
#if (__GNUC__ == 4) && (__GNUC_MINOR__ <= 6)
#if (__GNUC__ == 4) && (__GNUC_MINOR__ <= 6) && !defined(__clang__)
auto ts = std::chrono::monotonic_clock::now ();
#else
auto ts = std::chrono::steady_clock::now ();
@@ -49,12 +49,25 @@ void Log::SetLogFile (const std::string& fullFilePath)
if (logFile->is_open ())
{
SetLogStream (logFile);
LogPrint("Logging to file ", fullFilePath, " enabled.");
LogPrint(eLogInfo, "Log: will send messages to ", fullFilePath);
}
else
delete logFile;
}
void Log::SetLogLevel (const std::string& level)
{
if (level == "error") { m_MinLevel = eLogError; }
else if (level == "warn") { m_MinLevel = eLogWarning; }
else if (level == "info") { m_MinLevel = eLogInfo; }
else if (level == "debug") { m_MinLevel = eLogDebug; }
else {
LogPrint(eLogError, "Log: Unknown loglevel: ", level);
return;
}
LogPrint(eLogInfo, "Log: min msg level set to ", level);
}
void Log::SetLogStream (std::ostream * logStream)
{
if (m_LogStream) delete m_LogStream;

18
Log.h
View File

@@ -38,9 +38,11 @@ class Log: public i2p::util::MsgQueue<LogMsg>
~Log () { delete m_LogStream; };
void SetLogFile (const std::string& fullFilePath);
void SetLogLevel (const std::string& level);
void SetLogStream (std::ostream * logStream);
std::ostream * GetLogStream () const { return m_LogStream; };
const std::string& GetTimestamp ();
LogLevel GetLogLevel () { return m_MinLevel; };
private:
@@ -49,8 +51,9 @@ class Log: public i2p::util::MsgQueue<LogMsg>
private:
std::ostream * m_LogStream;
enum LogLevel m_MinLevel;
std::string m_Timestamp;
#if (__GNUC__ == 4) && (__GNUC_MINOR__ <= 6) // gcc 4.6
#if (__GNUC__ == 4) && (__GNUC_MINOR__ <= 6) && !defined(__clang__) // gcc 4.6
std::chrono::monotonic_clock::time_point m_LastTimestampUpdate;
#else
std::chrono::steady_clock::time_point m_LastTimestampUpdate;
@@ -108,22 +111,17 @@ void LogPrint (std::stringstream& s, TValue arg, TArgs... args)
template<typename... TArgs>
void LogPrint (LogLevel level, TArgs... args)
{
if (g_Log && level > g_Log->GetLogLevel ())
return;
LogMsg * msg = new LogMsg (g_Log, level);
LogPrint (msg->s, args...);
msg->s << std::endl;
if (g_Log)
if (g_Log) {
g_Log->Put (msg);
else
{
} else {
msg->Process ();
delete msg;
}
}
template<typename... TArgs>
void LogPrint (TArgs... args)
{
LogPrint (eLogInfo, args...);
}
#endif

View File

@@ -3,7 +3,7 @@ SHLIB := libi2pd.so
ARLIB := libi2pd.a
SHLIB_CLIENT := libi2pdclient.so
ARLIB_CLIENT := libi2pdclient.a
I2PD := i2p
I2PD := i2pd
GREP := fgrep
DEPS := obj/make.dep
@@ -21,16 +21,18 @@ else ifeq ($(shell echo $(UNAME) | $(GREP) -c FreeBSD),1)
else ifeq ($(UNAME),Linux)
DAEMON_SRC += DaemonLinux.cpp
include Makefile.linux
else # win32
DAEMON_SRC += DaemonWin32.cpp
else # win32 mingw
DAEMON_SRC += DaemonWin32.cpp Win32/Win32Service.cpp
include Makefile.mingw
endif
all: mk_build_dir $(SHLIB) $(SHLIB_CLIENT) $(ARLIB) $(ARLIB_CLIENT) $(I2PD)
all: mk_build_dir $(ARLIB) $(ARLIB_CLIENT) $(I2PD)
mk_build_dir:
mkdir -p obj
api: $(SHLIB) $(ARLIB)
api: mk_build_dir $(SHLIB) $(ARLIB)
api_client: mk_build_dir $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT)
## NOTE: The NEEDED_CXXFLAGS are here so that CXXFLAGS can be specified at build time
## **without** overwriting the CXXFLAGS which we need in order to build.
@@ -82,4 +84,5 @@ dist:
.PHONY: deps
.PHONY: dist
.PHONY: api
.PHONY: api_client
.PHONY: mk_build_dir

View File

@@ -1,4 +1,4 @@
CXX = g++
CXX = clang++
CXXFLAGS = -O2
## NOTE: NEEDED_CXXFLAGS is here so that custom CXXFLAGS can be specified at build time
## **without** overwriting the CXXFLAGS which we need in order to build.
@@ -6,7 +6,7 @@ CXXFLAGS = -O2
## (e.g. -fstack-protector-strong -Wformat -Werror=format-security), we do not want to remove
## -std=c++11. If you want to remove this variable please do so in a way that allows setting
## custom FLAGS to work at build-time.
NEEDED_CXXFLAGS = -std=c++11
NEEDED_CXXFLAGS = -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1
INCFLAGS = -I/usr/include/ -I/usr/local/include/
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib
LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread

View File

@@ -1,5 +1,6 @@
CXXFLAGS = -g -Wall
INCFLAGS =
# set defaults instead redefine
CXXFLAGS ?= -g -Wall
INCFLAGS ?=
## NOTE: The NEEDED_CXXFLAGS are here so that custom CXXFLAGS can be specified at build time
## **without** overwriting the CXXFLAGS which we need in order to build.
@@ -15,7 +16,7 @@ ifeq ($(shell expr match $(CXX) 'clang'),5)
else ifeq ($(shell expr match ${CXXVER} "4\.[0-9][0-9]"),4) # gcc >= 4.10
NEEDED_CXXFLAGS += -std=c++11
else ifeq ($(shell expr match ${CXXVER} "4\.[7-9]"),3) # >= 4.7
NEEDED_CXXFLAGS += -std=c++11
NEEDED_CXXFLAGS += -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1
else ifeq ($(shell expr match ${CXXVER} "4\.6"),3) # = 4.6
NEEDED_CXXFLAGS += -std=c++0x
else ifeq ($(shell expr match ${CXXVER} "5\.[0-9]"),3) # gcc >= 5.0

View File

@@ -1,6 +1,7 @@
CXX = g++
CXXFLAGS = -O2 -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN
NEEDED_CXXFLAGS = -std=c++11
BOOST_SUFFIX = -mgw48-mt-1_59
INCFLAGS = -I/usr/include/ -I/usr/local/include/ -I/c/dev/openssl/include -I/c/dev/boost/include/boost-1_59
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib -L/c/dev/openssl -L/c/dev/boost/lib
LDLIBS = -lboost_system-mgw48-mt-1_59 -lboost_date_time-mgw48-mt-1_59 -lboost_filesystem-mgw48-mt-1_59 -lboost_regex-mgw48-mt-1_59 -lboost_program_options-mgw48-mt-1_59 -lssl -lcrypto -lz -lpthread -lwsock32 -lws2_32 -lgdi32
LDLIBS = -lboost_system$(BOOST_SUFFIX) -lboost_date_time$(BOOST_SUFFIX) -lboost_filesystem$(BOOST_SUFFIX) -lboost_regex$(BOOST_SUFFIX) -lboost_program_options$(BOOST_SUFFIX) -lssl -lcrypto -lz -lwsock32 -lws2_32 -lgdi32 -liphlpapi -static-libgcc -static-libstdc++ -Wl,-Bstatic -lstdc++ -lpthread

View File

@@ -1,9 +1,9 @@
CXX = clang++
CXXFLAGS = -g -Wall -std=c++11 -DCRYPTOPP_DISABLE_ASM -DMAC_OSX
#CXXFLAGS = -g -O2 -Wall -std=c++11 -DCRYPTOPP_DISABLE_ASM
INCFLAGS = -I/usr/local/include
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib
LDLIBS = -lcryptopp -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
CXXFLAGS = -g -Wall -std=c++11 -DMAC_OSX
#CXXFLAGS = -g -O2 -Wall -std=c++11
INCFLAGS = -I/usr/local/include -I/usr/local/ssl/include
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib -L/usr/local/ssl/lib
LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
ifeq ($(USE_UPNP),1)
LDFLAGS += -ldl

View File

@@ -56,7 +56,7 @@ namespace transport
nonZero++;
if (nonZero - sharedKey > 32)
{
LogPrint (eLogWarning, "First 32 bytes of shared key is all zeros. Ignored");
LogPrint (eLogWarning, "NTCP: First 32 bytes of shared key is all zeros, ignored");
return;
}
}
@@ -81,7 +81,7 @@ namespace transport
m_SendQueue.clear ();
m_NextMessage = nullptr;
m_TerminationTimer.cancel ();
LogPrint (eLogInfo, "NTCP session terminated");
LogPrint (eLogDebug, "NTCP: session terminated");
}
}
@@ -136,7 +136,7 @@ namespace transport
{
if (ecode)
{
LogPrint (eLogError, "Couldn't send Phase 1 message: ", ecode.message ());
LogPrint (eLogError, "NTCP: couldn't send Phase 1 message: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
@@ -152,7 +152,7 @@ namespace transport
{
if (ecode)
{
LogPrint (eLogError, "Phase 1 read error: ", ecode.message ());
LogPrint (eLogError, "NTCP: phase 1 read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
@@ -166,7 +166,7 @@ namespace transport
{
if ((m_Establisher->phase1.HXxorHI[i] ^ ident[i]) != digest[i])
{
LogPrint (eLogError, "Wrong ident");
LogPrint (eLogError, "NTCP: phase 1 error: ident mismatch");
Terminate ();
return;
}
@@ -187,8 +187,8 @@ namespace transport
memcpy (xy + 256, y, 256);
SHA256(xy, 512, m_Establisher->phase2.encrypted.hxy);
uint32_t tsB = htobe32 (i2p::util::GetSecondsSinceEpoch ());
m_Establisher->phase2.encrypted.timestamp = tsB;
// TODO: fill filler
memcpy (m_Establisher->phase2.encrypted.timestamp, &tsB, 4);
RAND_bytes (m_Establisher->phase2.encrypted.filler, 12);
i2p::crypto::AESKey aesKey;
CreateAESKey (m_Establisher->phase1.pubKey, aesKey);
@@ -207,7 +207,7 @@ namespace transport
{
if (ecode)
{
LogPrint (eLogError, "Couldn't send Phase 2 message: ", ecode.message ());
LogPrint (eLogError, "NTCP: Couldn't send Phase 2 message: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
@@ -223,7 +223,7 @@ namespace transport
{
if (ecode)
{
LogPrint (eLogError, "Phase 2 read error: ", ecode.message (), ". Wrong ident assumed");
LogPrint (eLogError, "NTCP: Phase 2 read error: ", ecode.message (), ". Wrong ident assumed");
if (ecode != boost::asio::error::operation_aborted)
{
// this RI is not valid
@@ -251,7 +251,7 @@ namespace transport
SHA256 (xy, 512, digest);
if (memcmp(m_Establisher->phase2.encrypted.hxy, digest, 32))
{
LogPrint (eLogError, "Incorrect hash");
LogPrint (eLogError, "NTCP: Phase 2 process error: incorrect hash");
transports.ReuseDHKeysPair (m_DHKeysPair);
m_DHKeysPair = nullptr;
Terminate ();
@@ -287,7 +287,7 @@ namespace transport
s.Insert (m_Establisher->phase2.pubKey, 256); // y
s.Insert (m_RemoteIdentity->GetIdentHash (), 32); // ident
s.Insert (tsA); // tsA
s.Insert (m_Establisher->phase2.encrypted.timestamp); // tsB
s.Insert (m_Establisher->phase2.encrypted.timestamp, 4); // tsB
s.Sign (keys, buf);
m_Encryption.Encrypt(m_ReceiveBuffer, len, m_ReceiveBuffer);
@@ -299,7 +299,7 @@ namespace transport
{
if (ecode)
{
LogPrint (eLogError, "Couldn't send Phase 3 message: ", ecode.message ());
LogPrint (eLogError, "NTCP: Couldn't send Phase 3 message: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
@@ -319,7 +319,7 @@ namespace transport
{
if (ecode)
{
LogPrint (eLogError, "Phase 3 read error: ", ecode.message ());
LogPrint (eLogError, "NTCP: Phase 3 read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
@@ -331,7 +331,7 @@ namespace transport
SetRemoteIdentity (std::make_shared<i2p::data::IdentityEx> (buf + 2, size));
if (m_Server.FindNTCPSession (m_RemoteIdentity->GetIdentHash ()))
{
LogPrint (eLogError, "NTCP session already exists");
LogPrint (eLogError, "NTCP: session already exists");
Terminate ();
}
size_t expectedSize = size + 2/*size*/ + 4/*timestamp*/ + m_RemoteIdentity->GetSignatureLen ();
@@ -354,7 +354,7 @@ namespace transport
{
if (ecode)
{
LogPrint (eLogError, "Phase 3 extra read error: ", ecode.message ());
LogPrint (eLogError, "NTCP: Phase 3 extra read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
@@ -380,7 +380,7 @@ namespace transport
s.Insert (tsB); // tsB
if (!s.Verify (m_RemoteIdentity, buf))
{
LogPrint (eLogError, "signature verification failed");
LogPrint (eLogError, "NTCP: signature verification failed");
Terminate ();
return;
}
@@ -411,13 +411,13 @@ namespace transport
{
if (ecode)
{
LogPrint (eLogWarning, "Couldn't send Phase 4 message: ", ecode.message ());
LogPrint (eLogWarning, "NTCP: Couldn't send Phase 4 message: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
else
{
LogPrint (eLogInfo, "NTCP server session from ", m_Socket.remote_endpoint (), " connected");
LogPrint (eLogInfo, "NTCP: Server session from ", m_Socket.remote_endpoint (), " connected");
m_Server.AddNTCPSession (shared_from_this ());
Connected ();
@@ -431,7 +431,7 @@ namespace transport
{
if (ecode)
{
LogPrint (eLogError, "Phase 4 read error: ", ecode.message (), ". Check your clock");
LogPrint (eLogError, "NTCP: Phase 4 read error: ", ecode.message (), ". Check your clock");
if (ecode != boost::asio::error::operation_aborted)
{
// this router doesn't like us
@@ -449,15 +449,15 @@ namespace transport
s.Insert (m_Establisher->phase2.pubKey, 256); // y
s.Insert (i2p::context.GetIdentHash (), 32); // ident
s.Insert (tsA); // tsA
s.Insert (m_Establisher->phase2.encrypted.timestamp); // tsB
s.Insert (m_Establisher->phase2.encrypted.timestamp, 4); // tsB
if (!s.Verify (m_RemoteIdentity, m_ReceiveBuffer))
{
LogPrint (eLogError, "signature verification failed");
LogPrint (eLogError, "NTCP: Phase 4 process error: signature verification failed");
Terminate ();
return;
}
LogPrint (eLogInfo, "NTCP session to ", m_Socket.remote_endpoint (), " connected");
LogPrint (eLogDebug, "NTCP: session to ", m_Socket.remote_endpoint (), " connected");
Connected ();
m_ReceiveBufferOffset = 0;
@@ -477,7 +477,7 @@ namespace transport
{
if (ecode)
{
LogPrint (eLogError, "Read error: ", ecode.message ());
LogPrint (eLogError, "NTCP: Read error: ", ecode.message ());
if (!m_NumReceivedBytes) m_Server.Ban (m_ConnectedFrom);
//if (ecode != boost::asio::error::operation_aborted)
Terminate ();
@@ -519,7 +519,7 @@ namespace transport
moreBytes = m_Socket.read_some (boost::asio::buffer (m_ReceiveBuffer + m_ReceiveBufferOffset, moreBytes));
if (ec)
{
LogPrint (eLogError, "Read more bytes error: ", ec.message ());
LogPrint (eLogError, "NTCP: Read more bytes error: ", ec.message ());
Terminate ();
return;
}
@@ -542,20 +542,20 @@ namespace transport
{
if (!m_NextMessage) // new message, header expected
{
// descrypt header and extract length
// decrypt header and extract length
uint8_t buf[16];
m_Decryption.Decrypt (encrypted, buf);
uint16_t dataSize = bufbe16toh (buf);
if (dataSize)
{
// new message
if (dataSize > NTCP_MAX_MESSAGE_SIZE)
if (dataSize + 16U > NTCP_MAX_MESSAGE_SIZE - 2) // + 6 + padding
{
LogPrint (eLogError, "NTCP data size ", dataSize, " exceeds max size");
LogPrint (eLogError, "NTCP: data size ", dataSize, " exceeds max size");
return false;
}
auto msg = dataSize <= I2NP_MAX_SHORT_MESSAGE_SIZE - 2 ? NewI2NPShortMessage () : NewI2NPMessage ();
m_NextMessage = ToSharedI2NPMessage (msg);
auto msg = (dataSize + 16U) <= I2NP_MAX_SHORT_MESSAGE_SIZE - 2 ? NewI2NPShortMessage () : NewI2NPMessage ();
m_NextMessage = msg;
memcpy (m_NextMessage->buf, buf, 16);
m_NextMessageOffset = 16;
m_NextMessage->offset = 2; // size field
@@ -564,7 +564,7 @@ namespace transport
else
{
// timestamp
LogPrint ("Timestamp");
LogPrint (eLogDebug, "NTCP: Timestamp");
return true;
}
}
@@ -582,7 +582,7 @@ namespace transport
if (!memcmp (m_NextMessage->buf + m_NextMessageOffset - 4, checksum, 4))
m_Handler.PutNextMessage (m_NextMessage);
else
LogPrint (eLogWarning, "Incorrect adler checksum of NTCP message. Dropped");
LogPrint (eLogWarning, "NTCP: Incorrect adler checksum of message, dropped");
m_NextMessage = nullptr;
}
return true;
@@ -604,7 +604,7 @@ namespace transport
{
// regular I2NP
if (msg->offset < 2)
LogPrint (eLogError, "Malformed I2NP message"); // TODO:
LogPrint (eLogError, "NTCP: Malformed I2NP message"); // TODO:
sendBuffer = msg->GetBuffer () - 2;
len = msg->GetLength ();
htobe16buf (sendBuffer, len);
@@ -644,7 +644,7 @@ namespace transport
m_IsSending = false;
if (ecode)
{
LogPrint (eLogWarning, "Couldn't send msgs: ", ecode.message ());
LogPrint (eLogWarning, "NTCP: Couldn't send msgs: ", ecode.message ());
// we shouldn't call Terminate () here, because HandleReceive takes care
// TODO: 'delete this' statement in Terminate () must be eliminated later
// Terminate ();
@@ -699,7 +699,7 @@ namespace transport
{
if (ecode != boost::asio::error::operation_aborted)
{
LogPrint ("No activity fo ", NTCP_TERMINATION_TIMEOUT, " seconds");
LogPrint (eLogWarning, "NTCP: No activity fo ", NTCP_TERMINATION_TIMEOUT, " seconds");
//Terminate ();
m_Socket.close ();// invoke Terminate () from HandleReceive
}
@@ -732,7 +732,7 @@ namespace transport
m_NTCPAcceptor = new boost::asio::ip::tcp::acceptor (m_Service,
boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address.port));
LogPrint (eLogInfo, "Start listening TCP port ", address.port);
LogPrint (eLogInfo, "NTCP: Start listening TCP port ", address.port);
auto conn = std::make_shared<NTCPSession>(*this);
m_NTCPAcceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAccept, this,
conn, std::placeholders::_1));
@@ -745,7 +745,7 @@ namespace transport
m_NTCPV6Acceptor->bind (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address.port));
m_NTCPV6Acceptor->listen ();
LogPrint (eLogInfo, "Start listening V6 TCP port ", address.port);
LogPrint (eLogInfo, "NTCP: Start listening V6 TCP port ", address.port);
auto conn = std::make_shared<NTCPSession> (*this);
m_NTCPV6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAcceptV6,
this, conn, std::placeholders::_1));
@@ -788,32 +788,33 @@ namespace transport
}
catch (std::exception& ex)
{
LogPrint ("NTCP server: ", ex.what ());
LogPrint (eLogError, "NTCP: runtime exception: ", ex.what ());
}
}
}
void NTCPServer::AddNTCPSession (std::shared_ptr<NTCPSession> session)
bool NTCPServer::AddNTCPSession (std::shared_ptr<NTCPSession> session)
{
if (session && session->GetRemoteIdentity ())
if (!session || !session->GetRemoteIdentity ()) return false;
auto& ident = session->GetRemoteIdentity ()->GetIdentHash ();
auto it = m_NTCPSessions.find (ident);
if (it != m_NTCPSessions.end ())
{
std::unique_lock<std::mutex> l(m_NTCPSessionsMutex);
m_NTCPSessions[session->GetRemoteIdentity ()->GetIdentHash ()] = session;
LogPrint (eLogWarning, "NTCP: session to ", ident.ToBase64 (), " already exists");
return false;
}
m_NTCPSessions.insert (std::pair<i2p::data::IdentHash, std::shared_ptr<NTCPSession> >(ident, session));
return true;
}
void NTCPServer::RemoveNTCPSession (std::shared_ptr<NTCPSession> session)
{
if (session && session->GetRemoteIdentity ())
{
std::unique_lock<std::mutex> l(m_NTCPSessionsMutex);
m_NTCPSessions.erase (session->GetRemoteIdentity ()->GetIdentHash ());
}
}
std::shared_ptr<NTCPSession> NTCPServer::FindNTCPSession (const i2p::data::IdentHash& ident)
{
std::unique_lock<std::mutex> l(m_NTCPSessionsMutex);
auto it = m_NTCPSessions.find (ident);
if (it != m_NTCPSessions.end ())
return it->second;
@@ -828,14 +829,14 @@ namespace transport
auto ep = conn->GetSocket ().remote_endpoint(ec);
if (!ec)
{
LogPrint (eLogInfo, "Connected from ", ep);
LogPrint (eLogDebug, "NTCP: Connected from ", ep);
auto it = m_BanList.find (ep.address ());
if (it != m_BanList.end ())
{
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
if (ts < it->second)
{
LogPrint (eLogInfo, ep.address (), " is banned for ", it->second - ts, " more seconds");
LogPrint (eLogWarning, "NTCP: ", ep.address (), " is banned for ", it->second - ts, " more seconds");
conn = nullptr;
}
else
@@ -845,7 +846,7 @@ namespace transport
conn->ServerLogin ();
}
else
LogPrint (eLogError, "Connected from error ", ec.message ());
LogPrint (eLogError, "NTCP: Connected from error ", ec.message ());
}
@@ -865,14 +866,14 @@ namespace transport
auto ep = conn->GetSocket ().remote_endpoint(ec);
if (!ec)
{
LogPrint (eLogInfo, "Connected from ", ep);
LogPrint (eLogDebug, "NTCP: Connected from ", ep);
auto it = m_BanList.find (ep.address ());
if (it != m_BanList.end ())
{
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
if (ts < it->second)
{
LogPrint (eLogInfo, ep.address (), " is banned for ", it->second - ts, " more seconds");
LogPrint (eLogWarning, "NTCP: ", ep.address (), " is banned for ", it->second - ts, " more seconds");
conn = nullptr;
}
else
@@ -882,7 +883,7 @@ namespace transport
conn->ServerLogin ();
}
else
LogPrint (eLogError, "Connected from error ", ec.message ());
LogPrint (eLogError, "NTCP: Connected from error ", ec.message ());
}
if (error != boost::asio::error::operation_aborted)
@@ -895,27 +896,27 @@ namespace transport
void NTCPServer::Connect (const boost::asio::ip::address& address, int port, std::shared_ptr<NTCPSession> conn)
{
LogPrint (eLogInfo, "Connecting to ", address ,":", port);
m_Service.post([conn, this]()
{
this->AddNTCPSession (conn);
});
conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port),
std::bind (&NTCPServer::HandleConnect, this, std::placeholders::_1, conn));
LogPrint (eLogDebug, "NTCP: Connecting to ", address ,":", port);
m_Service.post([=]()
{
if (this->AddNTCPSession (conn))
conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port),
std::bind (&NTCPServer::HandleConnect, this, std::placeholders::_1, conn));
});
}
void NTCPServer::HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCPSession> conn)
{
if (ecode)
{
LogPrint (eLogError, "Connect error: ", ecode.message ());
LogPrint (eLogError, "NTCP: Connect error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true);
conn->Terminate ();
}
else
{
LogPrint (eLogInfo, "Connected to ", conn->GetSocket ().remote_endpoint ());
LogPrint (eLogDebug, "NTCP: Connected to ", conn->GetSocket ().remote_endpoint ());
if (conn->GetSocket ().local_endpoint ().protocol () == boost::asio::ip::tcp::v6()) // ipv6
context.UpdateNTCPV6Address (conn->GetSocket ().local_endpoint ().address ());
conn->ClientLogin ();
@@ -926,7 +927,7 @@ namespace transport
{
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
m_BanList[addr] = ts + NTCP_BAN_EXPIRATION_TIMEOUT;
LogPrint (eLogInfo, addr, " has been banned for ", NTCP_BAN_EXPIRATION_TIMEOUT, " seconds");
LogPrint (eLogWarning, "NTCP: ", addr, " has been banned for ", NTCP_BAN_EXPIRATION_TIMEOUT, " seconds");
}
}
}

View File

@@ -17,8 +17,6 @@ namespace i2p
{
namespace transport
{
#pragma pack(1)
struct NTCPPhase1
{
uint8_t pubKey[256];
@@ -31,12 +29,10 @@ namespace transport
struct
{
uint8_t hxy[32];
uint32_t timestamp;
uint8_t timestamp[4];
uint8_t filler[12];
} encrypted;
};
#pragma pack()
const size_t NTCP_MAX_MESSAGE_SIZE = 16384;
const size_t NTCP_BUFFER_SIZE = 4160; // fits 4 tunnel messages (4*1028)
@@ -143,7 +139,7 @@ namespace transport
void Start ();
void Stop ();
void AddNTCPSession (std::shared_ptr<NTCPSession> session);
bool AddNTCPSession (std::shared_ptr<NTCPSession> session);
void RemoveNTCPSession (std::shared_ptr<NTCPSession> session);
std::shared_ptr<NTCPSession> FindNTCPSession (const i2p::data::IdentHash& ident);
void Connect (const boost::asio::ip::address& address, int port, std::shared_ptr<NTCPSession> conn);
@@ -166,8 +162,7 @@ namespace transport
boost::asio::io_service m_Service;
boost::asio::io_service::work m_Work;
boost::asio::ip::tcp::acceptor * m_NTCPAcceptor, * m_NTCPV6Acceptor;
std::mutex m_NTCPSessionsMutex;
std::map<i2p::data::IdentHash, std::shared_ptr<NTCPSession> > m_NTCPSessions;
std::map<i2p::data::IdentHash, std::shared_ptr<NTCPSession> > m_NTCPSessions; // access from m_Thread only
std::map<boost::asio::ip::address, uint32_t> m_BanList; // IP -> ban expiration time in seconds
public:

128
NetDb.cpp
View File

@@ -80,22 +80,20 @@ namespace data
int numMsgs = 0;
while (msg)
{
LogPrint(eLogDebug, "NetDb: got request with type ", (int) msg->GetTypeID ());
switch (msg->GetTypeID ())
{
case eI2NPDatabaseStore:
LogPrint ("DatabaseStore");
HandleDatabaseStoreMsg (msg);
break;
case eI2NPDatabaseSearchReply:
LogPrint ("DatabaseSearchReply");
HandleDatabaseSearchReplyMsg (msg);
break;
case eI2NPDatabaseLookup:
LogPrint ("DatabaseLookup");
HandleDatabaseLookupMsg (msg);
break;
default: // WTF?
LogPrint (eLogError, "NetDb: unexpected message type ", msg->GetTypeID ());
LogPrint (eLogError, "NetDb: unexpected message type ", (int) msg->GetTypeID ());
//i2p::HandleI2NPMessage (msg);
}
if (numMsgs > 100) break;
@@ -128,6 +126,11 @@ namespace data
if (ts - lastExploratory >= 30) // exploratory every 30 seconds
{
auto numRouters = m_RouterInfos.size ();
if (numRouters == 0)
{
LogPrint(eLogError, "NetDb: no known routers, reseed seems to be totally failed");
break;
}
if (numRouters < 2500 || ts - lastExploratory >= 90)
{
numRouters = 800/numRouters;
@@ -141,7 +144,7 @@ namespace data
}
catch (std::exception& ex)
{
LogPrint ("NetDb: ", ex.what ());
LogPrint (eLogError, "NetDb: runtime exception: ", ex.what ());
}
}
}
@@ -161,11 +164,11 @@ namespace data
auto ts = r->GetTimestamp ();
r->Update (buf, len);
if (r->GetTimestamp () > ts)
LogPrint ("RouterInfo updated");
LogPrint (eLogInfo, "NetDb: RouterInfo updated: ", ident.ToBase32());
}
else
{
LogPrint ("New RouterInfo added");
LogPrint (eLogInfo, "NetDb: RouterInfo added: ", ident.ToBase32());
r = std::make_shared<RouterInfo> (buf, len);
{
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
@@ -191,10 +194,10 @@ namespace data
{
it->second->Update (buf, len);
if (it->second->IsValid ())
LogPrint (eLogInfo, "LeaseSet updated");
LogPrint (eLogInfo, "NetDb: LeaseSet updated: ", ident.ToBase32());
else
{
LogPrint (eLogInfo, "LeaseSet update failed");
LogPrint (eLogWarning, "NetDb: LeaseSet update failed: ", ident.ToBase32());
m_LeaseSets.erase (it);
}
}
@@ -203,11 +206,11 @@ namespace data
auto leaseSet = std::make_shared<LeaseSet> (buf, len);
if (leaseSet->IsValid ())
{
LogPrint (eLogInfo, "New LeaseSet added");
LogPrint (eLogInfo, "NetDb: LeaseSet added: ", ident.ToBase32());
m_LeaseSets[ident] = leaseSet;
}
else
LogPrint (eLogError, "New LeaseSet validation failed");
LogPrint (eLogError, "NetDb: new LeaseSet validation failed: ", ident.ToBase32());
}
}
}
@@ -247,24 +250,23 @@ namespace data
// TODO: Move to reseed and/or scheduled tasks. (In java version, scheduler fix this as well as sort RIs.)
bool NetDb::CreateNetDb(boost::filesystem::path directory)
{
LogPrint (directory.string(), " doesn't exist, trying to create it.");
LogPrint (eLogInfo, "NetDb: storage directory doesn't exist, trying to create it.");
if (!boost::filesystem::create_directory (directory))
{
LogPrint("Failed to create directory ", directory.string());
LogPrint (eLogError, "NetDb: failed to create directory ", directory);
return false;
}
// list of chars might appear in base64 string
const char * chars = GetBase64SubstitutionTable (); // 64 bytes
boost::filesystem::path suffix;
for (int i = 0; i < 64; i++)
{
#ifndef _WIN32
suffix = std::string ("/r") + chars[i];
#else
suffix = std::string ("\\r") + chars[i];
#endif
if (!boost::filesystem::create_directory( boost::filesystem::path (directory / suffix) )) return false;
auto p = directory / (std::string ("r") + chars[i]);
if (!boost::filesystem::exists (p) && !boost::filesystem::create_directory (p))
{
LogPrint (eLogError, "NetDb: failed to create directory ", p);
return false;
}
}
return true;
}
@@ -280,7 +282,7 @@ namespace data
while (reseedRetries < 10 && !m_Reseeder->ReseedNowSU3 ())
reseedRetries++;
if (reseedRetries >= 10)
LogPrint (eLogWarning, "Failed to reseed after 10 attempts");
LogPrint (eLogWarning, "NetDb: failed to reseed after 10 attempts");
}
void NetDb::Load ()
@@ -328,8 +330,7 @@ namespace data
}
}
}
LogPrint (numRouters, " routers loaded");
LogPrint (m_Floodfills.size (), " floodfills loaded");
LogPrint (eLogInfo, "NetDb: ", numRouters, " routers loaded (", m_Floodfills.size (), " floodfils)");
}
void NetDb::SaveUpdated ()
@@ -407,10 +408,10 @@ namespace data
}
}
if (count > 0)
LogPrint (count," new/updated routers saved");
LogPrint (eLogInfo, "NetDb: ", count, " new/updated routers saved");
if (deletedCount > 0)
{
LogPrint (deletedCount," routers deleted");
LogPrint (eLogDebug, "NetDb: ", deletedCount, " routers deleted");
// clean up RouterInfos table
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
for (auto it = m_RouterInfos.begin (); it != m_RouterInfos.end ();)
@@ -431,7 +432,7 @@ namespace data
auto dest = m_Requests.CreateRequest (destination, false, requestComplete); // non-exploratory
if (!dest)
{
LogPrint (eLogWarning, "Destination ", destination.ToBase64(), " is requested already");
LogPrint (eLogWarning, "NetDb: destination ", destination.ToBase32(), " is requested already");
return;
}
@@ -440,7 +441,7 @@ namespace data
transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
else
{
LogPrint (eLogError, "No floodfills found");
LogPrint (eLogError, "NetDb: ", destination.ToBase32(), " destination requested, but no floodfills found");
m_Requests.RequestComplete (destination, nullptr);
}
}
@@ -452,7 +453,7 @@ namespace data
IdentHash ident (buf + DATABASE_STORE_KEY_OFFSET);
if (ident.IsZero ())
{
LogPrint (eLogError, "Database store with zero ident. Dropped");
LogPrint (eLogError, "NetDb: database store with zero ident, dropped");
return;
}
uint32_t replyToken = bufbe32toh (buf + DATABASE_STORE_REPLY_TOKEN_OFFSET);
@@ -471,43 +472,49 @@ namespace data
if (outbound)
outbound->SendTunnelDataMsg (buf + offset, tunnelID, deliveryStatus);
else
LogPrint (eLogError, "No outbound tunnels for DatabaseStore reply found");
LogPrint (eLogError, "NetDb: no outbound tunnels for DatabaseStore reply found");
}
offset += 32;
if (context.IsFloodfill ())
{
// flood it
auto floodMsg = ToSharedI2NPMessage (NewI2NPShortMessage ());
auto floodMsg = NewI2NPShortMessage ();
uint8_t * payload = floodMsg->GetPayload ();
memcpy (payload, buf, 33); // key + type
htobe32buf (payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, 0); // zero reply token
memcpy (payload + DATABASE_STORE_HEADER_SIZE, buf + offset, len - offset);
floodMsg->len += DATABASE_STORE_HEADER_SIZE + len -offset;
floodMsg->FillI2NPMessageHeader (eI2NPDatabaseStore);
std::set<IdentHash> excluded;
for (int i = 0; i < 3; i++)
{
auto floodfill = GetClosestFloodfill (ident, excluded);
if (floodfill)
transports.SendMessage (floodfill->GetIdentHash (), floodMsg);
auto msgLen = len - offset;
floodMsg->len += DATABASE_STORE_HEADER_SIZE + msgLen;
if (floodMsg->len < floodMsg->maxLen)
{
memcpy (payload + DATABASE_STORE_HEADER_SIZE, buf + offset, msgLen);
floodMsg->FillI2NPMessageHeader (eI2NPDatabaseStore);
std::set<IdentHash> excluded;
for (int i = 0; i < 3; i++)
{
auto floodfill = GetClosestFloodfill (ident, excluded);
if (floodfill)
transports.SendMessage (floodfill->GetIdentHash (), floodMsg);
}
}
else
LogPrint (eLogError, "Database store message is too long ", floodMsg->len);
}
}
if (buf[DATABASE_STORE_TYPE_OFFSET]) // type
{
LogPrint ("LeaseSet");
LogPrint (eLogDebug, "NetDb: store request: LeaseSet");
AddLeaseSet (ident, buf + offset, len - offset, m->from);
}
else
{
LogPrint ("RouterInfo");
LogPrint (eLogDebug, "NetDb: store request: RouterInfo");
size_t size = bufbe16toh (buf + offset);
offset += 2;
if (size > 2048 || size > len - offset)
{
LogPrint ("Invalid RouterInfo length ", (int)size);
LogPrint (eLogError, "NetDb: invalid RouterInfo length ", (int)size);
return;
}
uint8_t uncompressed[2048];
@@ -524,7 +531,7 @@ namespace data
int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48);
key[l] = 0;
int num = buf[32]; // num
LogPrint ("DatabaseSearchReply for ", key, " num=", num);
LogPrint (eLogDebug, "NetDb: DatabaseSearchReply for ", key, " num=", num);
IdentHash ident (buf);
auto dest = m_Requests.FindRequest (ident);
if (dest)
@@ -556,7 +563,7 @@ namespace data
});
// request destination
LogPrint ("Try ", key, " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 ());
LogPrint (eLogDebug, "NetDb: Try ", key, " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 ());
auto msg = dest->CreateRequestMessage (nextFloodfill, inbound);
msgs.push_back (i2p::tunnel::TunnelMessageBlock
{
@@ -567,7 +574,7 @@ namespace data
}
}
else
LogPrint (key, " was not found on 7 floodfills");
LogPrint (eLogWarning, "NetDb: ", key, " was not found on ", count, " floodfills");
if (msgs.size () > 0)
outbound->SendTunnelDataMsg (msgs);
@@ -583,7 +590,7 @@ namespace data
m_Requests.RequestComplete (ident, nullptr);
}
else
LogPrint ("Requested destination for ", key, " not found");
LogPrint (eLogWarning, "NetDb: requested destination for ", key, " not found");
// try responses
for (int i = 0; i < num; i++)
@@ -592,17 +599,17 @@ namespace data
char peerHash[48];
int l1 = i2p::data::ByteStreamToBase64 (router, 32, peerHash, 48);
peerHash[l1] = 0;
LogPrint (i,": ", peerHash);
LogPrint (eLogDebug, "NetDb: ", i, ": ", peerHash);
auto r = FindRouter (router);
if (!r || i2p::util::GetMillisecondsSinceEpoch () > r->GetTimestamp () + 3600*1000LL)
{
// router with ident not found or too old (1 hour)
LogPrint ("Found new/outdated router. Requesting RouterInfo ...");
LogPrint (eLogDebug, "NetDb: found new/outdated router. Requesting RouterInfo ...");
RequestDestination (router);
}
else
LogPrint ("Bayan");
LogPrint (eLogDebug, "NetDb: [:|||:]");
}
}
@@ -612,14 +619,14 @@ namespace data
IdentHash ident (buf);
if (ident.IsZero ())
{
LogPrint (eLogError, "DatabaseLookup for zero ident. Ignored");
LogPrint (eLogError, "NetDb: DatabaseLookup for zero ident. Ignored");
return;
}
char key[48];
int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48);
key[l] = 0;
uint8_t flag = buf[64];
LogPrint ("DatabaseLookup for ", key, " recieved flags=", (int)flag);
LogPrint (eLogDebug, "NetDb: DatabaseLookup for ", key, " recieved flags=", (int)flag);
uint8_t lookupType = flag & DATABASE_LOOKUP_TYPE_FLAGS_MASK;
const uint8_t * excluded = buf + 65;
uint32_t replyTunnelID = 0;
@@ -632,14 +639,14 @@ namespace data
excluded += 2;
if (numExcluded > 512)
{
LogPrint ("Number of excluded peers", numExcluded, " exceeds 512");
LogPrint (eLogWarning, "NetDb: number of excluded peers", numExcluded, " exceeds 512");
numExcluded = 0; // TODO:
}
std::shared_ptr<I2NPMessage> replyMsg;
if (lookupType == DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP)
{
LogPrint ("Exploratory close to ", key, " ", numExcluded, " excluded");
LogPrint (eLogInfo, "NetDb: exploratory close to ", key, " ", numExcluded, " excluded");
std::set<IdentHash> excludedRouters;
for (int i = 0; i < numExcluded; i++)
{
@@ -666,7 +673,7 @@ namespace data
auto router = FindRouter (ident);
if (router)
{
LogPrint ("Requested RouterInfo ", key, " found");
LogPrint (eLogDebug, "NetDb: requested RouterInfo ", key, " found");
router->LoadBuffer ();
if (router->GetBuffer ())
replyMsg = CreateDatabaseStoreMsg (router);
@@ -679,14 +686,14 @@ namespace data
auto leaseSet = FindLeaseSet (ident);
if (leaseSet) // we don't send back our LeaseSets
{
LogPrint ("Requested LeaseSet ", key, " found");
LogPrint (eLogDebug, "NetDb: requested LeaseSet ", key, " found");
replyMsg = CreateDatabaseStoreMsg (leaseSet);
}
}
if (!replyMsg)
{
LogPrint ("Requested ", key, " not found. ", numExcluded, " excluded");
LogPrint (eLogWarning, "NetDb: Requested ", key, " not found. ", numExcluded, " excluded");
std::set<IdentHash> excludedRouters;
for (int i = 0; i < numExcluded; i++)
{
@@ -736,14 +743,14 @@ namespace data
uint8_t randomHash[32];
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
std::set<const RouterInfo *> floodfills;
LogPrint ("Exploring new ", numDestinations, " routers ...");
LogPrint (eLogInfo, "NetDb: exploring new ", numDestinations, " routers ...");
for (int i = 0; i < numDestinations; i++)
{
RAND_bytes (randomHash, 32);
auto dest = m_Requests.CreateRequest (randomHash, true); // exploratory
if (!dest)
{
LogPrint (eLogWarning, "Exploratory destination is requested already");
LogPrint (eLogWarning, "NetDb: exploratory destination is requested already");
return;
}
auto floodfill = GetClosestFloodfill (randomHash, dest->GetExcludedPeers ());
@@ -779,6 +786,7 @@ namespace data
void NetDb::Publish ()
{
i2p::context.UpdateStats (); // for floodfill
std::set<IdentHash> excluded; // TODO: fill up later
for (int i = 0; i < 2; i++)
{
@@ -787,7 +795,7 @@ namespace data
{
uint32_t replyToken;
RAND_bytes ((uint8_t *)&replyToken, 4);
LogPrint ("Publishing our RouterInfo to ", i2p::data::GetIdentHashAbbreviation(floodfill->GetIdentHash ()), ". reply token=", replyToken);
LogPrint (eLogInfo, "NetDb: Publishing our RouterInfo to ", i2p::data::GetIdentHashAbbreviation(floodfill->GetIdentHash ()), ". reply token=", replyToken);
transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken));
excluded.insert (floodfill->GetIdentHash ());
}
@@ -973,7 +981,7 @@ namespace data
{
if (!it->second->HasNonExpiredLeases ()) // all leases expired
{
LogPrint ("LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired");
LogPrint (eLogWarning, "NetDb: LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired");
it = m_LeaseSets.erase (it);
}
else

View File

@@ -57,7 +57,7 @@ namespace data
for (int i = 0; i < 64; i++)
{
auto path1 = path / (std::string ("p") + chars[i]);
if (!boost::filesystem::create_directory (path1))
if (!boost::filesystem::exists (path1) && !boost::filesystem::create_directory (path1))
{
LogPrint (eLogError, "Failed to create directory ", path1);
return;

128
README.md
View File

@@ -17,129 +17,25 @@ BTC: 1K7Ds6KUeR8ya287UC4rYTjvC96vXyZbDY
LTC: LKQirrYrDeTuAPnpYq5y7LVKtywfkkHi59
ANC: AQJYweYYUqM1nVfLqfoSMpUMfzxvS4Xd7z
Requirements for Linux/FreeBSD/OSX
----------------------------------
GCC 4.6 or newer, Boost 1.46 or newer, openssl, zlib. Clang can be used instead of
GCC.
Requirements for Windows
------------------------
VS2013 (known to work with 12.0.21005.1 or newer), Boost 1.46 or newer,
crypto++ 5.62. See Win32/README-Build.txt for instructions on how to build i2pd
and its dependencies.
Downloads
------------
Official binary releases could be found at:
http://i2pd.website/releases/
older releases
http://download.i2p.io/purplei2p/i2pd/releases/
Build Statuses
---------------
- Linux x64 - [![Build Status](https://jenkins.greyhat.no/buildStatus/icon?job=i2pd-linux)](https://jenkins.nordcloud.no/job/i2pd-linux/)
- Linux ARM - To be added
- Mac OS X - Got it working, but not well tested. (Only works with clang, not GCC.)
- Microsoft VC13 - To be added
Testing
-------
First, build it.
On Ubuntu/Debian based
* sudo apt-get install libboost-dev libboost-filesystem-dev libboost-program-options-dev libboost-regex-dev libboost-date-time-dev libssl-dev zlib1g-dev
* $ cd i2pd
* $ make
Then, run it:
$ ./i2p
The client should now reseed by itself.
To visit an I2P page, you need to find the b32 address of your destination.
After that, go to the webconsole and add it behind the url. (Remove http:// from the address)
This should resulting in for example:
http://localhost:7070/4oes3rlgrpbkmzv4lqcfili23h3cvpwslqcfjlk6vvguxyggspwa.b32.i2p
Cmdline options
---------------
* --host= - The external IP (deprecated).
* --port= - The port to listen on
* --httpport= - The http port to listen on
* --log= - Enable or disable logging to file. 1 for yes, 0 for no.
* --daemon= - Enable or disable daemon mode. 1 for yes, 0 for no.
* --service= - 1 if uses system folders (/var/run/i2pd.pid, /var/log/i2pd.log, /var/lib/i2pd).
* --v6= - 1 if supports communication through ipv6, off by default
* --floodfill= - 1 if router is floodfill, off by default
* --bandwidth= - L if bandwidth is limited to 32Kbs/sec, O if not. Always O if floodfill, otherwise L by default.
* --httpproxyport= - The port to listen on (HTTP Proxy)
* --socksproxyport= - The port to listen on (SOCKS Proxy)
* --proxykeys= - optional keys file for proxy's local destination
* --ircport= - The local port of IRC tunnel to listen on. 6668 by default
* --ircdest= - I2P destination address of IRC server. For example irc.postman.i2p
* --irckeys= - optional keys file for tunnel's local destination
* --eepkeys= - File name containing destination keys, for example privKeys.dat.
The file will be created if it does not already exist (issue #110).
* --eephost= - Address incoming trafic forward to. 127.0.0.1 by default
* --eepport= - Port incoming trafic forward to. 80 by default
* --samport= - Port of SAM bridge. Usually 7656. SAM is off if not specified
* --bobport= - Port of BOB command channel. Usually 2827. BOB is off if not specified
* --i2pcontrolport= - Port of I2P control service. Usually 7650. I2PControl is off if not specified
* --conf= - Config file (default: ~/.i2pd/i2p.conf or /var/lib/i2pd/i2p.conf)
This parameter will be silently ignored if the specified config file does not exist.
Options specified on the command line take precedence over those in the config file.
Config files
Supported OS
------------
INI-like, syntax is the following : <key> = <value>.
All command-line parameters are allowed as keys, for example:
* Linux x86/x64 - Proved working.
* Mac OS X - Not well tested. (Only works with clang, not GCC)
* Windows - [![Build status](https://ci.appveyor.com/api/projects/status/1908qe4p48ff1x23?svg=true)](https://ci.appveyor.com/project/PurpleI2P/i2pd)
i2p.conf:
More documentation
------------------
log = 1
v6 = 0
ircdest = irc.postman.i2p
tunnels.cfg (filename of this config is subject of change):
; outgoing tunnel sample, to remote service
; mandatory parameters:
; * type -- always "client"
; * port -- local port to listen to
; * destination -- i2p hostname
; optional parameters (may be omitted)
; * keys -- our identity, if unset, will be generated on every startup,
; if set and file missing, keys will be generated and placed to this file
[IRC]
type = client
port = 6668
destination = irc.echelon.i2p
keys = irc-keys.dat
; incoming tunnel sample, for local service
; mandatory parameters:
; * type -- always "server"
; * host -- ip address of our service
; * port -- port of our service
; * keys -- file with LeaseSet of address in i2p
; optional parameters (may be omitted)
; * inport -- optional, i2p service port, if unset - the same as 'port'
; * accesslist -- comma-separated list of i2p addresses, allowed to connect
; every address is b32 without '.b32.i2p' part
[LOCALSITE]
type = server
host = 127.0.0.1
port = 80
keys = site-keys.dat
inport = 81
accesslist = <b32>[,<b32>]
* [Building from source / unix](docs/build_notes_unix.md)
* [Building from source / windows](docs/build_notes_windows.md)
* [Configuring your i2pd](docs/configuration.md)
* [Github wiki](https://github.com/PurpleI2P/i2pd/wiki/)

View File

@@ -30,6 +30,7 @@ namespace data
"https://netdb.i2p2.no/", // Only SU3 (v3) support, SNI required
"https://us.reseed.i2p2.no:444/",
"https://uk.reseed.i2p2.no:444/",
"https://www.torontocrypto.org:8443/"
"https://reseed.i2p.vzaws.com:8443/", // Only SU3 (v3) support
"https://user.mx24.eu/", // Only HTTPS and SU3 (v3) support
"https://ieb9oopo.mooo.com/" // Only HTTPS and SU3 (v3) support
@@ -47,14 +48,14 @@ namespace data
{
auto ind = rand () % httpsReseedHostList.size ();
std::string& reseedHost = httpsReseedHostList[ind];
return ReseedFromSU3 (reseedHost, true);
return ReseedFromSU3 (reseedHost);
}
int Reseeder::ReseedFromSU3 (const std::string& host, bool https)
int Reseeder::ReseedFromSU3 (const std::string& host)
{
std::string url = host + "i2pseeds.su3";
LogPrint (eLogInfo, "Dowloading SU3 from ", host);
std::string su3 = https ? HttpsRequest (url) : i2p::util::http::httpRequest (url);
LogPrint (eLogInfo, "Reseed: Downloading SU3 from ", host);
std::string su3 = HttpsRequest (url);
if (su3.length () > 0)
{
std::stringstream s(su3);
@@ -62,7 +63,7 @@ namespace data
}
else
{
LogPrint (eLogWarning, "SU3 download failed");
LogPrint (eLogWarning, "Reseed: SU3 download failed");
return 0;
}
}
@@ -74,7 +75,7 @@ namespace data
return ProcessSU3Stream (s);
else
{
LogPrint (eLogError, "Can't open file ", filename);
LogPrint (eLogError, "Reseed: Can't open file ", filename);
return 0;
}
}
@@ -89,7 +90,7 @@ namespace data
s.read (magicNumber, 7); // magic number and zero byte 6
if (strcmp (magicNumber, SU3_MAGIC_NUMBER))
{
LogPrint (eLogError, "Unexpected SU3 magic number");
LogPrint (eLogError, "Reseed: Unexpected SU3 magic number");
return 0;
}
s.seekg (1, std::ios::cur); // su3 file format version
@@ -113,7 +114,7 @@ namespace data
s.read ((char *)&fileType, 1); // file type
if (fileType != 0x00) // zip file
{
LogPrint (eLogError, "Can't handle file type ", (int)fileType);
LogPrint (eLogError, "Reseed: Can't handle file type ", (int)fileType);
return 0;
}
s.seekg (1, std::ios::cur); // unused
@@ -121,7 +122,7 @@ namespace data
s.read ((char *)&contentType, 1); // content type
if (contentType != 0x03) // reseed data
{
LogPrint (eLogError, "Unexpected content type ", (int)contentType);
LogPrint (eLogError, "Reseed: Unexpected content type ", (int)contentType);
return 0;
}
s.seekg (12, std::ios::cur); // unused
@@ -155,13 +156,13 @@ namespace data
BIGNUM * s = BN_new (), * n = BN_new ();
BN_bin2bn (signature, signatureLength, s);
BN_bin2bn (it->second, i2p::crypto::RSASHA5124096_KEY_LENGTH, n);
BN_mod_exp (s, s, i2p::crypto::rsae, n, bnctx); // s = s^e mod n
BN_mod_exp (s, s, i2p::crypto::GetRSAE (), n, bnctx); // s = s^e mod n
uint8_t * enSigBuf = new uint8_t[signatureLength];
i2p::crypto::bn2buf (s, enSigBuf, signatureLength);
// digest is right aligned
// we can't use RSA_verify due wrong padding in SU3
if (memcmp (enSigBuf + (signatureLength - 64), digest, 64))
LogPrint (eLogWarning, "SU3 signature verification failed");
LogPrint (eLogWarning, "Reseed: SU3 signature verification failed");
delete[] enSigBuf;
BN_free (s); BN_free (n);
BN_CTX_free (bnctx);
@@ -172,10 +173,10 @@ namespace data
s.seekg (pos, std::ios::beg);
}
else
LogPrint (eLogWarning, "Signature type ", signatureType, " is not supported");
LogPrint (eLogWarning, "Reseed: Signature type ", signatureType, " is not supported");
}
else
LogPrint (eLogWarning, "Certificate for ", signerID, " not loaded");
LogPrint (eLogWarning, "Reseed: Certificate for ", signerID, " not loaded");
// handle content
int numFiles = 0;
@@ -219,7 +220,7 @@ namespace data
size_t pos = s.tellg ();
if (!FindZipDataDescriptor (s))
{
LogPrint (eLogError, "SU3 archive data descriptor not found");
LogPrint (eLogError, "Reseed: SU3 archive data descriptor not found");
return numFiles;
}
s.read ((char *)&crc_32, 4);
@@ -233,10 +234,10 @@ namespace data
s.seekg (pos, std::ios::beg); // back to compressed data
}
LogPrint (eLogDebug, "Proccessing file ", localFileName, " ", compressedSize, " bytes");
LogPrint (eLogDebug, "Reseed: Proccessing file ", localFileName, " ", compressedSize, " bytes");
if (!compressedSize)
{
LogPrint (eLogWarning, "Unexpected size 0. Skipped");
LogPrint (eLogWarning, "Reseed: Unexpected size 0. Skipped");
continue;
}
@@ -262,10 +263,10 @@ namespace data
numFiles++;
}
else
LogPrint (eLogError, "CRC32 verification failed");
LogPrint (eLogError, "Reseed: CRC32 verification failed");
}
else
LogPrint (eLogError, "decompression error ", err);
LogPrint (eLogError, "Reseed: SU3 decompression error ", err);
delete[] uncompressed;
inflateEnd (&inflator);
}
@@ -281,7 +282,7 @@ namespace data
else
{
if (signature != ZIP_CENTRAL_DIRECTORY_HEADER_SIGNATURE)
LogPrint (eLogWarning, "Missing zip central directory header");
LogPrint (eLogWarning, "Reseed: Missing zip central directory header");
break; // no more files
}
size_t end = s.tellg ();
@@ -334,7 +335,7 @@ namespace data
SSL_free (ssl);
}
else
LogPrint (eLogError, "Can't open certificate file ", filename);
LogPrint (eLogError, "Reseed: Can't open certificate file ", filename);
SSL_CTX_free (ctx);
}
@@ -344,7 +345,7 @@ namespace data
if (!boost::filesystem::exists (reseedDir))
{
LogPrint (eLogWarning, "Reseed certificates not loaded. ", reseedDir, " doesn't exist");
LogPrint (eLogWarning, "Reseed: certificates not loaded, ", reseedDir, " doesn't exist");
return;
}
@@ -358,7 +359,7 @@ namespace data
numCertificates++;
}
}
LogPrint (eLogInfo, numCertificates, " certificates loaded");
LogPrint (eLogInfo, "Reseed: ", numCertificates, " certificates loaded");
}
std::string Reseeder::HttpsRequest (const std::string& address)
@@ -381,7 +382,7 @@ namespace data
s.handshake (boost::asio::ssl::stream_base::client, ecode);
if (!ecode)
{
LogPrint (eLogInfo, "Connected to ", u.host_, ":", u.port_);
LogPrint (eLogInfo, "Reseed: Connected to ", u.host_, ":", u.port_);
// send request
std::stringstream ss;
ss << "GET " << u.path_ << " HTTP/1.1\r\nHost: " << u.host_
@@ -400,13 +401,13 @@ namespace data
return i2p::util::http::GetHttpContent (rs);
}
else
LogPrint (eLogError, "SSL handshake failed: ", ecode.message ());
LogPrint (eLogError, "Reseed: SSL handshake failed: ", ecode.message ());
}
else
LogPrint (eLogError, "Couldn't connect to ", u.host_, ": ", ecode.message ());
LogPrint (eLogError, "Reseed: Couldn't connect to ", u.host_, ": ", ecode.message ());
}
else
LogPrint (eLogError, "Couldn't resolve address ", u.host_, ": ", ecode.message ());
LogPrint (eLogError, "Reseed: Couldn't resolve address ", u.host_, ": ", ecode.message ());
return "";
}
}

View File

@@ -29,7 +29,7 @@ namespace data
void LoadCertificate (const std::string& filename);
int ReseedFromSU3 (const std::string& host, bool https = false);
int ReseedFromSU3 (const std::string& host);
int ProcessSU3File (const char * filename);
int ProcessSU3Stream (std::istream& s);

View File

@@ -46,8 +46,8 @@ namespace i2p
int port = i2p::util::config::GetArg("-port", 0);
if (!port)
port = rand () % (30777 - 9111) + 9111; // I2P network ports range
routerInfo.AddSSUAddress (i2p::util::config::GetCharArg("-host", "127.0.0.1"), port, routerInfo.GetIdentHash ());
routerInfo.AddNTCPAddress (i2p::util::config::GetCharArg("-host", "127.0.0.1"), port);
routerInfo.AddSSUAddress (i2p::util::config::GetArg("-host", "127.0.0.1").c_str (), port, routerInfo.GetIdentHash ());
routerInfo.AddNTCPAddress (i2p::util::config::GetArg("-host", "127.0.0.1").c_str (), port);
routerInfo.SetCaps (i2p::data::RouterInfo::eReachable |
i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer); // LR, BC
routerInfo.SetProperty ("coreVersion", I2P_VERSION);
@@ -147,22 +147,31 @@ namespace i2p
void RouterContext::SetHighBandwidth ()
{
if (!m_RouterInfo.IsHighBandwidth ())
if (!m_RouterInfo.IsHighBandwidth () || m_RouterInfo.IsExtraBandwidth ())
{
m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eHighBandwidth);
m_RouterInfo.SetCaps ((m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eHighBandwidth) & ~i2p::data::RouterInfo::eExtraBandwidth);
UpdateRouterInfo ();
}
}
void RouterContext::SetLowBandwidth ()
{
if (m_RouterInfo.IsHighBandwidth ())
if (m_RouterInfo.IsHighBandwidth () || m_RouterInfo.IsExtraBandwidth ())
{
m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () & ~i2p::data::RouterInfo::eHighBandwidth);
m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () & ~i2p::data::RouterInfo::eHighBandwidth & ~i2p::data::RouterInfo::eExtraBandwidth);
UpdateRouterInfo ();
}
}
void RouterContext::SetExtraBandwidth ()
{
if (!m_RouterInfo.IsExtraBandwidth () || !m_RouterInfo.IsHighBandwidth ())
{
m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eExtraBandwidth | i2p::data::RouterInfo::eHighBandwidth);
UpdateRouterInfo ();
}
}
bool RouterContext::IsUnreachable () const
{
return m_RouterInfo.GetCaps () & i2p::data::RouterInfo::eUnreachable;
@@ -255,8 +264,11 @@ namespace i2p
auto mtu = i2p::util::net::GetMTU (host);
if (mtu)
{
LogPrint ("Our v6 MTU=", mtu);
if (mtu > 1472) mtu = 1472;
LogPrint (eLogDebug, "Router: Our v6 MTU=", mtu);
if (mtu > 1472) { // TODO: magic constant
mtu = 1472;
LogPrint(eLogWarning, "Router: MTU dropped to upper limit of 1472 bytes");
}
}
m_RouterInfo.AddSSUAddress (host.to_string ().c_str (), port, GetIdentHash (), mtu ? mtu : 1472); // TODO
updated = true;

View File

@@ -39,6 +39,12 @@ namespace i2p
return std::shared_ptr<const i2p::data::RouterInfo> (&m_RouterInfo,
[](const i2p::data::RouterInfo *) {});
}
std::shared_ptr<i2p::garlic::GarlicDestination> GetSharedDestination ()
{
return std::shared_ptr<i2p::garlic::GarlicDestination> (this,
[](i2p::garlic::GarlicDestination *) {});
}
uint32_t GetUptime () const;
uint32_t GetStartupTime () const { return m_StartupTime; };
uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; };
@@ -56,6 +62,7 @@ namespace i2p
void SetFloodfill (bool floodfill);
void SetHighBandwidth ();
void SetLowBandwidth ();
void SetExtraBandwidth ();
bool AcceptsTunnels () const { return m_AcceptsTunnels; };
void SetAcceptsTunnels (bool acceptsTunnels) { m_AcceptsTunnels = acceptsTunnels; };
bool SupportsV6 () const { return m_RouterInfo.IsV6 (); };

View File

@@ -62,10 +62,9 @@ namespace data
}
else
{
LogPrint (eLogError, "RouterInfo signature verification failed");
LogPrint (eLogError, "RouterInfo: signature verification failed");
m_IsUnreachable = true;
}
m_RouterIdentity->DropVerifier ();
}
void RouterInfo::SetRouterIdentity (std::shared_ptr<const IdentityEx> identity)
@@ -83,7 +82,7 @@ namespace data
m_BufferLen = s.tellg ();
if (m_BufferLen < 40)
{
LogPrint(eLogError, "File", m_FullPath, " is malformed");
LogPrint(eLogError, "RouterInfo: File", m_FullPath, " is malformed");
return false;
}
s.seekg(0, std::ios::beg);
@@ -93,7 +92,7 @@ namespace data
}
else
{
LogPrint (eLogError, "Can't open file ", m_FullPath);
LogPrint (eLogError, "RouterInfo: Can't open file ", m_FullPath);
return false;
}
return true;
@@ -117,7 +116,7 @@ namespace data
int l = m_BufferLen - m_RouterIdentity->GetSignatureLen ();
if (!m_RouterIdentity->Verify ((uint8_t *)m_Buffer, l, (uint8_t *)m_Buffer + l))
{
LogPrint (eLogError, "RouterInfo signature verification failed");
LogPrint (eLogError, "RouterInfo: signature verification failed");
m_IsUnreachable = true;
}
m_RouterIdentity->DropVerifier ();
@@ -171,9 +170,8 @@ namespace data
}
else
{
// TODO: resolve address for SSU
LogPrint (eLogWarning, "Unexpected SSU address ", value);
isValidAddress = false;
m_SupportedTransports |= eSSUV4; // TODO:
address.addressString = value;
}
}
else
@@ -266,6 +264,10 @@ namespace data
case CAPS_FLAG_HIGH_BANDWIDTH3:
m_Caps |= Caps::eHighBandwidth;
break;
case CAPS_FLAG_EXTRA_BANDWIDTH1:
case CAPS_FLAG_EXTRA_BANDWIDTH2:
m_Caps |= Caps::eExtraBandwidth;
break;
case CAPS_FLAG_HIDDEN:
m_Caps |= Caps::eHidden;
break;
@@ -292,11 +294,15 @@ namespace data
std::string caps;
if (m_Caps & eFloodfill)
{
caps += CAPS_FLAG_HIGH_BANDWIDTH3; // highest bandwidth
if (m_Caps & eExtraBandwidth) caps += CAPS_FLAG_EXTRA_BANDWIDTH1; // 'P'
caps += CAPS_FLAG_HIGH_BANDWIDTH3; // 'O'
caps += CAPS_FLAG_FLOODFILL; // floodfill
}
else
caps += (m_Caps & eHighBandwidth) ? CAPS_FLAG_HIGH_BANDWIDTH3 : CAPS_FLAG_LOW_BANDWIDTH2; // bandwidth
{
if (m_Caps & eExtraBandwidth) caps += CAPS_FLAG_EXTRA_BANDWIDTH1;
caps += (m_Caps & eHighBandwidth) ? CAPS_FLAG_HIGH_BANDWIDTH3 : CAPS_FLAG_LOW_BANDWIDTH2; // bandwidth
}
if (m_Caps & eHidden) caps += CAPS_FLAG_HIDDEN; // hidden
if (m_Caps & eReachable) caps += CAPS_FLAG_REACHABLE; // reachable
if (m_Caps & eUnreachable) caps += CAPS_FLAG_UNREACHABLE; // unreachable
@@ -433,7 +439,7 @@ namespace data
if (!m_Buffer)
{
if (LoadFile ())
LogPrint ("Buffer for ", GetIdentHashAbbreviation (GetIdentHash ()), " loaded from file");
LogPrint (eLogDebug, "RouterInfo: Buffer for ", GetIdentHashAbbreviation (GetIdentHash ()), " loaded from file");
}
return m_Buffer;
}
@@ -464,10 +470,10 @@ namespace data
if (f.is_open ())
f.write ((char *)m_Buffer, m_BufferLen);
else
LogPrint(eLogError, "Can't save RouterInfo to ", fullPath);
LogPrint(eLogError, "RouterInfo: Can't save to ", fullPath);
}
else
LogPrint (eLogError, "Can't save RouterInfo m_Buffer==NULL");
LogPrint (eLogError, "RouterInfo: Can't save, m_Buffer == NULL");
}
size_t RouterInfo::ReadString (char * str, std::istream& s)
@@ -514,7 +520,7 @@ namespace data
for (auto it: m_Addresses) // don't insert same address twice
if (it == addr) return;
m_Addresses.push_back(addr);
m_SupportedTransports |= addr.host.is_v6 () ? eNTCPV6 : eSSUV4;
m_SupportedTransports |= addr.host.is_v6 () ? eSSUV6 : eSSUV4;
m_Caps |= eSSUTesting;
m_Caps |= eSSUIntroducer;
}

View File

@@ -23,7 +23,9 @@ namespace data
const char CAPS_FLAG_HIGH_BANDWIDTH1 = 'M';
const char CAPS_FLAG_HIGH_BANDWIDTH2 = 'N';
const char CAPS_FLAG_HIGH_BANDWIDTH3 = 'O';
const char CAPS_FLAG_EXTRA_BANDWIDTH1 = 'P';
const char CAPS_FLAG_EXTRA_BANDWIDTH2 = 'X';
const char CAPS_FLAG_SSU_TESTING = 'B';
const char CAPS_FLAG_SSU_INTRODUCER = 'C';
@@ -44,11 +46,12 @@ namespace data
{
eFloodfill = 0x01,
eHighBandwidth = 0x02,
eReachable = 0x04,
eSSUTesting = 0x08,
eSSUIntroducer = 0x10,
eHidden = 0x20,
eUnreachable = 0x40
eExtraBandwidth = 0x04,
eReachable = 0x08,
eSSUTesting = 0x10,
eSSUIntroducer = 0x20,
eHidden = 0x40,
eUnreachable = 0x80
};
enum TransportStyle
@@ -131,7 +134,8 @@ namespace data
bool IsPeerTesting () const { return m_Caps & eSSUTesting; };
bool IsHidden () const { return m_Caps & eHidden; };
bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; };
bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; };
uint8_t GetCaps () const { return m_Caps; };
void SetCaps (uint8_t caps);
void SetCaps (const char * caps);

84
SAM.cpp
View File

@@ -78,7 +78,7 @@ namespace client
{
if (ecode)
{
LogPrint ("SAM handshake read error: ", ecode.message ());
LogPrint (eLogError, "SAM: handshake read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
@@ -88,7 +88,7 @@ namespace client
char * eol = (char *)memchr (m_Buffer, '\n', bytes_transferred);
if (eol)
*eol = 0;
LogPrint ("SAM handshake ", m_Buffer);
LogPrint (eLogDebug, "SAM: handshake ", m_Buffer);
char * separator = strchr (m_Buffer, ' ');
if (separator)
{
@@ -127,7 +127,7 @@ namespace client
}
else
{
LogPrint ("SAM handshake mismatch");
LogPrint (eLogError, "SAM: handshake mismatch");
Terminate ();
}
}
@@ -137,7 +137,7 @@ namespace client
{
if (ecode)
{
LogPrint ("SAM handshake reply send error: ", ecode.message ());
LogPrint (eLogError, "SAM: handshake reply send error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
@@ -168,7 +168,7 @@ namespace client
{
if (ecode)
{
LogPrint ("SAM reply send error: ", ecode.message ());
LogPrint (eLogError, "SAM: reply send error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
@@ -185,7 +185,7 @@ namespace client
{
if (ecode)
{
LogPrint ("SAM read error: ", ecode.message ());
LogPrint (eLogError, "SAM: read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
@@ -240,19 +240,19 @@ namespace client
}
else
{
LogPrint (eLogError, "SAM unexpected message ", m_Buffer);
LogPrint (eLogError, "SAM: unexpected message ", m_Buffer);
Terminate ();
}
}
else
{
LogPrint (eLogError, "SAM malformed message ", m_Buffer);
LogPrint (eLogError, "SAM: malformed message ", m_Buffer);
Terminate ();
}
}
else
{
LogPrint (eLogWarning, "SAM incomplete message ", bytes_transferred);
LogPrint (eLogWarning, "SAM: incomplete message ", bytes_transferred);
m_BufferOffset = bytes_transferred;
// try to receive remaining message
Receive ();
@@ -262,7 +262,7 @@ namespace client
void SAMSocket::ProcessSessionCreate (char * buf, size_t len)
{
LogPrint ("SAM session create: ", buf);
LogPrint (eLogDebug, "SAM: session create: ", buf);
std::map<std::string, std::string> params;
ExtractParams (buf, params);
std::string& style = params[SAM_PARAM_STYLE];
@@ -333,7 +333,7 @@ namespace client
void SAMSocket::ProcessStreamConnect (char * buf, size_t len)
{
LogPrint (eLogDebug, "SAM stream connect: ", buf);
LogPrint (eLogDebug, "SAM: stream connect: ", buf);
std::map<std::string, std::string> params;
ExtractParams (buf, params);
std::string& id = params[SAM_PARAM_ID];
@@ -382,14 +382,14 @@ namespace client
Connect (leaseSet);
else
{
LogPrint ("SAM destination to connect not found");
LogPrint (eLogError, "SAM: destination to connect not found");
SendMessageReply (SAM_STREAM_STATUS_CANT_REACH_PEER, strlen(SAM_STREAM_STATUS_CANT_REACH_PEER), true);
}
}
void SAMSocket::ProcessStreamAccept (char * buf, size_t len)
{
LogPrint (eLogDebug, "SAM stream accept: ", buf);
LogPrint (eLogDebug, "SAM: stream accept: ", buf);
std::map<std::string, std::string> params;
ExtractParams (buf, params);
std::string& id = params[SAM_PARAM_ID];
@@ -415,7 +415,7 @@ namespace client
size_t SAMSocket::ProcessDatagramSend (char * buf, size_t len, const char * data)
{
LogPrint (eLogDebug, "SAM datagram send: ", buf, " ", len);
LogPrint (eLogDebug, "SAM: datagram send: ", buf, " ", len);
std::map<std::string, std::string> params;
ExtractParams (buf, params);
size_t size = boost::lexical_cast<int>(params[SAM_PARAM_SIZE]), offset = data - buf;
@@ -431,14 +431,14 @@ namespace client
d->SendDatagramTo ((const uint8_t *)data, size, dest.GetIdentHash ());
}
else
LogPrint (eLogError, "SAM missing datagram destination");
LogPrint (eLogError, "SAM: missing datagram destination");
}
else
LogPrint (eLogError, "SAM session is not created from DATAGRAM SEND");
LogPrint (eLogError, "SAM: session is not created from DATAGRAM SEND");
}
else
{
LogPrint (eLogWarning, "SAM sent datagram size ", size, " exceeds buffer ", len - offset);
LogPrint (eLogWarning, "SAM: sent datagram size ", size, " exceeds buffer ", len - offset);
return 0; // try to receive more
}
return offset + size;
@@ -446,7 +446,7 @@ namespace client
void SAMSocket::ProcessDestGenerate ()
{
LogPrint (eLogDebug, "SAM dest generate");
LogPrint (eLogDebug, "SAM: dest generate");
auto keys = i2p::data::PrivateKeys::CreateRandomKeys ();
#ifdef _MSC_VER
size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY,
@@ -460,7 +460,7 @@ namespace client
void SAMSocket::ProcessNamingLookup (char * buf, size_t len)
{
LogPrint (eLogDebug, "SAM naming lookup: ", buf);
LogPrint (eLogDebug, "SAM: naming lookup: ", buf);
std::map<std::string, std::string> params;
ExtractParams (buf, params);
std::string& name = params[SAM_PARAM_NAME];
@@ -483,7 +483,7 @@ namespace client
}
else
{
LogPrint ("SAM naming failed. Unknown address ", name);
LogPrint (eLogError, "SAM: naming failed, unknown address ", name);
#ifdef _MSC_VER
size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY_INVALID_KEY, name.c_str());
#else
@@ -502,7 +502,7 @@ namespace client
}
else
{
LogPrint (eLogInfo, "SAM naming lookup failed. LeaseSet for ", ident.ToBase32 (), " not found");
LogPrint (eLogError, "SAM: naming lookup failed. LeaseSet for ", ident.ToBase32 (), " not found");
#ifdef _MSC_VER
size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY_INVALID_KEY,
context.GetAddressBook ().ToAddress (ident).c_str());
@@ -548,7 +548,7 @@ namespace client
{
if (m_BufferOffset >= SAM_SOCKET_BUFFER_SIZE)
{
LogPrint (eLogError, "Buffer is full. Terminate");
LogPrint (eLogError, "SAM: Buffer is full, terminate");
Terminate ();
return;
}
@@ -561,7 +561,7 @@ namespace client
{
if (ecode)
{
LogPrint ("SAM read error: ", ecode.message ());
LogPrint (eLogError, "SAM: read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
@@ -595,7 +595,7 @@ namespace client
{
if (ecode)
{
LogPrint ("SAM stream read error: ", ecode.message ());
LogPrint (eLogError, "SAM: stream read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
@@ -610,7 +610,7 @@ namespace client
{
if (ecode)
{
LogPrint ("SAM socket write error: ", ecode.message ());
LogPrint (eLogError, "SAM: socket write error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
@@ -622,7 +622,7 @@ namespace client
{
if (stream)
{
LogPrint ("SAM incoming I2P connection for session ", m_ID);
LogPrint (eLogDebug, "SAM: incoming I2P connection for session ", m_ID);
m_Stream = stream;
context.GetAddressBook ().InsertAddress (stream->GetRemoteIdentity ());
auto session = m_Owner.FindSession (m_ID);
@@ -642,12 +642,12 @@ namespace client
I2PReceive ();
}
else
LogPrint (eLogInfo, "SAM I2P acceptor has been reset");
LogPrint (eLogWarning, "SAM: I2P acceptor has been reset");
}
void SAMSocket::HandleI2PDatagramReceive (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
{
LogPrint (eLogDebug, "SAM datagram received ", len);
LogPrint (eLogDebug, "SAM: datagram received ", len);
auto base64 = from.ToBase64 ();
#ifdef _MSC_VER
size_t l = sprintf_s ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), len);
@@ -661,7 +661,7 @@ namespace client
std::bind (&SAMSocket::HandleWriteI2PData, shared_from_this (), std::placeholders::_1));
}
else
LogPrint (eLogWarning, "SAM received datagram size ", len," exceeds buffer");
LogPrint (eLogWarning, "SAM: received datagram size ", len," exceeds buffer");
}
SAMSession::SAMSession (std::shared_ptr<ClientDestination> dest):
@@ -686,10 +686,10 @@ namespace client
sockets.clear ();
}
SAMBridge::SAMBridge (int port):
SAMBridge::SAMBridge (const std::string& address, int port):
m_IsRunning (false), m_Thread (nullptr),
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)),
m_DatagramEndpoint (boost::asio::ip::udp::v4 (), port-1), m_DatagramSocket (m_Service, m_DatagramEndpoint)
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)
{
}
@@ -733,7 +733,7 @@ namespace client
}
catch (std::exception& ex)
{
LogPrint ("SAM: ", ex.what ());
LogPrint (eLogError, "SAM: runtime exception: ", ex.what ());
}
}
}
@@ -753,14 +753,14 @@ namespace client
auto ep = socket->GetSocket ().remote_endpoint (ec);
if (!ec)
{
LogPrint ("New SAM connection from ", ep);
LogPrint (eLogDebug, "SAM: new connection from ", ep);
socket->ReceiveHandshake ();
}
else
LogPrint (eLogError, "SAM connection from error ", ec.message ());
LogPrint (eLogError, "SAM: incoming connection error ", ec.message ());
}
else
LogPrint ("SAM accept error: ", ecode.message ());
LogPrint (eLogError, "SAM: accept error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Accept ();
@@ -794,7 +794,7 @@ namespace client
std::unique_lock<std::mutex> l(m_SessionsMutex);
auto ret = m_Sessions.insert (std::pair<std::string, SAMSession *>(id, new SAMSession (localDestination)));
if (!ret.second)
LogPrint ("Session ", id, " already exists");
LogPrint (eLogWarning, "SAM: Session ", id, " already exists");
return ret.first->second;
}
return nullptr;
@@ -839,7 +839,7 @@ namespace client
char * eol = strchr ((char *)m_DatagramReceiveBuffer, '\n');
*eol = 0; eol++;
size_t payloadLen = bytes_transferred - ((uint8_t *)eol - m_DatagramReceiveBuffer);
LogPrint ("SAM datagram received ", m_DatagramReceiveBuffer," size=", payloadLen);
LogPrint (eLogDebug, "SAM: datagram received ", m_DatagramReceiveBuffer," size=", payloadLen);
char * sessionID = strchr ((char *)m_DatagramReceiveBuffer, ' ');
if (sessionID)
{
@@ -857,17 +857,17 @@ namespace client
SendDatagramTo ((uint8_t *)eol, payloadLen, dest.GetIdentHash ());
}
else
LogPrint ("Session ", sessionID, " not found");
LogPrint (eLogError, "SAM: Session ", sessionID, " not found");
}
else
LogPrint ("Missing destination key");
LogPrint (eLogError, "SAM: Missing destination key");
}
else
LogPrint ("Missing sessionID");
LogPrint (eLogError, "SAM: Missing sessionID");
ReceiveDatagram ();
}
else
LogPrint ("SAM datagram receive error: ", ecode.message ());
LogPrint (eLogError, "SAM: datagram receive error: ", ecode.message ());
}
}
}

4
SAM.h
View File

@@ -41,7 +41,7 @@ namespace client
const char SAM_DEST_REPLY_I2P_ERROR[] = "DEST REPLY RESULT=I2P_ERROR\n";
const char SAM_NAMING_LOOKUP[] = "NAMING LOOKUP";
const char SAM_NAMING_REPLY[] = "NAMING REPLY RESULT=OK NAME=ME VALUE=%s\n";
const char SAM_DATAGRAM_RECEIVED[] = "DATAGRAM RECEIVED DESTINATION=%s SIZE=%lu\n";
const char SAM_DATAGRAM_RECEIVED[] = "DATAGRAM RECEIVED DESTINATION=%s SIZE=%zu\n";
const char SAM_NAMING_REPLY_INVALID_KEY[] = "NAMING REPLY RESULT=INVALID_KEY NAME=%s\n";
const char SAM_NAMING_REPLY_KEY_NOT_FOUND[] = "NAMING REPLY RESULT=INVALID_KEY_NOT_FOUND NAME=%s\n";
const char SAM_PARAM_MIN[] = "MIN";
@@ -146,7 +146,7 @@ namespace client
{
public:
SAMBridge (int port);
SAMBridge (const std::string& address, int port);
~SAMBridge ();
void Start ();

View File

@@ -560,8 +560,8 @@ namespace proxy
}
}
SOCKSServer::SOCKSServer(int port, std::shared_ptr<i2p::client::ClientDestination> localDestination) :
TCPIPAcceptor (port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ())
SOCKSServer::SOCKSServer(const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination) :
TCPIPAcceptor (address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ())
{
}

View File

@@ -15,7 +15,7 @@ namespace proxy
{
public:
SOCKSServer(int port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr);
SOCKSServer(const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr);
~SOCKSServer() {};
protected:

229
SSU.cpp
View File

@@ -86,7 +86,7 @@ namespace transport
}
catch (std::exception& ex)
{
LogPrint (eLogError, "SSU server: ", ex.what ());
LogPrint (eLogError, "SSU: server runtime exception: ", ex.what ());
}
}
}
@@ -101,7 +101,7 @@ namespace transport
}
catch (std::exception& ex)
{
LogPrint (eLogError, "SSU V6 server: ", ex.what ());
LogPrint (eLogError, "SSU: v6 server runtime exception: ", ex.what ());
}
}
}
@@ -116,7 +116,7 @@ namespace transport
}
catch (std::exception& ex)
{
LogPrint (eLogError, "SSU receivers: ", ex.what ());
LogPrint (eLogError, "SSU: receivers runtime exception: ", ex.what ());
}
}
}
@@ -174,12 +174,12 @@ namespace transport
moreBytes = m_Socket.available();
}
m_Service.post (std::bind (&SSUServer::HandleReceivedPackets, this, packets));
m_Service.post (std::bind (&SSUServer::HandleReceivedPackets, this, packets, &m_Sessions));
Receive ();
}
else
{
LogPrint ("SSU receive error: ", ecode.message ());
LogPrint (eLogError, "SSU: receive error: ", ecode.message ());
delete packet;
}
}
@@ -201,17 +201,18 @@ namespace transport
moreBytes = m_SocketV6.available();
}
m_ServiceV6.post (std::bind (&SSUServer::HandleReceivedPackets, this, packets));
m_ServiceV6.post (std::bind (&SSUServer::HandleReceivedPackets, this, packets, &m_SessionsV6));
ReceiveV6 ();
}
else
{
LogPrint ("SSU V6 receive error: ", ecode.message ());
LogPrint (eLogError, "SSU: v6 receive error: ", ecode.message ());
delete packet;
}
}
void SSUServer::HandleReceivedPackets (std::vector<SSUPacket *> packets)
void SSUServer::HandleReceivedPackets (std::vector<SSUPacket *> packets,
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > * sessions)
{
std::shared_ptr<SSUSession> session;
for (auto it1: packets)
@@ -222,17 +223,14 @@ namespace transport
if (!session || session->GetRemoteEndpoint () != packet->from) // we received packet for other session than previous
{
if (session) session->FlushData ();
auto it = m_Sessions.find (packet->from);
if (it != m_Sessions.end ())
auto it = sessions->find (packet->from);
if (it != sessions->end ())
session = it->second;
if (!session)
{
session = std::make_shared<SSUSession> (*this, packet->from);
session->WaitForConnect ();
{
std::unique_lock<std::mutex> l(m_SessionsMutex);
m_Sessions[packet->from] = session;
}
(*sessions)[packet->from] = session;
LogPrint (eLogInfo, "New SSU session from ", packet->from.address ().to_string (), ":", packet->from.port (), " created");
}
}
@@ -265,100 +263,135 @@ namespace transport
std::shared_ptr<SSUSession> SSUServer::FindSession (const boost::asio::ip::udp::endpoint& e) const
{
auto it = m_Sessions.find (e);
if (it != m_Sessions.end ())
auto& sessions = e.address ().is_v6 () ? m_SessionsV6 : m_Sessions;
auto it = sessions.find (e);
if (it != sessions.end ())
return it->second;
else
return nullptr;
}
std::shared_ptr<SSUSession> SSUServer::GetSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest)
void SSUServer::CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest)
{
auto address = router->GetSSUAddress (!context.SupportsV6 ());
if (address)
CreateSession (router, address->host, address->port, peerTest);
else
LogPrint (eLogWarning, "SSU: Router ", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), " doesn't have SSU address");
}
void SSUServer::CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
const boost::asio::ip::address& addr, int port, bool peerTest)
{
std::shared_ptr<SSUSession> session;
if (router)
{
auto address = router->GetSSUAddress (!context.SupportsV6 ());
if (router->UsesIntroducer ())
m_Service.post (std::bind (&SSUServer::CreateSessionThroughIntroducer, this, router, peerTest)); // always V4 thread
else
{
boost::asio::ip::udp::endpoint remoteEndpoint (addr, port);
auto& s = addr.is_v6 () ? m_ServiceV6 : m_Service;
s.post (std::bind (&SSUServer::CreateDirectSession, this, router, remoteEndpoint, peerTest));
}
}
}
void SSUServer::CreateDirectSession (std::shared_ptr<const i2p::data::RouterInfo> router, boost::asio::ip::udp::endpoint remoteEndpoint, bool peerTest)
{
auto& sessions = remoteEndpoint.address ().is_v6 () ? m_SessionsV6 : m_Sessions;
auto it = sessions.find (remoteEndpoint);
if (it != sessions.end ())
{
auto session = it->second;
if (peerTest && session->GetState () == eSessionStateEstablished)
session->SendPeerTest ();
}
else
{
// otherwise create new session
auto session = std::make_shared<SSUSession> (*this, remoteEndpoint, router, peerTest);
sessions[remoteEndpoint] = session;
// connect
LogPrint (eLogInfo, "SSU: Creating new session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), "] ",
remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port ());
session->Connect ();
}
}
void SSUServer::CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest)
{
if (router && router->UsesIntroducer ())
{
auto address = router->GetSSUAddress (true); // v4 only for now
if (address)
{
boost::asio::ip::udp::endpoint remoteEndpoint (address->host, address->port);
auto it = m_Sessions.find (remoteEndpoint);
// check if session if presented alredy
if (it != m_Sessions.end ())
{
session = it->second;
auto session = it->second;
if (peerTest && session->GetState () == eSessionStateEstablished)
session->SendPeerTest ();
}
else
return;
}
// create new session
int numIntroducers = address->introducers.size ();
if (numIntroducers > 0)
{
// otherwise create new session
session = std::make_shared<SSUSession> (*this, remoteEndpoint, router, peerTest);
std::shared_ptr<SSUSession> introducerSession;
const i2p::data::RouterInfo::Introducer * introducer = nullptr;
// we might have a session to introducer already
for (int i = 0; i < numIntroducers; i++)
{
std::unique_lock<std::mutex> l(m_SessionsMutex);
m_Sessions[remoteEndpoint] = session;
}
if (!router->UsesIntroducer ())
{
// connect directly
LogPrint ("Creating new SSU session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), "] ",
remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port ());
session->Connect ();
}
else
{
// connect through introducer
int numIntroducers = address->introducers.size ();
if (numIntroducers > 0)
{
std::shared_ptr<SSUSession> introducerSession;
const i2p::data::RouterInfo::Introducer * introducer = nullptr;
// we might have a session to introducer already
for (int i = 0; i < numIntroducers; i++)
{
introducer = &(address->introducers[i]);
it = m_Sessions.find (boost::asio::ip::udp::endpoint (introducer->iHost, introducer->iPort));
if (it != m_Sessions.end ())
{
introducerSession = it->second;
break;
}
}
if (introducerSession) // session found
LogPrint ("Session to introducer already exists");
else // create new
{
LogPrint ("Creating new session to introducer");
introducer = &(address->introducers[0]); // TODO:
boost::asio::ip::udp::endpoint introducerEndpoint (introducer->iHost, introducer->iPort);
introducerSession = std::make_shared<SSUSession> (*this, introducerEndpoint, router);
std::unique_lock<std::mutex> l(m_SessionsMutex);
m_Sessions[introducerEndpoint] = introducerSession;
}
// introduce
LogPrint ("Introduce new SSU session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()),
"] through introducer ", introducer->iHost, ":", introducer->iPort);
session->WaitForIntroduction ();
if (i2p::context.GetRouterInfo ().UsesIntroducer ()) // if we are unreachable
{
uint8_t buf[1];
Send (buf, 0, remoteEndpoint); // send HolePunch
}
introducerSession->Introduce (*introducer);
}
else
auto intr = &(address->introducers[i]);
boost::asio::ip::udp::endpoint ep (intr->iHost, intr->iPort);
if (ep.address ().is_v4 ()) // ipv4 only
{
LogPrint (eLogWarning, "Can't connect to unreachable router. No introducers presented");
std::unique_lock<std::mutex> l(m_SessionsMutex);
m_Sessions.erase (remoteEndpoint);
session.reset ();
}
if (!introducer) introducer = intr; // we pick first one for now
it = m_Sessions.find (ep);
if (it != m_Sessions.end ())
{
introducerSession = it->second;
break;
}
}
}
if (!introducer)
{
LogPrint (eLogWarning, "SSU: Can't connect to unreachable router and no ipv4 introducers present");
return;
}
if (introducerSession) // session found
LogPrint (eLogInfo, "SSU: Session to introducer already exists");
else // create new
{
LogPrint (eLogInfo, "SSU: Creating new session to introducer");
boost::asio::ip::udp::endpoint introducerEndpoint (introducer->iHost, introducer->iPort);
introducerSession = std::make_shared<SSUSession> (*this, introducerEndpoint, router);
m_Sessions[introducerEndpoint] = introducerSession;
}
// create session
auto session = std::make_shared<SSUSession> (*this, remoteEndpoint, router, peerTest);
m_Sessions[remoteEndpoint] = session;
// introduce
LogPrint (eLogInfo, "SSU: Introduce new session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()),
"] through introducer ", introducer->iHost, ":", introducer->iPort);
session->WaitForIntroduction ();
if (i2p::context.GetRouterInfo ().UsesIntroducer ()) // if we are unreachable
{
uint8_t buf[1];
Send (buf, 0, remoteEndpoint); // send HolePunch
}
introducerSession->Introduce (*introducer, router);
}
else
LogPrint (eLogWarning, "SSU: Can't connect to unreachable router and no introducers present");
}
else
LogPrint (eLogWarning, "Router ", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), " doesn't have SSU address");
LogPrint (eLogWarning, "SSU: Router ", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), " doesn't have SSU address");
}
return session;
}
void SSUServer::DeleteSession (std::shared_ptr<SSUSession> session)
@@ -366,21 +399,27 @@ namespace transport
if (session)
{
session->Close ();
std::unique_lock<std::mutex> l(m_SessionsMutex);
m_Sessions.erase (session->GetRemoteEndpoint ());
auto& ep = session->GetRemoteEndpoint ();
if (ep.address ().is_v6 ())
m_SessionsV6.erase (ep);
else
m_Sessions.erase (ep);
}
}
void SSUServer::DeleteAllSessions ()
{
std::unique_lock<std::mutex> l(m_SessionsMutex);
for (auto it: m_Sessions)
it.second->Close ();
m_Sessions.clear ();
for (auto it: m_SessionsV6)
it.second->Close ();
m_SessionsV6.clear ();
}
template<typename Filter>
std::shared_ptr<SSUSession> SSUServer::GetRandomSession (Filter filter)
std::shared_ptr<SSUSession> SSUServer::GetRandomV4Session (Filter filter) // v4 only
{
std::vector<std::shared_ptr<SSUSession> > filteredSessions;
for (auto s :m_Sessions)
@@ -393,9 +432,9 @@ namespace transport
return nullptr;
}
std::shared_ptr<SSUSession> SSUServer::GetRandomEstablishedSession (std::shared_ptr<const SSUSession> excluded)
std::shared_ptr<SSUSession> SSUServer::GetRandomEstablishedV4Session (std::shared_ptr<const SSUSession> excluded) // v4 only
{
return GetRandomSession (
return GetRandomV4Session (
[excluded](std::shared_ptr<SSUSession> session)->bool
{
return session->GetState () == eSessionStateEstablished && !session->IsV6 () &&
@@ -410,7 +449,7 @@ namespace transport
std::set<SSUSession *> ret;
for (int i = 0; i < maxNumIntroducers; i++)
{
auto session = GetRandomSession (
auto session = GetRandomV4Session (
[&ret, ts](std::shared_ptr<SSUSession> session)->bool
{
return session->GetRelayTag () && !ret.count (session.get ()) &&
@@ -487,11 +526,11 @@ namespace transport
}
}
m_Introducers = newList;
if (m_Introducers.empty ())
if (m_Introducers.size () < SSU_MAX_NUM_INTRODUCERS)
{
auto introducer = i2p::data::netdb.GetRandomIntroducer ();
if (introducer)
GetSession (introducer);
CreateSession (introducer);
}
ScheduleIntroducersUpdateTimer ();
}
@@ -556,7 +595,7 @@ namespace transport
it++;
}
if (numDeleted > 0)
LogPrint (eLogInfo, numDeleted, " peer tests have been expired");
LogPrint (eLogDebug, "SSU: ", numDeleted, " peer tests have been expired");
SchedulePeerTestsCleanupTimer ();
}
}

17
SSU.h
View File

@@ -40,10 +40,13 @@ namespace transport
~SSUServer ();
void Start ();
void Stop ();
std::shared_ptr<SSUSession> GetSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false);
void CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false);
void CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
const boost::asio::ip::address& addr, int port, bool peerTest = false);
void CreateDirectSession (std::shared_ptr<const i2p::data::RouterInfo> router, boost::asio::ip::udp::endpoint remoteEndpoint, bool peerTest);
std::shared_ptr<SSUSession> FindSession (std::shared_ptr<const i2p::data::RouterInfo> router) const;
std::shared_ptr<SSUSession> FindSession (const boost::asio::ip::udp::endpoint& e) const;
std::shared_ptr<SSUSession> GetRandomEstablishedSession (std::shared_ptr<const SSUSession> excluded);
std::shared_ptr<SSUSession> GetRandomEstablishedV4Session (std::shared_ptr<const SSUSession> excluded);
void DeleteSession (std::shared_ptr<SSUSession> session);
void DeleteAllSessions ();
@@ -69,10 +72,12 @@ namespace transport
void ReceiveV6 ();
void HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet);
void HandleReceivedFromV6 (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet);
void HandleReceivedPackets (std::vector<SSUPacket *> packets);
void HandleReceivedPackets (std::vector<SSUPacket *> packets,
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> >* sessions);
void CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false);
template<typename Filter>
std::shared_ptr<SSUSession> GetRandomSession (Filter filter);
std::shared_ptr<SSUSession> GetRandomV4Session (Filter filter);
std::set<SSUSession *> FindIntroducers (int maxNumIntroducers);
void ScheduleIntroducersUpdateTimer ();
@@ -98,14 +103,14 @@ namespace transport
boost::asio::ip::udp::socket m_Socket, m_SocketV6;
boost::asio::deadline_timer m_IntroducersUpdateTimer, m_PeerTestsCleanupTimer;
std::list<boost::asio::ip::udp::endpoint> m_Introducers; // introducers we are connected to
mutable std::mutex m_SessionsMutex;
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > m_Sessions;
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > m_Sessions, m_SessionsV6;
std::map<uint32_t, boost::asio::ip::udp::endpoint> m_Relays; // we are introducer
std::map<uint32_t, PeerTest> m_PeerTests; // nonce -> creation time in milliseconds
public:
// for HTTP only
const decltype(m_Sessions)& GetSessions () const { return m_Sessions; };
const decltype(m_SessionsV6)& GetSessionsV6 () const { return m_SessionsV6; };
};
}
}

View File

@@ -14,13 +14,13 @@ namespace transport
{
if (msg->len + fragmentSize > msg->maxLen)
{
LogPrint (eLogInfo, "SSU I2NP message size ", msg->maxLen, " is not enough");
auto newMsg = ToSharedI2NPMessage(NewI2NPMessage ());
LogPrint (eLogWarning, "SSU: I2NP message size ", msg->maxLen, " is not enough");
auto newMsg = NewI2NPMessage ();
*newMsg = *msg;
msg = newMsg;
}
memcpy (msg->buf + msg->len, fragment, fragmentSize);
msg->len += fragmentSize;
if (msg->Concat (fragment, fragmentSize) < fragmentSize)
LogPrint (eLogError, "SSU: I2NP buffer overflow ", msg->maxLen);
nextFragmentNum++;
}
@@ -64,11 +64,11 @@ namespace transport
m_PacketSize >>= 4;
m_PacketSize <<= 4;
if (m_PacketSize > m_MaxPacketSize) m_PacketSize = m_MaxPacketSize;
LogPrint ("MTU=", ssuAddress->mtu, " packet size=", m_PacketSize);
LogPrint (eLogDebug, "SSU: MTU=", ssuAddress->mtu, " packet size=", m_PacketSize);
}
else
{
LogPrint (eLogWarning, "Unexpected MTU ", ssuAddress->mtu);
LogPrint (eLogWarning, "SSU: Unexpected MTU ", ssuAddress->mtu);
m_PacketSize = m_MaxPacketSize;
}
}
@@ -162,7 +162,7 @@ namespace transport
uint8_t fragmentNum = fragmentInfo >> 17; // bits 23 - 17
if (fragmentSize >= SSU_V4_MAX_PACKET_SIZE)
{
LogPrint (eLogError, "Fragment size ", fragmentSize, "exceeds max SSU packet size");
LogPrint (eLogError, "SSU: Fragment size ", fragmentSize, " exceeds max SSU packet size");
return;
}
@@ -171,7 +171,7 @@ namespace transport
if (it == m_IncompleteMessages.end ())
{
// create new message
auto msg = ToSharedI2NPMessage (NewI2NPShortMessage ());
auto msg = NewI2NPShortMessage ();
msg->len -= I2NP_SHORT_HEADER_SIZE;
it = m_IncompleteMessages.insert (std::make_pair (msgID,
std::unique_ptr<IncompleteMessage>(new IncompleteMessage (msg)))).first;
@@ -199,23 +199,23 @@ namespace transport
break;
}
if (isLast)
LogPrint (eLogDebug, "Message ", msgID, " complete");
LogPrint (eLogDebug, "SSU: Message ", msgID, " complete");
}
}
else
{
if (fragmentNum < incompleteMessage->nextFragmentNum)
// duplicate fragment
LogPrint (eLogWarning, "Duplicate fragment ", (int)fragmentNum, " of message ", msgID, ". Ignored");
LogPrint (eLogWarning, "SSU: Duplicate fragment ", (int)fragmentNum, " of message ", msgID, ", ignored");
else
{
// missing fragment
LogPrint (eLogWarning, "Missing fragments from ", (int)incompleteMessage->nextFragmentNum, " to ", fragmentNum - 1, " of message ", msgID);
LogPrint (eLogWarning, "SSU: Missing fragments from ", (int)incompleteMessage->nextFragmentNum, " to ", fragmentNum - 1, " of message ", msgID);
auto savedFragment = new Fragment (fragmentNum, buf, fragmentSize, isLast);
if (incompleteMessage->savedFragments.insert (std::unique_ptr<Fragment>(savedFragment)).second)
incompleteMessage->lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch ();
else
LogPrint (eLogWarning, "Fragment ", (int)fragmentNum, " of message ", msgID, " already saved");
LogPrint (eLogWarning, "SSU: Fragment ", (int)fragmentNum, " of message ", msgID, " already saved");
}
isLast = false;
}
@@ -241,18 +241,18 @@ namespace transport
m_Handler.PutNextMessage (msg);
}
else
LogPrint (eLogWarning, "SSU message ", msgID, " already received");
LogPrint (eLogWarning, "SSU: Message ", msgID, " already received");
}
else
{
// we expect DeliveryStatus
if (msg->GetTypeID () == eI2NPDeliveryStatus)
{
LogPrint ("SSU session established");
LogPrint (eLogDebug, "SSU: session established");
m_Session.Established ();
}
else
LogPrint (eLogError, "SSU unexpected message ", (int)msg->GetTypeID ());
LogPrint (eLogError, "SSU: unexpected message ", (int)msg->GetTypeID ());
}
}
else
@@ -271,7 +271,7 @@ namespace transport
//uint8_t * start = buf;
uint8_t flag = *buf;
buf++;
LogPrint (eLogDebug, "Process SSU data flags=", (int)flag, " len=", len);
LogPrint (eLogDebug, "SSU: Process data, flags=", (int)flag, ", len=", len);
// process acks if presented
if (flag & (DATA_FLAG_ACK_BITFIELDS_INCLUDED | DATA_FLAG_EXPLICIT_ACKS_INCLUDED))
ProcessAcks (buf, flag);
@@ -280,7 +280,7 @@ namespace transport
{
uint8_t extendedDataSize = *buf;
buf++; // size
LogPrint (eLogDebug, "SSU extended data of ", extendedDataSize, " bytes presented");
LogPrint (eLogDebug, "SSU: extended data of ", extendedDataSize, " bytes present");
buf += extendedDataSize;
}
// process data
@@ -292,7 +292,7 @@ namespace transport
uint32_t msgID = msg->ToSSU ();
if (m_SentMessages.count (msgID) > 0)
{
LogPrint (eLogWarning, "SSU message ", msgID, " already sent");
LogPrint (eLogWarning, "SSU: message ", msgID, " already sent");
return;
}
if (m_SentMessages.empty ()) // schedule resend at first message only
@@ -349,7 +349,7 @@ namespace transport
}
catch (boost::system::system_error& ec)
{
LogPrint (eLogError, "Can't send SSU fragment ", ec.what ());
LogPrint (eLogError, "SSU: Can't send data fragment ", ec.what ());
}
if (!isLast)
{
@@ -383,7 +383,7 @@ namespace transport
{
if (fragmentNum > 64)
{
LogPrint (eLogWarning, "Fragment number ", fragmentNum, " exceeds 64");
LogPrint (eLogWarning, "SSU: Fragment number ", fragmentNum, " exceeds 64");
return;
}
uint8_t buf[64 + 18];
@@ -437,7 +437,7 @@ namespace transport
}
catch (boost::system::system_error& ec)
{
LogPrint (eLogError, "Can't resend SSU fragment ", ec.what ());
LogPrint (eLogError, "SSU: Can't resend data fragment ", ec.what ());
}
}
@@ -447,7 +447,7 @@ namespace transport
}
else
{
LogPrint (eLogError, "SSU message has not been ACKed after ", MAX_NUM_RESENDS, " attempts. Deleted");
LogPrint (eLogError, "SSU: message has not been ACKed after ", MAX_NUM_RESENDS, " attempts, deleted");
it = m_SentMessages.erase (it);
}
}
@@ -491,7 +491,7 @@ namespace transport
{
if (ts > it->second->lastFragmentInsertTime + INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT)
{
LogPrint (eLogError, "SSU message ", it->first, " was not completed in ", INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT, " seconds. Deleted");
LogPrint (eLogWarning, "SSU: message ", it->first, " was not completed in ", INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT, " seconds, deleted");
it = m_IncompleteMessages.erase (it);
}
else

View File

@@ -27,8 +27,8 @@ namespace transport
const int RESEND_INTERVAL = 3; // in seconds
const int MAX_NUM_RESENDS = 5;
const int DECAY_INTERVAL = 20; // in seconds
const int MAX_NUM_RECEIVED_MESSAGES = 1000; // how many msgID we store for duplicates check
const int INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds
const unsigned int MAX_NUM_RECEIVED_MESSAGES = 1000; // how many msgID we store for duplicates check
// data flags
const uint8_t DATA_FLAG_EXTENDED_DATA_INCLUDED = 0x02;
const uint8_t DATA_FLAG_WANT_REPLY = 0x04;

View File

@@ -70,7 +70,7 @@ namespace transport
nonZero++;
if (nonZero - sharedKey > 32)
{
LogPrint ("First 32 bytes of shared key is all zeros. Ignored");
LogPrint (eLogWarning, "SSU: first 32 bytes of shared key is all zeros. Ignored");
return;
}
}
@@ -90,7 +90,7 @@ namespace transport
if (m_State == eSessionStateIntroduced)
{
// HolePunch received
LogPrint ("SSU HolePunch of ", len, " bytes received");
LogPrint (eLogDebug, "SSU: HolePunch of ", len, " bytes received");
m_State = eSessionStateUnknown;
Connect ();
}
@@ -120,7 +120,7 @@ namespace transport
Decrypt (buf, len, address->key);
else
{
LogPrint (eLogError, "MAC verification failed ", len, " bytes from ", senderEndpoint);
LogPrint (eLogError, "SSU: MAC verification failed ", len, " bytes from ", senderEndpoint);
m_Server.DeleteSession (shared_from_this ());
return;
}
@@ -131,10 +131,10 @@ namespace transport
}
}
size_t SSUSession::GetSSUHeaderSize (uint8_t * buf) const
size_t SSUSession::GetSSUHeaderSize (const uint8_t * buf) const
{
size_t s = sizeof (SSUHeader);
if (((SSUHeader *)buf)->IsExtendedOptions ())
if (((const SSUHeader *)buf)->IsExtendedOptions ())
s += buf[s] + 1; // byte right after header is extended options length
return s;
}
@@ -145,6 +145,11 @@ namespace transport
if (len <= sizeof (SSUHeader)) return; // drop empty message
//TODO: since we are accessing a uint8_t this is unlikely to crash due to alignment but should be improved
auto headerSize = GetSSUHeaderSize (buf);
if (headerSize >= len)
{
LogPrint (eLogError, "SSU header size ", headerSize, " exceeds packet length ", len);
return;
}
SSUHeader * header = (SSUHeader *)buf;
switch (header->GetPayloadType ())
{
@@ -152,64 +157,70 @@ namespace transport
ProcessData (buf + headerSize, len - headerSize);
break;
case PAYLOAD_TYPE_SESSION_REQUEST:
ProcessSessionRequest (buf, len, senderEndpoint);
ProcessSessionRequest (buf + headerSize, len - headerSize, senderEndpoint);
break;
case PAYLOAD_TYPE_SESSION_CREATED:
ProcessSessionCreated (buf, len);
ProcessSessionCreated (buf, len); // buf with header
break;
case PAYLOAD_TYPE_SESSION_CONFIRMED:
ProcessSessionConfirmed (buf, len);
ProcessSessionConfirmed (buf, len); // buf with header
break;
case PAYLOAD_TYPE_PEER_TEST:
LogPrint (eLogDebug, "SSU peer test received");
LogPrint (eLogDebug, "SSU: peer test received");
ProcessPeerTest (buf + headerSize, len - headerSize, senderEndpoint);
break;
case PAYLOAD_TYPE_SESSION_DESTROYED:
{
LogPrint (eLogDebug, "SSU session destroy received");
LogPrint (eLogDebug, "SSU: session destroy received");
m_Server.DeleteSession (shared_from_this ());
break;
}
case PAYLOAD_TYPE_RELAY_RESPONSE:
ProcessRelayResponse (buf, len);
ProcessRelayResponse (buf + headerSize, len - headerSize);
if (m_State != eSessionStateEstablished)
m_Server.DeleteSession (shared_from_this ());
break;
case PAYLOAD_TYPE_RELAY_REQUEST:
LogPrint (eLogDebug, "SSU relay request received");
LogPrint (eLogDebug, "SSU: relay request received");
ProcessRelayRequest (buf + headerSize, len - headerSize, senderEndpoint);
break;
case PAYLOAD_TYPE_RELAY_INTRO:
LogPrint (eLogDebug, "SSU relay intro received");
LogPrint (eLogDebug, "SSU: relay intro received");
ProcessRelayIntro (buf + headerSize, len - headerSize);
break;
default:
LogPrint (eLogWarning, "Unexpected SSU payload type ", (int)header->GetPayloadType ());
LogPrint (eLogWarning, "SSU: Unexpected payload type ", (int)header->GetPayloadType ());
}
}
void SSUSession::ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
void SSUSession::ProcessSessionRequest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
{
LogPrint (eLogDebug, "Session request received");
LogPrint (eLogDebug, "SSU message: session request");
m_RemoteEndpoint = senderEndpoint;
if (!m_DHKeysPair)
m_DHKeysPair = transports.GetNextDHKeysPair ();
CreateAESandMacKey (buf + sizeof (SSUHeader));
SendSessionCreated (buf + sizeof (SSUHeader));
CreateAESandMacKey (buf);
SendSessionCreated (buf);
}
void SSUSession::ProcessSessionCreated (uint8_t * buf, size_t len)
{
if (!IsOutgoing () || !m_DHKeysPair)
{
LogPrint (eLogWarning, "Unsolicited session created message");
LogPrint (eLogWarning, "SSU: Unsolicited session created message");
return;
}
LogPrint (eLogDebug, "Session created received");
LogPrint (eLogDebug, "SSU message: session created");
m_Timer.cancel (); // connect timer
SignedData s; // x,y, our IP, our port, remote IP, remote port, relayTag, signed on time
uint8_t * payload = buf + sizeof (SSUHeader);
auto headerSize = GetSSUHeaderSize (buf);
if (headerSize >= len)
{
LogPrint (eLogError, "Session created header size ", headerSize, " exceeds packet length ", len);
return;
}
uint8_t * payload = buf + headerSize;
uint8_t * y = payload;
CreateAESandMacKey (y);
s.Insert (m_DHKeysPair->GetPublicKey (), 256); // x
@@ -236,7 +247,7 @@ namespace transport
uint16_t ourPort = bufbe16toh (payload);
s.Insert (payload, 2); // our port
payload += 2; // port
LogPrint ("Our external address is ", ourIP.to_string (), ":", ourPort);
LogPrint (eLogInfo, "SSU: Our external address is ", ourIP.to_string (), ":", ourPort);
i2p::context.UpdateAddress (ourIP);
if (m_RemoteEndpoint.address ().is_v4 ())
s.Insert (m_RemoteEndpoint.address ().to_v4 ().to_bytes ().data (), 4); // remote IP v4
@@ -253,18 +264,24 @@ namespace transport
if (paddingSize > 0) signatureLen += (16 - paddingSize);
//TODO: since we are accessing a uint8_t this is unlikely to crash due to alignment but should be improved
m_SessionKeyDecryption.SetIV (((SSUHeader *)buf)->iv);
m_SessionKeyDecryption.Decrypt (payload, signatureLen, payload);
m_SessionKeyDecryption.Decrypt (payload, signatureLen, payload); // TODO: non-const payload
// verify
if (!s.Verify (m_RemoteIdentity, payload))
LogPrint (eLogError, "Session created SSU signature verification failed");
LogPrint (eLogError, "SSU: message 'created' signature verification failed");
SendSessionConfirmed (y, ourAddress, addressSize + 2);
}
void SSUSession::ProcessSessionConfirmed (uint8_t * buf, size_t len)
void SSUSession::ProcessSessionConfirmed (const uint8_t * buf, size_t len)
{
LogPrint (eLogDebug, "Session confirmed received");
uint8_t * payload = buf + sizeof (SSUHeader);
LogPrint (eLogDebug, "SSU: Session confirmed received");
auto headerSize = GetSSUHeaderSize (buf);
if (headerSize >= len)
{
LogPrint (eLogError, "SSU: Session confirmed header size ", len, " exceeds packet length ", len);
return;
}
const uint8_t * payload = buf + headerSize;
payload++; // identity fragment info
uint16_t identitySize = bufbe16toh (payload);
payload += 2; // size of identity fragment
@@ -280,7 +297,7 @@ namespace transport
payload += paddingSize;
// verify
if (m_SignedData && !m_SignedData->Verify (m_RemoteIdentity, payload))
LogPrint (eLogError, "Session confirmed SSU signature verification failed");
LogPrint (eLogError, "SSU message 'confirmed' signature verification failed");
m_Data.Send (CreateDeliveryStatusMsg (0));
Established ();
}
@@ -308,7 +325,7 @@ namespace transport
m_Server.Send (buf, isV4 ? 304 : 320, m_RemoteEndpoint);
}
void SSUSession::SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer)
void SSUSession::SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer, uint32_t nonce)
{
auto address = i2p::context.GetRouterInfo ().GetSSUAddress ();
if (!address)
@@ -329,7 +346,7 @@ namespace transport
payload++;
memcpy (payload, (const uint8_t *)address->key, 32);
payload += 32;
RAND_bytes (payload, 4); // nonce
htobe32buf (payload, nonce); // nonce
uint8_t iv[16];
RAND_bytes (iv, 16); // random iv
@@ -384,7 +401,7 @@ namespace transport
s.Insert (address->host.to_v6 ().to_bytes ().data (), 16); // our IP V6
s.Insert<uint16_t> (htobe16 (address->port)); // our port
uint32_t relayTag = 0;
if (i2p::context.GetRouterInfo ().IsIntroducer ())
if (i2p::context.GetRouterInfo ().IsIntroducer () && !IsV6 ())
{
RAND_bytes((uint8_t *)&relayTag, 4);
if (!relayTag) relayTag = 1;
@@ -461,7 +478,7 @@ namespace transport
Send (buf, msgLen);
}
void SSUSession::ProcessRelayRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from)
void SSUSession::ProcessRelayRequest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from)
{
uint32_t relayTag = bufbe32toh (buf);
auto session = m_Server.FindRelaySession (relayTag);
@@ -475,11 +492,11 @@ namespace transport
uint8_t challengeSize = *buf;
buf++; // challenge size
buf += challengeSize;
uint8_t * introKey = buf;
const uint8_t * introKey = buf;
buf += 32; // introkey
uint32_t nonce = bufbe32toh (buf);
SendRelayResponse (nonce, from, introKey, session->m_RemoteEndpoint);
SendRelayIntro (session.get (), from);
SendRelayIntro (session, from);
}
}
@@ -491,7 +508,7 @@ namespace transport
// Charlie's address always v4
if (!to.address ().is_v4 ())
{
LogPrint (eLogError, "Charlie's IP must be v4");
LogPrint (eLogError, "SSU: Charlie's IP must be v4");
return;
}
*payload = 4;
@@ -534,16 +551,16 @@ namespace transport
FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_RESPONSE, buf, isV4 ? 64 : 80, introKey, iv, introKey);
m_Server.Send (buf, isV4 ? 64 : 80, from);
}
LogPrint (eLogDebug, "SSU relay response sent");
LogPrint (eLogDebug, "SSU: relay response sent");
}
void SSUSession::SendRelayIntro (SSUSession * session, const boost::asio::ip::udp::endpoint& from)
void SSUSession::SendRelayIntro (std::shared_ptr<SSUSession> session, const boost::asio::ip::udp::endpoint& from)
{
if (!session) return;
// Alice's address always v4
if (!from.address ().is_v4 ())
{
LogPrint (eLogError, "Alice's IP must be v4");
LogPrint (eLogError, "SSU: Alice's IP must be v4");
return;
}
uint8_t buf[48 + 18];
@@ -559,42 +576,62 @@ namespace transport
RAND_bytes (iv, 16); // random iv
FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_INTRO, buf, 48, session->m_SessionKey, iv, session->m_MacKey);
m_Server.Send (buf, 48, session->m_RemoteEndpoint);
LogPrint (eLogDebug, "SSU relay intro sent");
LogPrint (eLogDebug, "SSU: relay intro sent");
}
void SSUSession::ProcessRelayResponse (uint8_t * buf, size_t len)
void SSUSession::ProcessRelayResponse (const uint8_t * buf, size_t len)
{
LogPrint (eLogDebug, "Relay response received");
uint8_t * payload = buf + sizeof (SSUHeader);
uint8_t remoteSize = *payload;
payload++; // remote size
//boost::asio::ip::address_v4 remoteIP (bufbe32toh (payload));
payload += remoteSize; // remote address
//uint16_t remotePort = bufbe16toh (payload);
payload += 2; // remote port
uint8_t ourSize = *payload;
payload++; // our size
LogPrint (eLogDebug, "SSU message: Relay response received");
uint8_t remoteSize = *buf;
buf++; // remote size
boost::asio::ip::address_v4 remoteIP (bufbe32toh (buf));
buf += remoteSize; // remote address
uint16_t remotePort = bufbe16toh (buf);
buf += 2; // remote port
uint8_t ourSize = *buf;
buf++; // our size
boost::asio::ip::address ourIP;
if (ourSize == 4)
{
boost::asio::ip::address_v4::bytes_type bytes;
memcpy (bytes.data (), payload, 4);
memcpy (bytes.data (), buf, 4);
ourIP = boost::asio::ip::address_v4 (bytes);
}
else
{
boost::asio::ip::address_v6::bytes_type bytes;
memcpy (bytes.data (), payload, 16);
memcpy (bytes.data (), buf, 16);
ourIP = boost::asio::ip::address_v6 (bytes);
}
payload += ourSize; // our address
uint16_t ourPort = bufbe16toh (payload);
payload += 2; // our port
LogPrint ("Our external address is ", ourIP.to_string (), ":", ourPort);
buf += ourSize; // our address
uint16_t ourPort = bufbe16toh (buf);
buf += 2; // our port
LogPrint (eLogInfo, "SSU: Our external address is ", ourIP.to_string (), ":", ourPort);
i2p::context.UpdateAddress (ourIP);
uint32_t nonce = bufbe32toh (buf);
buf += 4; // nonce
auto it = m_RelayRequests.find (nonce);
if (it != m_RelayRequests.end ())
{
// check if we are waiting for introduction
boost::asio::ip::udp::endpoint remoteEndpoint (remoteIP, remotePort);
if (!m_Server.FindSession (remoteEndpoint))
{
// we didn't have correct endpoint when sent relay request
// now we do
LogPrint (eLogInfo, "SSU: RelayReponse connecting to endpoint ", remoteEndpoint);
if (i2p::context.GetRouterInfo ().UsesIntroducer ()) // if we are unreachable
m_Server.Send (buf, 0, remoteEndpoint); // send HolePunch
m_Server.CreateDirectSession (it->second, remoteEndpoint, false);
}
// delete request
m_RelayRequests.erase (it);
}
else
LogPrint (eLogError, "SSU: Unsolicited RelayResponse, nonce=", nonce);
}
void SSUSession::ProcessRelayIntro (uint8_t * buf, size_t len)
void SSUSession::ProcessRelayIntro (const uint8_t * buf, size_t len)
{
uint8_t size = *buf;
if (size == 4)
@@ -603,11 +640,11 @@ namespace transport
boost::asio::ip::address_v4 address (bufbe32toh (buf));
buf += 4; // address
uint16_t port = bufbe16toh (buf);
// send hole punch of 1 byte
// send hole punch of 0 bytes
m_Server.Send (buf, 0, boost::asio::ip::udp::endpoint (address, port));
}
else
LogPrint (eLogWarning, "Address size ", size, " is not supported");
LogPrint (eLogWarning, "SSU: Address size ", size, " is not supported");
}
void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len,
@@ -615,14 +652,13 @@ namespace transport
{
if (len < sizeof (SSUHeader))
{
LogPrint (eLogError, "Unexpected SSU packet length ", len);
LogPrint (eLogError, "SSU: Unexpected packet length ", len);
return;
}
//TODO: we are using a dirty solution here but should work for now
SSUHeader * header = (SSUHeader *)buf;
memcpy (header->iv, iv, 16);
header->flag = payloadType << 4; // MSB is 0
htobe32buf (&(header->time), i2p::util::GetSecondsSinceEpoch ());
htobe32buf (header->time, i2p::util::GetSecondsSinceEpoch ());
uint8_t * encrypted = &header->flag;
uint16_t encryptedLen = len - (encrypted - buf);
i2p::crypto::CBCEncryption encryption;
@@ -639,15 +675,14 @@ namespace transport
{
if (len < sizeof (SSUHeader))
{
LogPrint (eLogError, "Unexpected SSU packet length ", len);
LogPrint (eLogError, "SSU: Unexpected packet length ", len);
return;
}
//TODO: we are using a dirty solution here but should work for now
SSUHeader * header = (SSUHeader *)buf;
RAND_bytes (header->iv, 16); // random iv
m_SessionKeyEncryption.SetIV (header->iv);
header->flag = payloadType << 4; // MSB is 0
htobe32buf (&(header->time), i2p::util::GetSecondsSinceEpoch ());
htobe32buf (header->time, i2p::util::GetSecondsSinceEpoch ());
uint8_t * encrypted = &header->flag;
uint16_t encryptedLen = len - (encrypted - buf);
m_SessionKeyEncryption.Encrypt (encrypted, encryptedLen, encrypted);
@@ -661,10 +696,9 @@ namespace transport
{
if (len < sizeof (SSUHeader))
{
LogPrint (eLogError, "Unexpected SSU packet length ", len);
LogPrint (eLogError, "SSU: Unexpected packet length ", len);
return;
}
//TODO: since we are accessing a uint8_t this is unlikely to crash due to alignment but should be improved
}
SSUHeader * header = (SSUHeader *)buf;
uint8_t * encrypted = &header->flag;
uint16_t encryptedLen = len - (encrypted - buf);
@@ -678,10 +712,9 @@ namespace transport
{
if (len < sizeof (SSUHeader))
{
LogPrint (eLogError, "Unexpected SSU packet length ", len);
LogPrint (eLogError, "SSU: Unexpected packet length ", len);
return;
}
//TODO: since we are accessing a uint8_t this is unlikely to crash due to alignment but should be improved
}
SSUHeader * header = (SSUHeader *)buf;
uint8_t * encrypted = &header->flag;
uint16_t encryptedLen = len - (encrypted - buf);
@@ -696,10 +729,9 @@ namespace transport
{
if (len < sizeof (SSUHeader))
{
LogPrint (eLogError, "Unexpected SSU packet length ", len);
LogPrint (eLogError, "SSU: Unexpected packet length ", len);
return false;
}
//TODO: since we are accessing a uint8_t this is unlikely to crash due to alignment but should be improved
}
SSUHeader * header = (SSUHeader *)buf;
uint8_t * encrypted = &header->flag;
uint16_t encryptedLen = len - (encrypted - buf);
@@ -727,7 +759,7 @@ namespace transport
if (!IsOutgoing ()) // incoming session
ScheduleConnectTimer ();
else
LogPrint (eLogError, "SSU wait for connect for outgoing session");
LogPrint (eLogError, "SSU: wait for connect for outgoing session");
}
void SSUSession::ScheduleConnectTimer ()
@@ -743,12 +775,13 @@ namespace transport
if (!ecode)
{
// timeout expired
LogPrint ("SSU session was not established after ", SSU_CONNECT_TIMEOUT, " second");
LogPrint (eLogWarning, "SSU: session was not established after ", SSU_CONNECT_TIMEOUT, " seconds");
Failed ();
}
}
void SSUSession::Introduce (const i2p::data::RouterInfo::Introducer& introducer)
void SSUSession::Introduce (const i2p::data::RouterInfo::Introducer& introducer,
std::shared_ptr<const i2p::data::RouterInfo> to)
{
if (m_State == eSessionStateUnknown)
{
@@ -756,8 +789,11 @@ namespace transport
m_Timer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT));
m_Timer.async_wait (std::bind (&SSUSession::HandleConnectTimer,
shared_from_this (), std::placeholders::_1));
}
SendRelayRequest (introducer);
}
uint32_t nonce;
RAND_bytes ((uint8_t *)&nonce, 4);
m_RelayRequests[nonce] = to;
SendRelayRequest (introducer, nonce);
}
void SSUSession::WaitForIntroduction ()
@@ -817,7 +853,7 @@ namespace transport
{
if (ecode != boost::asio::error::operation_aborted)
{
LogPrint ("SSU no activity fo ", SSU_TERMINATION_TIMEOUT, " seconds");
LogPrint (eLogInfo, "SSU: no activity for", SSU_TERMINATION_TIMEOUT, " seconds");
Failed ();
}
}
@@ -861,7 +897,7 @@ namespace transport
const uint8_t * introKey = buf + size + 7;
if (port && !address)
{
LogPrint (eLogWarning, "Address of ", size, " bytes not supported");
LogPrint (eLogWarning, "SSU: Address of ", size, " bytes not supported");
return;
}
switch (m_Server.GetPeerTestParticipant (nonce))
@@ -871,13 +907,13 @@ namespace transport
{
if (m_State == eSessionStateEstablished)
{
LogPrint (eLogDebug, "SSU peer test from Bob. We are Alice");
LogPrint (eLogDebug, "SSU: peer test from Bob. We are Alice");
if (i2p::context.GetStatus () == eRouterStatusTesting) // still not OK
i2p::context.SetStatus (eRouterStatusFirewalled);
}
else
{
LogPrint (eLogDebug, "SSU first peer test from Charlie. We are Alice");
LogPrint (eLogDebug, "SSU: first peer test from Charlie. We are Alice");
i2p::context.SetStatus (eRouterStatusOK);
m_Server.UpdatePeerTest (nonce, ePeerTestParticipantAlice2);
SendPeerTest (nonce, senderEndpoint.address ().to_v4 ().to_ulong (),
@@ -888,11 +924,11 @@ namespace transport
case ePeerTestParticipantAlice2:
{
if (m_State == eSessionStateEstablished)
LogPrint (eLogDebug, "SSU peer test from Bob. We are Alice");
LogPrint (eLogDebug, "SSU: peer test from Bob. We are Alice");
else
{
// peer test successive
LogPrint (eLogDebug, "SSU second peer test from Charlie. We are Alice");
LogPrint (eLogDebug, "SSU: second peer test from Charlie. We are Alice");
i2p::context.SetStatus (eRouterStatusOK);
m_Server.RemovePeerTest (nonce);
}
@@ -900,7 +936,7 @@ namespace transport
}
case ePeerTestParticipantBob:
{
LogPrint (eLogDebug, "SSU peer test from Charlie. We are Bob");
LogPrint (eLogDebug, "SSU: peer test from Charlie. We are Bob");
auto session = m_Server.GetPeerTestSession (nonce); // session with Alice from PeerTest
if (session && session->m_State == eSessionStateEstablished)
session->Send (PAYLOAD_TYPE_PEER_TEST, buf, len); // back to Alice
@@ -909,7 +945,7 @@ namespace transport
}
case ePeerTestParticipantCharlie:
{
LogPrint (eLogDebug, "SSU peer test from Alice. We are Charlie");
LogPrint (eLogDebug, "SSU: peer test from Alice. We are Charlie");
SendPeerTest (nonce, senderEndpoint.address ().to_v4 ().to_ulong (),
senderEndpoint.port (), introKey); // to Alice with her actual address
m_Server.RemovePeerTest (nonce); // nonce has been used
@@ -923,15 +959,15 @@ namespace transport
// new test
if (port)
{
LogPrint (eLogDebug, "SSU peer test from Bob. We are Charlie");
LogPrint (eLogDebug, "SSU: peer test from Bob. We are Charlie");
m_Server.NewPeerTest (nonce, ePeerTestParticipantCharlie);
Send (PAYLOAD_TYPE_PEER_TEST, buf, len); // back to Bob
SendPeerTest (nonce, be32toh (address), be16toh (port), introKey); // to Alice with her address received from Bob
}
else
{
LogPrint (eLogDebug, "SSU peer test from Alice. We are Bob");
auto session = m_Server.GetRandomEstablishedSession (shared_from_this ()); // Charlie
LogPrint (eLogDebug, "SSU: peer test from Alice. We are Bob");
auto session = m_Server.GetRandomEstablishedV4Session (shared_from_this ()); // Charlie, TODO: implement v6 support
if (session)
{
m_Server.NewPeerTest (nonce, ePeerTestParticipantBob, shared_from_this ());
@@ -941,7 +977,7 @@ namespace transport
}
}
else
LogPrint (eLogError, "SSU unexpected peer test");
LogPrint (eLogError, "SSU: unexpected peer test");
}
}
}
@@ -1004,7 +1040,7 @@ namespace transport
void SSUSession::SendPeerTest ()
{
// we are Alice
LogPrint (eLogDebug, "SSU sending peer test");
LogPrint (eLogDebug, "SSU: sending peer test");
auto address = i2p::context.GetRouterInfo ().GetSSUAddress ();
if (!address)
{
@@ -1031,7 +1067,7 @@ namespace transport
// encrypt message with session key
FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, 48);
Send (buf, 48);
LogPrint (eLogDebug, "SSU keep-alive sent");
LogPrint (eLogDebug, "SSU: keep-alive sent");
ScheduleTermination ();
}
}
@@ -1049,9 +1085,9 @@ namespace transport
}
catch (std::exception& ex)
{
LogPrint (eLogError, "SSU send session destoriyed exception ", ex.what ());
LogPrint (eLogError, "SSU: exception while send session destoriyed: ", ex.what ());
}
LogPrint (eLogDebug, "SSU session destroyed sent");
LogPrint (eLogDebug, "SSU: session destroyed sent");
}
}
@@ -1063,7 +1099,7 @@ namespace transport
if (paddingSize > 0) msgSize += (16 - paddingSize);
if (msgSize > SSU_MTU_V4)
{
LogPrint (eLogWarning, "SSU payload size ", msgSize, " exceeds MTU");
LogPrint (eLogWarning, "SSU: payload size ", msgSize, " exceeds MTU");
return;
}
memcpy (buf + sizeof (SSUHeader), payload, len);

View File

@@ -14,18 +14,16 @@ namespace i2p
namespace transport
{
const uint8_t SSU_HEADER_EXTENDED_OPTIONS_INCLUDED = 0x04;
#pragma pack(1)
struct SSUHeader
{
uint8_t mac[16];
uint8_t iv[16];
uint8_t flag;
uint32_t time;
uint8_t time[4];
uint8_t GetPayloadType () const { return flag >> 4; };
bool IsExtendedOptions () const { return flag & SSU_HEADER_EXTENDED_OPTIONS_INCLUDED; };
};
#pragma pack()
const int SSU_CONNECT_TIMEOUT = 5; // 5 seconds
const int SSU_TERMINATION_TIMEOUT = 330; // 5.5 minutes
@@ -71,7 +69,8 @@ namespace transport
void Connect ();
void WaitForConnect ();
void Introduce (const i2p::data::RouterInfo::Introducer& introducer);
void Introduce (const i2p::data::RouterInfo::Introducer& introducer,
std::shared_ptr<const i2p::data::RouterInfo> to); // Alice to Charlie
void WaitForIntroduction ();
void Close ();
void Done ();
@@ -95,22 +94,22 @@ namespace transport
boost::asio::io_service& GetService ();
void CreateAESandMacKey (const uint8_t * pubKey);
size_t GetSSUHeaderSize (uint8_t * buf) const;
size_t GetSSUHeaderSize (const uint8_t * buf) const;
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 ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
void ProcessSessionRequest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
void SendSessionRequest ();
void SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer);
void SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer, uint32_t nonce);
void ProcessSessionCreated (uint8_t * buf, size_t len);
void SendSessionCreated (const uint8_t * x);
void ProcessSessionConfirmed (uint8_t * buf, size_t len);
void ProcessSessionConfirmed (const uint8_t * buf, size_t len);
void SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, size_t ourAddressLen);
void ProcessRelayRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from);
void ProcessRelayRequest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from);
void SendRelayResponse (uint32_t nonce, const boost::asio::ip::udp::endpoint& from,
const uint8_t * introKey, const boost::asio::ip::udp::endpoint& to);
void SendRelayIntro (SSUSession * session, const boost::asio::ip::udp::endpoint& from);
void ProcessRelayResponse (uint8_t * buf, size_t len);
void ProcessRelayIntro (uint8_t * buf, size_t len);
void SendRelayIntro (std::shared_ptr<SSUSession> session, const boost::asio::ip::udp::endpoint& from);
void ProcessRelayResponse (const uint8_t * buf, size_t len);
void ProcessRelayIntro (const uint8_t * buf, size_t len);
void Established ();
void Failed ();
void ScheduleConnectTimer ();
@@ -150,6 +149,7 @@ namespace transport
SSUData m_Data;
bool m_IsDataReceived;
std::unique_ptr<SignedData> m_SignedData; // we need it for SessionConfirmed only
std::map<uint32_t, std::shared_ptr<const i2p::data::RouterInfo> > m_RelayRequests; // nonce->Charlie
};

View File

@@ -13,19 +13,16 @@ namespace crypto
Ed25519 ()
{
BN_CTX * ctx = BN_CTX_new ();
BIGNUM * two = BN_new (), * tmp = BN_new ();
BN_set_word (two, 2);
BIGNUM * tmp = BN_new ();
q = BN_new ();
// 2^255-19
BN_set_word (tmp, 255);
BN_exp (q, two, tmp, ctx);
BN_set_bit (q, 255); // 2^255
BN_sub_word (q, 19);
l = BN_new ();
// 2^252 + 27742317777372353535851937790883648493
BN_set_word (tmp, 252);
BN_exp (l, two, tmp, ctx);
BN_set_bit (l, 252);
two_252_2 = BN_dup (l);
BN_dec2bn (&tmp, "27742317777372353535851937790883648493");
BN_add (l, l, tmp);
@@ -45,8 +42,10 @@ namespace crypto
tmp = BN_dup (q);
BN_sub_word (tmp, 1);
BN_div_word (tmp, 4);
BN_mod_exp (I, two, tmp, q, ctx);
BN_set_word (I, 2);
BN_mod_exp (I, I, tmp, q, ctx);
BN_free (tmp);
// 4*inv(5)
BIGNUM * By = BN_new ();
BN_set_word (By, 5);
@@ -54,24 +53,32 @@ namespace crypto
BN_mul_word (By, 4);
BIGNUM * Bx = RecoverX (By, ctx);
BN_mod (Bx, Bx, q, ctx); // % q
BN_mod (By, By, q, ctx); // % q
B = {Bx, By};
BN_free (two);
BN_free (tmp);
BN_mod (By, By, q, ctx); // % q
// precalculate Bi16 table
Bi16[0][0] = { BN_dup (Bx), BN_dup (By) };
for (int i = 0; i < 64; i++)
// precalculate Bi256 table
Bi256Carry = { Bx, By }; // B
for (int i = 0; i < 32; i++)
{
if (i) Bi16[i][0] = Sum (Bi16[i-1][14], Bi16[i-1][0], ctx);
for (int j = 1; j < 15; j++)
Bi16[i][j] = Sum (Bi16[i][j-1], Bi16[i][0], ctx); // (16+j+1)^i*B
Bi256[i][0] = Bi256Carry; // first point
for (int j = 1; j < 128; j++)
Bi256[i][j] = Sum (Bi256[i][j-1], Bi256[i][0], ctx); // (256+j+1)^i*B
Bi256Carry = Bi256[i][127];
for (int j = 0; j < 128; j++) // add first point 128 more times
Bi256Carry = Sum (Bi256Carry, Bi256[i][0], ctx);
}
BN_CTX_free (ctx);
}
Ed25519 (const Ed25519& other): q (BN_dup (other.q)), l (BN_dup (other.l)),
d (BN_dup (other.d)), I (BN_dup (other.I)), two_252_2 (BN_dup (other.two_252_2)),
Bi256Carry (other.Bi256Carry)
{
for (int i = 0; i < 32; i++)
for (int j = 0; j < 128; j++)
Bi256[i][j] = other.Bi256[i][j];
}
~Ed25519 ()
{
BN_free (q);
@@ -97,8 +104,9 @@ namespace crypto
EncodePoint (Normalize (publicKey, ctx), buf);
}
bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature, BN_CTX * ctx) const
bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const
{
BN_CTX * ctx = BN_CTX_new ();
BIGNUM * h = DecodeBN<64> (digest);
// signature 0..31 - R, 32..63 - S
// B*S = R + PK*h => R = B*S - PK*h
@@ -110,14 +118,16 @@ namespace crypto
EncodePoint (Normalize (Sum (Bs, -PKh, ctx), ctx), diff); // Bs - PKh encoded
bool passed = !memcmp (signature, diff, 32); // R
BN_free (h);
BN_CTX_free (ctx);
if (!passed)
LogPrint (eLogError, "25519 signature verification failed");
return passed;
}
void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len,
uint8_t * signature, BN_CTX * bnCtx) const
uint8_t * signature) const
{
BN_CTX * bnCtx = BN_CTX_new ();
// calculate r
SHA512_CTX ctx;
SHA512_Init (&ctx);
@@ -143,6 +153,7 @@ namespace crypto
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);
}
private:
@@ -154,36 +165,42 @@ namespace crypto
// z3 = (z1*z2-d*t1*t2)*(z1*z2+d*t1*t2)
// t3 = (y1*y2+x1*x2)*(x1*y2+y1*x2)
BIGNUM * x3 = BN_new (), * y3 = BN_new (), * z3 = BN_new (), * t3 = BN_new ();
BIGNUM * z1 = p1.z, * t1 = p1.t;
if (!z1) { z1 = BN_new (); BN_one (z1); }
BN_mul (x3, p1.x, p2.x, ctx); // A = x1*x2
BN_mul (y3, p1.y, p2.y, ctx); // B = y1*y2
BIGNUM * t1 = p1.t, * t2 = p2.t;
if (!t1) { t1 = BN_new (); BN_mul (t1, p1.x, p1.y, ctx); }
BIGNUM * z2 = p2.z, * t2 = p2.t;
if (!z2) { z2 = BN_new (); BN_one (z2); }
if (!t2) { t2 = BN_new (); BN_mul (t2, p2.x, p2.y, ctx); }
BIGNUM * A = BN_new (), * B = BN_new (), * C = BN_new (), * D = BN_new ();
BN_mul (A, p1.x, p2.x, ctx); // A = x1*x2
BN_mul (B, p1.y, p2.y, ctx); // B = y1*y2
BN_mul (C, t1, t2, ctx);
BN_mul (C, C, d, ctx); // C = d*t1*t2
BN_mul (D, z1, z2, ctx); // D = z1*z2
BN_mul (t3, t1, t2, ctx);
BN_mul (t3, t3, d, ctx); // C = d*t1*t2
if (!p1.t) BN_free (t1);
if (!p2.t) BN_free (t2);
if (p1.z)
{
if (p2.z)
BN_mul (z3, p1.z, p2.z, ctx); // D = z1*z2
else
BN_copy (z3, p1.z); // D = z1
}
else
{
if (p2.z)
BN_copy (z3, p2.z); // D = z2
else
BN_one (z3); // D = 1
}
BIGNUM * E = BN_new (), * F = BN_new (), * G = BN_new (), * H = BN_new ();
BN_add (x3, p1.x, p1.y);
BN_add (y3, p2.x, p2.y);
BN_mul (E, x3, y3, ctx); // (x1 + y1)*(x2 + y2)
BN_sub (E, E, A);
BN_sub (E, E, B); // E = (x1 + y1)*(x2 + y2) - A - B
BN_sub (F, D, C); // F = D - C
BN_add (G, D, C); // G = D + C
BN_add (H, B, A); // H = B + A
BN_free (A); BN_free (B); BN_free (C); BN_free (D);
if (!p1.z) BN_free (z1);
if (!p1.t) BN_free (t1);
if (!p2.z) BN_free (z2);
if (!p2.t) BN_free (t2);
BN_add (E, p1.x, p1.y);
BN_add (F, p2.x, p2.y);
BN_mul (E, E, F, ctx); // (x1 + y1)*(x2 + y2)
BN_sub (E, E, x3);
BN_sub (E, E, y3); // E = (x1 + y1)*(x2 + y2) - A - B
BN_sub (F, z3, t3); // F = D - C
BN_add (G, z3, t3); // G = D + C
BN_add (H, y3, x3); // H = B + A
BN_mod_mul (x3, E, F, q, ctx); // x3 = E*F
BN_mod_mul (y3, G, H, q, ctx); // y3 = G*H
@@ -198,27 +215,30 @@ namespace crypto
EDDSAPoint Double (const EDDSAPoint& p, BN_CTX * ctx) const
{
BIGNUM * x2 = BN_new (), * y2 = BN_new (), * z2 = BN_new (), * t2 = BN_new ();
BIGNUM * z = p.z, * t = p.t;
if (!z) { z = BN_new (); BN_one (z); }
if (!t) { t = BN_new (); BN_mul (t, p.x, p.y, ctx); }
BN_sqr (x2, p.x, ctx); // x2 = A = x^2
BN_sqr (y2, p.y, ctx); // y2 = B = y^2
BN_sqr (t2, t, ctx);
BN_mul (t2, t2, d, ctx); // t2 = C = d*t^2
BN_sqr (z2, z, ctx); // z2 = D = z^2
if (p.t)
BN_sqr (t2, p.t, ctx); // t2 = t^2
else
{
BN_mul (t2, p.x, p.y, ctx); // t = x*y
BN_sqr (t2, t2, ctx); // t2 = t^2
}
BN_mul (t2, t2, d, ctx); // t2 = C = d*t^2
if (p.z)
BN_sqr (z2, p.z, ctx); // z2 = D = z^2
else
BN_one (z2); // z2 = 1
BIGNUM * E = BN_new (), * F = BN_new (), * G = BN_new (), * H = BN_new ();
// E = (x+y)*(x+y)-A-B = x^2+y^2+2xy-A-B = 2xy
BN_mul (E, p.x, p.y, ctx);
BN_mul_word (E, 2); // E =2*x*y
BN_lshift1 (E, E); // E =2*x*y
BN_sub (F, z2, t2); // F = D - C
BN_add (G, z2, t2); // G = D + C
BN_add (H, y2, x2); // H = B + A
if (!p.z) BN_free (z);
if (!p.t) BN_free (t);
BN_mod_mul (x2, E, F, q, ctx); // x2 = E*F
BN_mod_mul (y2, G, H, q, ctx); // y2 = G*H
BN_mod_mul (z2, F, G, q, ctx); // z2 = F*G
@@ -246,20 +266,37 @@ namespace crypto
return res;
}
EDDSAPoint MulB (const uint8_t * e, BN_CTX * ctx) const // B*e. e is 32 bytes Little Endian
EDDSAPoint MulB (const uint8_t * e, BN_CTX * ctx) const // B*e, e is 32 bytes Little Endian
{
BIGNUM * zero = BN_new (), * one = BN_new ();
BN_zero (zero); BN_one (one);
EDDSAPoint res {zero, one};
bool carry = false;
for (int i = 0; i < 32; i++)
{
uint8_t x = e[i] & 0x0F; // 4 low bits
uint8_t x = e[i];
if (carry)
{
if (x < 255)
{
x++;
carry = false;
}
else
x = 0;
}
if (x > 0)
res = Sum (res, Bi16[i*2][x-1], ctx);
x = e[i] >> 4; // 4 high bits
if (x > 0)
res = Sum (res, Bi16[i*2+1][x-1], ctx);
{
if (x <= 128)
res = Sum (res, Bi256[i][x-1], ctx);
else
{
res = Sum (res, -Bi256[i][255-x], ctx); // -Bi[256-x]
carry = true;
}
}
}
if (carry) res = Sum (res, Bi256Carry, ctx);
return res;
}
@@ -341,7 +378,9 @@ namespace crypto
auto x = RecoverX (y, ctx);
if (BN_is_bit_set (x, 0) != isHighestBitSet)
BN_sub (x, q, x); // x = q - x
EDDSAPoint p {x, y};
BIGNUM * z = BN_new (), * t = BN_new ();
BN_one (z); BN_mod_mul (t, x, y, q, ctx); // pre-calculate t
EDDSAPoint p {x, y, z, t};
if (!IsOnCurve (p, ctx))
LogPrint (eLogError, "Decoded point is not on 25519");
return p;
@@ -384,42 +423,46 @@ namespace crypto
private:
BIGNUM * q, * l, * d, * I;
EDDSAPoint B; // base point
// transient values
BIGNUM * two_252_2; // 2^252-2
EDDSAPoint Bi16[64][15]; // per 4-bits, Bi16[i][j] = (16+j+1)^i*B, we don't store zeroes
EDDSAPoint Bi256[32][128]; // per byte, Bi256[i][j] = (256+j+1)^i*B, we don't store zeroes
// if j > 128 we use 256 - j and carry 1 to next byte
// Bi256[0][0] = B, base point
EDDSAPoint Bi256Carry; // Bi256[32][0]
};
static std::unique_ptr<Ed25519> g_Ed25519;
std::unique_ptr<Ed25519>& GetEd25519 ()
{
if (!g_Ed25519)
g_Ed25519.reset (new Ed25519 ());
g_Ed25519.reset (new Ed25519());
return g_Ed25519;
}
EDDSA25519Verifier::EDDSA25519Verifier (const uint8_t * signingKey):
m_Ctx (BN_CTX_new ()),
m_PublicKey (GetEd25519 ()->DecodePublicKey (signingKey, m_Ctx))
EDDSA25519Verifier::EDDSA25519Verifier (const uint8_t * signingKey)
{
memcpy (m_PublicKeyEncoded, signingKey, EDDSA25519_PUBLIC_KEY_LENGTH);
BN_CTX * ctx = BN_CTX_new ();
m_PublicKey = GetEd25519 ()->DecodePublicKey (m_PublicKeyEncoded, ctx);
BN_CTX_free (ctx);
}
bool EDDSA25519Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
{
uint8_t digest[64];
SHA512_CTX ctx;
SHA512_Init (&ctx);
SHA512_Update (&ctx, signature, EDDSA25519_SIGNATURE_LENGTH/2); // R
SHA512_Update (&ctx, m_PublicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key
SHA512_Update (&ctx, buf, len); // data
uint8_t digest[64];
SHA512_Update (&ctx, buf, len); // data
SHA512_Final (digest, &ctx);
return GetEd25519 ()->Verify (m_PublicKey, digest, signature, m_Ctx);
return GetEd25519 ()->Verify (m_PublicKey, digest, signature);
}
EDDSA25519Signer::EDDSA25519Signer (const uint8_t * signingPrivateKey):
m_Ctx (BN_CTX_new ())
EDDSA25519Signer::EDDSA25519Signer (const uint8_t * signingPrivateKey)
{
// expand key
SHA512 (signingPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH, m_ExpandedPrivateKey);
@@ -427,13 +470,15 @@ namespace crypto
m_ExpandedPrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] &= 0x1F; // drop first 3 bits
m_ExpandedPrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] |= 0x40; // set second bit
// generate and encode public key
auto publicKey = GetEd25519 ()->GeneratePublicKey (m_ExpandedPrivateKey, m_Ctx);
GetEd25519 ()->EncodePublicKey (publicKey, m_PublicKeyEncoded, m_Ctx);
BN_CTX * ctx = BN_CTX_new ();
auto publicKey = GetEd25519 ()->GeneratePublicKey (m_ExpandedPrivateKey, ctx);
GetEd25519 ()->EncodePublicKey (publicKey, m_PublicKeyEncoded, ctx);
BN_CTX_free (ctx);
}
void EDDSA25519Signer::Sign (const uint8_t * buf, int len, uint8_t * signature) const
{
GetEd25519 ()->Sign (m_ExpandedPrivateKey, m_PublicKeyEncoded, buf, len, signature, m_Ctx);
GetEd25519 ()->Sign (m_ExpandedPrivateKey, m_PublicKeyEncoded, buf, len, signature);
}
}
}

View File

@@ -44,11 +44,7 @@ namespace crypto
DSAVerifier (const uint8_t * signingKey)
{
m_PublicKey = DSA_new ();
m_PublicKey->p = BN_dup (dsap);
m_PublicKey->q = BN_dup (dsaq);
m_PublicKey->g = BN_dup (dsag);
m_PublicKey->priv_key = NULL;
m_PublicKey = CreateDSA ();
m_PublicKey->pub_key = BN_bin2bn (signingKey, DSA_PUBLIC_KEY_LENGTH, NULL);
}
@@ -86,12 +82,8 @@ namespace crypto
DSASigner (const uint8_t * signingPrivateKey)
{
m_PrivateKey = DSA_new ();
m_PrivateKey->p = BN_dup (dsap);
m_PrivateKey->q = BN_dup (dsaq);
m_PrivateKey->g = BN_dup (dsag);
m_PrivateKey = CreateDSA ();
m_PrivateKey->priv_key = BN_bin2bn (signingPrivateKey, DSA_PRIVATE_KEY_LENGTH, NULL);
m_PrivateKey->pub_key = NULL;
}
~DSASigner ()
@@ -116,12 +108,7 @@ namespace crypto
inline void CreateDSARandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
{
DSA * dsa = DSA_new ();
dsa->p = BN_dup (dsap);
dsa->q = BN_dup (dsaq);
dsa->g = BN_dup (dsag);
dsa->priv_key = NULL;
dsa->pub_key = NULL;
DSA * dsa = CreateDSA ();
DSA_generate_key (dsa);
bn2buf (dsa->priv_key, signingPrivateKey, DSA_PRIVATE_KEY_LENGTH);
bn2buf (dsa->pub_key, signingPublicKey, DSA_PUBLIC_KEY_LENGTH);
@@ -285,7 +272,7 @@ namespace crypto
{
m_PublicKey = RSA_new ();
memset (m_PublicKey, 0, sizeof (RSA));
m_PublicKey->e = BN_dup (rsae);
m_PublicKey->e = BN_dup (GetRSAE ());
m_PublicKey->n = BN_bin2bn (signingKey, keyLen, NULL);
}
@@ -319,7 +306,7 @@ namespace crypto
{
m_PrivateKey = RSA_new ();
memset (m_PrivateKey, 0, sizeof (RSA));
m_PrivateKey->e = BN_dup (rsae);
m_PrivateKey->e = BN_dup (GetRSAE ());
m_PrivateKey->n = BN_bin2bn (signingPrivateKey, keyLen, NULL);
m_PrivateKey->d = BN_bin2bn (signingPrivateKey + keyLen, keyLen, NULL);
}
@@ -345,10 +332,12 @@ namespace crypto
inline void CreateRSARandomKeys (size_t publicKeyLen, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
{
RSA * rsa = RSA_new ();
RSA_generate_key_ex (rsa, publicKeyLen*8, rsae, NULL);
BIGNUM * e = BN_dup (GetRSAE ()); // make it non-const
RSA_generate_key_ex (rsa, publicKeyLen*8, e, NULL);
bn2buf (rsa->n, signingPrivateKey, publicKeyLen);
bn2buf (rsa->d, signingPrivateKey + publicKeyLen, publicKeyLen);
bn2buf (rsa->n, signingPublicKey, publicKeyLen);
BN_free (e); // this e is not assigned to rsa->e
RSA_free (rsa);
}
@@ -373,6 +362,8 @@ namespace crypto
BIGNUM * x, * y;
BIGNUM * z, * t; // projective coordinates
EDDSAPoint (): x(nullptr), y(nullptr), z(nullptr), t(nullptr) {};
EDDSAPoint (const EDDSAPoint& other): x(nullptr), y(nullptr), z(nullptr), t(nullptr)
{ *this = other; };
EDDSAPoint (EDDSAPoint&& other): x(nullptr), y(nullptr), z(nullptr), t(nullptr)
{ *this = std::move (other); };
EDDSAPoint (BIGNUM * x1, BIGNUM * y1, BIGNUM * z1 = nullptr, BIGNUM * t1 = nullptr): x(x1), y(y1), z(z1), t(t1) {};
@@ -380,17 +371,22 @@ namespace crypto
EDDSAPoint& operator=(EDDSAPoint&& other)
{
if (x) BN_free (x);
if (y) BN_free (y);
if (z) BN_free (z);
if (t) BN_free (t);
x = other.x; other.x = nullptr;
y = other.y; other.y = nullptr;
z = other.z; other.z = nullptr;
t = other.t; other.t = nullptr;
if (x) BN_free (x); x = other.x; other.x = nullptr;
if (y) BN_free (y); y = other.y; other.y = nullptr;
if (z) BN_free (z); z = other.z; other.z = nullptr;
if (t) BN_free (t); t = other.t; other.t = nullptr;
return *this;
}
EDDSAPoint& operator=(const EDDSAPoint& other)
{
if (x) BN_free (x); x = other.x ? BN_dup (other.x) : nullptr;
if (y) BN_free (y); y = other.y ? BN_dup (other.y) : nullptr;
if (z) BN_free (z); z = other.z ? BN_dup (other.z) : nullptr;
if (t) BN_free (t); t = other.t ? BN_dup (other.t) : nullptr;
return *this;
}
EDDSAPoint operator-() const
{
BIGNUM * x1 = NULL, * y1 = NULL, * z1 = NULL, * t1 = NULL;
@@ -410,7 +406,6 @@ namespace crypto
public:
EDDSA25519Verifier (const uint8_t * signingKey);
~EDDSA25519Verifier () { BN_CTX_free (m_Ctx); };
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const;
size_t GetPublicKeyLen () const { return EDDSA25519_PUBLIC_KEY_LENGTH; };
@@ -418,7 +413,6 @@ namespace crypto
private:
BN_CTX * m_Ctx;
EDDSAPoint m_PublicKey;
uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH];
};
@@ -428,13 +422,11 @@ namespace crypto
public:
EDDSA25519Signer (const uint8_t * signingPrivateKey);
~EDDSA25519Signer () { BN_CTX_free (m_Ctx); };
void Sign (const uint8_t * buf, int len, uint8_t * signature) const;
const uint8_t * GetPublicKey () const { return m_PublicKeyEncoded; };
private:
BN_CTX * m_Ctx;
uint8_t m_ExpandedPrivateKey[64];
uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH];
};

View File

@@ -53,7 +53,7 @@ namespace stream
delete it;
m_SavedPackets.clear ();
LogPrint (eLogDebug, "Stream deleted");
LogPrint (eLogDebug, "Streaming: Stream deleted");
}
void Stream::Terminate ()
@@ -83,12 +83,12 @@ namespace stream
if (!receivedSeqn && !isSyn)
{
// plain ack
LogPrint (eLogDebug, "Plain ACK received");
LogPrint (eLogDebug, "Streaming: Plain ACK received");
delete packet;
return;
}
LogPrint (eLogDebug, "Received seqn=", receivedSeqn);
LogPrint (eLogDebug, "Streaming: Received seqn=", receivedSeqn);
if (isSyn || receivedSeqn == m_LastReceivedSequenceNumber + 1)
{
// we have received next in sequence message
@@ -128,13 +128,13 @@ namespace stream
if (receivedSeqn <= m_LastReceivedSequenceNumber)
{
// we have received duplicate
LogPrint (eLogWarning, "Duplicate message ", receivedSeqn, " received");
LogPrint (eLogWarning, "Streaming: Duplicate message ", receivedSeqn, " received");
SendQuickAck (); // resend ack for previous message again
delete packet; // packet dropped
}
else
{
LogPrint (eLogWarning, "Missing messages from ", m_LastReceivedSequenceNumber + 1, " to ", receivedSeqn - 1);
LogPrint (eLogWarning, "Streaming: Missing messages from ", m_LastReceivedSequenceNumber + 1, " to ", receivedSeqn - 1);
// save message and wait for missing message again
SavePacket (packet);
if (m_LastReceivedSequenceNumber >= 0)
@@ -169,44 +169,38 @@ namespace stream
// process flags
uint32_t receivedSeqn = packet->GetSeqn ();
uint16_t flags = packet->GetFlags ();
LogPrint (eLogDebug, "Process seqn=", receivedSeqn, ", flags=", flags);
LogPrint (eLogDebug, "Streaming: Process seqn=", receivedSeqn, ", flags=", flags);
const uint8_t * optionData = packet->GetOptionData ();
if (flags & PACKET_FLAG_SYNCHRONIZE)
LogPrint (eLogDebug, "Synchronize");
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 ());
optionData += m_RemoteIdentity->GetFullLen ();
LogPrint (eLogInfo, "From identity ", m_RemoteIdentity->GetIdentHash ().ToBase64 ());
if (!m_RemoteLeaseSet)
LogPrint (eLogDebug, "Incoming stream from ", m_RemoteIdentity->GetIdentHash ().ToBase64 ());
LogPrint (eLogDebug, "Streaming: Incoming stream from ", m_RemoteIdentity->GetIdentHash ().ToBase64 ());
}
if (flags & PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED)
{
uint16_t maxPacketSize = bufbe16toh (optionData);
LogPrint (eLogDebug, "Max packet size ", maxPacketSize);
LogPrint (eLogDebug, "Streaming: Max packet size ", maxPacketSize);
optionData += 2;
}
if (flags & PACKET_FLAG_SIGNATURE_INCLUDED)
{
LogPrint (eLogDebug, "Signature");
uint8_t signature[256];
auto signatureLen = m_RemoteIdentity->GetSignatureLen ();
memcpy (signature, optionData, signatureLen);
memset (const_cast<uint8_t *>(optionData), 0, signatureLen);
if (!m_RemoteIdentity->Verify (packet->GetBuffer (), packet->GetLength (), signature))
{
LogPrint (eLogError, "Signature verification failed");
Close ();
LogPrint (eLogError, "Streaming: Signature verification failed");
Close ();
flags |= PACKET_FLAG_CLOSE;
}
memcpy (const_cast<uint8_t *>(optionData), signature, signatureLen);
@@ -226,7 +220,6 @@ namespace stream
if (flags & (PACKET_FLAG_CLOSE | PACKET_FLAG_RESET))
{
LogPrint (eLogInfo, (flags & PACKET_FLAG_RESET) ? "Reset" : "Closed");
m_Status = eStreamStatusReset;
Close ();
}
@@ -254,7 +247,7 @@ namespace stream
}
if (nacked)
{
LogPrint (eLogDebug, "Packet ", seqn, " NACK");
LogPrint (eLogDebug, "Streaming: Packet ", seqn, " NACK");
it++;
continue;
}
@@ -418,7 +411,7 @@ namespace stream
}
if (lastReceivedSeqn < 0)
{
LogPrint (eLogError, "No packets have been received yet");
LogPrint (eLogError, "Streaming: No packets have been received yet");
return;
}
@@ -474,7 +467,7 @@ namespace stream
p.len = size;
SendPackets (std::vector<Packet *> { &p });
LogPrint ("Quick Ack sent. ", (int)numNacks, " NACKs");
LogPrint (eLogDebug, "Streaming: Quick Ack sent. ", (int)numNacks, " NACKs");
}
void Stream::Close ()
@@ -485,7 +478,7 @@ namespace stream
m_Status = eStreamStatusClosing;
Close (); // recursion
if (m_Status == eStreamStatusClosing) //still closing
LogPrint (eLogInfo, "Trying to send stream data before closing");
LogPrint (eLogInfo, "Streaming: Trying to send stream data before closing");
break;
case eStreamStatusReset:
SendClose ();
@@ -507,7 +500,7 @@ namespace stream
m_LocalDestination.DeleteStream (shared_from_this ());
break;
default:
LogPrint (eLogWarning, "Unexpected stream status ", (int)m_Status);
LogPrint (eLogWarning, "Streaming: Unexpected stream status ", (int)m_Status);
};
}
@@ -539,7 +532,7 @@ namespace stream
p->len = size;
m_Service.post (std::bind (&Stream::SendPacket, shared_from_this (), p));
LogPrint ("FIN sent");
LogPrint (eLogDebug, "Streaming: FIN sent");
}
size_t Stream::ConcatenatePackets (uint8_t * buf, size_t len)
@@ -593,7 +586,7 @@ namespace stream
UpdateCurrentRemoteLease ();
if (!m_RemoteLeaseSet)
{
LogPrint (eLogError, "Can't send packets. Missing remote LeaseSet");
LogPrint (eLogError, "Streaming: Can't send packets, missing remote LeaseSet");
return;
}
}
@@ -601,7 +594,7 @@ namespace stream
m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNewOutboundTunnel (m_CurrentOutboundTunnel);
if (!m_CurrentOutboundTunnel)
{
LogPrint (eLogError, "No outbound tunnels in the pool");
LogPrint (eLogError, "Streaming: No outbound tunnels in the pool");
return;
}
@@ -625,7 +618,7 @@ namespace stream
m_CurrentOutboundTunnel->SendTunnelDataMsg (msgs);
}
else
LogPrint (eLogWarning, "All leases are expired");
LogPrint (eLogWarning, "Streaming: All leases are expired");
}
@@ -644,7 +637,7 @@ namespace stream
// check for resend attempts
if (m_NumResendAttempts >= MAX_NUM_RESEND_ATTEMPTS)
{
LogPrint (eLogWarning, "Stream packet was not ACKed after ", MAX_NUM_RESEND_ATTEMPTS, " attempts. Terminate");
LogPrint (eLogWarning, "Streaming: packet was not ACKed after ", MAX_NUM_RESEND_ATTEMPTS, " attempts, terminate");
m_Status = eStreamStatusReset;
Close ();
return;
@@ -678,12 +671,12 @@ namespace stream
// no break here
case 4:
UpdateCurrentRemoteLease (); // pick another lease
LogPrint (eLogWarning, "Another remote lease has been selected for stream");
LogPrint (eLogWarning, "Streaming: Another remote lease has been selected for stream");
break;
case 3:
// pick another outbound tunnel
m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNextOutboundTunnel (m_CurrentOutboundTunnel);
LogPrint (eLogWarning, "Another outbound tunnel has been selected for stream");
LogPrint (eLogWarning, "Streaming: Another outbound tunnel has been selected for stream");
break;
default: ;
}
@@ -699,7 +692,7 @@ namespace stream
{
if (m_LastReceivedSequenceNumber < 0)
{
LogPrint (eLogWarning, "SYN has not been recived after ", ACK_SEND_TIMEOUT, " milliseconds after follow on. Terminate");
LogPrint (eLogWarning, "Streaming: SYN has not been recived after ", ACK_SEND_TIMEOUT, " milliseconds after follow on, terminate");
m_Status = eStreamStatusReset;
Close ();
return;
@@ -716,7 +709,7 @@ namespace stream
{
m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ());
if (!m_RemoteLeaseSet)
LogPrint ("LeaseSet ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), " not found");
LogPrint (eLogError, "Streaming: LeaseSet ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), " not found");
}
if (m_RemoteLeaseSet)
{
@@ -764,13 +757,14 @@ namespace stream
std::shared_ptr<I2NPMessage> Stream::CreateDataMessage (const uint8_t * payload, size_t len)
{
auto msg = ToSharedI2NPMessage (NewI2NPShortMessage ());
auto msg = NewI2NPShortMessage ();
if (len <= i2p::stream::COMPRESSION_THRESHOLD_SIZE)
m_LocalDestination.m_Deflator.SetCompressionLevel (Z_NO_COMPRESSION);
else
m_LocalDestination.m_Deflator.SetCompressionLevel (Z_DEFAULT_COMPRESSION);
uint8_t * buf = msg->GetPayload ();
buf += 4; // reserve for lengthlength
msg->len += 4;
size_t size = m_LocalDestination.m_Deflator.Deflate (payload, len, buf, msg->maxLen - msg->len);
if (size)
{
@@ -778,7 +772,7 @@ namespace stream
htobe16buf (buf + 4, m_LocalDestination.GetLocalPort ()); // source port
htobe16buf (buf + 6, m_Port); // destination port
buf[9] = i2p::client::PROTOCOL_TYPE_STREAMING; // streaming protocol
msg->len += size + 4;
msg->len += size;
msg->FillI2NPMessageHeader (eI2NPData);
}
else
@@ -787,7 +781,7 @@ namespace stream
}
StreamingDestination::StreamingDestination (std::shared_ptr<i2p::client::ClientDestination> owner, uint16_t localPort):
m_Owner (owner), m_LocalPort (localPort)
m_Owner (owner), m_LocalPort (localPort), m_PendingIncomingTimer (m_Owner->GetService ())
{
}
@@ -802,6 +796,7 @@ namespace stream
void StreamingDestination::Stop ()
{
ResetAcceptor ();
m_PendingIncomingTimer.cancel ();
{
std::unique_lock<std::mutex> l(m_StreamsMutex);
m_Streams.clear ();
@@ -818,7 +813,7 @@ namespace stream
it->second->HandleNextPacket (packet);
else
{
LogPrint ("Unknown stream sendStreamID=", sendStreamID);
LogPrint (eLogError, "Streaming: Unknown stream sendStreamID=", sendStreamID);
delete packet;
}
}
@@ -832,8 +827,21 @@ namespace stream
m_Acceptor (incomingStream);
else
{
LogPrint ("Acceptor for incoming stream is not set");
DeleteStream (incomingStream);
LogPrint (eLogWarning, "Streaming: Acceptor for incoming stream is not set");
if (m_PendingIncomingStreams.size () < MAX_PENDING_INCOMING_BACKLOG)
{
m_PendingIncomingStreams.push_back (incomingStream);
m_PendingIncomingTimer.cancel ();
m_PendingIncomingTimer.expires_from_now (boost::posix_time::seconds(PENDING_INCOMING_TIMEOUT));
m_PendingIncomingTimer.async_wait (std::bind (&StreamingDestination::HandlePendingIncomingTimer,
this, std::placeholders::_1));
LogPrint (eLogDebug, "Streaming: Pending incoming stream added");
}
else
{
LogPrint (eLogWarning, "Streaming: Pending incoming streams backlog exceeds ", MAX_PENDING_INCOMING_BACKLOG);
incomingStream->Close ();
}
}
}
else // follow on packet without SYN
@@ -847,12 +855,12 @@ namespace stream
return;
}
// TODO: should queue it up
LogPrint ("Unknown stream receiveStreamID=", receiveStreamID);
LogPrint (eLogError, "Streaming: Unknown stream receiveStreamID=", receiveStreamID);
delete packet;
}
}
}
std::shared_ptr<Stream> StreamingDestination::CreateNewOutgoingStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port)
{
auto s = std::make_shared<Stream> (m_Owner->GetService (), *this, remote, port);
@@ -880,6 +888,36 @@ namespace stream
}
}
void StreamingDestination::SetAcceptor (const Acceptor& acceptor)
{
m_Owner->GetService ().post([acceptor, this](void)
{
m_Acceptor = acceptor;
for (auto it: m_PendingIncomingStreams)
if (it->GetStatus () == eStreamStatusOpen) // still open?
m_Acceptor (it);
m_PendingIncomingStreams.clear ();
m_PendingIncomingTimer.cancel ();
});
}
void StreamingDestination::ResetAcceptor ()
{
if (m_Acceptor) m_Acceptor (nullptr);
m_Acceptor = nullptr;
}
void StreamingDestination::HandlePendingIncomingTimer (const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
{
LogPrint (eLogWarning, "Streaming: Pending incoming timeout expired");
for (auto it: m_PendingIncomingStreams)
it->Close ();
m_PendingIncomingStreams.clear ();
}
}
void StreamingDestination::HandleDataMessagePayload (const uint8_t * buf, size_t len)
{
// unzip it

View File

@@ -49,6 +49,8 @@ namespace stream
const int MAX_WINDOW_SIZE = 128;
const int INITIAL_RTT = 8000; // in milliseconds
const int INITIAL_RTO = 9000; // in milliseconds
const size_t MAX_PENDING_INCOMING_BACKLOG = 128;
const int PENDING_INCOMING_TIMEOUT = 10; // in seconds
struct Packet
{
@@ -201,8 +203,8 @@ namespace stream
std::shared_ptr<Stream> CreateNewOutgoingStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0);
void DeleteStream (std::shared_ptr<Stream> stream);
void SetAcceptor (const Acceptor& acceptor) { m_Acceptor = acceptor; };
void ResetAcceptor () { if (m_Acceptor) m_Acceptor (nullptr); m_Acceptor = nullptr; };
void SetAcceptor (const Acceptor& acceptor);
void ResetAcceptor ();
bool IsAcceptorSet () const { return m_Acceptor != nullptr; };
std::shared_ptr<i2p::client::ClientDestination> GetOwner () const { return m_Owner; };
uint16_t GetLocalPort () const { return m_LocalPort; };
@@ -213,6 +215,7 @@ namespace stream
void HandleNextPacket (Packet * packet);
std::shared_ptr<Stream> CreateNewIncomingStream ();
void HandlePendingIncomingTimer (const boost::system::error_code& ecode);
private:
@@ -221,6 +224,8 @@ namespace stream
std::mutex m_StreamsMutex;
std::map<uint32_t, std::shared_ptr<Stream> > m_Streams;
Acceptor m_Acceptor;
std::list<std::shared_ptr<Stream> > m_PendingIncomingStreams;
boost::asio::deadline_timer m_PendingIncomingTimer;
public:

View File

@@ -45,7 +45,7 @@ namespace tunnel
{
auto num = m_TunnelDataMsgs.size ();
if (num > 1)
LogPrint (eLogDebug, "TransitTunnel: ",GetTunnelID (),"->", GetNextTunnelID (), " ", num);
LogPrint (eLogDebug, "TransitTunnel: ", GetTunnelID (), "->", GetNextTunnelID (), " ", num);
i2p::transport::transports.SendMessages (GetNextIdentHash (), m_TunnelDataMsgs);
m_TunnelDataMsgs.clear ();
}
@@ -53,12 +53,12 @@ namespace tunnel
void TransitTunnel::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
{
LogPrint (eLogError, "We are not a gateway for transit tunnel ", GetTunnelID ());
LogPrint (eLogError, "TransitTunnel: We are not a gateway for ", GetTunnelID ());
}
void TransitTunnel::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg)
{
LogPrint (eLogError, "Incoming tunnel message is not supported ", GetTunnelID ());
LogPrint (eLogError, "TransitTunnel: Incoming tunnel message is not supported ", GetTunnelID ());
}
void TransitTunnelGateway::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
@@ -81,7 +81,7 @@ namespace tunnel
auto newMsg = CreateEmptyTunnelDataMsg ();
EncryptTunnelMsg (tunnelMsg, newMsg);
LogPrint (eLogDebug, "TransitTunnel endpoint for ", GetTunnelID ());
LogPrint (eLogDebug, "TransitTunnel: handle msg for endpoint ", GetTunnelID ());
m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg);
}
@@ -92,12 +92,12 @@ namespace tunnel
{
if (isEndpoint)
{
LogPrint (eLogInfo, "TransitTunnel endpoint: ", receiveTunnelID, " created");
LogPrint (eLogInfo, "TransitTunnel: endpoint ", receiveTunnelID, " created");
return new TransitTunnelEndpoint (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
}
else if (isGateway)
{
LogPrint (eLogInfo, "TransitTunnel gateway: ", receiveTunnelID, " created");
LogPrint (eLogInfo, "TransitTunnel: gateway ", receiveTunnelID, " created");
return new TransitTunnelGateway (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
}
else

View File

@@ -126,12 +126,12 @@ namespace transport
if (!m_SSUServer)
{
m_SSUServer = new SSUServer (address.port);
LogPrint ("Start listening UDP port ", address.port);
LogPrint (eLogInfo, "Transports: Start listening UDP port ", address.port);
m_SSUServer->Start ();
DetectExternalIP ();
}
else
LogPrint ("SSU server already exists");
LogPrint (eLogError, "Transports: SSU server already exists");
}
}
m_PeerCleanupTimer.expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT));
@@ -176,7 +176,7 @@ namespace transport
}
catch (std::exception& ex)
{
LogPrint ("Transports: ", ex.what ());
LogPrint (eLogError, "Transports: runtime exception: ", ex.what ());
}
}
}
@@ -200,8 +200,9 @@ namespace transport
bool Transports::IsBandwidthExceeded () const
{
if (i2p::context.GetRouterInfo ().IsHighBandwidth ()) return false;
return std::max (m_InBandwidth, m_OutBandwidth) > LOW_BANDWIDTH_LIMIT;
if (i2p::context.GetRouterInfo ().IsExtraBandwidth ()) return false;
auto bw = std::max (m_InBandwidth, m_OutBandwidth);
return bw > (i2p::context.GetRouterInfo ().IsHighBandwidth () ? HIGH_BANDWIDTH_LIMIT : LOW_BANDWIDTH_LIMIT);
}
void Transports::SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg)
@@ -231,12 +232,12 @@ namespace transport
{
auto r = netdb.FindRouter (ident);
it = m_Peers.insert (std::pair<i2p::data::IdentHash, Peer>(ident, { 0, r, {},
i2p::util::GetSecondsSinceEpoch () })).first;
i2p::util::GetSecondsSinceEpoch (), {} })).first;
connected = ConnectToPeer (ident, it->second);
}
catch (std::exception& ex)
{
LogPrint (eLogError, "Transports::PostMessages ", ex.what ());
LogPrint (eLogError, "Transports: PostMessages exception:", ex.what ());
}
if (!connected) return;
}
@@ -278,30 +279,51 @@ namespace transport
{
if (address->addressString.length () > 0) // trying to resolve
{
LogPrint (eLogInfo, "Resolving ", address->addressString);
LogPrint (eLogDebug, "Transports: Resolving NTCP ", address->addressString);
NTCPResolve (address->addressString, ident);
return true;
}
}
}
else
LogPrint (eLogWarning, "Transports: NTCP address is not present for ", i2p::data::GetIdentHashAbbreviation (ident), ", trying SSU");
}
else if (peer.numAttempts == 1)// SSU
if (peer.numAttempts == 1)// SSU
{
peer.numAttempts++;
if (m_SSUServer)
{
if (m_SSUServer->GetSession (peer.router))
if (m_SSUServer && peer.router->IsSSU (!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);
return true;
}
else // we don't have address
{
if (address->addressString.length () > 0) // trying to resolve
{
LogPrint (eLogDebug, "Transports: Resolving SSU ", address->addressString);
SSUResolve (address->addressString, ident);
return true;
}
}
}
}
LogPrint (eLogError, "No NTCP and SSU addresses available");
LogPrint (eLogError, "Transports: No NTCP or SSU addresses available");
peer.Done ();
m_Peers.erase (ident);
return false;
}
else // otherwise request RI
{
LogPrint ("Router not found. Requested");
LogPrint (eLogInfo, "Transports: RouterInfo for ", ident.ToBase64 (), " not found, requested");
i2p::data::netdb.RequestDestination (ident, std::bind (
&Transports::RequestComplete, this, std::placeholders::_1, ident));
}
@@ -313,20 +335,20 @@ namespace transport
m_Service.post (std::bind (&Transports::HandleRequestComplete, this, r, ident));
}
void Transports::HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident)
void Transports::HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, i2p::data::IdentHash ident)
{
auto it = m_Peers.find (ident);
if (it != m_Peers.end ())
{
if (r)
{
LogPrint ("Router found. Trying to connect");
LogPrint (eLogDebug, "Transports: RouterInfo for ", ident.ToBase64 (), " found, Trying to connect");
it->second.router = r;
ConnectToPeer (ident, it->second);
}
else
{
LogPrint ("Router not found. Failed to send messages");
LogPrint (eLogError, "Transports: RouterInfo not found, Failed to send messages");
m_Peers.erase (it);
}
}
@@ -350,7 +372,7 @@ namespace transport
if (!ecode && peer.router)
{
auto address = (*it).endpoint ().address ();
LogPrint (eLogInfo, (*it).host_name (), " has been resolved to ", address);
LogPrint (eLogDebug, "Transports: ", (*it).host_name (), " has been resolved to ", address);
auto addr = peer.router->GetNTCPAddress ();
if (addr)
{
@@ -359,7 +381,38 @@ namespace transport
return;
}
}
LogPrint (eLogError, "Unable to resolve NTCP address: ", ecode.message ());
LogPrint (eLogError, "Transports: Unable to resolve NTCP address: ", ecode.message ());
m_Peers.erase (it1);
}
}
void Transports::SSUResolve (const std::string& addr, const i2p::data::IdentHash& ident)
{
auto resolver = std::make_shared<boost::asio::ip::tcp::resolver>(m_Service);
resolver->async_resolve (boost::asio::ip::tcp::resolver::query (addr, ""),
std::bind (&Transports::HandleSSUResolve, this,
std::placeholders::_1, std::placeholders::_2, ident, resolver));
}
void Transports::HandleSSUResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver)
{
auto it1 = m_Peers.find (ident);
if (it1 != m_Peers.end ())
{
auto& peer = it1->second;
if (!ecode && peer.router)
{
auto address = (*it).endpoint ().address ();
LogPrint (eLogDebug, "Transports: ", (*it).host_name (), " has been resolved to ", address);
auto addr = peer.router->GetSSUAddress (!context.SupportsV6 ());;
if (addr)
{
m_SSUServer->CreateSession (peer.router, address, addr->port);
return;
}
}
LogPrint (eLogError, "Transports: Unable to resolve SSU address: ", ecode.message ());
m_Peers.erase (it1);
}
}
@@ -376,7 +429,7 @@ namespace transport
if (ssuSession) // try SSU first
{
m_SSUServer->DeleteSession (ssuSession);
LogPrint ("SSU session closed");
LogPrint (eLogDebug, "Transports: SSU session closed");
}
// TODO: delete NTCP
}
@@ -389,19 +442,19 @@ namespace transport
for (int i = 0; i < 5; i++)
{
auto router = i2p::data::netdb.GetRandomPeerTestRouter ();
if (router && router->IsSSU ())
m_SSUServer->GetSession (router, true); // peer test
if (router && router->IsSSU (!context.SupportsV6 ()))
m_SSUServer->CreateSession (router, true); // peer test
else
{
// if not peer test capable routers found pick any
router = i2p::data::netdb.GetRandomRouter ();
if (router && router->IsSSU ())
m_SSUServer->GetSession (router); // no peer test
m_SSUServer->CreateSession (router); // no peer test
}
}
}
else
LogPrint (eLogError, "Can't detect external IP. SSU is not available");
LogPrint (eLogError, "Transports: Can't detect external IP. SSU is not available");
}
void Transports::PeerTest ()
@@ -412,14 +465,14 @@ namespace transport
for (int i = 0; i < 5; i++)
{
auto router = i2p::data::netdb.GetRandomPeerTestRouter ();
if (router && router->IsSSU ())
if (router && router->IsSSU (!context.SupportsV6 ()))
{
if (!statusChanged)
{
statusChanged = true;
i2p::context.SetStatus (eRouterStatusTesting); // first time only
}
m_SSUServer->GetSession (router, true); // peer test
m_SSUServer->CreateSession (router, true); // peer test
}
}
}
@@ -449,7 +502,7 @@ namespace transport
it->second.delayedMessages.clear ();
}
else // incoming connection
m_Peers.insert (std::make_pair (ident, Peer{ 0, nullptr, { session }, i2p::util::GetSecondsSinceEpoch () }));
m_Peers.insert (std::make_pair (ident, Peer{ 0, nullptr, { session }, i2p::util::GetSecondsSinceEpoch (), {} }));
});
}
@@ -489,7 +542,7 @@ namespace transport
{
if (it->second.sessions.empty () && ts > it->second.creationTime + SESSION_CREATION_TIMEOUT)
{
LogPrint (eLogError, "Session to peer ", it->first.ToBase64 (), " has not been created in ", SESSION_CREATION_TIMEOUT, " seconds");
LogPrint (eLogWarning, "Transports: Session to peer ", it->first.ToBase64 (), " has not been created in ", SESSION_CREATION_TIMEOUT, " seconds");
it = m_Peers.erase (it);
}
else

View File

@@ -67,6 +67,7 @@ namespace transport
const size_t SESSION_CREATION_TIMEOUT = 10; // in seconds
const uint32_t LOW_BANDWIDTH_LIMIT = 32*1024; // 32KBs
const uint32_t HIGH_BANDWIDTH_LIMIT = 256*1024; // 256KBs
class Transports
{
public:
@@ -105,7 +106,7 @@ namespace transport
void Run ();
void RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident);
void HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident);
void HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, i2p::data::IdentHash ident);
void PostMessages (i2p::data::IdentHash ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > msgs);
void PostCloseSession (std::shared_ptr<const i2p::data::RouterInfo> router);
bool ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer);
@@ -114,6 +115,9 @@ namespace transport
void NTCPResolve (const std::string& addr, const i2p::data::IdentHash& ident);
void HandleNTCPResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver);
void SSUResolve (const std::string& addr, const i2p::data::IdentHash& ident);
void HandleSSUResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver);
void UpdateBandwidth ();
void DetectExternalIP ();

View File

@@ -85,14 +85,14 @@ namespace tunnel
// send message
if (outboundTunnel)
outboundTunnel->SendTunnelDataMsg (GetNextIdentHash (), 0, ToSharedI2NPMessage (msg));
outboundTunnel->SendTunnelDataMsg (GetNextIdentHash (), 0, msg);
else
i2p::transport::transports.SendMessage (GetNextIdentHash (), ToSharedI2NPMessage (msg));
i2p::transport::transports.SendMessage (GetNextIdentHash (), msg);
}
bool Tunnel::HandleTunnelBuildResponse (uint8_t * msg, size_t len)
{
LogPrint ("TunnelBuildResponse ", (int)msg[0], " records.");
LogPrint (eLogDebug, "Tunnel: TunnelBuildResponse ", (int)msg[0], " records.");
i2p::crypto::CBCDecryption decryption;
TunnelHopConfig * hop = m_Config->GetLastHop ();
@@ -111,7 +111,7 @@ namespace tunnel
decryption.Decrypt(record, TUNNEL_BUILD_RECORD_SIZE, record);
}
else
LogPrint ("Tunnel hop index ", idx, " is out of range");
LogPrint (eLogWarning, "Tunnel: hop index ", idx, " is out of range");
hop1 = hop1->prev;
}
hop = hop->prev;
@@ -123,7 +123,7 @@ namespace tunnel
{
const uint8_t * record = msg + 1 + hop->recordIndex*TUNNEL_BUILD_RECORD_SIZE;
uint8_t ret = record[BUILD_RESPONSE_RECORD_RET_OFFSET];
LogPrint ("Ret code=", (int)ret);
LogPrint (eLogDebug, "Tunnel: Build response ret code=", (int)ret);
auto profile = i2p::data::netdb.FindRouterProfile (hop->ident->GetIdentHash ());
if (profile)
profile->TunnelBuildResponse (ret);
@@ -163,7 +163,7 @@ namespace tunnel
void Tunnel::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
{
LogPrint (eLogInfo, "Can't send I2NP messages without delivery instructions");
LogPrint (eLogInfo, "Tunnel: Can't send I2NP messages without delivery instructions");
}
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > Tunnel::GetPeers () const
@@ -181,6 +181,15 @@ namespace tunnel
ret.push_back (it->ident);
return ret;
}
void Tunnel::PrintHops (std::stringstream& s) const
{
for (auto& it: m_Hops)
{
s << "-->";
s << i2p::data::GetIdentHashAbbreviation (it->ident->GetIdentHash ());
}
}
void InboundTunnel::HandleTunnelDataMsg (std::shared_ptr<const I2NPMessage> msg)
{
@@ -193,9 +202,8 @@ namespace tunnel
void InboundTunnel::Print (std::stringstream& s) const
{
s << "-->" << i2p::data::GetIdentHashAbbreviation (GetNextIdentHash ()) << ":" << GetNextTunnelID ();
s << "-->" << (GetNumHops () - 1) << " hops ";
s << GetTunnelID () << ":me";
PrintHops (s);
s << "-->" << GetTunnelID () << ":me";
}
void OutboundTunnel::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg)
@@ -235,8 +243,9 @@ namespace tunnel
void OutboundTunnel::Print (std::stringstream& s) const
{
s << "me-->" << i2p::data::GetIdentHashAbbreviation (GetNextIdentHash ()) << ":" << GetNextTunnelID ();
s << "-->" << (GetNumHops () - 1) << " hops-->";
s << GetTunnelID () << ":me";
PrintHops (s);
s << "-->";
}
Tunnels tunnels;
@@ -324,9 +333,10 @@ namespace tunnel
return tunnel;
}
std::shared_ptr<TunnelPool> Tunnels::CreateTunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels)
std::shared_ptr<TunnelPool> Tunnels::CreateTunnelPool (int numInboundHops,
int numOutboundHops, int numInboundTunnels, int numOutboundTunnels)
{
auto pool = std::make_shared<TunnelPool> (localDestination, numInboundHops, numOutboundHops, numInboundTunnels, numOutboundTunnels);
auto pool = std::make_shared<TunnelPool> (numInboundHops, numOutboundHops, numInboundTunnels, numOutboundTunnels);
std::unique_lock<std::mutex> l(m_PoolsMutex);
m_Pools.push_back (pool);
return pool;
@@ -432,7 +442,7 @@ namespace tunnel
HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ());
break;
default:
LogPrint (eLogError, "Unexpected messsage type ", (int)typeID);
LogPrint (eLogError, "Tunnel: Unexpected messsage type ", (int)typeID);
}
msg = m_Queue.Get ();
@@ -456,7 +466,7 @@ namespace tunnel
}
catch (std::exception& ex)
{
LogPrint ("Tunnels: ", ex.what ());
LogPrint (eLogError, "Tunnel: runtime exception: ", ex.what ());
}
}
}
@@ -476,7 +486,7 @@ namespace tunnel
auto typeID = msg->GetTypeID ();
LogPrint (eLogDebug, "TunnelGateway of ", (int)len, " bytes for tunnel ", tunnel->GetTunnelID (), ". Msg type ", (int)typeID);
if (typeID == eI2NPDatabaseStore || typeID == eI2NPDatabaseSearchReply)
if (IsRouterInfoMsg (msg) || typeID == eI2NPDatabaseSearchReply)
// transit DatabaseStore my contain new/updated RI
// or DatabaseSearchReply with new routers
i2p::data::netdb.PostI2NPMsg (msg);
@@ -511,7 +521,7 @@ namespace tunnel
case eTunnelStatePending:
if (ts > tunnel->GetCreationTime () + TUNNEL_CREATION_TIMEOUT)
{
LogPrint ("Pending tunnel build request ", it->first, " timeout. Deleted");
LogPrint (eLogError, "Tunnel: Pending build request ", it->first, " timeout, deleted");
// update stats
auto config = tunnel->GetTunnelConfig ();
if (config)
@@ -536,7 +546,7 @@ namespace tunnel
it++;
break;
case eTunnelStateBuildFailed:
LogPrint ("Pending tunnel build request ", it->first, " failed. Deleted");
LogPrint (eLogError, "Tunnel: Pending build request ", it->first, " failed, deleted");
it = pendingTunnels.erase (it);
m_NumFailedTunnelCreations++;
break;
@@ -561,7 +571,7 @@ namespace tunnel
auto tunnel = *it;
if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
{
LogPrint ("Tunnel ", tunnel->GetTunnelID (), " expired");
LogPrint (eLogDebug, "Tunnel: ", tunnel->GetTunnelID (), " expired");
auto pool = tunnel->GetTunnelPool ();
if (pool)
pool->TunnelExpired (tunnel);
@@ -592,7 +602,7 @@ namespace tunnel
auto inboundTunnel = GetNextInboundTunnel ();
auto router = i2p::data::netdb.GetRandomRouter ();
if (!inboundTunnel || !router) return;
LogPrint ("Creating one hop outbound tunnel...");
LogPrint (eLogDebug, "Creating one hop outbound tunnel");
CreateTunnel<OutboundTunnel> (
std::make_shared<TunnelConfig> (std::vector<std::shared_ptr<const i2p::data::IdentityEx> > { router->GetRouterIdentity () },
inboundTunnel->GetNextTunnelID (), inboundTunnel->GetNextIdentHash ())
@@ -609,7 +619,7 @@ namespace tunnel
auto tunnel = it->second;
if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
{
LogPrint ("Tunnel ", tunnel->GetTunnelID (), " expired");
LogPrint (eLogDebug, "Tunnel: ", tunnel->GetTunnelID (), " expired");
auto pool = tunnel->GetTunnelPool ();
if (pool)
pool->TunnelExpired (tunnel);
@@ -637,10 +647,13 @@ namespace tunnel
if (m_InboundTunnels.empty ())
{
LogPrint ("Creating zero hops inbound tunnel...");
LogPrint (eLogDebug, "Creating zero hops inbound tunnel...");
CreateZeroHopsInboundTunnel ();
if (!m_ExploratoryPool)
m_ExploratoryPool = CreateTunnelPool (&i2p::context, 2, 2, 5, 5); // 2-hop exploratory, 5 tunnels
{
m_ExploratoryPool = CreateTunnelPool (2, 2, 5, 5); // 2-hop exploratory, 5 tunnels
m_ExploratoryPool->SetLocalDestination (i2p::context.GetSharedDestination ());
}
return;
}
@@ -648,7 +661,7 @@ namespace tunnel
{
// trying to create one more inbound tunnel
auto router = i2p::data::netdb.GetRandomRouter ();
LogPrint ("Creating one hop inbound tunnel...");
LogPrint (eLogDebug, "Creating one hop inbound tunnel...");
CreateTunnel<InboundTunnel> (
std::make_shared<TunnelConfig> (std::vector<std::shared_ptr<const i2p::data::IdentityEx> > { router->GetRouterIdentity () })
);
@@ -663,7 +676,7 @@ namespace tunnel
if (ts > it->second->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
{
auto tmp = it->second;
LogPrint ("Transit tunnel ", tmp->GetTunnelID (), " expired");
LogPrint (eLogDebug, "Transit tunnel ", tmp->GetTunnelID (), " expired");
{
std::unique_lock<std::mutex> l(m_TransitTunnelsMutex);
it = m_TransitTunnels.erase (it);

View File

@@ -62,7 +62,6 @@ namespace tunnel
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > GetInvertedPeers () const;
TunnelState GetState () const { return m_State; };
void SetState (TunnelState state) { m_State = state; };
int GetNumHops () const { return m_Hops.size (); }
bool IsEstablished () const { return m_State == eTunnelStateEstablished; };
bool IsFailed () const { return m_State == eTunnelStateFailed; };
bool IsRecreated () const { return m_IsRecreated; };
@@ -76,7 +75,11 @@ namespace tunnel
// implements TunnelBase
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out);
protected:
void PrintHops (std::stringstream& s) const;
private:
std::shared_ptr<const TunnelConfig> m_Config;
@@ -150,7 +153,8 @@ namespace tunnel
std::shared_ptr<TTunnel> CreateTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<OutboundTunnel> outboundTunnel = nullptr);
void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<InboundTunnel> tunnel);
void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> tunnel);
std::shared_ptr<TunnelPool> CreateTunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOuboundHops, int numInboundTunnels, int numOutboundTunnels);
std::shared_ptr<TunnelPool> CreateTunnelPool (int numInboundHops,
int numOuboundHops, int numInboundTunnels, int numOutboundTunnels);
void DeleteTunnelPool (std::shared_ptr<TunnelPool> pool);
void StopTunnelPool (std::shared_ptr<TunnelPool> pool);

View File

@@ -33,6 +33,7 @@ namespace tunnel
{
RAND_bytes (layerKey, 32);
RAND_bytes (ivKey, 32);
RAND_bytes (replyKey, 32);
RAND_bytes (replyIV, 16);
RAND_bytes ((uint8_t *)&tunnelID, 4);
isGateway = true;
@@ -100,7 +101,7 @@ namespace tunnel
clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] = flag;
htobe32buf (clearText + BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET, i2p::util::GetHoursSinceEpoch ());
htobe32buf (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET, replyMsgID);
// TODO: fill padding
RAND_bytes (clearText + BUILD_REQUEST_RECORD_PADDING_OFFSET, BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE - BUILD_REQUEST_RECORD_PADDING_OFFSET);
i2p::crypto::ElGamalEncryption elGamalEncryption (ident->GetEncryptionPublicKey ());
elGamalEncryption.Encrypt (clearText, BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE, record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET);
memcpy (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)ident->GetIdentHash (), 16);
@@ -194,25 +195,6 @@ namespace tunnel
}
return peers;
}
void Print (std::stringstream& s) const
{
TunnelHopConfig * hop = m_FirstHop;
if (!IsInbound ()) // outbound
s << "me";
s << "-->" << m_FirstHop->tunnelID;
while (hop)
{
s << ":" << GetIdentHashAbbreviation (hop->ident->GetIdentHash ()) << "-->";
if (!hop->isEndpoint)
s << hop->nextTunnelID;
else
return;
hop = hop->next;
}
// we didn't reach enpoint that mean we are last hop
s << ":me";
}
private:

View File

@@ -93,7 +93,7 @@ namespace tunnel
if (fragment + size < decrypted + TUNNEL_DATA_ENCRYPTED_SIZE)
{
// this is not last message. we have to copy it
m.data = ToSharedI2NPMessage (NewI2NPShortMessage ());
m.data = NewI2NPShortMessage ();
m.data->offset += TUNNEL_GATEWAY_HEADER_SIZE; // reserve room for TunnelGateway header
m.data->len += TUNNEL_GATEWAY_HEADER_SIZE;
*(m.data) = *msg;
@@ -148,12 +148,12 @@ namespace tunnel
if (msg.data->len + size > msg.data->maxLen)
{
LogPrint (eLogInfo, "Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough");
auto newMsg = ToSharedI2NPMessage (NewI2NPMessage ());
auto newMsg = NewI2NPMessage ();
*newMsg = *(msg.data);
msg.data = newMsg;
}
memcpy (msg.data->buf + msg.data->len, fragment, size); // concatenate fragment
msg.data->len += size;
if (msg.data->Concat (fragment, size) < size) // concatenate fragment
LogPrint (eLogError, "Tunnel endpoint I2NP buffer overflow ", msg.data->maxLen);
if (isLastFragment)
{
// message complete
@@ -204,12 +204,12 @@ namespace tunnel
if (msg.data->len + size > msg.data->maxLen)
{
LogPrint (eLogInfo, "Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough");
auto newMsg = ToSharedI2NPMessage (NewI2NPMessage ());
auto newMsg = NewI2NPMessage ();
*newMsg = *(msg.data);
msg.data = newMsg;
}
memcpy (msg.data->buf + msg.data->len, it->second.data->GetBuffer (), size); // concatenate out-of-sync fragment
msg.data->len += size;
if (msg.data->Concat (it->second.data->GetBuffer (), size) < size) // concatenate out-of-sync fragment
LogPrint (eLogError, "Tunnel endpoint I2NP buffer overflow ", msg.data->maxLen);
if (it->second.isLastFragment)
{
// message complete
@@ -225,36 +225,32 @@ namespace tunnel
void TunnelEndpoint::HandleNextMessage (const TunnelMessageBlock& msg)
{
LogPrint (eLogInfo, "TunnelMessage: handle fragment of ", msg.data->GetLength ()," bytes. Msg type ", (int)msg.data->GetTypeID ());
auto typeID = msg.data->GetTypeID ();
LogPrint (eLogInfo, "TunnelMessage: handle fragment of ", msg.data->GetLength ()," bytes. Msg type ", (int)typeID);
switch (msg.deliveryType)
{
case eDeliveryTypeLocal:
i2p::HandleI2NPMessage (msg.data);
break;
case eDeliveryTypeTunnel:
i2p::transport::transports.SendMessage (msg.hash, i2p::CreateTunnelGatewayMsg (msg.tunnelID, msg.data));
break;
case eDeliveryTypeRouter:
if (msg.hash == i2p::context.GetRouterInfo ().GetIdentHash ()) // check if message is sent to us
i2p::HandleI2NPMessage (msg.data);
if (!m_IsInbound) // outbound transit tunnel
i2p::transport::transports.SendMessage (msg.hash, i2p::CreateTunnelGatewayMsg (msg.tunnelID, msg.data));
else
{
// to somebody else
if (!m_IsInbound) // outbound transit tunnel
{
/* auto typeID = msg.data->GetTypeID ();
if (typeID == eI2NPDatabaseStore || typeID == eI2NPDatabaseSearchReply )
// catch RI or reply with new list of routers
i2p::data::netdb.PostI2NPMsg (msg.data);*/
i2p::transport::transports.SendMessage (msg.hash, msg.data);
}
else // we shouldn't send this message. possible leakage
LogPrint (eLogError, "Message to another router arrived from an inbound tunnel. Dropped");
}
LogPrint (eLogError, "Delivery type tunnel arrived from an inbound tunnel. Dropped");
break;
case eDeliveryTypeRouter:
if (!m_IsInbound) // outbound transit tunnel
i2p::transport::transports.SendMessage (msg.hash, msg.data);
else // we shouldn't send this message. possible leakage
LogPrint (eLogError, "Delivery type router arrived from an inbound tunnel. Dropped");
break;
default:
LogPrint (eLogError, "TunnelMessage: Unknown delivery type ", (int)msg.deliveryType);
};
// catch RI or reply with new list of routers
if ((IsRouterInfoMsg (msg.data) || typeID == eI2NPDatabaseSearchReply) &&
!m_IsInbound && msg.deliveryType != eDeliveryTypeLocal)
i2p::data::netdb.PostI2NPMsg (msg.data);
}
}
}

View File

@@ -143,7 +143,7 @@ namespace tunnel
void TunnelGatewayBuffer::CreateCurrentTunnelDataMessage ()
{
m_CurrentTunnelDataMsg = ToSharedI2NPMessage (NewI2NPShortMessage ());
m_CurrentTunnelDataMsg = NewI2NPShortMessage ();
m_CurrentTunnelDataMsg->Align (12);
// we reserve space for padding
m_CurrentTunnelDataMsg->offset += TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE;

View File

@@ -14,8 +14,8 @@ namespace i2p
{
namespace tunnel
{
TunnelPool::TunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels):
m_LocalDestination (localDestination), m_NumInboundHops (numInboundHops), m_NumOutboundHops (numOutboundHops),
TunnelPool::TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels):
m_NumInboundHops (numInboundHops), m_NumOutboundHops (numOutboundHops),
m_NumInboundTunnels (numInboundTunnels), m_NumOutboundTunnels (numOutboundTunnels), m_IsActive (true)
{
}
@@ -34,12 +34,12 @@ namespace tunnel
if (m_NumInboundHops > size)
{
m_NumInboundHops = size;
LogPrint (eLogInfo, "Inbound tunnel length has beed adjusted to ", size, " for explicit peers");
LogPrint (eLogInfo, "Tunnels: Inbound tunnel length has beed adjusted to ", size, " for explicit peers");
}
if (m_NumOutboundHops > size)
{
m_NumOutboundHops = size;
LogPrint (eLogInfo, "Outbound tunnel length has beed adjusted to ", size, " for explicit peers");
LogPrint (eLogInfo, "Tunnels: Outbound tunnel length has beed adjusted to ", size, " for explicit peers");
}
m_NumInboundTunnels = 1;
m_NumOutboundTunnels = 1;
@@ -203,7 +203,7 @@ namespace tunnel
{
for (auto it: m_Tests)
{
LogPrint ("Tunnel test ", (int)it.first, " failed");
LogPrint (eLogWarning, "Tunnels: test of ", (int)it.first, " failed");
// if test failed again with another tunnel we consider it failed
if (it.second.first)
{
@@ -266,7 +266,7 @@ namespace tunnel
if (m_LocalDestination)
m_LocalDestination->ProcessGarlicMessage (msg);
else
LogPrint (eLogWarning, "Local destination doesn't exist. Dropped");
LogPrint (eLogWarning, "Tunnels: local destination doesn't exist, dropped");
}
void TunnelPool::ProcessDeliveryStatus (std::shared_ptr<I2NPMessage> msg)
@@ -284,7 +284,7 @@ namespace tunnel
it->second.first->SetState (eTunnelStateEstablished);
if (it->second.second->GetState () == eTunnelStateTestFailed)
it->second.second->SetState (eTunnelStateEstablished);
LogPrint ("Tunnel test ", it->first, " successive. ", i2p::util::GetMillisecondsSinceEpoch () - timestamp, " milliseconds");
LogPrint (eLogDebug, "Tunnels: test of ", it->first, " successful. ", i2p::util::GetMillisecondsSinceEpoch () - timestamp, " milliseconds");
m_Tests.erase (it);
}
else
@@ -292,13 +292,13 @@ namespace tunnel
if (m_LocalDestination)
m_LocalDestination->ProcessDeliveryStatusMessage (msg);
else
LogPrint (eLogWarning, "Local destination doesn't exist. Dropped");
LogPrint (eLogWarning, "Tunnels: Local destination doesn't exist, dropped");
}
}
std::shared_ptr<const i2p::data::RouterInfo> TunnelPool::SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop) const
{
bool isExploratory = (m_LocalDestination == &i2p::context); // TODO: implement it better
bool isExploratory = (i2p::tunnel::tunnels.GetExploratoryPool () == shared_from_this ());
auto hop = isExploratory ? i2p::data::netdb.GetRandomRouter (prevHop):
i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop);
@@ -328,7 +328,7 @@ namespace tunnel
auto hop = SelectNextHop (prevHop);
if (!hop)
{
LogPrint (eLogError, "Can't select next hop");
LogPrint (eLogError, "Tunnels: Can't select next hop for ", prevHop->GetIdentHashBase64 ());
return false;
}
prevHop = hop;
@@ -353,7 +353,7 @@ namespace tunnel
peers.push_back (r->GetRouterIdentity ());
else
{
LogPrint (eLogInfo, "Can't find router for ", ident.ToBase64 ());
LogPrint (eLogInfo, "Tunnels: Can't find router for ", ident.ToBase64 ());
i2p::data::netdb.RequestDestination (ident);
return false;
}
@@ -366,7 +366,7 @@ namespace tunnel
auto outboundTunnel = GetNextOutboundTunnel ();
if (!outboundTunnel)
outboundTunnel = tunnels.GetNextOutboundTunnel ();
LogPrint ("Creating destination inbound tunnel...");
LogPrint (eLogDebug, "Tunnels: Creating destination inbound tunnel...");
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > peers;
if (SelectPeers (peers, true))
{
@@ -375,7 +375,7 @@ namespace tunnel
tunnel->SetTunnelPool (shared_from_this ());
}
else
LogPrint (eLogError, "Can't create inbound tunnel. No peers available");
LogPrint (eLogError, "Tunnels: Can't create inbound tunnel, no peers available");
}
void TunnelPool::RecreateInboundTunnel (std::shared_ptr<InboundTunnel> tunnel)
@@ -383,7 +383,7 @@ namespace tunnel
auto outboundTunnel = GetNextOutboundTunnel ();
if (!outboundTunnel)
outboundTunnel = tunnels.GetNextOutboundTunnel ();
LogPrint ("Re-creating destination inbound tunnel...");
LogPrint (eLogDebug, "Tunnels: Re-creating destination inbound tunnel...");
auto newTunnel = tunnels.CreateTunnel<InboundTunnel> (std::make_shared<TunnelConfig>(tunnel->GetPeers ()), outboundTunnel);
newTunnel->SetTunnelPool (shared_from_this());
}
@@ -395,7 +395,7 @@ namespace tunnel
inboundTunnel = tunnels.GetNextInboundTunnel ();
if (inboundTunnel)
{
LogPrint ("Creating destination outbound tunnel...");
LogPrint (eLogDebug, "Tunnels: Creating destination outbound tunnel...");
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > peers;
if (SelectPeers (peers, false))
{
@@ -404,10 +404,10 @@ namespace tunnel
tunnel->SetTunnelPool (shared_from_this ());
}
else
LogPrint (eLogError, "Can't create outbound tunnel. No peers available");
LogPrint (eLogError, "Tunnels: Can't create outbound tunnel, no peers available");
}
else
LogPrint (eLogError, "Can't create outbound tunnel. No inbound tunnels found");
LogPrint (eLogError, "Tunnels: Can't create outbound tunnel, no inbound tunnels found");
}
void TunnelPool::RecreateOutboundTunnel (std::shared_ptr<OutboundTunnel> tunnel)
@@ -417,19 +417,19 @@ namespace tunnel
inboundTunnel = tunnels.GetNextInboundTunnel ();
if (inboundTunnel)
{
LogPrint ("Re-creating destination outbound tunnel...");
LogPrint (eLogDebug, "Tunnels: Re-creating destination outbound tunnel...");
auto newTunnel = tunnels.CreateTunnel<OutboundTunnel> (
std::make_shared<TunnelConfig> (tunnel->GetPeers (),
inboundTunnel->GetNextTunnelID (), inboundTunnel->GetNextIdentHash ()));
newTunnel->SetTunnelPool (shared_from_this ());
}
else
LogPrint ("Can't re-create outbound tunnel. No inbound tunnels found");
LogPrint (eLogDebug, "Tunnels: Can't re-create outbound tunnel, no inbound tunnels found");
}
void TunnelPool::CreatePairedInboundTunnel (std::shared_ptr<OutboundTunnel> outboundTunnel)
{
LogPrint (eLogInfo, "Creating paired inbound tunnel...");
LogPrint (eLogDebug, "Tunnels: Creating paired inbound tunnel...");
auto tunnel = tunnels.CreateTunnel<InboundTunnel> (std::make_shared<TunnelConfig>(outboundTunnel->GetInvertedPeers ()), outboundTunnel);
tunnel->SetTunnelPool (shared_from_this ());
}

View File

@@ -27,11 +27,11 @@ namespace tunnel
{
public:
TunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels);
TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels);
~TunnelPool ();
i2p::garlic::GarlicDestination * GetLocalDestination () const { return m_LocalDestination; };
void SetLocalDestination (i2p::garlic::GarlicDestination * destination) { m_LocalDestination = destination; };
std::shared_ptr<i2p::garlic::GarlicDestination> GetLocalDestination () const { return m_LocalDestination; };
void SetLocalDestination (std::shared_ptr<i2p::garlic::GarlicDestination> destination) { m_LocalDestination = destination; };
void SetExplicitPeers (std::shared_ptr<std::vector<i2p::data::IdentHash> > explicitPeers);
void CreateTunnels ();
@@ -67,7 +67,7 @@ namespace tunnel
private:
i2p::garlic::GarlicDestination * m_LocalDestination;
std::shared_ptr<i2p::garlic::GarlicDestination> m_LocalDestination;
int m_NumInboundHops, m_NumOutboundHops, m_NumInboundTunnels, m_NumOutboundTunnels;
std::shared_ptr<std::vector<i2p::data::IdentHash> > m_ExplicitPeers;
mutable std::mutex m_InboundTunnelsMutex;

View File

@@ -46,7 +46,7 @@ template<class M, typename F>
F GetKnownProcAddressImpl(M hmod, const char *name, F) {
auto proc = reinterpret_cast<F>(dlsym(hmod, name));
if (!proc) {
LogPrint("Error resolving ", name, " from UPNP library. This often happens if there is version mismatch!");
LogPrint(eLogError, "UPnP: Error resolving ", name, " from library, version mismatch?");
}
return proc;
}
@@ -83,7 +83,7 @@ namespace transport
#endif
if (m_Module == NULL)
{
LogPrint ("Error loading UPNP library. This often happens if there is version mismatch!");
LogPrint (eLogError, "UPnP: Error loading UPNP library, version mismatch?");
return;
}
else
@@ -144,20 +144,20 @@ namespace transport
r = UPNP_GetExternalIPAddressFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);
if(r != UPNPCOMMAND_SUCCESS)
{
LogPrint ("UPnP: UPNP_GetExternalIPAddress () returned ", r);
LogPrint (eLogError, "UPnP: UPNP_GetExternalIPAddress () returned ", r);
return;
}
else
{
if (m_externalIPAddress[0])
{
LogPrint ("UPnP: ExternalIPAddress = ", m_externalIPAddress);
LogPrint (eLogInfo, "UPnP: ExternalIPAddress = ", m_externalIPAddress);
i2p::context.UpdateAddress (boost::asio::ip::address::from_string (m_externalIPAddress));
return;
}
else
{
LogPrint ("UPnP: GetExternalIPAddress failed.");
LogPrint (eLogError, "UPnP: GetExternalIPAddress failed.");
return;
}
}
@@ -189,12 +189,12 @@ namespace transport
#endif
if (r!=UPNPCOMMAND_SUCCESS)
{
LogPrint ("AddPortMapping (", strPort.c_str () ,", ", strPort.c_str () ,", ", m_NetworkAddr, ") failed with code ", r);
LogPrint (eLogError, "UPnP: AddPortMapping (", strPort.c_str () ,", ", strPort.c_str () ,", ", m_NetworkAddr, ") failed with code ", r);
return;
}
else
{
LogPrint ("UPnP Port Mapping successful. (", m_NetworkAddr ,":", strPort.c_str(), " type ", strType.c_str () ," -> ", m_externalIPAddress ,":", strPort.c_str() ,")");
LogPrint (eLogDebug, "UPnP: Port Mapping successful. (", m_NetworkAddr ,":", strPort.c_str(), " type ", strType.c_str () ," -> ", m_externalIPAddress ,":", strPort.c_str() ,")");
return;
}
std::this_thread::sleep_for(std::chrono::minutes(20)); // c++11
@@ -224,7 +224,7 @@ namespace transport
}
int r = 0;
r = UPNP_DeletePortMappingFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strType.c_str (), 0);
LogPrint ("UPNP_DeletePortMapping() returned : ", r, "\n");
LogPrint (eLogError, "UPnP: DeletePortMapping() returned : ", r, "\n");
}
void UPnP::Close ()

14
Win32/Itoopie.cmd Normal file
View File

@@ -0,0 +1,14 @@
@echo off
convert Itoopie.svg ^
-fuzz 90%% -fill transparent -floodfill 2x2 white -fuzz 20%% -fill #AE0E99 -opaque red ^
-fill #FBBC11 -opaque yellow ^
( -clone 0 -resize 256x256 ) ^
( -clone 0 -resize 128x128 ) ^
( -clone 0 -resize 64x64 ) ^
( -clone 0 -resize 48x48 ) ^
( -clone 0 -resize 32x32 ) ^
( -clone 0 -resize 24x24 ) ^
( -clone 0 -resize 16x16 ) ^
( -size 150x57 xc:white -clone 0 -geometry 57x57+46+0 -composite -gravity center -write BMP3:ictoopie.bmp +delete ) ^
( -clone 0 -write Itoopie_purple.png +delete ) ^
-delete 0 ictoopie.ico

View File

@@ -1,84 +0,0 @@
Building i2pd for Windows
=========================
Requirements for building:
* Visual Studio 2013 (tested with VS2013 Update 1, Update 3, and Update 4)
* Boost (tested with 1.56, 1.57, and 1.58)
* Crypto++ (tested with 5.6.2)
Building Boost (32-bit)
-----------------------
Open a Visual Studio x86 command prompt and run the following:
cd C:\path\to\boost\sources
bootstrap
b2 toolset=msvc-12.0 --build-type=complete --libdir=C:\Boost\lib\Win32 install --with-filesystem --with-program_options --with-regex --with-date_time
Building Boost (64-bit)
-----------------------
Open a Visual Studio x64 command prompt and run the following:
cd C:\path\to\boost\sources
bootstrap
b2 toolset=msvc-12.0 --build-type=complete --libdir=C:\Boost\lib\x64 architecture=x86 address-model=64 install --with-filesystem --with-program_options --with-regex --with-date_time
After Boost is compiled, set the environment variable `BOOST` to the directory
Boost was installed to. If you followed the instructions outlined here, you
should set it to `C:\Boost`. Additionally, set the BOOSTVER variable to the
version of Boost that you're using, but instead of a '.' use a '_'. For
example, I have `BOOSTVER` set to `1_58`.
Building Crypto++
-----------------
* Open the crypttest Solution in VS2013
* Visual Studio will ask to update the Solution/Project. Allow it.
* Build the `cryptopp` project, both the Debug and Release targets and for both
Win32 and x64.
* Create a folder called `cryptopp` in the crypto++ source directory, then copy
the header files to this new directory.
* Set the `CRYPTOPP` environment variable pointing to the Crypto++ source directory.
Building i2pd
-------------
## Prep work ##
I strongly advise setting up your own `INCLUDES` and `LIBS` instead of relying
on the settings in the i2pd project file. By using your own settings, if the
i2pd devs change the paths in the project file, your builds will still work.
To do this, create or edit the file
`%localappdata%\Microsoft\MSBuild\v4.0\Microsoft.Cpp.Win32.user`.
For comparison, my file is reproduced below:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets">
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<LibraryPath>$(CRYPTOPP)\$(Platform)\Output\$(Configuration);$(BOOST)\lib\$(Platform);$(LibraryPath)</LibraryPath>
<IncludePath>$(CRYPTOPP);$(BOOST)\include\boost-$(BOOSTVER);$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup />
<ItemGroup />
</Project>
If you want to build x64 binaries as well, you'll want to edit or create the
file `%localappdata%\Microsoft\MSBuild\v4.0\Microsoft.Cpp.x64.user`. If you
followed the steps outlined earlier you can copy (or link) the win32 file to
the x64 one.
## Anti-Climatic End ##
After following the above instructions, you'll be able to build Debug Win32,
Debug x64, Release Win32, and Release x64 i2pd binaries.

Binary file not shown.

47
Win32/Resource.rc2 Normal file
View File

@@ -0,0 +1,47 @@
//
// Resource.RC2 - resources Microsoft Visual C++ does not edit directly
//
#ifdef APSTUDIO_INVOKED
#error this file is not editable by Microsoft Visual C++
#endif //APSTUDIO_INVOKED
#include "../version.h"
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION I2PD_VERSION_MAJOR,I2PD_VERSION_MINOR,I2PD_VERSION_MICRO,I2PD_VERSION_PATCH
PRODUCTVERSION I2P_VERSION_MAJOR,I2P_VERSION_MINOR,I2P_VERSION_MICRO,I2P_VERSION_PATCH
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Purple I2P"
VALUE "FileDescription", "C++ I2P daemon"
VALUE "FileVersion", I2PD_VERSION
VALUE "InternalName", CODENAME
VALUE "LegalCopyright", "Copyright (C) 2013-2015, The PurpleI2P Project"
VALUE "OriginalFilename", "i2pd"
VALUE "ProductName", "Purple I2P"
VALUE "ProductVersion", I2P_VERSION
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END

View File

@@ -76,7 +76,7 @@ I2PService::I2PService(PSTR pszServiceName,
BOOL fCanShutdown,
BOOL fCanPauseContinue)
{
m_name = (pszServiceName == NULL) ? "" : pszServiceName;
m_name = (pszServiceName == NULL) ? (PSTR)"" : pszServiceName;
m_statusHandle = NULL;
@@ -132,13 +132,13 @@ void I2PService::Start(DWORD dwArgc, PSTR *pszArgv)
}
catch (DWORD dwError)
{
LogPrint("Win32Service Start", dwError);
LogPrint(eLogError, "Win32Service Start", dwError);
SetServiceStatus(SERVICE_STOPPED, dwError);
}
catch (...)
{
LogPrint("Win32Service failed to start.", EVENTLOG_ERROR_TYPE);
LogPrint(eLogError, "Win32Service failed to start.", EVENTLOG_ERROR_TYPE);
SetServiceStatus(SERVICE_STOPPED);
}
@@ -147,7 +147,7 @@ void I2PService::Start(DWORD dwArgc, PSTR *pszArgv)
void I2PService::OnStart(DWORD dwArgc, PSTR *pszArgv)
{
LogPrint("Win32Service in OnStart",
LogPrint(eLogInfo, "Win32Service in OnStart",
EVENTLOG_INFORMATION_TYPE);
Daemon.start();
@@ -186,13 +186,13 @@ void I2PService::Stop()
}
catch (DWORD dwError)
{
LogPrint("Win32Service Stop", dwError);
LogPrint(eLogInfo, "Win32Service Stop", dwError);
SetServiceStatus(dwOriginalState);
}
catch (...)
{
LogPrint("Win32Service failed to stop.", EVENTLOG_ERROR_TYPE);
LogPrint(eLogError, "Win32Service failed to stop.", EVENTLOG_ERROR_TYPE);
SetServiceStatus(dwOriginalState);
}
@@ -202,7 +202,7 @@ void I2PService::Stop()
void I2PService::OnStop()
{
// Log a service stop message to the Application log.
LogPrint("Win32Service in OnStop", EVENTLOG_INFORMATION_TYPE);
LogPrint(eLogInfo, "Win32Service in OnStop", EVENTLOG_INFORMATION_TYPE);
Daemon.stop();
@@ -228,13 +228,13 @@ void I2PService::Pause()
}
catch (DWORD dwError)
{
LogPrint("Win32Service Pause", dwError);
LogPrint(eLogError, "Win32Service Pause", dwError);
SetServiceStatus(SERVICE_RUNNING);
}
catch (...)
{
LogPrint("Win32Service failed to pause.", EVENTLOG_ERROR_TYPE);
LogPrint(eLogError, "Win32Service failed to pause.", EVENTLOG_ERROR_TYPE);
SetServiceStatus(SERVICE_RUNNING);
}
@@ -258,13 +258,13 @@ void I2PService::Continue()
}
catch (DWORD dwError)
{
LogPrint("Win32Service Continue", dwError);
LogPrint(eLogError, "Win32Service Continue", dwError);
SetServiceStatus(SERVICE_PAUSED);
}
catch (...)
{
LogPrint("Win32Service failed to resume.", EVENTLOG_ERROR_TYPE);
LogPrint(eLogError, "Win32Service failed to resume.", EVENTLOG_ERROR_TYPE);
SetServiceStatus(SERVICE_PAUSED);
}
@@ -286,11 +286,11 @@ void I2PService::Shutdown()
}
catch (DWORD dwError)
{
LogPrint("Win32Service Shutdown", dwError);
LogPrint(eLogError, "Win32Service Shutdown", dwError);
}
catch (...)
{
LogPrint("Win32Service failed to shut down.", EVENTLOG_ERROR_TYPE);
LogPrint(eLogError, "Win32Service failed to shut down.", EVENTLOG_ERROR_TYPE);
}
}

BIN
Win32/ictoopie.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

6
Win32/winres.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef WINRES_H__
#define WINRES_H__
#include <winresrc.h>
#endif

21
api.cpp
View File

@@ -7,6 +7,7 @@
#include "RouterContext.h"
#include "Identity.h"
#include "Destination.h"
#include "Crypto.h"
#include "util.h"
#include "api.h"
@@ -18,32 +19,38 @@ namespace api
{
i2p::util::filesystem::SetAppName (appName);
i2p::util::config::OptionParser(argc, argv);
i2p::crypto::InitCrypto ();
i2p::context.Init ();
}
void TerminateI2P ()
{
i2p::crypto::TerminateCrypto ();
}
void StartI2P (std::ostream * logStream)
{
if (logStream)
StartLog (logStream);
else
StartLog (i2p::util::filesystem::GetFullPath (i2p::util::filesystem::GetAppName () + ".log"));
LogPrint(eLogInfo, "API: starting NetDB");
i2p::data::netdb.Start();
LogPrint("NetDB started");
LogPrint(eLogInfo, "API: starting Transports");
i2p::transport::transports.Start();
LogPrint("Transports started");
LogPrint(eLogInfo, "API: starting Tunnels");
i2p::tunnel::tunnels.Start();
LogPrint("Tunnels started");
}
void StopI2P ()
{
LogPrint("Shutdown started.");
LogPrint(eLogInfo, "API: shutting down");
LogPrint(eLogInfo, "API: stopping Tunnels");
i2p::tunnel::tunnels.Stop();
LogPrint("Tunnels stopped");
LogPrint(eLogInfo, "API: stopping Transports");
i2p::transport::transports.Stop();
LogPrint("Transports stopped");
LogPrint(eLogInfo, "API: stopping NetDB");
i2p::data::netdb.Stop();
LogPrint("NetDB stopped");
StopLog ();
}

1
api.h
View File

@@ -13,6 +13,7 @@ namespace api
{
// initialization start and stop
void InitI2P (int argc, char* argv[], const char * appName);
void TerminateI2P ();
void StartI2P (std::ostream * logStream = nullptr);
// write system log to logStream, if not specified to <appName>.log in application's folder
void StopI2P ();

197
appveyor.yml Normal file
View File

@@ -0,0 +1,197 @@
version: 1.0.{build}
pull_requests:
do_not_increment_build_number: true
branches:
only:
- openssl
skip_tags: true
os: Visual Studio 2015
shallow_clone: true
clone_depth: 1
init:
- cmd: >-
mkdir \projects\instdir
rem Appveyor has win32 openssl pre-installed that is picked up erroneously even for 64-bit. Cleaning the mess... Should happen before restoring cache.
rem Might consider passing OPENSSL_ROOT_DIR
if exist \OpenSSL-Win32 rmdir /S /Q \OpenSSL-Win32
if exist \OpenSSL-Win64 rmdir /S /Q \OpenSSL-Win64
if exist \OpenSSL rmdir /S /Q \OpenSSL
environment:
BOOST_ROOT: C:\Libraries\boost_1_59_0
MINIUPNPC: miniupnpc-1.9.20151026
OPENSSL: OpenSSL_1_0_2e
ZLIB: zlib-1.2.8
matrix:
# - type: static
# msvc: 14
# x64: 0
# - type: static
# variant: Release
# # FIXME why is this necessary with Appveyor???
# cmake: -DSSL_EAY=/mingw32/lib/libssl.a -DLIB_EAY=/mingw32/lib/libcrypto.a
- type: shared
variant: Release
- type: static
msvc: 12
x64: 1
variant: RelWithDebInfo
- type: static
msvc: 14
variant: RelWithDebInfo
cmake: -DWITH_PCH=ON
# - type: static
# msvc: 12
# - type: shared
# msvc: 14
# variant: Debug
# - type: shared
# variant: Release
# cmake: -DWITH_PCH=ON
# x64: 1
install:
- if not exist \projects\miniupnpc\ (
mkdir \projects\miniupnpc
&& curl -sL http://miniupnp.free.fr/files/download.php?file=%MINIUPNPC%.tar.gz -o \projects\miniupnpc\%MINIUPNPC%.tar.gz
)
- tar --strip-components=1 --directory=\projects\miniupnpc -xzf \projects\miniupnpc\%MINIUPNPC%.tar.gz
- if not exist \projects\zlib\ (
mkdir \projects\zlib
&& cd \projects\zlib
&& curl -sLO http://zlib.net/%ZLIB%.tar.gz
)
- tar --strip-components=1 --directory=\projects\zlib -xzf \projects\zlib\%ZLIB%.tar.gz
- patch -p0 C:/projects/zlib/CMakeLists.txt %APPVEYOR_BUILD_FOLDER%/build/cmake-zlib-static.patch
- patch -p0 C:/projects/zlib/CMakeLists.txt %APPVEYOR_BUILD_FOLDER%/build/cmake-zlib-amd64.patch
- if "%type%" == "static" (
set "static=ON"
&& set "boostlib=lib"
) else (
set "static=OFF"
&& set "dll=dll"
)
- if "%x64%"=="1" (
set "bitness=64"
&& set "openssl_target=VC-WIN64A"
&& set "zlib_asm=-DAMD64=ON"
) else (
set "bitness=32"
&& set "openssl_target=VC-WIN32"
&& set "zlib_asm=-DASM686=ON "-DCMAKE_ASM_MASM_FLAGS=/W0 /safeseh""
)
- C:\msys64\usr\bin\bash -lc "export PATH=/mingw%bitness%/bin:/usr/bin:. && cd /c/projects/miniupnpc && CC=gcc make -f Makefile.mingw init miniupnpc.dll > c:\projects\instdir\build_miniupnpc.log 2>&1 || cat c:\projects\instdir\build_miniupnpc.log"
- set /a generator=%msvc%+2001
- if defined msvc (
(
if "%x64%" == "1" (
call "C:\Program Files (x86)\Microsoft Visual Studio %msvc%.0\VC\vcvarsall.bat" amd64
&& set "generator=Visual Studio %msvc% %generator% Win64"
) else (
call "C:\Program Files (x86)\Microsoft Visual Studio %msvc%.0\VC\vcvarsall.bat" x86
&& set "generator=Visual Studio %msvc% %generator%"
)
)
&& set "zlib_root=C:/stage/zlib-Win%bitness%-vc%msvc%-%type%"
&& if "%variant%" neq "Debug" (
set "boost_variant=variant=release"
&& set "boostdbg=-gd"
)
) else (
set "generator=Unix Makefiles"
)
- if defined msvc if not exist %zlib_root% (
mkdir \projects\zlib-build
&& cd \projects\zlib-build
&& cmake ../zlib -G "%generator%" %zlib_asm% -DWITH_STATIC=%static% -DCMAKE_INSTALL_PREFIX=%zlib_root% > c:\projects\instdir\build_zlib.log
&& cmake --build . --config Release --target INSTALL >> c:\projects\instdir\build_zlib.log
|| type c:\projects\instdir\build_zlib.log
)
- cmd: >-
rem cinst nasm
cd \projects
if not exist nasm-2.11.08-installer.exe curl --silent --location --remote-name http://www.nasm.us/pub/nasm/releasebuilds/2.11.08/win32/nasm-2.11.08-installer.exe
nasm-2.11.08-installer.exe /S
set "PATH=%PATH%;C:\Program Files (x86)\nasm"
if not exist %OPENSSL%.zip curl --silent --location --remote-name https://github.com/openssl/openssl/archive/%OPENSSL%.zip
- cd %BOOST_ROOT%
- if defined msvc if not exist "stage%bitness%\lib\%boostlib%boost_system-vc%msvc%0-mt%boostdbg%*" (
bootstrap > c:\projects\instdir\build_boost.log
&& b2 toolset=msvc-%msvc%.0 %boost_variant% link=%type% runtime-link=%type% address-model=%bitness% --build-type=minimal --with-filesystem --with-program_options --with-regex --with-date_time --stagedir=stage%bitness% >> c:\projects\instdir\build_boost.log
|| type c:\projects\instdir\build_boost.log
)
- if defined msvc if not exist C:\stage\OpenSSL-Win%bitness%-vc%msvc%-%type%\ (
cd \projects
&& 7z x %OPENSSL%.zip > NUL
&& cd openssl-%OPENSSL%
&& perl Configure %openssl_target% no-rc2 no-rc4 no-rc5 no-idea no-bf no-cast no-whirlpool no-md2 no-md4 no-ripemd no-mdc2 no-camellia no-seed no-comp no-krb5 no-gmp no-rfc3779 no-ec2m no-ssl2 no-jpake no-srp no-sctp no-srtp --prefix=c:\stage\OpenSSL-Win%bitness%-vc%msvc%-%type% > c:\projects\instdir\build_openssl.log
&& ( if "%x64%" == "1" ( ms\do_win64a >> c:\projects\instdir\build_openssl.log ) else ( ms\do_nasm >> c:\projects\instdir\build_openssl.log ) )
&& nmake -f ms\nt%dll%.mak install >> c:\projects\instdir\build_openssl.log 2>&1
|| type c:\projects\instdir\build_openssl.log
)
- mklink /J \OpenSSL \stage\OpenSSL-Win%bitness%-vc%msvc%-%type%
- rem already there: mingw-w64-i686-openssl mingw-w64-i686-gcc cmake
- if not defined msvc (
C:\msys64\usr\bin\bash -lc "pacman --needed --noconfirm -Sy bash pacman pacman-mirrors msys2-runtime msys2-runtime-devel"
&& if "%x64%" == "1" (
C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-x86_64-boost mingw-w64-x86_64-miniupnpc"
) else (
C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-i686-boost mingw-w64-i686-miniupnpc"
)
)
cache:
- C:\projects\%OPENSSL%.zip
- C:\projects\nasm-2.11.08-installer.exe
- C:\projects\miniupnpc\%MINIUPNPC%.tar.gz
- C:\stage
- '%BOOST_ROOT%\stage32'
- '%BOOST_ROOT%\stage64'
- C:\projects\zlib\%ZLIB%.tar.gz
build_script:
- cmd: >-
mkdir \projects\build
rem FIXME use fixup_bundle in cmake
rem msbuild i2pd.sln /p:Configuration=Release
if defined variant ( set cmake_extra=-DCMAKE_BUILD_TYPE=%variant% && set "cmake_build=--config %variant%" )
echo "bitness=%bitness%; static=%static%; dll=%dll%; type=%type%; generator=%generator%; variant=%variant%; cmake=%cmake%; cmake_extra=%cmake_extra%"
- if not defined msvc (
C:\msys64\usr\bin\bash -lc "export PATH=/mingw%bitness%/bin:/usr/bin && cd /c/projects/build && cmake /c/projects/i2pd/build -G 'Unix Makefiles' -DWITH_AESNI=ON -DWITH_UPNP=ON %cmake% %cmake_extra% -DWITH_STATIC=%static% -DWITH_HARDENING=ON -DCMAKE_INSTALL_PREFIX:PATH=/c/projects/instdir -DCMAKE_FIND_ROOT_PATH=/mingw%bitness% && make install"
&& 7z a -tzip -mx9 -mmt C:\projects\i2pd\i2pd-mingw-win%bitness%-%type%.zip C:\projects\instdir\* C:\msys64\mingw%bitness%\bin\zlib1.dll C:\msys64\mingw%bitness%\bin\*eay32.dll
)
- rem We are fine with multiple generated configurations in MS solution. Will use later
- if defined msvc (
cd \projects\build
&& cmake ..\i2pd\build -G "%generator%" -DWITH_UPNP=ON %cmake% -DWITH_STATIC=%static% -DZLIB_ROOT=%zlib_root% -DBoost_LIBRARY_DIR:PATH=%BOOST_ROOT%/stage%bitness%/lib -DCMAKE_INSTALL_PREFIX:PATH=c:/projects/instdir
&& cmake --build . %cmake_build% --target install
&& 7z a -tzip -mx9 -mmt C:\projects\i2pd\i2pd-vc%msvc%-win%bitness%-%type%.zip C:\projects\instdir\*
&& cmake --build . %cmake_build% --target package
&& xcopy i2pd*win*.exe ..\i2pd\
)
test: off
artifacts:
- path: i2pd-vc12-win64-static.zip
- path: i2pd-vc12-win32-static.zip
- path: i2pd-vc12-win64-shared.zip
- path: i2pd-vc12-win32-shared.zip
- path: i2pd-vc14-win64-static.zip
- path: i2pd-vc14-win32-static.zip
- path: i2pd-vc14-win64-shared.zip
- path: i2pd-vc14-win32-shared.zip
- path: i2pd-mingw-win64-static.zip
- path: i2pd-mingw-win32-static.zip
- path: i2pd-mingw-win64-shared.zip
- path: i2pd-mingw-win32-shared.zip
- path: i2pd-2.1.0-win64.exe
- path: i2pd-2.1.0-win32.exe

View File

@@ -1,51 +0,0 @@
Build notes
===========
Common build/install process:
* git clone https://github.com/PrivacySolutions/i2pd.git
* cd i2pd/build
* cmake -DCMAKE_BUILD_TYPE=Release <more options> .
* make
* make install
Available cmake options:
* CMAKE_BUILD_TYPE -- build profile (Debug/Release)
* WITH_AESNI -- AES-NI support (ON/OFF)
* WITH_HARDENING -- enable hardening features (ON/OFF) (gcc only)
Debian
------
Required "-dev" packages:
* cmake
* libboost-filesystem-dev
* libboost-program-options-dev
* libboost-regex-dev
* libboost-system-dev
* libboost-date-time-dev
* libcrypto++-dev
FreeBSD
-------
Branch 9.X has gcc v4.2, that knows nothing about required c++11 standart.
Required ports:
* devel/cmake
* devel/boost-libs
* lang/gcc47 # or later version
* security/cryptopp
To use newer compiler you should set these variables:
export CC=/usr/local/bin/gcc47
export CXX=/usr/local/bin/g++47
Replace "47" with your actual gcc version
Branch 10.X has more reliable clang version, that can finally build i2pd,
but i still recommend to use gcc, otherwise you will fight it's bugs by
your own.

View File

@@ -1,4 +1,6 @@
cmake_minimum_required ( VERSION 2.8.12 )
# this addresses CMP0059 with CMake > 3.3 for PCH flags
cmake_policy( VERSION 2.8.12 )
project ( "i2pd" )
# configurale options
@@ -46,11 +48,19 @@ set (LIBI2PD_SRC
"${CMAKE_SOURCE_DIR}/api.cpp"
)
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR MSYS)
list (APPEND LIBI2PD_SRC "${CMAKE_SOURCE_DIR}/I2PEndian.cpp")
endif ()
add_library(libi2pd ${LIBI2PD_SRC})
set_target_properties(libi2pd PROPERTIES OUTPUT_NAME "i2pd")
install(TARGETS libi2pd
EXPORT libi2pd
ARCHIVE DESTINATION lib
COMPONENT Libraries)
# TODO Make libi2pd available to 3rd party projects via CMake as imported target
# FIXME This pulls stdafx
# install(EXPORT libi2pd DESTINATION ${CMAKE_INSTALL_LIBDIR})
set (CLIENT_SRC
"${CMAKE_SOURCE_DIR}/AddressBook.cpp"
@@ -75,7 +85,7 @@ set (DAEMON_SRC
if (WITH_UPNP)
add_definitions(-DUSE_UPNP)
if (NOT MSVC)
if (NOT MSVC AND NOT MSYS)
set(DL_LIB ${CMAKE_DL_LIBS})
endif ()
endif ()
@@ -88,7 +98,16 @@ endif ()
# compiler flags customization (by vendor)
if (MSVC)
add_definitions( -D_WIN32_WINNT=_WIN32_WINNT_WINXP -DWIN32_LEAN_AND_MEAN -DNOMINMAX ) #-DOPENSSL_NO_SSL2 -DOPENSSL_USE_DEPRECATED
# TODO Check & report to Boost dev, there should be no need for these two
add_definitions( -DBOOST_THREAD_NO_LIB -DBOOST_CHRONO_NO_LIB )
set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL" )
set( CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /INCREMENTAL:NO /LTCG" )
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} /GL" )
set( CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /INCREMENTAL:NO /LTCG" )
else()
if (MSYS OR MINGW)
add_definitions( -DWIN32_LEAN_AND_MEAN )
endif ()
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Winvalid-pch" )
set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -pedantic" )
# TODO: The following is incompatible with static build and enabled hardening for OpenWRT.
@@ -102,14 +121,15 @@ include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" CXX11_SUPPORTED)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" CXX0X_SUPPORTED)
if (CXX11_SUPPORTED)
add_definitions( "-std=c++11" )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" )
elseif (CXX0X_SUPPORTED) # gcc 4.6
add_definitions( "-std=c++0x" )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x" )
elseif (NOT MSVC)
message(SEND_ERROR "C++11 standart not seems to be supported by compiler. Too old version?")
endif ()
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pipe")
if (WITH_HARDENING)
add_definitions( "-D_FORTIFY_SOURCE=2" )
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat -Wformat-security -Werror=format-security" )
@@ -119,6 +139,11 @@ elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
# more tweaks
endif ()
if (WITH_HARDENING AND MSVC)
# Most security options like dynamic base, buffer & stack checks are ON by default
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /guard:cf" )
endif ()
# compiler flags customization (by system)
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/DaemonLinux.cpp")
@@ -130,13 +155,17 @@ elseif (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
add_definitions( "-D_GLIBCXX_USE_NANOSLEEP=1" )
elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/DaemonLinux.cpp")
elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows")
elseif (CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/DaemonLinux.cpp")
elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR MSYS)
list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/DaemonWin32.cpp")
list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/Win32/Win32Service.cpp")
list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/Win32/Resource.rc")
endif ()
if (WITH_AESNI)
add_definitions ( "-maes -DAESNI" )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes" )
add_definitions ( -DAESNI )
endif()
# libraries
@@ -151,9 +180,8 @@ endif()
if (WITH_STATIC)
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_STATIC_RUNTIME ON)
if (WIN32)
if (WIN32 AND NOT MSYS AND NOT MINGW)
# http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace
# Note that you might need to rebuild Crypto++
foreach(flag_var
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
@@ -171,43 +199,44 @@ if (WITH_STATIC)
set( CMAKE_THREAD_LIBS_INIT "gcc_eh -Wl,-u,pthread_create,-u,pthread_once,-u,pthread_mutex_lock,-u,pthread_mutex_unlock,-u,pthread_join,-u,pthread_equal,-u,pthread_detach,-u,pthread_cond_wait,-u,pthread_cond_signal,-u,pthread_cond_destroy,-u,pthread_cond_broadcast,-u,pthread_cancel" )
endif ()
else()
if (NOT WIN32)
if (NOT WIN32 AND NOT MSYS)
# TODO: Consider separate compilation for LIBI2PD_SRC for library.
# No need in -fPIC overhead for binary if not interested in library
# HINT: revert c266cff CMakeLists.txt: compilation speed up
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC" )
endif ()
add_definitions(-DBOOST_ALL_DYN_LINK)
add_definitions(-DBOOST_SYSTEM_DYN_LINK -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_PROGRAM_OPTIONS_DYN_LINK -DBOOST_DATE_TIME_DYN_LINK -DBOOST_REGEX_DYN_LINK)
endif ()
if (WITH_PCH)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
include_directories(${CMAKE_BINARY_DIR})
add_library(stdafx STATIC "${CMAKE_SOURCE_DIR}/stdafx.cpp")
if(MSVC)
target_compile_options(stdafx PRIVATE /Ycstdafx.h /Zm135)
target_compile_options(stdafx PRIVATE /Ycstdafx.h /Zm155)
add_custom_command(TARGET stdafx POST_BUILD
COMMAND xcopy /y stdafx.dir\\$<CONFIG>\\*.pdb libi2pd.dir\\$<CONFIG>\\
COMMAND xcopy /y stdafx.dir\\$<CONFIG>\\*.pdb i2pdclient.dir\\$<CONFIG>\\
COMMAND xcopy /y stdafx.dir\\$<CONFIG>\\*.pdb i2pd.dir\\$<CONFIG>\\
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
target_compile_options(libi2pd PRIVATE /FIstdafx.h /Yustdafx.h /Zm135 "/Fp${CMAKE_BINARY_DIR}/stdafx.dir/$<CONFIG>/stdafx.pch")
target_compile_options(i2pdclient PRIVATE /FIstdafx.h /Yustdafx.h /Zm135 "/Fp${CMAKE_BINARY_DIR}/stdafx.dir/$<CONFIG>/stdafx.pch")
target_compile_options(libi2pd PRIVATE /FIstdafx.h /Yustdafx.h /Zm155 "/Fp${CMAKE_BINARY_DIR}/stdafx.dir/$<CONFIG>/stdafx.pch")
target_compile_options(i2pdclient PRIVATE /FIstdafx.h /Yustdafx.h /Zm155 "/Fp${CMAKE_BINARY_DIR}/stdafx.dir/$<CONFIG>/stdafx.pch")
else()
string(TOUPPER ${CMAKE_BUILD_TYPE} BTU)
get_directory_property(DEFS DEFINITIONS)
string(REPLACE " " ";" FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${BTU}} ${DEFS}")
add_custom_command(TARGET stdafx PRE_BUILD
COMMAND ${CMAKE_CXX_COMPILER} ${FLAGS} -c ${CMAKE_CURRENT_SOURCE_DIR}/../stdafx.h
COMMAND ${CMAKE_CXX_COMPILER} ${FLAGS} -c ${CMAKE_CURRENT_SOURCE_DIR}/../stdafx.h -o ${CMAKE_BINARY_DIR}/stdafx.h.gch
)
target_compile_options(libi2pd PRIVATE -include stdafx.h)
target_compile_options(i2pdclient PRIVATE -include stdafx.h)
endif()
target_link_libraries(libi2pd stdafx)
target_link_libraries(i2pdclient stdafx)
endif()
find_package ( Boost COMPONENTS system filesystem regex program_options date_time thread chrono REQUIRED )
target_link_libraries(i2pdclient libi2pd)
find_package ( Boost COMPONENTS system filesystem regex program_options date_time REQUIRED )
if(NOT DEFINED Boost_INCLUDE_DIRS)
message(SEND_ERROR "Boost is not found, or your boost version was bellow 1.46. Please download Boost!")
endif()
@@ -227,11 +256,21 @@ endif()
find_package ( ZLIB )
if (NOT ZLIB_FOUND )
# We are probably on Windows
find_program( PATCH patch C:/Program Files/Git/usr/bin C:/msys64/usr/bin C:/msys32/usr/bin C:/Strawberry/c/bin )
include( ExternalProject )
if( CMAKE_SIZEOF_VOID_P EQUAL 8 )
set( ZLIB_EXTRA -DAMD64=ON )
else()
set( ZLIB_EXTRA -DASM686=ON "-DCMAKE_ASM_MASM_FLAGS=/W0 /safeseh" )
endif()
ExternalProject_Add(zlib-project
URL http://zlib.net/zlib-1.2.8.tar.gz
URL_MD5 44d667c142d7cda120332623eab69f40
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/zlib
PATCH_COMMAND "${PATCH}" -p0 < ${CMAKE_CURRENT_SOURCE_DIR}/cmake-zlib-static.patch
&& "${PATCH}" -p0 < ${CMAKE_CURRENT_SOURCE_DIR}/cmake-zlib-amd64.patch
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
-DWITH_STATIC=${WITH_STATIC} ${ZLIB_EXTRA}
)
if (WITH_PCH)
add_dependencies( stdafx zlib-project )
@@ -240,9 +279,14 @@ if (NOT ZLIB_FOUND )
endif ()
# ExternalProject_Get_Property(zlib-project install_dir)
set ( ZLIB_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/zlib/include" CACHE FILEPATH "zlib include dir" FORCE)
set ( ZLIB_LIBRARY debug zlibd optimized zlib CACHE STRING "zlib libraries" FORCE)
if (NOT WITH_STATIC)
set ( ZLIB_LIBRARY debug zlibd optimized zlib CACHE STRING "zlib libraries" FORCE)
endif ()
endif ()
link_directories("${CMAKE_CURRENT_BINARY_DIR}/zlib/lib")
if (WITH_STATIC AND (MSVC OR MSYS))
set ( ZLIB_LIBRARY debug zlibstaticd optimized zlibstatic CACHE STRING "zlib libraries" FORCE)
endif ()
link_directories(${CMAKE_CURRENT_BINARY_DIR}/zlib/lib ${ZLIB_ROOT}/lib)
# load includes
include_directories( ${Boost_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} )
@@ -277,13 +321,13 @@ if (WITH_BINARY)
if (WITH_PCH)
if (MSVC)
target_compile_options("${PROJECT_NAME}" PRIVATE /FIstdafx.h /Yustdafx.h /Zm135 "/Fp${CMAKE_BINARY_DIR}/stdafx.dir/$<CONFIG>/stdafx.pch")
target_compile_options("${PROJECT_NAME}" PRIVATE /FIstdafx.h /Yustdafx.h /Zm155 "/Fp${CMAKE_BINARY_DIR}/stdafx.dir/$<CONFIG>/stdafx.pch")
else()
target_compile_options("${PROJECT_NAME}" PRIVATE -include stdafx.h)
endif()
endif()
if (WITH_HARDENING AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if (WITH_HARDENING AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT MSYS AND NOT MINGW)
set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-z relro -z now" )
endif ()
@@ -292,10 +336,125 @@ if (WITH_BINARY)
if(${LAST_Boost_LIBRARIES} MATCHES ".*pthread.*")
list(REMOVE_AT Boost_LIBRARIES -1)
endif()
target_link_libraries( "${PROJECT_NAME}" libi2pd i2pdclient ${DL_LIB} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} )
install(TARGETS "${PROJECT_NAME}" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} )
if (MSYS OR MINGW)
set (MINGW_EXTRA -lws2_32 -lmswsock -liphlpapi )
endif ()
target_link_libraries( "${PROJECT_NAME}" libi2pd i2pdclient ${DL_LIB} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${MINGW_EXTRA} )
install(TARGETS "${PROJECT_NAME}" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime)
set (APPS "\${CMAKE_INSTALL_PREFIX}/bin/${PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX}")
set (DIRS "${Boost_LIBRARY_DIR};${OPENSSL_INCLUDE_DIR}/../bin;${ZLIB_INCLUDE_DIR}/../bin;/mingw32/bin")
if (MSVC)
install(FILES $<TARGET_PDB_FILE:${PROJECT_NAME}> DESTINATION "bin" CONFIGURATIONS DEBUG)
install(FILES $<TARGET_PDB_FILE:${PROJECT_NAME}> DESTINATION ${CMAKE_INSTALL_BINDIR} CONFIGURATIONS DEBUG RELWITHDEBINFO COMPONENT Symbols)
# TODO Somehow this picks lots of unrelevant stuff with MSYS. OS X testing needed.
INSTALL(CODE "
include(BundleUtilities)
fixup_bundle(\"${APPS}\" \"\" \"${DIRS}\")
" COMPONENT Runtime)
endif ()
endif ()
install(FILES ../LICENSE
DESTINATION .
COMPONENT Runtime
)
# Take a copy on Appveyor
install(FILES "C:/projects/openssl-$ENV{OPENSSL}/LICENSE"
DESTINATION .
COMPONENT Runtime
RENAME LICENSE_OPENSSL
OPTIONAL # for local builds only!
)
file(GLOB_RECURSE I2PD_SOURCES "../*.cpp" "../build" "../Win32" "../Makefile*")
install(FILES ${I2PD_SOURCES} DESTINATION src/ COMPONENT Source)
# install(DIRECTORY ../ DESTINATION src/
# # OPTIONAL
# COMPONENT Source FILES_MATCHING
# PATTERN .git EXCLUDE
# PATTERN "*.cpp"
# )
file(GLOB I2PD_HEADERS "../*.h")
install(FILES ${I2PD_HEADERS} DESTINATION src/ COMPONENT Headers)
# install(DIRECTORY ../ DESTINATION src/
# # OPTIONAL
# COMPONENT Headers FILES_MATCHING
# PATTERN .git EXCLUDE
# PATTERN "*.h"
# )
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Purple I2P, a C++ I2P daemon")
set(CPACK_PACKAGE_VENDOR "Purple I2P")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/../README.md")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/../LICENSE")
file(READ ../version.h version_h)
string(REGEX REPLACE ".*I2PD_VERSION_MAJOR ([0-9]+).*" "\\1" CPACK_PACKAGE_VERSION_MAJOR "${version_h}")
string(REGEX REPLACE ".*I2PD_VERSION_MINOR ([0-9]+).*" "\\1" CPACK_PACKAGE_VERSION_MINOR "${version_h}")
string(REGEX REPLACE ".*I2PD_VERSION_MICRO ([0-9]+).*" "\\1" CPACK_PACKAGE_VERSION_MICRO "${version_h}")
string(REGEX REPLACE ".*I2PD_VERSION_PATCH ([0-9]+).*" "\\1" CPACK_PACKAGE_VERSION_PATCH "${version_h}")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "Purple I2P")# ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}")
include(CPackComponent)
cpack_add_component(Runtime
DESCRIPTION "Main files"
REQUIRED INSTALL_TYPES minimal)
cpack_add_component(Symbols
DISPLAY_NAME "Debug symbols"
DESCRIPTION "Debug symbols for use with WinDbg or Visual Studio"
INSTALL_TYPES recommended full
)
cpack_add_component(Libraries
DESCRIPTION "Binary libraries for development"
INSTALL_TYPES full dev3rd
)
cpack_add_component(Source
DISPLAY_NAME "Source code"
DESCRIPTION "I2pd source code"
INSTALL_TYPES full
)
cpack_add_component(Headers
DISPLAY_NAME "Header files"
DESCRIPTION "I2pd header files for development"
INSTALL_TYPES full dev3rd
)
install(FILES ${MINIUPNPC_INCLUDE_DIR}/miniupnpc/miniupnpc.dll
DESTINATION bin
COMPONENT MiniUPnPc
OPTIONAL
)
install(FILES ${MINIUPNPC_INCLUDE_DIR}/miniupnpc/LICENSE
DESTINATION .
COMPONENT MiniUPnPc
RENAME LICENSE_MINIUPNPC
OPTIONAL
)
cpack_add_component(MiniUPnPc
INSTALL_TYPES full recommended
# DOWNLOADED
# ARCHIVE_FILE miniupnpc-win32.zip
)
cpack_add_install_type(recommended DISPLAY_NAME Recommended)
cpack_add_install_type(dev3rd DISPLAY_NAME "Third party development")
cpack_add_install_type(full DISPLAY_NAME Full)
cpack_add_install_type(minimal DISPLAY_NAME Minimal)
if((WIN32 OR MSYS) AND NOT UNIX)
# There is a bug in NSI that does not handle full unix paths properly. Make
# sure there is at least one set of four (4) backlasshes.
set(CPACK_NSIS_DEFINES "RequestExecutionLevel user")
set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/../Win32\\\\ictoopie.bmp")
set(CPACK_NSIS_INSTALLED_ICON_NAME "bin/i2pd.exe")
SET(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_DESCRIPTION_SUMMARY}")
set(CPACK_NSIS_HELP_LINK "https:\\\\\\\\github.com\\\\PurpleI2P\\\\i2pd\\\\issues")
set(CPACK_NSIS_URL_INFO_ABOUT "https:\\\\\\\\github.com\\\\PurpleI2P\\\\i2pd")
set(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Install i2pd as windows service.lnk' '$INSTDIR\\\\bin\\\\i2pd.exe' '--service=install'
CreateShortCut '$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Remove i2pd windows service.lnk' '$INSTDIR\\\\bin\\\\i2pd.exe' '--service=remove'")
set(CPACK_NSIS_DELETE_ICONS_EXTRA "Delete '$SMPROGRAMS\\\\$START_MENU\\\\Install i2pd as windows service.lnk'
Delete '$SMPROGRAMS\\\\$START_MENU\\\\Remove i2pd windows service.lnk'")
else()
set(CPACK_STRIP_FILES "bin/i2pd")
set(CPACK_SOURCE_STRIP_FILES "")
endif()
set(CPACK_PACKAGE_EXECUTABLES "i2pd" "C++ I2P daemon")
set(CPACK_SOURCE_GENERATOR "TGZ")
include(CPack)

View File

@@ -1,12 +1,11 @@
FROM ubuntu
RUN apt-get update && apt-get install -y libboost-dev libboost-filesystem-dev \
libboost-program-options-dev libboost-regex-dev libcrypto++-dev \
libboost-date-time-dev git build-essential
libboost-program-options-dev libboost-regex-dev libboost-date-time-dev \
libssl-dev git build-essential
RUN git clone https://github.com/PurpleI2P/i2pd.git
WORKDIR /i2pd
RUN make
CMD ./i2p
CMD ./i2pd

View File

@@ -0,0 +1,10 @@
--- CMakeLists.txt.orig 2015-12-07 14:19:36.447689600 -0600
+++ CMakeLists.txt 2015-12-07 14:18:23.004419900 -0600
@@ -165,6 +165,7 @@
ENABLE_LANGUAGE(ASM_MASM)
set(ZLIB_ASMS
contrib/masmx64/gvmat64.asm
+ contrib/masmx64/inffas8664.c
contrib/masmx64/inffasx64.asm
)
endif()

View File

@@ -0,0 +1,28 @@
--- CMakeLists.txt.orig 2013-04-28 17:57:10.000000000 -0500
+++ CMakeLists.txt 2015-12-03 12:53:52.371087900 -0600
@@ -7,6 +7,7 @@
option(ASM686 "Enable building i686 assembly implementation")
option(AMD64 "Enable building amd64 assembly implementation")
+option(WITH_STATIC "Static runtime on Windows" OFF)
set(INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables")
set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation directory for libraries")
@@ -66,6 +67,17 @@
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
endif()
+if(WITH_STATIC AND (MSVC OR MSYS))
+ # http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace
+ foreach(flag_var
+ CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
+ CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
+ if(${flag_var} MATCHES "/MD")
+ string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
+ endif(${flag_var} MATCHES "/MD")
+ endforeach(flag_var)
+endif()
+
if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
# If we're doing an out of source build and the user has a zconf.h
# in their source tree...

View File

@@ -1,61 +0,0 @@
# - Find Crypto++
if(CRYPTO++_INCLUDE_DIR AND CRYPTO++_LIBRARIES)
set(CRYPTO++_FOUND TRUE)
else(CRYPTO++_INCLUDE_DIR AND CRYPTO++_LIBRARIES)
find_path(CRYPTO++_INCLUDE_DIR cryptopp/cryptlib.h
/usr/include
/usr/local/include
$ENV{SystemDrive}/Crypto++/include
$ENV{CRYPTOPP}
$ENV{CRYPTOPP}/..
$ENV{CRYPTOPP}/include
${PROJECT_SOURCE_DIR}/../..
)
find_library(CRYPTO++_LIBRARIES NAMES cryptopp
PATHS
/usr/lib
/usr/local/lib
/opt/local/lib
$ENV{SystemDrive}/Crypto++/lib
$ENV{CRYPTOPP}/lib
)
if(MSVC AND NOT CRYPTO++_LIBRARIES) # Give a chance for MSVC multiconfig
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(PLATFORM x64)
else()
set(PLATFORM Win32)
endif()
find_library(CRYPTO++_LIBRARIES_RELEASE NAMES cryptlib cryptopp
HINTS
${PROJECT_SOURCE_DIR}/../../cryptopp/${PLATFORM}/Output/Release
PATHS
$ENV{CRYPTOPP}/Win32/Output/Release
)
find_library(CRYPTO++_LIBRARIES_DEBUG NAMES cryptlib cryptopp
HINTS
${PROJECT_SOURCE_DIR}/../../cryptopp/${PLATFORM}/Output/Debug
PATHS
$ENV{CRYPTOPP}/Win32/Output/Debug
)
set(CRYPTO++_LIBRARIES
debug ${CRYPTO++_LIBRARIES_DEBUG}
optimized ${CRYPTO++_LIBRARIES_RELEASE}
CACHE PATH "Path to Crypto++ library" FORCE
)
endif()
if(CRYPTO++_INCLUDE_DIR AND CRYPTO++_LIBRARIES)
set(CRYPTO++_FOUND TRUE)
message(STATUS "Found Crypto++: ${CRYPTO++_INCLUDE_DIR}, ${CRYPTO++_LIBRARIES}")
else(CRYPTO++_INCLUDE_DIR AND CRYPTO++_LIBRARIES)
set(CRYPTO++_FOUND FALSE)
message(STATUS "Crypto++ not found.")
endif(CRYPTO++_INCLUDE_DIR AND CRYPTO++_LIBRARIES)
mark_as_advanced(CRYPTO++_INCLUDE_DIR CRYPTO++_LIBRARIES)
endif(CRYPTO++_INCLUDE_DIR AND CRYPTO++_LIBRARIES)

View File

@@ -0,0 +1,978 @@
; CPack install script designed for a nmake build
;--------------------------------
; You must define these values
!define VERSION "@CPACK_PACKAGE_VERSION@"
!define PATCH "@CPACK_PACKAGE_VERSION_PATCH@"
!define INST_DIR "@CPACK_TEMPORARY_DIRECTORY@"
;--------------------------------
;Variables
Var MUI_TEMP
Var STARTMENU_FOLDER
Var SV_ALLUSERS
Var START_MENU
Var DO_NOT_ADD_TO_PATH
Var ADD_TO_PATH_ALL_USERS
Var ADD_TO_PATH_CURRENT_USER
Var INSTALL_DESKTOP
Var IS_DEFAULT_INSTALLDIR
;--------------------------------
;Include Modern UI
!include "MUI.nsh"
;Default installation folder
InstallDir "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@"
;--------------------------------
;General
;Name and file
Name "@CPACK_NSIS_PACKAGE_NAME@"
OutFile "@CPACK_TOPLEVEL_DIRECTORY@/@CPACK_OUTPUT_FILE_NAME@"
;Set compression
SetCompressor @CPACK_NSIS_COMPRESSOR@
;Require administrator access
RequestExecutionLevel admin
@CPACK_NSIS_DEFINES@
!include Sections.nsh
;--- Component support macros: ---
; The code for the add/remove functionality is from:
; http://nsis.sourceforge.net/Add/Remove_Functionality
; It has been modified slightly and extended to provide
; inter-component dependencies.
Var AR_SecFlags
Var AR_RegFlags
@CPACK_NSIS_SECTION_SELECTED_VARS@
; Loads the "selected" flag for the section named SecName into the
; variable VarName.
!macro LoadSectionSelectedIntoVar SecName VarName
SectionGetFlags ${${SecName}} $${VarName}
IntOp $${VarName} $${VarName} & ${SF_SELECTED} ;Turn off all other bits
!macroend
; Loads the value of a variable... can we get around this?
!macro LoadVar VarName
IntOp $R0 0 + $${VarName}
!macroend
; Sets the value of a variable
!macro StoreVar VarName IntValue
IntOp $${VarName} 0 + ${IntValue}
!macroend
!macro InitSection SecName
; This macro reads component installed flag from the registry and
;changes checked state of the section on the components page.
;Input: section index constant name specified in Section command.
ClearErrors
;Reading component status from registry
ReadRegDWORD $AR_RegFlags HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" "Installed"
IfErrors "default_${SecName}"
;Status will stay default if registry value not found
;(component was never installed)
IntOp $AR_RegFlags $AR_RegFlags & ${SF_SELECTED} ;Turn off all other bits
SectionGetFlags ${${SecName}} $AR_SecFlags ;Reading default section flags
IntOp $AR_SecFlags $AR_SecFlags & 0xFFFE ;Turn lowest (enabled) bit off
IntOp $AR_SecFlags $AR_RegFlags | $AR_SecFlags ;Change lowest bit
; Note whether this component was installed before
!insertmacro StoreVar ${SecName}_was_installed $AR_RegFlags
IntOp $R0 $AR_RegFlags & $AR_RegFlags
;Writing modified flags
SectionSetFlags ${${SecName}} $AR_SecFlags
"default_${SecName}:"
!insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected
!macroend
!macro FinishSection SecName
; This macro reads section flag set by user and removes the section
;if it is not selected.
;Then it writes component installed flag to registry
;Input: section index constant name specified in Section command.
SectionGetFlags ${${SecName}} $AR_SecFlags ;Reading section flags
;Checking lowest bit:
IntOp $AR_SecFlags $AR_SecFlags & ${SF_SELECTED}
IntCmp $AR_SecFlags 1 "leave_${SecName}"
;Section is not selected:
;Calling Section uninstall macro and writing zero installed flag
!insertmacro "Remove_${${SecName}}"
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \
"Installed" 0
Goto "exit_${SecName}"
"leave_${SecName}:"
;Section is selected:
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \
"Installed" 1
"exit_${SecName}:"
!macroend
!macro RemoveSection_CPack SecName
; This macro is used to call section's Remove_... macro
;from the uninstaller.
;Input: section index constant name specified in Section command.
!insertmacro "Remove_${${SecName}}"
!macroend
; Determine whether the selection of SecName changed
!macro MaybeSelectionChanged SecName
!insertmacro LoadVar ${SecName}_selected
SectionGetFlags ${${SecName}} $R1
IntOp $R1 $R1 & ${SF_SELECTED} ;Turn off all other bits
; See if the status has changed:
IntCmp $R0 $R1 "${SecName}_unchanged"
!insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected
IntCmp $R1 ${SF_SELECTED} "${SecName}_was_selected"
!insertmacro "Deselect_required_by_${SecName}"
goto "${SecName}_unchanged"
"${SecName}_was_selected:"
!insertmacro "Select_${SecName}_depends"
"${SecName}_unchanged:"
!macroend
;--- End of Add/Remove macros ---
;--------------------------------
;Interface Settings
!define MUI_HEADERIMAGE
!define MUI_ABORTWARNING
;--------------------------------
; path functions
!verbose 3
!include "WinMessages.NSH"
!verbose 4
;----------------------------------------
; based upon a script of "Written by KiCHiK 2003-01-18 05:57:02"
;----------------------------------------
!verbose 3
!include "WinMessages.NSH"
!verbose 4
;====================================================
; get_NT_environment
; Returns: the selected environment
; Output : head of the stack
;====================================================
!macro select_NT_profile UN
Function ${UN}select_NT_profile
StrCmp $ADD_TO_PATH_ALL_USERS "1" 0 environment_single
DetailPrint "Selected environment for all users"
Push "all"
Return
environment_single:
DetailPrint "Selected environment for current user only."
Push "current"
Return
FunctionEnd
!macroend
!insertmacro select_NT_profile ""
!insertmacro select_NT_profile "un."
;----------------------------------------------------
!define NT_current_env 'HKCU "Environment"'
!define NT_all_env 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
!ifndef WriteEnvStr_RegKey
!ifdef ALL_USERS
!define WriteEnvStr_RegKey \
'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
!else
!define WriteEnvStr_RegKey 'HKCU "Environment"'
!endif
!endif
; AddToPath - Adds the given dir to the search path.
; Input - head of the stack
; Note - Win9x systems requires reboot
Function AddToPath
Exch $0
Push $1
Push $2
Push $3
# don't add if the path doesn't exist
IfFileExists "$0\*.*" "" AddToPath_done
ReadEnvStr $1 PATH
; if the path is too long for a NSIS variable NSIS will return a 0
; length string. If we find that, then warn and skip any path
; modification as it will trash the existing path.
StrLen $2 $1
IntCmp $2 0 CheckPathLength_ShowPathWarning CheckPathLength_Done CheckPathLength_Done
CheckPathLength_ShowPathWarning:
Messagebox MB_OK|MB_ICONEXCLAMATION "Warning! PATH too long installer unable to modify PATH!"
Goto AddToPath_done
CheckPathLength_Done:
Push "$1;"
Push "$0;"
Call StrStr
Pop $2
StrCmp $2 "" "" AddToPath_done
Push "$1;"
Push "$0\;"
Call StrStr
Pop $2
StrCmp $2 "" "" AddToPath_done
GetFullPathName /SHORT $3 $0
Push "$1;"
Push "$3;"
Call StrStr
Pop $2
StrCmp $2 "" "" AddToPath_done
Push "$1;"
Push "$3\;"
Call StrStr
Pop $2
StrCmp $2 "" "" AddToPath_done
Call IsNT
Pop $1
StrCmp $1 1 AddToPath_NT
; Not on NT
StrCpy $1 $WINDIR 2
FileOpen $1 "$1\autoexec.bat" a
FileSeek $1 -1 END
FileReadByte $1 $2
IntCmp $2 26 0 +2 +2 # DOS EOF
FileSeek $1 -1 END # write over EOF
FileWrite $1 "$\r$\nSET PATH=%PATH%;$3$\r$\n"
FileClose $1
SetRebootFlag true
Goto AddToPath_done
AddToPath_NT:
StrCmp $ADD_TO_PATH_ALL_USERS "1" ReadAllKey
ReadRegStr $1 ${NT_current_env} "PATH"
Goto DoTrim
ReadAllKey:
ReadRegStr $1 ${NT_all_env} "PATH"
DoTrim:
StrCmp $1 "" AddToPath_NTdoIt
Push $1
Call Trim
Pop $1
StrCpy $0 "$1;$0"
AddToPath_NTdoIt:
StrCmp $ADD_TO_PATH_ALL_USERS "1" WriteAllKey
WriteRegExpandStr ${NT_current_env} "PATH" $0
Goto DoSend
WriteAllKey:
WriteRegExpandStr ${NT_all_env} "PATH" $0
DoSend:
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
AddToPath_done:
Pop $3
Pop $2
Pop $1
Pop $0
FunctionEnd
; RemoveFromPath - Remove a given dir from the path
; Input: head of the stack
Function un.RemoveFromPath
Exch $0
Push $1
Push $2
Push $3
Push $4
Push $5
Push $6
IntFmt $6 "%c" 26 # DOS EOF
Call un.IsNT
Pop $1
StrCmp $1 1 unRemoveFromPath_NT
; Not on NT
StrCpy $1 $WINDIR 2
FileOpen $1 "$1\autoexec.bat" r
GetTempFileName $4
FileOpen $2 $4 w
GetFullPathName /SHORT $0 $0
StrCpy $0 "SET PATH=%PATH%;$0"
Goto unRemoveFromPath_dosLoop
unRemoveFromPath_dosLoop:
FileRead $1 $3
StrCpy $5 $3 1 -1 # read last char
StrCmp $5 $6 0 +2 # if DOS EOF
StrCpy $3 $3 -1 # remove DOS EOF so we can compare
StrCmp $3 "$0$\r$\n" unRemoveFromPath_dosLoopRemoveLine
StrCmp $3 "$0$\n" unRemoveFromPath_dosLoopRemoveLine
StrCmp $3 "$0" unRemoveFromPath_dosLoopRemoveLine
StrCmp $3 "" unRemoveFromPath_dosLoopEnd
FileWrite $2 $3
Goto unRemoveFromPath_dosLoop
unRemoveFromPath_dosLoopRemoveLine:
SetRebootFlag true
Goto unRemoveFromPath_dosLoop
unRemoveFromPath_dosLoopEnd:
FileClose $2
FileClose $1
StrCpy $1 $WINDIR 2
Delete "$1\autoexec.bat"
CopyFiles /SILENT $4 "$1\autoexec.bat"
Delete $4
Goto unRemoveFromPath_done
unRemoveFromPath_NT:
StrCmp $ADD_TO_PATH_ALL_USERS "1" unReadAllKey
ReadRegStr $1 ${NT_current_env} "PATH"
Goto unDoTrim
unReadAllKey:
ReadRegStr $1 ${NT_all_env} "PATH"
unDoTrim:
StrCpy $5 $1 1 -1 # copy last char
StrCmp $5 ";" +2 # if last char != ;
StrCpy $1 "$1;" # append ;
Push $1
Push "$0;"
Call un.StrStr ; Find `$0;` in $1
Pop $2 ; pos of our dir
StrCmp $2 "" unRemoveFromPath_done
; else, it is in path
# $0 - path to add
# $1 - path var
StrLen $3 "$0;"
StrLen $4 $2
StrCpy $5 $1 -$4 # $5 is now the part before the path to remove
StrCpy $6 $2 "" $3 # $6 is now the part after the path to remove
StrCpy $3 $5$6
StrCpy $5 $3 1 -1 # copy last char
StrCmp $5 ";" 0 +2 # if last char == ;
StrCpy $3 $3 -1 # remove last char
StrCmp $ADD_TO_PATH_ALL_USERS "1" unWriteAllKey
WriteRegExpandStr ${NT_current_env} "PATH" $3
Goto unDoSend
unWriteAllKey:
WriteRegExpandStr ${NT_all_env} "PATH" $3
unDoSend:
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
unRemoveFromPath_done:
Pop $6
Pop $5
Pop $4
Pop $3
Pop $2
Pop $1
Pop $0
FunctionEnd
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Uninstall sutff
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
###########################################
# Utility Functions #
###########################################
;====================================================
; IsNT - Returns 1 if the current system is NT, 0
; otherwise.
; Output: head of the stack
;====================================================
; IsNT
; no input
; output, top of the stack = 1 if NT or 0 if not
;
; Usage:
; Call IsNT
; Pop $R0
; ($R0 at this point is 1 or 0)
!macro IsNT un
Function ${un}IsNT
Push $0
ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion
StrCmp $0 "" 0 IsNT_yes
; we are not NT.
Pop $0
Push 0
Return
IsNT_yes:
; NT!!!
Pop $0
Push 1
FunctionEnd
!macroend
!insertmacro IsNT ""
!insertmacro IsNT "un."
; StrStr
; input, top of stack = string to search for
; top of stack-1 = string to search in
; output, top of stack (replaces with the portion of the string remaining)
; modifies no other variables.
;
; Usage:
; Push "this is a long ass string"
; Push "ass"
; Call StrStr
; Pop $R0
; ($R0 at this point is "ass string")
!macro StrStr un
Function ${un}StrStr
Exch $R1 ; st=haystack,old$R1, $R1=needle
Exch ; st=old$R1,haystack
Exch $R2 ; st=old$R1,old$R2, $R2=haystack
Push $R3
Push $R4
Push $R5
StrLen $R3 $R1
StrCpy $R4 0
; $R1=needle
; $R2=haystack
; $R3=len(needle)
; $R4=cnt
; $R5=tmp
loop:
StrCpy $R5 $R2 $R3 $R4
StrCmp $R5 $R1 done
StrCmp $R5 "" done
IntOp $R4 $R4 + 1
Goto loop
done:
StrCpy $R1 $R2 "" $R4
Pop $R5
Pop $R4
Pop $R3
Pop $R2
Exch $R1
FunctionEnd
!macroend
!insertmacro StrStr ""
!insertmacro StrStr "un."
Function Trim ; Added by Pelaca
Exch $R1
Push $R2
Loop:
StrCpy $R2 "$R1" 1 -1
StrCmp "$R2" " " RTrim
StrCmp "$R2" "$\n" RTrim
StrCmp "$R2" "$\r" RTrim
StrCmp "$R2" ";" RTrim
GoTo Done
RTrim:
StrCpy $R1 "$R1" -1
Goto Loop
Done:
Pop $R2
Exch $R1
FunctionEnd
Function ConditionalAddToRegisty
Pop $0
Pop $1
StrCmp "$0" "" ConditionalAddToRegisty_EmptyString
WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" \
"$1" "$0"
;MessageBox MB_OK "Set Registry: '$1' to '$0'"
DetailPrint "Set install registry entry: '$1' to '$0'"
ConditionalAddToRegisty_EmptyString:
FunctionEnd
;--------------------------------
!ifdef CPACK_USES_DOWNLOAD
Function DownloadFile
IfFileExists $INSTDIR\* +2
CreateDirectory $INSTDIR
Pop $0
; Skip if already downloaded
IfFileExists $INSTDIR\$0 0 +2
Return
StrCpy $1 "@CPACK_DOWNLOAD_SITE@"
try_again:
NSISdl::download "$1/$0" "$INSTDIR\$0"
Pop $1
StrCmp $1 "success" success
StrCmp $1 "Cancelled" cancel
MessageBox MB_OK "Download failed: $1"
cancel:
Return
success:
FunctionEnd
!endif
;--------------------------------
; Installation types
@CPACK_NSIS_INSTALLATION_TYPES@
;--------------------------------
; Component sections
@CPACK_NSIS_COMPONENT_SECTIONS@
;--------------------------------
; Define some macro setting for the gui
@CPACK_NSIS_INSTALLER_MUI_ICON_CODE@
@CPACK_NSIS_INSTALLER_ICON_CODE@
@CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC@
@CPACK_NSIS_INSTALLER_MUI_FINISHPAGE_RUN_CODE@
;--------------------------------
;Pages
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_LICENSE "@CPACK_RESOURCE_FILE_LICENSE@"
Page custom InstallOptionsPage
!insertmacro MUI_PAGE_DIRECTORY
;Start Menu Folder Page Configuration
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "SHCTX"
!define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
!define MUI_STARTMENUPAGE_DEFAULTFOLDER "Purple I2P"
!insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER
@CPACK_NSIS_PAGE_COMPONENTS@
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
;--------------------------------
;Languages
!insertmacro MUI_LANGUAGE "English" ;first language is the default language
!insertmacro MUI_LANGUAGE "Albanian"
!insertmacro MUI_LANGUAGE "Arabic"
!insertmacro MUI_LANGUAGE "Basque"
!insertmacro MUI_LANGUAGE "Belarusian"
!insertmacro MUI_LANGUAGE "Bosnian"
!insertmacro MUI_LANGUAGE "Breton"
!insertmacro MUI_LANGUAGE "Bulgarian"
!insertmacro MUI_LANGUAGE "Croatian"
!insertmacro MUI_LANGUAGE "Czech"
!insertmacro MUI_LANGUAGE "Danish"
!insertmacro MUI_LANGUAGE "Dutch"
!insertmacro MUI_LANGUAGE "Estonian"
!insertmacro MUI_LANGUAGE "Farsi"
!insertmacro MUI_LANGUAGE "Finnish"
!insertmacro MUI_LANGUAGE "French"
!insertmacro MUI_LANGUAGE "German"
!insertmacro MUI_LANGUAGE "Greek"
!insertmacro MUI_LANGUAGE "Hebrew"
!insertmacro MUI_LANGUAGE "Hungarian"
!insertmacro MUI_LANGUAGE "Icelandic"
!insertmacro MUI_LANGUAGE "Indonesian"
!insertmacro MUI_LANGUAGE "Irish"
!insertmacro MUI_LANGUAGE "Italian"
!insertmacro MUI_LANGUAGE "Japanese"
!insertmacro MUI_LANGUAGE "Korean"
!insertmacro MUI_LANGUAGE "Kurdish"
!insertmacro MUI_LANGUAGE "Latvian"
!insertmacro MUI_LANGUAGE "Lithuanian"
!insertmacro MUI_LANGUAGE "Luxembourgish"
!insertmacro MUI_LANGUAGE "Macedonian"
!insertmacro MUI_LANGUAGE "Malay"
!insertmacro MUI_LANGUAGE "Mongolian"
!insertmacro MUI_LANGUAGE "Norwegian"
!insertmacro MUI_LANGUAGE "Polish"
!insertmacro MUI_LANGUAGE "Portuguese"
!insertmacro MUI_LANGUAGE "PortugueseBR"
!insertmacro MUI_LANGUAGE "Romanian"
!insertmacro MUI_LANGUAGE "Russian"
!insertmacro MUI_LANGUAGE "Serbian"
!insertmacro MUI_LANGUAGE "SerbianLatin"
!insertmacro MUI_LANGUAGE "SimpChinese"
!insertmacro MUI_LANGUAGE "Slovak"
!insertmacro MUI_LANGUAGE "Slovenian"
!insertmacro MUI_LANGUAGE "Spanish"
!insertmacro MUI_LANGUAGE "Swedish"
!insertmacro MUI_LANGUAGE "Thai"
!insertmacro MUI_LANGUAGE "TradChinese"
!insertmacro MUI_LANGUAGE "Turkish"
!insertmacro MUI_LANGUAGE "Ukrainian"
!insertmacro MUI_LANGUAGE "Welsh"
;--------------------------------
;Reserve Files
;These files should be inserted before other files in the data block
;Keep these lines before any File command
;Only for solid compression (by default, solid compression is enabled for BZIP2 and LZMA)
ReserveFile "NSIS.InstallOptions.ini"
!insertmacro MUI_RESERVEFILE_INSTALLOPTIONS
;--------------------------------
;Installer Sections
Section "-Core installation"
;Use the entire tree produced by the INSTALL target. Keep the
;list of directories here in sync with the RMDir commands below.
SetOutPath "$INSTDIR"
@CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS@
@CPACK_NSIS_FULL_INSTALL@
;Store installation folder
WriteRegStr SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "" $INSTDIR
;Create uninstaller
WriteUninstaller "$INSTDIR\Uninstall.exe"
Push "DisplayName"
Push "@CPACK_NSIS_DISPLAY_NAME@"
Call ConditionalAddToRegisty
Push "DisplayVersion"
Push "@CPACK_PACKAGE_VERSION@"
Call ConditionalAddToRegisty
Push "Publisher"
Push "@CPACK_PACKAGE_VENDOR@"
Call ConditionalAddToRegisty
Push "UninstallString"
Push "$INSTDIR\Uninstall.exe"
Call ConditionalAddToRegisty
Push "NoRepair"
Push "1"
Call ConditionalAddToRegisty
!ifdef CPACK_NSIS_ADD_REMOVE
;Create add/remove functionality
Push "ModifyPath"
Push "$INSTDIR\AddRemove.exe"
Call ConditionalAddToRegisty
!else
Push "NoModify"
Push "1"
Call ConditionalAddToRegisty
!endif
; Optional registration
Push "DisplayIcon"
Push "$INSTDIR\@CPACK_NSIS_INSTALLED_ICON_NAME@"
Call ConditionalAddToRegisty
Push "HelpLink"
Push "@CPACK_NSIS_HELP_LINK@"
Call ConditionalAddToRegisty
Push "URLInfoAbout"
Push "@CPACK_NSIS_URL_INFO_ABOUT@"
Call ConditionalAddToRegisty
Push "Contact"
Push "@CPACK_NSIS_CONTACT@"
Call ConditionalAddToRegisty
!insertmacro MUI_INSTALLOPTIONS_READ $INSTALL_DESKTOP "NSIS.InstallOptions.ini" "Field 5" "State"
!insertmacro MUI_STARTMENU_WRITE_BEGIN Application
;Create shortcuts
CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER"
@CPACK_NSIS_CREATE_ICONS@
@CPACK_NSIS_CREATE_ICONS_EXTRA@
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
;Read a value from an InstallOptions INI file
!insertmacro MUI_INSTALLOPTIONS_READ $DO_NOT_ADD_TO_PATH "NSIS.InstallOptions.ini" "Field 2" "State"
!insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_ALL_USERS "NSIS.InstallOptions.ini" "Field 3" "State"
!insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_CURRENT_USER "NSIS.InstallOptions.ini" "Field 4" "State"
; Write special uninstall registry entries
Push "StartMenu"
Push "$STARTMENU_FOLDER"
Call ConditionalAddToRegisty
Push "DoNotAddToPath"
Push "$DO_NOT_ADD_TO_PATH"
Call ConditionalAddToRegisty
Push "AddToPathAllUsers"
Push "$ADD_TO_PATH_ALL_USERS"
Call ConditionalAddToRegisty
Push "AddToPathCurrentUser"
Push "$ADD_TO_PATH_CURRENT_USER"
Call ConditionalAddToRegisty
Push "InstallToDesktop"
Push "$INSTALL_DESKTOP"
Call ConditionalAddToRegisty
!insertmacro MUI_STARTMENU_WRITE_END
@CPACK_NSIS_EXTRA_INSTALL_COMMANDS@
SectionEnd
Section "-Add to path"
Push $INSTDIR\bin
StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 doNotAddToPath
StrCmp $DO_NOT_ADD_TO_PATH "1" doNotAddToPath 0
Call AddToPath
doNotAddToPath:
SectionEnd
;--------------------------------
; Create custom pages
Function InstallOptionsPage
!insertmacro MUI_HEADER_TEXT "Install Options" "Choose options for installing @CPACK_NSIS_PACKAGE_NAME@"
!insertmacro MUI_INSTALLOPTIONS_DISPLAY "NSIS.InstallOptions.ini"
FunctionEnd
;--------------------------------
; determine admin versus local install
Function un.onInit
ClearErrors
UserInfo::GetName
IfErrors noLM
Pop $0
UserInfo::GetAccountType
Pop $1
StrCmp $1 "Admin" 0 +3
SetShellVarContext all
;MessageBox MB_OK 'User "$0" is in the Admin group'
Goto done
StrCmp $1 "Power" 0 +3
SetShellVarContext all
;MessageBox MB_OK 'User "$0" is in the Power Users group'
Goto done
noLM:
;Get installation folder from registry if available
done:
FunctionEnd
;--- Add/Remove callback functions: ---
!macro SectionList MacroName
;This macro used to perform operation on multiple sections.
;List all of your components in following manner here.
@CPACK_NSIS_COMPONENT_SECTION_LIST@
!macroend
Section -FinishComponents
;Removes unselected components and writes component status to registry
!insertmacro SectionList "FinishSection"
!ifdef CPACK_NSIS_ADD_REMOVE
; Get the name of the installer executable
System::Call 'kernel32::GetModuleFileNameA(i 0, t .R0, i 1024) i r1'
StrCpy $R3 $R0
; Strip off the last 13 characters, to see if we have AddRemove.exe
StrLen $R1 $R0
IntOp $R1 $R0 - 13
StrCpy $R2 $R0 13 $R1
StrCmp $R2 "AddRemove.exe" addremove_installed
; We're not running AddRemove.exe, so install it
CopyFiles $R3 $INSTDIR\AddRemove.exe
addremove_installed:
!endif
SectionEnd
;--- End of Add/Remove callback functions ---
;--------------------------------
; Component dependencies
Function .onSelChange
!insertmacro SectionList MaybeSelectionChanged
FunctionEnd
;--------------------------------
;Uninstaller Section
Section "Uninstall"
ReadRegStr $START_MENU SHCTX \
"Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "StartMenu"
;MessageBox MB_OK "Start menu is in: $START_MENU"
ReadRegStr $DO_NOT_ADD_TO_PATH SHCTX \
"Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "DoNotAddToPath"
ReadRegStr $ADD_TO_PATH_ALL_USERS SHCTX \
"Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "AddToPathAllUsers"
ReadRegStr $ADD_TO_PATH_CURRENT_USER SHCTX \
"Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "AddToPathCurrentUser"
;MessageBox MB_OK "Add to path: $DO_NOT_ADD_TO_PATH all users: $ADD_TO_PATH_ALL_USERS"
ReadRegStr $INSTALL_DESKTOP SHCTX \
"Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "InstallToDesktop"
;MessageBox MB_OK "Install to desktop: $INSTALL_DESKTOP "
@CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS@
;Remove files we installed.
;Keep the list of directories here in sync with the File commands above.
@CPACK_NSIS_DELETE_FILES@
@CPACK_NSIS_DELETE_DIRECTORIES@
!ifdef CPACK_NSIS_ADD_REMOVE
;Remove the add/remove program
Delete "$INSTDIR\AddRemove.exe"
!endif
;Remove the uninstaller itself.
Delete "$INSTDIR\Uninstall.exe"
DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"
;Remove the installation directory if it is empty.
RMDir "$INSTDIR"
; Remove the registry entries.
DeleteRegKey SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"
; Removes all optional components
!insertmacro SectionList "RemoveSection_CPack"
!insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP
Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk"
@CPACK_NSIS_DELETE_ICONS@
@CPACK_NSIS_DELETE_ICONS_EXTRA@
;Delete empty start menu parent diretories
StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP"
startMenuDeleteLoop:
ClearErrors
RMDir $MUI_TEMP
GetFullPathName $MUI_TEMP "$MUI_TEMP\.."
IfErrors startMenuDeleteLoopDone
StrCmp "$MUI_TEMP" "$SMPROGRAMS" startMenuDeleteLoopDone startMenuDeleteLoop
startMenuDeleteLoopDone:
; If the user changed the shortcut, then untinstall may not work. This should
; try to fix it.
StrCpy $MUI_TEMP "$START_MENU"
Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk"
@CPACK_NSIS_DELETE_ICONS_EXTRA@
;Delete empty start menu parent diretories
StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP"
secondStartMenuDeleteLoop:
ClearErrors
RMDir $MUI_TEMP
GetFullPathName $MUI_TEMP "$MUI_TEMP\.."
IfErrors secondStartMenuDeleteLoopDone
StrCmp "$MUI_TEMP" "$SMPROGRAMS" secondStartMenuDeleteLoopDone secondStartMenuDeleteLoop
secondStartMenuDeleteLoopDone:
DeleteRegKey /ifempty SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"
Push $INSTDIR\bin
StrCmp $DO_NOT_ADD_TO_PATH_ "1" doNotRemoveFromPath 0
Call un.RemoveFromPath
doNotRemoveFromPath:
SectionEnd
;--------------------------------
; determine admin versus local install
; Is install for "AllUsers" or "JustMe"?
; Default to "JustMe" - set to "AllUsers" if admin or on Win9x
; This function is used for the very first "custom page" of the installer.
; This custom page does not show up visibly, but it executes prior to the
; first visible page and sets up $INSTDIR properly...
; Choose different default installation folder based on SV_ALLUSERS...
; "Program Files" for AllUsers, "My Documents" for JustMe...
Function .onInit
StrCmp "@CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL@" "ON" 0 inst
ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "UninstallString"
StrCmp $0 "" inst
MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION \
"@CPACK_NSIS_PACKAGE_NAME@ is already installed. $\n$\nDo you want to uninstall the old version before installing the new one?" \
IDYES uninst IDNO inst
Abort
;Run the uninstaller
uninst:
ClearErrors
StrLen $2 "\Uninstall.exe"
StrCpy $3 $0 -$2 # remove "\Uninstall.exe" from UninstallString to get path
ExecWait '$0 _?=$3' ;Do not copy the uninstaller to a temp file
IfErrors uninst_failed inst
uninst_failed:
MessageBox MB_OK|MB_ICONSTOP "Uninstall failed."
Abort
inst:
; Reads components status for registry
!insertmacro SectionList "InitSection"
; check to see if /D has been used to change
; the install directory by comparing it to the
; install directory that is expected to be the
; default
StrCpy $IS_DEFAULT_INSTALLDIR 0
StrCmp "$INSTDIR" "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" 0 +2
StrCpy $IS_DEFAULT_INSTALLDIR 1
StrCpy $SV_ALLUSERS "JustMe"
; if default install dir then change the default
; if it is installed for JustMe
StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2
StrCpy $INSTDIR "$DOCUMENTS\@CPACK_PACKAGE_INSTALL_DIRECTORY@"
ClearErrors
UserInfo::GetName
IfErrors noLM
Pop $0
UserInfo::GetAccountType
Pop $1
StrCmp $1 "Admin" 0 +4
SetShellVarContext all
;MessageBox MB_OK 'User "$0" is in the Admin group'
StrCpy $SV_ALLUSERS "AllUsers"
Goto done
StrCmp $1 "Power" 0 +4
SetShellVarContext all
;MessageBox MB_OK 'User "$0" is in the Power Users group'
StrCpy $SV_ALLUSERS "AllUsers"
Goto done
noLM:
StrCpy $SV_ALLUSERS "AllUsers"
;Get installation folder from registry if available
done:
StrCmp $SV_ALLUSERS "AllUsers" 0 +3
StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2
StrCpy $INSTDIR "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@"
StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 noOptionsPage
!insertmacro MUI_INSTALLOPTIONS_EXTRACT "NSIS.InstallOptions.ini"
noOptionsPage:
FunctionEnd

17
debian/changelog vendored
View File

@@ -1,11 +1,12 @@
i2pd (20140919-2) unstable; urgency=low
i2pd (2.2.0-2) unstable; urgency=low
* updated to latest sources
* updated to version 2.2.0
-- hagen <hagen@i2pmail.org> Wed, 23 Dec 2015 01:29:40 +0000
i2pd (2.1.0-1) unstable; urgency=low
* updated to version 2.1.0/0.9.23
* updated deps
-- hagen <hagen@i2pmail.org> Fri, 19 Sep 2014 05:16:12 +0000
i2pd (20140919-1) unstable; urgency=low
* Initial release (Closes: #nnnn)
-- hagen <hagen@i2pmail.org> Mon, 19 Sep 2014 00:00:00 +0000

2
debian/compat vendored
View File

@@ -1 +1 @@
8
9

38
debian/control vendored
View File

@@ -2,21 +2,43 @@ Source: i2pd
Section: net
Priority: extra
Maintainer: hagen <hagen@i2pmail.org>
Build-Depends: debhelper (>= 8.0.0), dpkg-dev (>= 1.16.1~),
cmake (>= 2.8), gcc (>= 4.6) | clang (>= 3.3),
Build-Depends: debhelper (>= 9.0.0), dpkg-dev (>= 1.16.1~),
gcc (>= 4.6) | clang (>= 3.3),
libboost-regex-dev,
libboost-system-dev (>= 1.46),
libboost-date-time-dev,
libboost-filesystem-dev,
libboost-program-options-dev,
libcrypto++-dev
libssl-dev
Standards-Version: 3.9.3
Homepage: https://github.com/PrivacySolutions/i2pd
Vcs-Git: git://github.com/PrivacySolutions/i2pd.git
Vcs-Browser: https://github.com/PrivacySolutions/i2pd.git
Homepage: https://github.com/PurpleI2P/i2pd
Vcs-Git: git://github.com/PurpleI2P/i2pd.git
Vcs-Browser: https://github.com/PurpleI2P/i2pd.git
Package: i2pd
Architecture: any
Pre-Depends: adduser
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: i2p router written in C++
Mainly runs on linux, but also supports OSX, BSD and Windows
Recommends: privoxy
Suggests: tor
Description: load-balanced unspoofable packet switching network - C++ port
I2P is an anonymizing network, offering a simple layer that identity-sensitive
applications can use to securely communicate. All data is wrapped with several
layers of encryption, and the network is both distributed and dynamic, with no
trusted parties.
.
This package contains the port of the I2P router to C++. Unless willing
to test and report problems, you should install the 'i2p' package instead.
Package: i2pd-dbg
Architecture: any
Priority: extra
Section: debug
Depends: i2pd (= ${binary:Version}), ${misc:Depends}
Description: i2pd debugging symbols
I2P is an anonymizing network, offering a simple layer that identity-sensitive
applications can use to securely communicate. All data is wrapped with several
layers of encryption, and the network is both distributed and dynamic, with no
trusted parties.
.
This package contains symbols required for debugging.

59
debian/copyright vendored
View File

@@ -3,38 +3,39 @@ Upstream-Name: i2pd
Source: https://github.com/PurpleI2P
Files: *
Copyright: 2013-2014 PurpleI2P
Copyright: 2013-2015 PurpleI2P
License: BSD-3-clause
Copyright (c) 2013-2015, The PurpleI2P Project
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are
permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of
conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used
to endorse or promote products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Copyright (c) 2013-2015, The PurpleI2P Project
.
All rights reserved.
.
Redistribution and use in source and binary forms, with or without modification, are
permitted provided that the following conditions are met:
.
1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
.
2. Redistributions in binary form must reproduce the above copyright notice, this list of
conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.
.
3. Neither the name of the copyright holder nor the names of its contributors may be used
to endorse or promote products derived from this software without specific prior written
permission.
.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Files: debian/*
Copyright: 2014 hagen <hagen@i2pmail.org>
Copyright: 2014-2015 hagen <hagen@i2pmail.org>
2013-2015 Kill Your TV <killyourtv@i2pmail.org>
License: GPL-2.0+
This package is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

1
debian/docs vendored
View File

@@ -1 +1,2 @@
README.md
docs/configuration.md

Some files were not shown because too many files have changed in this diff Show More