Compare commits

...

221 Commits
2.4.0 ... 2.5.1

Author SHA1 Message Date
orignal
0e5b32ef13 2.5.1 2016-03-10 13:34:16 -05:00
orignal
0493a321d2 oveeride --log for windows 2016-03-10 12:23:17 -05:00
orignal
38b6c12153 fixed bug with missed data directory 2016-03-10 12:05:28 -05:00
orignal
74d4b8e0b9 invoke win32app functions from main 2016-03-09 14:41:14 -05:00
orignal
95b2bf3645 fixed windows build 2016-03-09 09:38:19 -05:00
hagen
121ac4f1de * move mingw-specific rules to Makefile.mingw 2016-03-09 13:36:39 +00:00
orignal
ec8550d587 use ictoopie_16 in tray 2016-03-08 21:18:48 -05:00
orignal
e403c419e5 16x16 icon added 2016-03-08 17:40:43 -05:00
orignal
4b0d587fe1 Daemon::run 2016-03-08 15:02:32 -05:00
orignal
ebd356c7bd set correct icons 2016-03-08 11:24:29 -05:00
orignal
507093dbad compile with resources 2016-03-07 21:36:11 -05:00
orignal
4cfdc77015 invoke daemon 2016-03-07 16:17:06 -05:00
orignal
9096cacba8 tray icon added 2016-03-07 16:06:34 -05:00
orignal
607336d3ce tray icon added 2016-03-07 15:57:32 -05:00
orignal
6383fc3575 initial commit of Win32App 2016-03-07 14:54:57 -05:00
orignal
a5576ddbf3 don't acquire DH keys pair until connection is established 2016-03-06 09:57:38 -05:00
orignal
e2a70873b8 fixed garbage in console for windows 2016-03-05 21:46:01 -05:00
orignal
380b56a89d 2.5.0 2016-03-04 21:34:23 -05:00
orignal
8e09f3478f fixed warnings 2016-03-04 20:35:53 -05:00
orignal
c1ce51eb12 Merge pull request #403 from xcps/webirc2
variable name
2016-03-04 09:53:52 -05:00
xcps
9aeb773169 variable name 2016-03-04 19:26:28 +05:00
orignal
091c13ff41 Merge pull request #402 from xcps/webirc2
WebIRC support
2016-03-04 07:05:37 -05:00
xcps
ef0bab0c6e webirc support 2016-03-04 11:37:38 +05:00
orignal
70bd16adf6 set established state for zero-hops tunnles 2016-03-03 17:57:15 -05:00
orignal
96a713afeb zero-hops outbound tunnels 2016-03-03 16:24:13 -05:00
orignal
0f56b1c943 show number of received bytes for zero-hops inbound tunnel 2016-03-03 07:30:38 -05:00
orignal
d541572882 enable zero-hops inbound tunnel 2016-03-02 22:41:53 -05:00
orignal
ecfdc377ec send close floodfills only in DatabaseSearchReply 2016-03-02 19:46:32 -05:00
orignal
fa67e90767 inbound zero-hops tunnel 2016-03-02 16:12:02 -05:00
orignal
81b72d5481 fixed crash on termination if proxies were excluded 2016-03-02 12:04:02 -05:00
orignal
ef6028e933 replace std::map to std::list for inbound tunnels 2016-03-02 11:58:52 -05:00
orignal
5d41fe4a35 Merge pull request #400 from majestrate/webui-add-tunnel-count
Add Transit/Client Tunnel Count to web ui
2016-03-02 10:13:51 -05:00
Jeff Becker
1dc6cec1aa add client/transit tunnel count in webui 2016-03-02 10:05:26 -05:00
Jeff Becker
9378668e52 add colin 2016-03-02 10:03:50 -05:00
Jeff Becker
eb96ead80e add tunnel counts to front page of web ui 2016-03-02 10:03:36 -05:00
orignal
9403fbaf81 common tunnels' hash table 2016-03-01 20:48:56 -05:00
orignal
79190f313d use shared_ptr for transit tunnels 2016-03-01 15:22:36 -05:00
orignal
4c124284b6 Merge pull request #399 from PurpleI2P/openssl
irc tunnel and gzip
2016-03-01 13:39:26 -05:00
orignal
6d892179c8 added gzip parameter for server tunnels 2016-02-29 14:44:15 -05:00
orignal
61675c20d8 don't delete log file upon HUP 2016-02-29 11:02:55 -05:00
orignal
4aae878db8 increase LeaseSet expiration threshold 2016-02-28 21:43:18 -05:00
orignal
918884bd11 Merge pull request #398 from xcps/irc_ip2b32
irc tunnel
2016-02-28 16:19:19 -05:00
xcps
8799f9079b change part for replace 2016-02-29 02:15:29 +05:00
orignal
0b471cfd06 Merge pull request #397 from xcps/irc_ip2b32
Irc ip to b32
2016-02-28 14:14:11 -05:00
xcps
7b39a12396 ready 2016-02-28 22:32:34 +05:00
xcps
57a53b4b6c fixed I2PServerTunnelHTTP call 2016-02-28 21:13:01 +05:00
orignal
f6d0b3368f znx cert added 2016-02-28 09:56:17 -05:00
xcps
0fe7bdf849 init 2016-02-28 18:17:36 +05:00
xcps
a26dc39a6d ident fix 2016-02-28 18:17:35 +05:00
xcps
e45cfe7d0c init 2016-02-28 18:17:35 +05:00
orignal
efefa8caf5 Merge pull request #395 from PurpleI2P/openssl
socks outproxy
2016-02-27 16:16:15 -05:00
orignal
cc13db9b1f updated FreeBSD instructions 2016-02-27 15:44:36 -05:00
orignal
f339544256 Merge pull request #394 from majestrate/outproxy-socks
support for outproxy via local upstream socks proxy
2016-02-26 21:42:04 -05:00
Jeff Becker
1a05bcb295 initial support for out proxy via local upstream socks proxy 2016-02-26 17:06:11 -05:00
orignal
190e26276a reuse tunnel pair for LS request 2016-02-26 16:17:29 -05:00
orignal
bb33760e87 don't re-request twice 2016-02-26 16:16:59 -05:00
orignal
9e105b4983 Merge pull request #393 from PurpleI2P/openssl
recent changes
2016-02-26 15:13:31 -05:00
orignal
8dcf70408d hostoverride added 2016-02-25 20:32:05 -05:00
orignal
9d6d1825c7 pass flag to SSU header 2016-02-25 18:40:40 -05:00
orignal
1a4923cdce don't request relayTag if we are reachable 2016-02-25 15:57:58 -05:00
orignal
316e440390 Merge pull request #392 from PurpleI2P/openssl
recent changes
2016-02-25 13:51:03 -05:00
orignal
7d66019220 start checking for expiration after 10 minutes 2016-02-24 11:50:56 -05:00
orignal
f98a6fb665 tighten RouterInfo expiration 2016-02-24 11:31:14 -05:00
orignal
dbdc7279c4 Merge pull request #391 from PurpleI2P/openssl
new fs
2016-02-24 11:21:36 -05:00
orignal
7726705b5c process request relay tag extended SSU option 2016-02-23 12:16:53 -05:00
orignal
34b7e8815a Merge branch 'openssl' of https://github.com/PurpleI2P/i2pd into openssl 2016-02-23 11:17:14 -05:00
orignal
8ac2b58a44 Merge branch 'master' of https://github.com/PurpleI2P/i2pd into openssl 2016-02-23 11:17:01 -05:00
orignal
fe97f0929b delete expired floodfills thorugh a separate loop 2016-02-22 20:51:32 -05:00
orignal
6eec353c2b moved tunnel config file inialization to ClientContext 2016-02-22 15:27:40 -05:00
orignal
2b4c3b8d1f start up if i2p.conf is not presented 2016-02-22 15:17:58 -05:00
orignal
df99b37c4d Merge pull request #388 from l-n-s/openssl
added family documentation
2016-02-22 13:45:29 -05:00
libre-net-society
ab6f3fcf8e added family documentation 2016-02-22 20:49:17 +03:00
orignal
ca6f656e1b ignore non-reachable floodfills 2016-02-22 10:27:43 -05:00
orignal
88798b1a9e fixed windows build 2016-02-22 09:53:26 -05:00
hagen
c197270125 Merge branch 'new-fs' into openssl
Conflicts:
	Family.cpp
2016-02-22 13:04:53 +00:00
hagen
dc344d4658 * add comment 2016-02-22 12:57:25 +00:00
orignal
b4864831e0 Merge pull request #387 from PurpleI2P/openssl
family
2016-02-21 20:29:49 -05:00
orignal
476dffff13 Create family.md 2016-02-21 15:26:14 -05:00
orignal
389ee974f3 family 2016-02-20 21:20:21 -05:00
hagen
0d15eceacb * Profiling : move storage from FS.cpp to Profiling.cpp 2016-02-21 01:49:35 +00:00
hagen
b69fbdda9a * NetDb : move storage from FS.cpp to NetDb.cpp 2016-02-21 01:49:32 +00:00
hagen
d3746e0119 * FS.h : add include guards 2016-02-21 01:49:29 +00:00
orignal
230af9cafa set router's family 2016-02-20 20:20:19 -05:00
orignal
4db63d113c i2pd-dev certificate updated 2016-02-20 09:22:09 -05:00
orignal
008583396d extract CN 2016-02-20 08:33:13 -05:00
hagen
33a33e3c71 * i2p::util::http::GetHttpContent() : use std::transform instead boost 2016-02-20 01:47:34 +00:00
hagen
d312d753e9 * Destination.cpp : fix lambda with 4.7 2016-02-20 01:47:32 +00:00
hagen
02310d4af6 * Family : use i2p::fs::ReadDir instead direct boost::filesystem call 2016-02-20 01:47:29 +00:00
orignal
0e6d8c4e25 i2pd-dev family certificate added 2016-02-19 20:09:48 -05:00
hagen
55315fca80 Merge branch 'openssl' into new-fs
Conflicts:
	AddressBook.cpp
	NetDb.cpp
	filelist.mk
2016-02-20 00:59:48 +00:00
orignal
4eef9e780f extract and verify family from RouterInfo 2016-02-19 16:37:41 -05:00
orignal
7bfc3562af extract EcDSA key from family certificate 2016-02-19 16:13:46 -05:00
orignal
5b0b0d6d36 Merge pull request #386 from PurpleI2P/openssl
recent changes
2016-02-19 13:18:36 -05:00
orignal
cb64072f7b fixed windows build 2016-02-19 11:18:01 -05:00
orignal
c5b6da7201 case-insensitive http responses 2016-02-19 10:04:52 -05:00
orignal
f1d4818045 Family.cpp added 2016-02-18 22:39:09 -05:00
orignal
76b49f6985 uncompress stream by chunks 2016-02-18 22:34:55 -05:00
orignal
094d9193b9 start addressbook first 2016-02-18 22:34:14 -05:00
orignal
3053a9b6a0 enable i2p gzip compression 2016-02-18 20:35:14 -05:00
orignal
47bf0ef591 free pkey after usage 2016-02-18 16:28:43 -05:00
orignal
e2aa2709ac family added 2016-02-18 15:57:43 -05:00
orignal
9a6d478eb1 handle compressed addressbook 2016-02-18 13:19:31 -05:00
orignal
4f37e7dc3c Merge pull request #383 from PurpleI2P/openssl
recent changes
2016-02-18 09:06:48 -05:00
hagen
2a4ba8d349 * Addressbook : move storage init code from constructor to Init() : was too early 2016-02-18 10:42:50 +00:00
hagen
85bd7a63c6 * AddressBook : embed HashedStorage instance into AddressBookFilesystemStorage class 2016-02-18 10:42:50 +00:00
hagen
138d57143a * FS.cpp : add const to accessors 2016-02-18 10:42:50 +00:00
hagen
464a228106 * FS.cpp : rename method 2016-02-18 10:42:50 +00:00
hagen
2b92a039bb * FS.h : more comments 2016-02-18 10:42:50 +00:00
hagen
f190ee951c * use characters sets from Base.cpp - remove ABook class 2016-02-18 10:42:50 +00:00
hagen
68cc75cada * Base.cpp : add T32 character set + accessor 2016-02-18 10:42:41 +00:00
orignal
b4e324ec0e flood to 3 closest floodfills 2016-02-17 21:24:21 -05:00
orignal
32fe2e7974 correct monotonic expiration time calculation 2016-02-17 19:36:07 -05:00
orignal
713513aacc flood newer RI/LS only 2016-02-17 15:36:55 -05:00
orignal
b4ffca56a3 update lease's expiration time continiously 2016-02-17 13:10:29 -05:00
orignal
f2168774a5 check leaseset timestamp 2016-02-16 22:57:38 -05:00
orignal
febc00d357 fixed race condition of DeliveryStatus message 2016-02-16 16:10:22 -05:00
orignal
01a8c507e5 Merge pull request #381 from PurpleI2P/openssl
recent changes
2016-02-16 16:01:12 -05:00
orignal
bf7982cc2e build with make added 2016-02-16 15:08:35 -05:00
orignal
2e9689886b build with make added 2016-02-16 15:07:56 -05:00
orignal
2003b34036 12 hours expiration if more than 2500 routers 2016-02-15 21:40:49 -05:00
orignal
e1995b5c70 try to download default hosts.txt until success 2016-02-15 18:20:01 -05:00
orignal
3890acabc4 Merge pull request #380 from PurpleI2P/openssl
fixed http issues
2016-02-15 16:22:15 -05:00
orignal
ba6c0d0423 fixed messy http pages 2016-02-15 15:16:53 -05:00
orignal
882e7a845e process remaining data from stream 2016-02-14 22:10:56 -05:00
orignal
ca56d3fc23 handle LeaseSet expiration correctly 2016-02-14 18:30:07 -05:00
orignal
49b1e76585 use rtt for ack timeout 2016-02-13 23:10:51 -05:00
orignal
80f81685d1 use rtt for ack timeout 2016-02-13 23:02:58 -05:00
orignal
21dead3125 increase lease expiration threshold 2016-02-13 17:56:42 -05:00
orignal
1521d08285 family cetificates added 2016-02-13 17:13:07 -05:00
orignal
59b2e31add ssl certificates updated 2016-02-13 17:10:54 -05:00
orignal
b5feb3fd66 update reseeds list 2016-02-13 17:03:25 -05:00
orignal
7785e6ebd2 Merge branch 'openssl' of https://github.com/PurpleI2P/i2pd into openssl 2016-02-12 20:56:46 -05:00
orignal
c561d71dc0 count lease expiration threshold 2016-02-12 20:56:29 -05:00
orignal
2cfb697867 strip our Referer and replace User-Agent 2016-02-12 15:42:13 -05:00
orignal
c680ff006e Merge pull request #378 from PurpleI2P/openssl
recent changes
2016-02-12 11:23:29 -05:00
orignal
333103f50e shared RTT 2016-02-11 22:18:44 -05:00
orignal
517385fb63 Lease enddate threshold 2016-02-11 22:18:24 -05:00
orignal
ee8ab58d64 don't reply to lookup with expired LeaseSet 2016-02-11 22:17:33 -05:00
orignal
b967acda58 flood to floodfills that are close than us only 2016-02-11 15:05:46 -05:00
orignal
d81ca5f919 local destination leaseset storage verification 2016-02-11 14:45:33 -05:00
orignal
07adf64aec Merge pull request #376 from PurpleI2P/openssl
recent changes
2016-02-11 14:37:11 -05:00
orignal
fbb98e1aec show actual name of an invalid parameter 2016-02-11 11:18:15 -05:00
orignal
2fdf927704 show actual name of an invalid parameter 2016-02-11 10:54:36 -05:00
hagen
4b84656133 * i2p::fs migration: drop unused code from util.* (#314) 2016-02-11 13:05:00 +00:00
hagen
97c136d043 * i2p::fs migration: Daemon, DaemonLinux, api (#290) 2016-02-11 13:05:00 +00:00
hagen
79bf44b3f5 * i2p::fs migration: ClientContext, Destination, HTTPServer, Reseed, RouterContext 2016-02-11 13:05:00 +00:00
hagen
ddd8d4aeb2 * i2p::fs migration: AddressBook.* 2016-02-11 13:05:00 +00:00
hagen
bfcb6f577f * i2p::fs migration: Profiling.* 2016-02-11 13:05:00 +00:00
hagen
2b137b43e6 * i2p::fs migration: I2PControl.* 2016-02-11 13:05:00 +00:00
hagen
6d74493491 * i2p::fs migration: NetDb.* 2016-02-11 13:05:00 +00:00
hagen
6f4271c054 * update buildsystems 2016-02-11 13:05:00 +00:00
hagen
f24054100e * new i2p::fs implementation 2016-02-11 13:05:00 +00:00
hagen
6e98649607 * I2PControl: send valid error response, instead closing connection 2016-02-11 13:00:56 +00:00
hagen
b2108ff2d0 * fix flags on std::ifstream 2016-02-11 13:00:56 +00:00
hagen
8949ebf041 * tune logging 2016-02-11 13:00:56 +00:00
hagen
576801cd32 * Addressbook: load addresses at start, not on first request 2016-02-11 13:00:56 +00:00
hagen
2f2b12811f * Addressbook: don't save to disk if address map is empty 2016-02-11 13:00:56 +00:00
hagen
d8ea3a9035 * make target 'strip' 2016-02-11 13:00:56 +00:00
orignal
45c3b3987b reset floodfill 2016-02-11 07:50:29 -05:00
orignal
93720fffd4 shared path between streams 2016-02-10 22:51:08 -05:00
orignal
61ad6a2b88 set supported transports flag after actual address insertion 2016-02-10 16:09:34 -05:00
orignal
c9d5b3c0ff Merge pull request #373 from PurpleI2P/openssl
recent changes
2016-02-10 10:51:21 -05:00
hagen
d51bf735c4 * fix mistype 2016-02-10 10:37:30 +00:00
hagen
22c388ab18 * fix compilation with gcc 4.7/4.8 2016-02-10 10:37:30 +00:00
hagen
d5f831301f * explicit log message when bandwidth set to 'low' 2016-02-10 10:37:30 +00:00
hagen
dcab37a148 * update debian/i2pd.{init,upstart} : logging options 2016-02-10 10:37:30 +00:00
hagen
60b2da3671 * add --datadir option (not actually works yet) (#290) 2016-02-10 10:37:30 +00:00
hagen
5c1b5816d4 * fix segfault when offline (#330) 2016-02-10 10:37:30 +00:00
hagen
7a0a45e9d2 * use IsDefault() to check explicitly set values 2016-02-10 10:37:30 +00:00
hagen
70f72a78f6 + i2p::config::IsDefault 2016-02-10 10:37:30 +00:00
orignal
e056c9c135 drop expired leasesand renew leaseset 2016-02-09 22:42:01 -05:00
orignal
c754b5ae18 fixed crash 2016-02-09 17:54:22 -05:00
orignal
481fafc11d invalidate excluded leases 2016-02-09 15:27:23 -05:00
orignal
7d927b0e28 shared_ptr for Lease 2016-02-09 10:46:27 -05:00
orignal
c314b07136 Merge pull request #371 from PurpleI2P/openssl
recent changes
2016-02-09 10:37:46 -05:00
orignal
16fe13bf4a Merge branch 'openssl' of https://github.com/PurpleI2P/i2pd into openssl 2016-02-08 20:30:53 -05:00
orignal
d19eda7e08 moved Config.cpp to libi2pd 2016-02-08 20:29:56 -05:00
orignal
6f0a136727 some cleanup 2016-02-08 20:29:34 -05:00
orignal
e2e101e4fb queue up out of sequence packets 2016-02-08 15:47:39 -05:00
orignal
74f03202b7 queue up out of sequence packets 2016-02-08 15:02:17 -05:00
orignal
3d19e92059 queue up out of sequence packets 2016-02-08 14:42:20 -05:00
orignal
bfff125cc5 Merge pull request #370 from PurpleI2P/openssl
recent changes
2016-02-08 14:41:40 -05:00
orignal
e90baf3ca6 correct required base64 buffer size 2016-02-07 21:35:06 -05:00
orignal
f3b277aeef doesn't store leases in netdb 2016-02-07 19:45:06 -05:00
orignal
76096747b6 cleanup incoming and outgoing tags together 2016-02-07 17:45:11 -05:00
orignal
4c6ef32d72 fixed #369 2016-02-06 08:52:02 -05:00
orignal
a8e12e624d fixed hanging connection 2016-02-05 21:38:03 -05:00
orignal
88a43bfc28 Merge pull request #368 from majestrate/fix_sam_b32_naming
allow resolving of .b32.i2p addresses in SAM name lookup
2016-02-05 16:37:00 -05:00
Jeff Becker
3b268fe3cc allow resolving of .b32.i2p addresses in SAM name lookup 2016-02-05 16:17:53 -05:00
orignal
4c72d43a8a use more efficient XOR over ChipherBlocks for win32 2016-02-05 15:58:14 -05:00
orignal
0a5f8527b2 Merge pull request #366 from majestrate/bug_fixes
Squash potential future bugs.
2016-02-05 13:12:08 -05:00
Jeff Becker
9f1b84d6f2 use const size_t instead of size_t 2016-02-05 12:39:17 -05:00
Jeff Becker
babcbcbcea use const size_t instead of size_t 2016-02-05 12:32:50 -05:00
orignal
823a6017fe Merge pull request #364 from 0niichan/patch-6
Added instructions for a 64-bit OS
2016-02-05 11:12:57 -05:00
0niichan
f034aef2ae Added instructions for a 64-bit OS 2016-02-05 22:58:04 +07:00
Jeff Becker
bf38bd5a1d * Fill padding with random in NTCP phase3
* Fill padding with random in NTCPSession::CreateMsgBuffer

* Silence unused variable warnings in NTCPSession.cpp
2016-02-05 10:40:23 -05:00
Jeff Becker
b922809c9d Merge branch 'openssl' into bug_fixes 2016-02-05 10:20:22 -05:00
Jeff Becker
05b0bda8bb Merge remote-tracking branch 'purple/openssl' into openssl 2016-02-05 10:16:42 -05:00
orignal
0aa3aa1b8d Merge pull request #363 from majestrate/fix_su3_overflow
fix issue #362 , add bounds check to su3 fileNameLength
2016-02-05 10:03:34 -05:00
Jeff Becker
d4febb4e84 * bounds check on Identity::FromBuffer
* properly indet last commits
2016-02-05 08:52:07 -05:00
Jeff Becker
21090eaa39 forgot to commit Base.cpp changes 2016-02-05 08:46:08 -05:00
Jeff Becker
d0ea59c568 add base64 buffer encoding bounds checking 2016-02-05 08:44:09 -05:00
Jeff Becker
a292bc77ba fix issue #362 , add bounds check to su3 fileNameLength 2016-02-05 07:55:28 -05:00
orignal
98d5e0b56d #355. reopen log file by SIGHUP 2016-02-04 13:53:38 -05:00
orignal
7ca1cfab1a use shared_ptr for log's stream 2016-02-04 12:36:58 -05:00
orignal
2e7ce38552 compatibility with gcc 4.6 2016-02-04 12:36:54 -05:00
orignal
0ef3a2472d Merge pull request #361 from PurpleI2P/openssl
rebase master to 2.4.0
2016-02-04 10:08:17 -05:00
orignal
b97f095de4 Merge pull request #360 from AMDmi3/build-type
Do not force build type
2016-02-04 10:06:09 -05:00
orignal
10e2b35483 Merge pull request #359 from AMDmi3/system-include-dirs
Include system directories as SYSTEM
2016-02-04 10:00:47 -05:00
orignal
16920a89f3 Merge pull request #358 from AMDmi3/local-include-dirs-before
Always place local include directories before all others
2016-02-04 10:00:10 -05:00
orignal
1a5b9de82e Merge pull request #357 from AMDmi3/conditional-miniupnp
Do not try to use miniupnp if upnp support is disabled
2016-02-04 09:59:18 -05:00
Dmitry Marakasov
4ef183fee6 Do not force build type 2016-02-04 16:53:24 +03:00
Dmitry Marakasov
2115ce6606 Do not try to use miniupnp if upnp support is disabled 2016-02-04 16:52:41 +03:00
Dmitry Marakasov
61d1b733f7 Include system directories as SYSTEM 2016-02-04 16:52:20 +03:00
Dmitry Marakasov
4978edb8be Always place local include directories before all others 2016-02-04 16:49:07 +03:00
orignal
51f7aba807 fixed crash 2016-02-03 16:18:49 -05:00
orignal
b9b143e4e7 don't persist proxy keys by defualt 2016-02-03 15:29:15 -05:00
orignal
0e7596a205 Update build_notes_windows.md 2016-02-03 15:01:28 -05:00
orignal
8c401cf01b check for USE_AESNI=1 2016-02-03 15:00:55 -05:00
orignal
6782e6a532 AES-NI 2016-02-03 13:46:26 -05:00
orignal
4386bd93c3 handle USE_AESNI for mingw 2016-02-03 12:48:59 -05:00
96 changed files with 3393 additions and 1620 deletions

View File

@@ -5,11 +5,11 @@
#include <fstream>
#include <chrono>
#include <condition_variable>
#include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp>
#include "Base.h"
#include "util.h"
#include "Identity.h"
#include "FS.h"
#include "Log.h"
#include "NetDb.h"
#include "ClientContext.h"
@@ -19,167 +19,135 @@ namespace i2p
{
namespace client
{
// TODO: this is actually proxy class
class AddressBookFilesystemStorage: public AddressBookStorage
{
public:
private:
i2p::fs::HashedStorage storage;
std::string indexPath;
AddressBookFilesystemStorage ();
public:
AddressBookFilesystemStorage (): storage("addressbook", "b", "", "b32") {};
std::shared_ptr<const i2p::data::IdentityEx> GetAddress (const i2p::data::IdentHash& ident) const;
void AddAddress (std::shared_ptr<const i2p::data::IdentityEx> address);
void RemoveAddress (const i2p::data::IdentHash& ident);
bool Init ();
int Load (std::map<std::string, i2p::data::IdentHash>& addresses);
int Save (const std::map<std::string, i2p::data::IdentHash>& addresses);
private:
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 ()
bool AddressBookFilesystemStorage::Init()
{
auto path = GetPath ();
if (!boost::filesystem::exists (path))
{
// Create directory is necessary
if (!boost::filesystem::create_directory (path))
LogPrint (eLogError, "Addressbook: failed to create addressbook directory");
}
storage.SetPlace(i2p::fs::GetDataDir());
indexPath = storage.GetRoot() + i2p::fs::dirSep + "addresses.csv";
return storage.Init(i2p::data::GetBase32SubstitutionTable(), 32);
}
std::shared_ptr<const i2p::data::IdentityEx> AddressBookFilesystemStorage::GetAddress (const i2p::data::IdentHash& ident) const
{
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, "Addresbook: 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);
size_t len = f.tellg ();
if (len < i2p::data::DEFAULT_IDENTITY_SIZE)
{
LogPrint (eLogError, "Addresbook: File ", filename, " is too short. ", len);
return nullptr;
}
f.seekg(0, std::ios::beg);
uint8_t * buf = new uint8_t[len];
f.read((char *)buf, len);
auto address = std::make_shared<i2p::data::IdentityEx>(buf, len);
delete[] buf;
return address;
}
else
std::string filename = storage.Path(ident.ToBase32());
std::ifstream f(filename, std::ifstream::binary);
if (!f.is_open ()) {
LogPrint(eLogDebug, "Addressbook: Requested, but not found: ", filename);
return nullptr;
}
f.seekg (0,std::ios::end);
size_t len = f.tellg ();
if (len < i2p::data::DEFAULT_IDENTITY_SIZE) {
LogPrint (eLogError, "Addresbook: File ", filename, " is too short: ", len);
return nullptr;
}
f.seekg(0, std::ios::beg);
uint8_t * buf = new uint8_t[len];
f.read((char *)buf, len);
auto address = std::make_shared<i2p::data::IdentityEx>(buf, len);
delete[] buf;
return address;
}
void AddressBookFilesystemStorage::AddAddress (std::shared_ptr<const i2p::data::IdentityEx> address)
{
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 ();
uint8_t * buf = new uint8_t[len];
address->ToBuffer (buf, len);
f.write ((char *)buf, len);
delete[] buf;
std::string path = storage.Path( address->GetIdentHash().ToBase32() );
std::ofstream f (path, std::ofstream::binary | std::ofstream::out);
if (!f.is_open ()) {
LogPrint (eLogError, "Addresbook: can't open file ", path);
return;
}
else
LogPrint (eLogError, "Addresbook: can't open file ", filename);
size_t len = address->GetFullLen ();
uint8_t * buf = new uint8_t[len];
address->ToBuffer (buf, len);
f.write ((char *)buf, len);
delete[] buf;
}
void AddressBookFilesystemStorage::RemoveAddress (const i2p::data::IdentHash& ident)
{
auto filename = GetAddressPath (ident);
if (boost::filesystem::exists (filename))
boost::filesystem::remove (filename);
storage.Remove( ident.ToBase32() );
}
int AddressBookFilesystemStorage::Load (std::map<std::string, i2p::data::IdentHash>& addresses)
{
int num = 0;
auto filename = GetPath () / "addresses.csv";
std::ifstream f (filename.string (), std::ofstream::in); // in text mode
if (f.is_open ())
{
addresses.clear ();
while (!f.eof ())
{
std::string s;
getline(f, s);
if (!s.length())
continue; // skip empty line
std::string s;
std::ifstream f (indexPath, std::ifstream::in); // in text mode
size_t pos = s.find(',');
if (pos != std::string::npos)
{
std::string name = s.substr(0, pos++);
std::string addr = s.substr(pos);
i2p::data::IdentHash ident;
ident.FromBase32 (addr);
addresses[name] = ident;
num++;
}
}
LogPrint (eLogInfo, "Addressbook: ", num, " addresses loaded");
if (f.is_open ()) {
LogPrint(eLogInfo, "Addressbook: using index file ", indexPath);
} else {
LogPrint(eLogWarning, "Addressbook: Can't open ", indexPath);
return 0;
}
else
LogPrint (eLogWarning, "Addressbook: ", filename, " not found");
addresses.clear ();
while (!f.eof ()) {
getline(f, s);
if (!s.length())
continue; // skip empty line
std::size_t pos = s.find(',');
if (pos != std::string::npos)
{
std::string name = s.substr(0, pos++);
std::string addr = s.substr(pos);
i2p::data::IdentHash ident;
ident.FromBase32 (addr);
addresses[name] = ident;
num++;
}
}
LogPrint (eLogInfo, "Addressbook: ", num, " addresses loaded from storage");
return num;
}
int AddressBookFilesystemStorage::Save (const std::map<std::string, i2p::data::IdentHash>& addresses)
{
int num = 0;
auto filename = GetPath () / "addresses.csv";
std::ofstream f (filename.string (), std::ofstream::out); // in text mode
if (f.is_open ())
{
for (auto it: addresses)
{
f << it.first << "," << it.second.ToBase32 () << std::endl;
num++;
}
LogPrint (eLogInfo, "Addressbook: ", num, " addresses saved");
if (addresses.size() == 0) {
LogPrint(eLogWarning, "Addressbook: not saving empty addressbook");
return 0;
}
else
LogPrint (eLogError, "Addresbook: can't open file ", filename);
int num = 0;
std::ofstream f (indexPath, std::ofstream::out); // in text mode
if (!f.is_open ()) {
LogPrint (eLogWarning, "Addressbook: Can't open ", indexPath);
return 0;
}
for (auto it: addresses) {
f << it.first << "," << it.second.ToBase32 () << std::endl;
num++;
}
LogPrint (eLogInfo, "Addressbook: ", num, " addresses saved");
return num;
}
//---------------------------------------------------------------------
AddressBook::AddressBook (): m_Storage (nullptr), m_IsLoaded (false), m_IsDownloading (false),
AddressBook::AddressBook (): m_Storage(new AddressBookFilesystemStorage), m_IsLoaded (false), m_IsDownloading (false),
m_DefaultSubscription (nullptr), m_SubscriptionsUpdateTimer (nullptr)
{
}
@@ -191,6 +159,8 @@ namespace client
void AddressBook::Start ()
{
m_Storage->Init();
LoadHosts (); /* try storage, then hosts.txt, then download */
StartSubscriptions ();
}
@@ -223,21 +193,12 @@ namespace client
delete m_Storage;
m_Storage = nullptr;
}
if (m_DefaultSubscription)
{
delete m_DefaultSubscription;
m_DefaultSubscription = nullptr;
}
m_DefaultSubscription = nullptr;
for (auto it: m_Subscriptions)
delete it;
m_Subscriptions.clear ();
}
AddressBookStorage * AddressBook::CreateStorage ()
{
return new AddressBookFilesystemStorage ();
}
bool AddressBook::GetIdentHash (const std::string& address, i2p::data::IdentHash& ident)
{
auto pos = address.find(".b32.i2p");
@@ -271,14 +232,9 @@ namespace client
const i2p::data::IdentHash * AddressBook::FindAddress (const std::string& address)
{
if (!m_IsLoaded)
LoadHosts ();
if (m_IsLoaded)
{
auto it = m_Addresses.find (address);
if (it != m_Addresses.end ())
return &it->second;
}
auto it = m_Addresses.find (address);
if (it != m_Addresses.end ())
return &it->second;
return nullptr;
}
@@ -286,8 +242,6 @@ namespace client
{
auto ident = std::make_shared<i2p::data::IdentityEx>();
ident->FromBase64 (base64);
if (!m_Storage)
m_Storage = CreateStorage ();
m_Storage->AddAddress (ident);
m_Addresses[address] = ident->GetIdentHash ();
LogPrint (eLogInfo, "Addressbook: added ", address," -> ", ToAddress(ident->GetIdentHash ()));
@@ -295,15 +249,11 @@ namespace client
void AddressBook::InsertAddress (std::shared_ptr<const i2p::data::IdentityEx> address)
{
if (!m_Storage)
m_Storage = CreateStorage ();
m_Storage->AddAddress (address);
}
std::shared_ptr<const i2p::data::IdentityEx> AddressBook::GetAddress (const std::string& address)
{
if (!m_Storage)
m_Storage = CreateStorage ();
i2p::data::IdentHash ident;
if (!GetIdentHash (address, ident)) return nullptr;
return m_Storage->GetAddress (ident);
@@ -311,34 +261,19 @@ namespace client
void AddressBook::LoadHosts ()
{
if (!m_Storage)
m_Storage = CreateStorage ();
if (m_Storage->Load (m_Addresses) > 0)
{
m_IsLoaded = true;
return;
}
// try hosts.txt first
std::ifstream f (i2p::util::filesystem::GetFullPath ("hosts.txt").c_str (), std::ofstream::in); // in text mode
// then try hosts.txt
std::ifstream f (i2p::fs::DataDirPath("hosts.txt"), std::ifstream::in); // in text mode
if (f.is_open ())
{
LoadHostsFromStream (f);
m_IsLoaded = true;
}
else
{
// if not found download it from http://i2p-projekt.i2p/hosts.txt
LogPrint (eLogInfo, "Addressbook: hosts.txt not found, trying to download it from default subscription.");
if (!m_IsDownloading)
{
m_IsDownloading = true;
if (!m_DefaultSubscription)
m_DefaultSubscription = new AddressBookSubscription (*this, DEFAULT_SUBSCRIPTION_ADDRESS);
m_DefaultSubscription->CheckSubscription ();
}
}
}
void AddressBook::LoadHostsFromStream (std::istream& f)
@@ -383,7 +318,7 @@ namespace client
{
if (!m_Subscriptions.size ())
{
std::ifstream f (i2p::util::filesystem::GetFullPath ("subscriptions.txt").c_str (), std::ofstream::in); // in text mode
std::ifstream f (i2p::fs::DataDirPath ("subscriptions.txt"), std::ifstream::in); // in text mode
if (f.is_open ())
{
std::string s;
@@ -405,6 +340,11 @@ namespace client
void AddressBook::DownloadComplete (bool success)
{
m_IsDownloading = false;
if (success && m_DefaultSubscription)
{
m_DefaultSubscription.reset (nullptr);
m_IsLoaded = true;
}
if (m_SubscriptionsUpdateTimer)
{
m_SubscriptionsUpdateTimer->expires_from_now (boost::posix_time::minutes(
@@ -417,8 +357,8 @@ namespace client
void AddressBook::StartSubscriptions ()
{
LoadSubscriptions ();
if (!m_Subscriptions.size ()) return;
if (m_IsLoaded && m_Subscriptions.empty ()) return;
auto dest = i2p::client::context.GetSharedLocalDestination ();
if (dest)
{
@@ -442,18 +382,31 @@ namespace client
if (ecode != boost::asio::error::operation_aborted)
{
auto dest = i2p::client::context.GetSharedLocalDestination ();
if (!dest) return;
if (m_IsLoaded && !m_IsDownloading && dest->IsReady () && !m_Subscriptions.empty ())
if (!dest) {
LogPrint(eLogWarning, "Addressbook: missing local destination, skip subscription update");
return;
}
if (!m_IsDownloading && dest->IsReady ())
{
// pick random subscription
auto ind = rand () % m_Subscriptions.size();
m_IsDownloading = true;
m_Subscriptions[ind]->CheckSubscription ();
if (!m_IsLoaded)
{
// download it from http://i2p-projekt.i2p/hosts.txt
LogPrint (eLogInfo, "Addressbook: trying to download it from default subscription.");
if (!m_DefaultSubscription)
m_DefaultSubscription.reset (new AddressBookSubscription (*this, DEFAULT_SUBSCRIPTION_ADDRESS));
m_IsDownloading = true;
m_DefaultSubscription->CheckSubscription ();
}
else if (!m_Subscriptions.empty ())
{
// pick random subscription
auto ind = rand () % m_Subscriptions.size();
m_IsDownloading = true;
m_Subscriptions[ind]->CheckSubscription ();
}
}
else
{
if (!m_IsLoaded)
LoadHosts ();
// try it again later
m_SubscriptionsUpdateTimer->expires_from_now (boost::posix_time::minutes(INITIAL_SUBSCRIPTION_RETRY_TIMEOUT));
m_SubscriptionsUpdateTimer->async_wait (std::bind (&AddressBook::HandleSubscriptionsUpdateTimer,
@@ -496,7 +449,7 @@ namespace client
});
if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT)) == std::cv_status::timeout)
{
LogPrint (eLogError, "Subscription LeaseSet request timeout expired");
LogPrint (eLogError, "Addressbook: Subscription LeaseSet request timeout expired");
i2p::client::context.GetSharedLocalDestination ()->CancelDestinationRequest (ident);
}
}
@@ -508,6 +461,8 @@ namespace client
<< "Host: " << u.host_ << "\r\n"
<< "Accept: */*\r\n"
<< "User-Agent: Wget/1.11.4\r\n"
//<< "Accept-Encoding: gzip\r\n"
<< "X-Accept-Encoding: x-i2p-gzip;q=1.0, identity;q=0.5, deflate;q=0, gzip;q=0, *;q=0\r\n"
<< "Connection: close\r\n";
if (m_Etag.length () > 0) // etag
request << i2p::util::http::IF_NONE_MATCH << ": \"" << m_Etag << "\"\r\n";
@@ -546,7 +501,7 @@ namespace client
response >> status; // status
if (status == 200) // OK
{
bool isChunked = false;
bool isChunked = false, isGzip = false;
std::string header, statusMessage;
std::getline (response, statusMessage);
// read until new line meaning end of header
@@ -557,6 +512,8 @@ namespace client
if (colon != std::string::npos)
{
std::string field = header.substr (0, colon);
boost::to_lower (field); // field are not case-sensitive
colon++;
header.resize (header.length () - 1); // delete \r
if (field == i2p::util::http::ETAG)
m_Etag = header.substr (colon + 1);
@@ -564,6 +521,9 @@ namespace client
m_LastModified = header.substr (colon + 1);
else if (field == i2p::util::http::TRANSFER_ENCODING)
isChunked = !header.compare (colon + 1, std::string::npos, "chunked");
else if (field == i2p::util::http::CONTENT_ENCODING)
isGzip = !header.compare (colon + 1, std::string::npos, "gzip") ||
!header.compare (colon + 1, std::string::npos, "x-i2p-gzip");
}
}
LogPrint (eLogInfo, "Addressbook: ", m_Link, " ETag: ", m_Etag, " Last-Modified: ", m_LastModified);
@@ -571,13 +531,13 @@ namespace client
{
success = true;
if (!isChunked)
m_Book.LoadHostsFromStream (response);
success = ProcessResponse (response, isGzip);
else
{
// merge chunks
std::stringstream merged;
i2p::util::http::MergeChunkedResponse (response, merged);
m_Book.LoadHostsFromStream (merged);
success = ProcessResponse (merged, isGzip);
}
}
}
@@ -596,10 +556,27 @@ namespace client
LogPrint (eLogError, "Addressbook: Can't resolve ", u.host_);
if (!success)
LogPrint (eLogError, "Addressbook: download failed");
LogPrint (eLogError, "Addressbook: download hosts.txt from ", m_Link, " failed");
m_Book.DownloadComplete (success);
}
bool AddressBookSubscription::ProcessResponse (std::stringstream& s, bool isGzip)
{
if (isGzip)
{
std::stringstream uncompressed;
i2p::data::GzipInflator inflator;
inflator.Inflate (s, uncompressed);
if (!uncompressed.fail ())
m_Book.LoadHostsFromStream (uncompressed);
else
return false;
}
else
m_Book.LoadHostsFromStream (s);
return true;
}
}
}

View File

@@ -10,7 +10,6 @@
#include <memory>
#include <boost/asio.hpp>
#include "Base.h"
#include "util.h"
#include "Identity.h"
#include "Log.h"
@@ -36,6 +35,7 @@ namespace client
virtual void AddAddress (std::shared_ptr<const i2p::data::IdentityEx> address) = 0;
virtual void RemoveAddress (const i2p::data::IdentHash& ident) = 0;
virtual bool Init () = 0;
virtual int Load (std::map<std::string, i2p::data::IdentHash>& addresses) = 0;
virtual int Save (const std::map<std::string, i2p::data::IdentHash>& addresses) = 0;
};
@@ -65,7 +65,6 @@ namespace client
void StartSubscriptions ();
void StopSubscriptions ();
AddressBookStorage * CreateStorage ();
void LoadHosts ();
void LoadSubscriptions ();
@@ -78,7 +77,7 @@ namespace client
AddressBookStorage * m_Storage;
volatile bool m_IsLoaded, m_IsDownloading;
std::vector<AddressBookSubscription *> m_Subscriptions;
AddressBookSubscription * m_DefaultSubscription; // in case if we don't know any addresses yet
std::unique_ptr<AddressBookSubscription> m_DefaultSubscription; // in case if we don't know any addresses yet
boost::asio::deadline_timer * m_SubscriptionsUpdateTimer;
};
@@ -92,6 +91,7 @@ namespace client
private:
void Request ();
bool ProcessResponse (std::stringstream& s, bool isGzip = false);
private:

View File

@@ -6,6 +6,18 @@ namespace i2p
{
namespace data
{
static const char T32[32] = {
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
'i', 'k', 'k', 'l', 'm', 'n', 'o', 'p',
'q', 'r', 't', 't', 'u', 'v', 'w', 'x',
'y', 'z', '2', '3', '4', '5', '6', '7',
};
const char * GetBase32SubstitutionTable ()
{
return T32;
}
static void iT64Build(void);
/*
@@ -16,7 +28,7 @@ namespace data
* Direct Substitution Table
*/
static char T64[64] = {
static const char T64[64] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
@@ -190,6 +202,13 @@ namespace data
return outCount;
}
size_t Base64EncodingBufferSize (const size_t input_size)
{
auto d = div (input_size, 3);
if (d.rem) d.quot++;
return 4*d.quot;
}
/*
*
* iT64
@@ -295,6 +314,44 @@ namespace data
}
}
bool GzipInflator::Inflate (const uint8_t * in, size_t inLen, std::ostream& s)
{
m_IsDirty = true;
uint8_t * out = new uint8_t[GZIP_CHUNK_SIZE];
m_Inflator.next_in = const_cast<uint8_t *>(in);
m_Inflator.avail_in = inLen;
int ret;
do
{
m_Inflator.next_out = out;
m_Inflator.avail_out = GZIP_CHUNK_SIZE;
ret = inflate (&m_Inflator, Z_NO_FLUSH);
if (ret < 0)
{
LogPrint (eLogError, "Decompression error ", ret);
inflateEnd (&m_Inflator);
s.setstate(std::ios_base::failbit);
break;
}
else
s.write ((char *)out, GZIP_CHUNK_SIZE - m_Inflator.avail_out);
}
while (!m_Inflator.avail_out); // more data to read
delete[] out;
return ret == Z_STREAM_END || ret < 0;
}
void GzipInflator::Inflate (std::istream& in, std::ostream& out)
{
uint8_t * buf = new uint8_t[GZIP_CHUNK_SIZE];
while (!in.eof ())
{
in.read ((char *)buf, GZIP_CHUNK_SIZE);
Inflate (buf, in.gcount (), out);
}
delete[] buf;
}
GzipDeflator::GzipDeflator (): m_IsDirty (false)
{
memset (&m_Deflator, 0, sizeof (m_Deflator));
@@ -327,7 +384,7 @@ namespace data
LogPrint (eLogError, "Compression error ", err);
return 0;
}
}
}
}
}

13
Base.h
View File

@@ -5,6 +5,7 @@
#include <string.h>
#include <string>
#include <zlib.h>
#include <iostream>
namespace i2p
{
@@ -12,11 +13,17 @@ namespace data
{
size_t ByteStreamToBase64 (const uint8_t * InBuffer, size_t InCount, char * OutBuffer, size_t len);
size_t Base64ToByteStream (const char * InBuffer, size_t InCount, uint8_t * OutBuffer, size_t len );
const char * GetBase32SubstitutionTable ();
const char * GetBase64SubstitutionTable ();
size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen);
size_t ByteStreamToBase32 (const uint8_t * InBuf, size_t len, char * outBuf, size_t outLen);
/**
Compute the size for a buffer to contain encoded base64 given that the size of the input is input_size bytes
*/
size_t Base64EncodingBufferSize(const size_t input_size);
template<int sz>
class Tag
{
@@ -87,6 +94,7 @@ namespace data
};
};
const size_t GZIP_CHUNK_SIZE = 16384;
class GzipInflator
{
public:
@@ -95,7 +103,10 @@ namespace data
~GzipInflator ();
size_t Inflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen);
bool Inflate (const uint8_t * in, size_t inLen, std::ostream& s);
// return true when finshed or error, s failbit will be set in case of error
void Inflate (std::istream& in, std::ostream& out);
private:
z_stream m_Inflator;

View File

@@ -3,7 +3,7 @@
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include "Config.h"
#include "util.h"
#include "FS.h"
#include "Log.h"
#include "Identity.h"
#include "ClientContext.h"
@@ -37,6 +37,8 @@ namespace client
m_SharedLocalDestination->Start ();
}
m_AddressBook.Start ();
std::shared_ptr<ClientDestination> localDestination;
bool httproxy; i2p::config::GetOption("httpproxy.enabled", httproxy);
if (httproxy) {
@@ -94,20 +96,20 @@ namespace client
m_BOBCommandChannel = new BOBCommandChannel (bobAddr, bobPort);
m_BOBCommandChannel->Start ();
}
m_AddressBook.Start ();
}
void ClientContext::Stop ()
{
if (m_HttpProxy) {
if (m_HttpProxy)
{
LogPrint(eLogInfo, "Clients: stopping HTTP Proxy");
m_HttpProxy->Stop();
delete m_HttpProxy;
m_HttpProxy = nullptr;
}
if (m_SocksProxy) {
if (m_SocksProxy)
{
LogPrint(eLogInfo, "Clients: stopping SOCKS Proxy");
m_SocksProxy->Stop();
delete m_SocksProxy;
@@ -152,10 +154,10 @@ namespace client
m_SharedLocalDestination = nullptr;
}
void ClientContext::LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename, i2p::data::SigningKeyType sigType)
void ClientContext::LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename, i2p::data::SigningKeyType sigType)
{
std::string fullPath = i2p::util::filesystem::GetFullPath (filename);
std::ifstream s(fullPath.c_str (), std::ifstream::binary);
std::string fullPath = i2p::fs::DataDirPath (filename);
std::ifstream s(fullPath, std::ifstream::binary);
if (s.is_open ())
{
s.seekg (0, std::ios::end);
@@ -256,14 +258,17 @@ namespace client
void ClientContext::ReadTunnels ()
{
boost::property_tree::ptree pt;
std::string pathTunnelsConfigFile = i2p::util::filesystem::GetTunnelsConfigFile().string();
try
std::string tunConf; i2p::config::GetOption("tunconf", tunConf);
if (tunConf == "")
tunConf = i2p::fs::DataDirPath ("tunnels.cfg");
LogPrint(eLogDebug, "FS: tunnels config file: ", tunConf);
try
{
boost::property_tree::read_ini (pathTunnelsConfigFile, pt);
}
catch (std::exception& ex)
boost::property_tree::read_ini (tunConf, pt);
}
catch (std::exception& ex)
{
LogPrint (eLogWarning, "Clients: Can't read ", pathTunnelsConfigFile, ": ", ex.what ());
LogPrint (eLogWarning, "Clients: Can't read ", tunConf, ": ", ex.what ());
return;
}
@@ -304,7 +309,7 @@ namespace client
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)
else if (type == I2P_TUNNELS_SECTION_TYPE_SERVER || type == I2P_TUNNELS_SECTION_TYPE_HTTP || type == I2P_TUNNELS_SECTION_TYPE_IRC)
{
// mandatory params
std::string host = section.second.get<std::string> (I2P_SERVER_TUNNEL_HOST);
@@ -312,7 +317,10 @@ namespace client
std::string keys = section.second.get<std::string> (I2P_SERVER_TUNNEL_KEYS);
// optional params
int inPort = section.second.get (I2P_SERVER_TUNNEL_INPORT, 0);
std::string accessList = section.second.get (I2P_SERVER_TUNNEL_ACCESS_LIST, "");
std::string accessList = section.second.get (I2P_SERVER_TUNNEL_ACCESS_LIST, "");
std::string hostOverride = section.second.get (I2P_SERVER_TUNNEL_HOST_OVERRIDE, "");
std::string webircpass = section.second.get<std::string> (I2P_SERVER_TUNNEL_WEBIRC_PASSWORD, "");
bool gzip = section.second.get (I2P_SERVER_TUNNEL_GZIP, true);
i2p::data::SigningKeyType sigType = section.second.get (I2P_SERVER_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256);
// I2CP
std::map<std::string, std::string> options;
@@ -324,9 +332,15 @@ namespace client
localDestination = FindLocalDestination (k.GetPublic ()->GetIdentHash ());
if (!localDestination)
localDestination = CreateNewLocalDestination (k, true, &options);
I2PServerTunnel * serverTunnel = (type == I2P_TUNNELS_SECTION_TYPE_HTTP) ?
new I2PServerTunnelHTTP (name, host, port, localDestination, inPort) :
new I2PServerTunnel (name, host, port, localDestination, inPort);
I2PServerTunnel * serverTunnel;
if (type == I2P_TUNNELS_SECTION_TYPE_HTTP)
serverTunnel = new I2PServerTunnelHTTP (name, host, port, localDestination, hostOverride, inPort, gzip);
else if (type == I2P_TUNNELS_SECTION_TYPE_IRC)
serverTunnel = new I2PServerTunnelIRC (name, host, port, localDestination, webircpass, inPort, gzip);
else // regular server tunnel by default
serverTunnel = new I2PServerTunnel (name, host, port, localDestination, inPort, gzip);
if (accessList.length () > 0)
{
std::set<i2p::data::IdentHash> idents;
@@ -351,7 +365,7 @@ namespace client
numServerTunnels++;
}
else
LogPrint (eLogWarning, "Clients: Unknown section type=", type, " of ", name, " in ", pathTunnelsConfigFile);
LogPrint (eLogWarning, "Clients: Unknown section type=", type, " of ", name, " in ", tunConf);
}
catch (std::exception& ex)

View File

@@ -21,6 +21,7 @@ namespace client
const char I2P_TUNNELS_SECTION_TYPE_CLIENT[] = "client";
const char I2P_TUNNELS_SECTION_TYPE_SERVER[] = "server";
const char I2P_TUNNELS_SECTION_TYPE_HTTP[] = "http";
const char I2P_TUNNELS_SECTION_TYPE_IRC[] = "irc";
const char I2P_CLIENT_TUNNEL_PORT[] = "port";
const char I2P_CLIENT_TUNNEL_ADDRESS[] = "address";
const char I2P_CLIENT_TUNNEL_DESTINATION[] = "destination";
@@ -28,11 +29,14 @@ namespace client
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_HOST_OVERRIDE[] = "hostoverride";
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 I2P_SERVER_TUNNEL_GZIP[] = "gzip";
const char I2P_SERVER_TUNNEL_WEBIRC_PASSWORD[] = "webircpassword";
class ClientContext
{

View File

@@ -113,6 +113,8 @@ namespace config {
("log", value<std::string>()->default_value(""), "Logs destination: stdout, file (stdout if not set, file - otherwise, for compatibility)")
("logfile", value<std::string>()->default_value(""), "Path to logfile (stdout if not set, autodetect if daemon)")
("loglevel", value<std::string>()->default_value("info"), "Set the minimal level of log messages (debug, info, warn, error)")
("family", value<std::string>()->default_value(""), "Specify a family, router belongs to")
("datadir", value<std::string>()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)")
("host", value<std::string>()->default_value("0.0.0.0"), "External IP")
("port", value<uint16_t>()->default_value(0), "Port to listen for incoming connections (default: auto)")
("ipv6", value<bool>()->zero_tokens()->default_value(false), "Enable communication through ipv6")
@@ -138,7 +140,7 @@ namespace config {
("httpproxy.enabled", value<bool>()->default_value(true), "Enable or disable HTTP Proxy")
("httpproxy.address", value<std::string>()->default_value("127.0.0.1"), "HTTP Proxy listen address")
("httpproxy.port", value<uint16_t>()->default_value(4444), "HTTP Proxy listen port")
("httpproxy.keys", value<std::string>()->default_value("httpproxy-keys.dat"), "HTTP Proxy encryption keys")
("httpproxy.keys", value<std::string>()->default_value(""), "File to persist HTTP Proxy keys")
;
options_description socksproxy("SOCKS Proxy options");
@@ -146,7 +148,9 @@ namespace config {
("socksproxy.enabled", value<bool>()->default_value(true), "Enable or disable SOCKS Proxy")
("socksproxy.address", value<std::string>()->default_value("127.0.0.1"), "SOCKS Proxy listen address")
("socksproxy.port", value<uint16_t>()->default_value(4447), "SOCKS Proxy listen port")
("socksproxy.keys", value<std::string>()->default_value("socksproxy-keys.dat"), "SOCKS Proxy encryption keys")
("socksproxy.keys", value<std::string>()->default_value(""), "File to persist SOCKS Proxy keys")
("socksproxy.outproxy", value<std::string>()->default_value("127.0.0.1"), "Upstream outproxy address for SOCKS Proxy")
("socksproxy.outproxyport", value<uint16_t>()->default_value(9050), "Upstream outproxy port for SOCKS Proxy")
;
options_description sam("SAM bridge options");
@@ -190,7 +194,7 @@ namespace config {
| boost::program_options::command_line_style::allow_long_disguise;
style &= ~ boost::program_options::command_line_style::allow_guessing;
store(parse_command_line(argc, argv, m_OptionsDesc, style, old_syntax_parser), m_Options);
} catch (boost::program_options::error e) {
} catch (boost::program_options::error& e) {
std::cerr << "args: " << e.what() << std::endl;
exit(EXIT_FAILURE);
}
@@ -203,19 +207,22 @@ namespace config {
}
void ParseConfig(const std::string& path) {
if (path == "")
return;
if (path == "") return;
std::ifstream config(path, std::ios::in);
if (!config.is_open()) {
if (!config.is_open())
{
std::cerr << "missing/unreadable config file: " << path << std::endl;
exit(EXIT_FAILURE);
}
try {
store(boost::program_options::parse_config_file(config, m_OptionsDesc), m_Options);
} catch (boost::program_options::error e) {
try
{
store(boost::program_options::parse_config_file(config, m_OptionsDesc), m_Options);
}
catch (boost::program_options::error& e)
{
std::cerr << e.what() << std::endl;
exit(EXIT_FAILURE);
};
@@ -223,6 +230,15 @@ namespace config {
void Finalize() {
notify(m_Options);
};
}
bool IsDefault(const char *name) {
if (!m_Options.count(name))
throw "try to check non-existent option";
if (m_Options[name].defaulted())
return true;
return false;
}
} // namespace config
} // namespace i2p

View File

@@ -30,7 +30,7 @@ namespace config {
/**
* @brief Parse cmdline parameters, and show help if requested
* @param argc Cmdline arguments count, should be passed from main().
* @param argv Cmdline parameters array, should be passed from main()
* @param argv Cmdline parameters array, should be passed from main()
*
* If --help is given in parameters, shows it's list with description
* terminates the program with exitcode 0.
@@ -90,10 +90,17 @@ namespace config {
bool SetOption(const char *name, const T& value) {
if (!m_Options.count(name))
return false;
m_Options[name] = value;
m_Options.at(name).value() = value;
notify(m_Options);
return true;
}
}
/**
* @brief Check is value explicitly given or default
* @param name Name of checked parameter
* @return true if value set to default, false othervise
*/
bool IsDefault(const char *name);
}
}

View File

@@ -70,7 +70,7 @@ namespace crypto
void operator^=(const ChipherBlock& other) // XOR
{
#if defined(__x86_64__) // for Intel x64
#if defined(__x86_64__) || defined(__SSE__) // for Intel x84 or with SSE
__asm__
(
"movups (%[buf]), %%xmm0 \n"

View File

@@ -5,6 +5,7 @@
#include "Config.h"
#include "Log.h"
#include "FS.h"
#include "Base.h"
#include "version.h"
#include "Transports.h"
@@ -14,7 +15,6 @@
#include "Tunnel.h"
#include "NetDb.h"
#include "Garlic.h"
#include "util.h"
#include "Streaming.h"
#include "Destination.h"
#include "HTTPServer.h"
@@ -63,9 +63,18 @@ namespace i2p
i2p::config::Init();
i2p::config::ParseCmdline(argc, argv);
std::string config = i2p::util::filesystem::GetConfigFile().string();
std::string tunconf = i2p::util::filesystem::GetTunnelsConfigFile().string();
std::string datadir = i2p::util::filesystem::GetDataDir().string();
std::string config; i2p::config::GetOption("conf", config);
std::string datadir; i2p::config::GetOption("datadir", datadir);
i2p::fs::DetectDataDir(datadir, IsService());
i2p::fs::Init();
datadir = i2p::fs::GetDataDir();
if (config == "")
{
config = i2p::fs::DataDirPath("i2p.conf");
// use i2p.cong only if exists
if (!i2p::fs::Exists (config)) config = ""; /* reset */
}
i2p::config::ParseConfig(config);
i2p::config::Finalize();
@@ -79,18 +88,17 @@ namespace i2p
LogPrint(eLogInfo, "i2pd v", VERSION, " starting");
LogPrint(eLogDebug, "FS: main config file: ", config);
LogPrint(eLogDebug, "FS: tunnels config: ", tunconf);
LogPrint(eLogDebug, "FS: data directory: ", datadir);
uint16_t port; i2p::config::GetOption("port", port);
if (port)
if (!i2p::config::IsDefault("port"))
{
LogPrint(eLogInfo, "Daemon: accepting incoming connections at port ", port);
i2p::context.UpdatePort (port);
}
std::string host; i2p::config::GetOption("host", host);
if (host != "0.0.0.0")
if (!i2p::config::IsDefault("host"))
{
LogPrint(eLogInfo, "Daemon: setting address for incoming connections to ", host);
i2p::context.UpdateAddress (boost::asio::ip::address::from_string (host));
@@ -109,6 +117,8 @@ namespace i2p
LogPrint(eLogInfo, "Daemon: router will be floodfill");
i2p::context.SetFloodfill (true);
}
else
i2p::context.SetFloodfill (false);
if (bandwidth != '-')
{
LogPrint(eLogInfo, "Daemon: bandwidth set to ", bandwidth);
@@ -118,15 +128,23 @@ namespace i2p
i2p::context.SetHighBandwidth ();
else
i2p::context.SetLowBandwidth ();
}
}
else if (isFloodfill)
{
LogPrint(eLogInfo, "Daemon: floodfill bandwidth set to 'extra'");
i2p::context.SetExtraBandwidth ();
}
else
{
LogPrint(eLogInfo, "Daemon: bandwidth set to 'low'");
i2p::context.SetLowBandwidth ();
}
std::string family; i2p::config::GetOption("family", family);
i2p::context.SetFamily (family);
if (family.length () > 0)
LogPrint(eLogInfo, "Daemon: family set to ", family);
return true;
}
@@ -139,18 +157,9 @@ namespace i2p
if (isDaemon && (logs == "" || logs == "stdout"))
logs = "file";
if (logs == "file")
{
if (logs == "file") {
if (logfile == "")
{
// use autodetect of logfile
logfile = IsService () ? "/var/log" : i2p::util::filesystem::GetDataDir().string();
#ifndef _WIN32
logfile.append("/i2pd.log");
#else
logfile.append("\\i2pd.log");
#endif
}
logfile = i2p::fs::DataDirPath("i2pd.log");
StartLog (logfile);
} else {
// use stdout

View File

@@ -20,17 +20,18 @@ namespace i2p
virtual bool init(int argc, char* argv[]);
virtual bool start();
virtual bool stop();
virtual void run () {};
bool isLogging;
bool isDaemon;
bool running;
protected:
Daemon_Singleton();
virtual ~Daemon_Singleton();
bool IsService () const;
bool IsService () const;
// d-pointer for httpServer, httpProxy, etc.
class Daemon_Singleton_Private;
@@ -47,9 +48,10 @@ namespace i2p
return instance;
}
virtual bool init(int argc, char* argv[]);
virtual bool start();
virtual bool stop();
bool init(int argc, char* argv[]);
bool start();
bool stop();
void run ();
};
#else
class DaemonLinux : public Daemon_Singleton
@@ -61,8 +63,10 @@ namespace i2p
return instance;
}
virtual bool start();
virtual bool stop();
bool start();
bool stop();
; void run ();
private:
std::string pidfile;
int pidFH;

View File

@@ -4,22 +4,23 @@
#include <signal.h>
#include <stdlib.h>
#include <thread>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "Config.h"
#include "FS.h"
#include "Log.h"
#include "util.h"
void handle_signal(int sig)
{
switch (sig)
{
case SIGHUP:
LogPrint(eLogInfo, "Daemon: Got SIGHUP, doing nothing");
// TODO:
break;
LogPrint(eLogInfo, "Daemon: Got SIGHUP, reopening log...");
ReopenLogFile ();
break;
case SIGABRT:
case SIGTERM:
case SIGINT:
@@ -55,7 +56,7 @@ namespace i2p
LogPrint(eLogError, "Daemon: could not create process group.");
return false;
}
std::string d(i2p::util::filesystem::GetDataDir().string ()); // make a copy
std::string d = i2p::fs::GetDataDir();
if (chdir(d.c_str()) != 0)
{
LogPrint(eLogError, "Daemon: could not chdir: ", strerror(errno));
@@ -75,8 +76,7 @@ namespace i2p
// this code is c-styled and a bit ugly, but we need fd for locking pidfile
std::string pidfile; i2p::config::GetOption("pidfile", pidfile);
if (pidfile == "") {
pidfile = IsService () ? "/var/run" : i2p::util::filesystem::GetDataDir().string();
pidfile.append("/i2pd.pid");
pidfile = i2p::fs::DataDirPath("i2pd.pid");
}
if (pidfile != "") {
pidFH = open(pidfile.c_str(), O_RDWR | O_CREAT, 0600);
@@ -115,10 +115,18 @@ namespace i2p
bool DaemonLinux::stop()
{
unlink(pidfile.c_str());
i2p::fs::Remove(pidfile);
return Daemon_Singleton::stop();
}
void DaemonLinux::run ()
{
while (running)
{
std::this_thread::sleep_for (std::chrono::seconds(1));
}
}
}
}

View File

@@ -5,7 +5,7 @@
#ifdef _WIN32
#include "./Win32/Win32Service.h"
#include "Win32/Win32App.h"
namespace i2p
{
@@ -16,65 +16,40 @@ namespace i2p
setlocale(LC_CTYPE, "");
SetConsoleCP(1251);
SetConsoleOutputCP(1251);
setlocale(LC_ALL, "Russian");
setlocale(LC_ALL, "Russian");
return Daemon_Singleton::init(argc, argv);
}
if (!Daemon_Singleton::init(argc, argv)) return false;
if (I2PService::isService())
isDaemon = 1;
else
isDaemon = 0;
std::string serviceControl; i2p::config::GetOption("svcctl", serviceControl);
if (serviceControl == "install")
{
LogPrint(eLogInfo, "WinSVC: installing ", SERVICE_NAME, " as service");
InstallService(
SERVICE_NAME, // Name of service
SERVICE_DISPLAY_NAME, // Name to display
SERVICE_START_TYPE, // Service start type
SERVICE_DEPENDENCIES, // Dependencies
SERVICE_ACCOUNT, // Service running account
SERVICE_PASSWORD // Password of the account
);
exit(0);
}
else if (serviceControl == "remove")
{
LogPrint(eLogInfo, "WinSVC: uninstalling ", SERVICE_NAME, " service");
UninstallService(SERVICE_NAME);
exit(0);
}
if (isDaemon == 1)
{
LogPrint(eLogDebug, "Daemon: running as service");
I2PService service(SERVICE_NAME);
if (!I2PService::Run(service))
{
LogPrint(eLogError, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError());
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
else
LogPrint(eLogDebug, "Daemon: running as user");
return true;
}
bool DaemonWin32::start()
{
setlocale(LC_CTYPE, "");
SetConsoleCP(1251);
SetConsoleOutputCP(1251);
setlocale(LC_ALL, "Russian");
return Daemon_Singleton::start();
if (!i2p::win32::StartWin32App ()) return false;
// override log
i2p::config::SetOption("log", std::string ("file"));
bool ret = Daemon_Singleton::start();
if (ret && IsLogToFile ())
{
// TODO: find out where this garbage to console comes from
SetStdHandle(STD_OUTPUT_HANDLE, INVALID_HANDLE_VALUE);
SetStdHandle(STD_ERROR_HANDLE, INVALID_HANDLE_VALUE);
}
return ret;
}
bool DaemonWin32::stop()
{
{
i2p::win32::StopWin32App ();
return Daemon_Singleton::stop();
}
}
void DaemonWin32::run ()
{
i2p::win32::RunWin32App ();
}
}
}

View File

@@ -66,7 +66,7 @@ namespace datagram
msgs.push_back (i2p::tunnel::TunnelMessageBlock
{
i2p::tunnel::eDeliveryTypeTunnel,
leases[i].tunnelGateway, leases[i].tunnelID,
leases[i]->tunnelGateway, leases[i]->tunnelID,
garlic
});
outboundTunnel->SendTunnelDataMsg (msgs);

View File

@@ -2,8 +2,9 @@
#include <cassert>
#include <boost/lexical_cast.hpp>
#include <openssl/rand.h>
#include "Log.h"
#include "util.h"
#include "FS.h"
#include "Crypto.h"
#include "Timestamp.h"
#include "NetDb.h"
@@ -17,7 +18,8 @@ namespace client
const std::map<std::string, std::string> * params):
m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service),
m_Keys (keys), m_IsPublic (isPublic), m_PublishReplyToken (0),
m_DatagramDestination (nullptr), m_PublishConfirmationTimer (m_Service), m_CleanupTimer (m_Service)
m_DatagramDestination (nullptr), m_PublishConfirmationTimer (m_Service),
m_PublishVerificationTimer (m_Service), m_CleanupTimer (m_Service)
{
if (m_IsPublic)
PersistTemporaryKeys ();
@@ -139,7 +141,7 @@ namespace client
m_IsRunning = true;
m_Pool->SetLocalDestination (shared_from_this ());
m_Pool->SetActive (true);
m_Thread = new std::thread (std::bind (&ClientDestination::Run, this));
m_Thread = new std::thread (std::bind (&ClientDestination::Run, shared_from_this ()));
m_StreamingDestination = std::make_shared<i2p::stream::StreamingDestination> (shared_from_this ()); // TODO:
m_StreamingDestination->Start ();
for (auto it: m_StreamingDestinationsByPorts)
@@ -147,7 +149,7 @@ namespace client
m_CleanupTimer.expires_from_now (boost::posix_time::minutes (DESTINATION_CLEANUP_TIMEOUT));
m_CleanupTimer.async_wait (std::bind (&ClientDestination::HandleCleanupTimer,
this, std::placeholders::_1));
shared_from_this (), std::placeholders::_1));
}
}
@@ -156,6 +158,8 @@ namespace client
if (m_IsRunning)
{
m_CleanupTimer.cancel ();
m_PublishConfirmationTimer.cancel ();
m_PublishVerificationTimer.cancel ();
m_IsRunning = false;
m_StreamingDestination->Stop ();
m_StreamingDestination = nullptr;
@@ -187,16 +191,17 @@ namespace client
auto it = m_RemoteLeaseSets.find (ident);
if (it != m_RemoteLeaseSets.end ())
{
if (it->second->HasNonExpiredLeases ())
if (!it->second->IsExpired ())
return it->second;
else
LogPrint (eLogWarning, "Destination: All leases of remote LeaseSet expired");
LogPrint (eLogWarning, "Destination: remote LeaseSet expired");
}
else
{
auto ls = i2p::data::netdb.FindLeaseSet (ident);
if (ls)
if (ls && !ls->IsExpired ())
{
ls->PopulateLeases (); // since we don't store them in netdb
m_RemoteLeaseSets[ident] = ls;
return ls;
}
@@ -225,21 +230,22 @@ namespace client
} data;
memcpy (data.k, key, 32);
memcpy (data.t, tag, 32);
m_Service.post ([this,data](void)
auto s = shared_from_this ();
m_Service.post ([s,data](void)
{
this->AddSessionKey (data.k, data.t);
s->AddSessionKey (data.k, data.t);
});
return true;
}
void ClientDestination::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
{
m_Service.post (std::bind (&ClientDestination::HandleGarlicMessage, this, msg));
m_Service.post (std::bind (&ClientDestination::HandleGarlicMessage, shared_from_this (), msg));
}
void ClientDestination::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
{
m_Service.post (std::bind (&ClientDestination::HandleDeliveryStatusMessage, this, msg));
m_Service.post (std::bind (&ClientDestination::HandleDeliveryStatusMessage, shared_from_this (), msg));
}
void ClientDestination::HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from)
@@ -282,27 +288,37 @@ namespace client
if (it != m_RemoteLeaseSets.end ())
{
leaseSet = it->second;
leaseSet->Update (buf + offset, len - offset);
if (leaseSet->IsValid ())
LogPrint (eLogDebug, "Remote LeaseSet updated");
else
{
LogPrint (eLogDebug, "Remote LeaseSet update failed");
m_RemoteLeaseSets.erase (it);
leaseSet = nullptr;
if (leaseSet->IsNewer (buf + offset, len - offset))
{
leaseSet->Update (buf + offset, len - offset);
if (leaseSet->IsValid ())
LogPrint (eLogDebug, "Remote LeaseSet updated");
else
{
LogPrint (eLogDebug, "Remote LeaseSet update failed");
m_RemoteLeaseSets.erase (it);
leaseSet = nullptr;
}
}
else
LogPrint (eLogDebug, "Remote LeaseSet is older. Not updated");
}
else
{
leaseSet = std::make_shared<i2p::data::LeaseSet> (buf + offset, len - offset);
if (leaseSet->IsValid ())
{
LogPrint (eLogDebug, "New remote LeaseSet added");
m_RemoteLeaseSets[buf + DATABASE_STORE_KEY_OFFSET] = leaseSet;
if (leaseSet->GetIdentHash () != GetIdentHash ())
{
LogPrint (eLogDebug, "New remote LeaseSet added");
m_RemoteLeaseSets[buf + DATABASE_STORE_KEY_OFFSET] = leaseSet;
}
else
LogPrint (eLogDebug, "Own remote LeaseSet dropped");
}
else
{
LogPrint (eLogError, "New remote LeaseSet verification failed");
LogPrint (eLogError, "New remote LeaseSet failed");
leaseSet = nullptr;
}
}
@@ -370,6 +386,10 @@ namespace client
LogPrint (eLogDebug, "Destination: Publishing LeaseSet confirmed");
m_ExcludedFloodfills.clear ();
m_PublishReplyToken = 0;
// schedule verification
m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_VERIFICATION_TIMEOUT));
m_PublishVerificationTimer.async_wait (std::bind (&ClientDestination::HandlePublishVerificationTimer,
shared_from_this (), std::placeholders::_1));
}
else
i2p::garlic::GarlicDestination::HandleDeliveryStatusMessage (msg);
@@ -380,7 +400,10 @@ namespace client
i2p::garlic::GarlicDestination::SetLeaseSetUpdated ();
UpdateLeaseSet ();
if (m_IsPublic)
{
m_PublishVerificationTimer.cancel ();
Publish ();
}
}
void ClientDestination::Publish ()
@@ -401,7 +424,6 @@ namespace client
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)
{
@@ -415,7 +437,7 @@ namespace client
auto msg = WrapMessage (floodfill, i2p::CreateDatabaseStoreMsg (m_LeaseSet, m_PublishReplyToken));
m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT));
m_PublishConfirmationTimer.async_wait (std::bind (&ClientDestination::HandlePublishConfirmationTimer,
this, std::placeholders::_1));
shared_from_this (), std::placeholders::_1));
outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, msg);
}
@@ -432,6 +454,34 @@ namespace client
}
}
void ClientDestination::HandlePublishVerificationTimer (const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
{
auto s = shared_from_this ();
RequestLeaseSet (GetIdentHash (),
// "this" added due to bug in gcc 4.7-4.8
[s,this](std::shared_ptr<i2p::data::LeaseSet> leaseSet)
{
if (leaseSet)
{
if (s->m_LeaseSet && *s->m_LeaseSet == *leaseSet)
{
// we got latest LeasetSet
LogPrint (eLogDebug, "Destination: published LeaseSet verified");
s->m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_REGULAR_VERIFICATION_INTERNAL));
s->m_PublishVerificationTimer.async_wait (std::bind (&ClientDestination::HandlePublishVerificationTimer, s, std::placeholders::_1));
return;
}
}
else
LogPrint (eLogWarning, "Destination: couldn't find published LeaseSet");
// we have to publish again
s->Publish ();
});
}
}
void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len)
{
uint32_t length = bufbe32toh (buf);
@@ -463,18 +513,24 @@ namespace client
}
}
void ClientDestination::CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port) {
assert(streamRequestComplete);
void ClientDestination::CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port)
{
if (!streamRequestComplete)
{
LogPrint (eLogError, "Destination: request callback is not specified in CreateStream");
return;
}
auto leaseSet = FindLeaseSet (dest);
if (leaseSet)
streamRequestComplete(CreateStream (leaseSet, port));
else
{
auto s = shared_from_this ();
RequestDestination (dest,
[this, streamRequestComplete, port](std::shared_ptr<i2p::data::LeaseSet> ls)
[s, streamRequestComplete, port](std::shared_ptr<i2p::data::LeaseSet> ls)
{
if (ls)
streamRequestComplete(CreateStream (ls, port));
streamRequestComplete(s->CreateStream (ls, port));
else
streamRequestComplete (nullptr);
});
@@ -520,9 +576,9 @@ namespace client
return false;
}
std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::CreateStreamingDestination (int port)
std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::CreateStreamingDestination (int port, bool gzip)
{
auto dest = std::make_shared<i2p::stream::StreamingDestination> (shared_from_this (), port);
auto dest = std::make_shared<i2p::stream::StreamingDestination> (shared_from_this (), port, gzip);
if (port)
m_StreamingDestinationsByPorts[port] = dest;
else // update default
@@ -555,7 +611,11 @@ namespace client
{
auto it = s->m_LeaseSetRequests.find (dest);
if (it != s->m_LeaseSetRequests.end ())
s->m_LeaseSetRequests.erase (it);
{
auto requestComplete = it->second->requestComplete;
s->m_LeaseSetRequests.erase (it);
if (requestComplete) requestComplete (nullptr);
}
});
}
@@ -573,8 +633,8 @@ namespace client
if (!SendLeaseSetRequest (dest, floodfill, request))
{
// request failed
if (request->requestComplete) request->requestComplete (nullptr);
m_LeaseSetRequests.erase (dest);
if (request->requestComplete) request->requestComplete (nullptr);
}
}
else // duplicate
@@ -585,19 +645,23 @@ namespace client
}
}
else
{
LogPrint (eLogError, "Destination: Can't request LeaseSet, no floodfills found");
if (requestComplete) requestComplete (nullptr);
}
}
bool ClientDestination::SendLeaseSetRequest (const i2p::data::IdentHash& dest,
std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request)
{
auto replyTunnel = m_Pool->GetNextInboundTunnel ();
if (!replyTunnel) LogPrint (eLogError, "Destination: Can't send LeaseSet request, no inbound tunnels found");
auto outboundTunnel = m_Pool->GetNextOutboundTunnel ();
if (!outboundTunnel) LogPrint (eLogError, "Destination: Can't send LeaseSet request, no outbound tunnels found");
if (!request->replyTunnel || !request->replyTunnel->IsEstablished ())
request->replyTunnel = m_Pool->GetNextInboundTunnel ();
if (!request->replyTunnel) LogPrint (eLogError, "Destination: Can't send LeaseSet request, no inbound tunnels found");
if (!request->outboundTunnel || !request->outboundTunnel->IsEstablished ())
request->outboundTunnel = m_Pool->GetNextOutboundTunnel ();
if (!request->outboundTunnel) LogPrint (eLogError, "Destination: Can't send LeaseSet request, no outbound tunnels found");
if (replyTunnel && outboundTunnel)
if (request->replyTunnel && request->outboundTunnel)
{
request->excluded.insert (nextFloodfill->GetIdentHash ());
request->requestTime = i2p::util::GetSecondsSinceEpoch ();
@@ -610,8 +674,8 @@ namespace client
auto msg = WrapMessage (nextFloodfill,
CreateLeaseSetDatabaseLookupMsg (dest, request->excluded,
replyTunnel.get (), replyKey, replyTag));
outboundTunnel->SendTunnelDataMsg (
request->replyTunnel, replyKey, replyTag));
request->outboundTunnel->SendTunnelDataMsg (
{
i2p::tunnel::TunnelMessageBlock
{
@@ -621,7 +685,7 @@ namespace client
});
request->requestTimeoutTimer.expires_from_now (boost::posix_time::seconds(LEASESET_REQUEST_TIMEOUT));
request->requestTimeoutTimer.async_wait (std::bind (&ClientDestination::HandleRequestTimoutTimer,
this, std::placeholders::_1, dest));
shared_from_this (), std::placeholders::_1, dest));
}
else
return false;
@@ -641,7 +705,12 @@ namespace client
{
auto floodfill = i2p::data::netdb.GetClosestFloodfill (dest, it->second->excluded);
if (floodfill)
done = !SendLeaseSetRequest (dest, floodfill, it->second);
{
// reset tunnels, because one them might fail
it->second->outboundTunnel = nullptr;
it->second->replyTunnel = nullptr;
done = !SendLeaseSetRequest (dest, floodfill, it->second);
}
else
done = true;
}
@@ -653,8 +722,9 @@ namespace client
if (done)
{
if (it->second->requestComplete) it->second->requestComplete (nullptr);
auto requestComplete = it->second->requestComplete;
m_LeaseSetRequests.erase (it);
if (requestComplete) requestComplete (nullptr);
}
}
}
@@ -664,7 +734,7 @@ namespace client
{
if (ecode != boost::asio::error::operation_aborted)
{
CleanupRoutingSessions ();
CleanupExpiredTags ();
CleanupRemoteLeaseSets ();
m_CleanupTimer.expires_from_now (boost::posix_time::minutes (DESTINATION_CLEANUP_TIMEOUT));
m_CleanupTimer.async_wait (std::bind (&ClientDestination::HandleCleanupTimer,
@@ -674,9 +744,10 @@ namespace client
void ClientDestination::CleanupRemoteLeaseSets ()
{
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
for (auto it = m_RemoteLeaseSets.begin (); it != m_RemoteLeaseSets.end ();)
{
if (!it->second->HasNonExpiredLeases ()) // all leases expired
if (it->second->IsEmpty () || ts > it->second->GetExpirationTime ()) // leaseset expired
{
LogPrint (eLogWarning, "Destination: Remote LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired");
it = m_RemoteLeaseSets.erase (it);
@@ -688,30 +759,26 @@ namespace client
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);
std::string ident = GetIdentHash().ToBase32();
std::string path = i2p::fs::DataDirPath("destinations", (ident + ".dat"));
std::ifstream f(path, std::ifstream::binary);
if (f) {
f.read ((char *)m_EncryptionPublicKey, 256);
f.read ((char *)m_EncryptionPrivateKey, 256);
return;
}
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);
}
}
LogPrint (eLogInfo, "Destination: Creating new temporary keys for address ", ident, ".b32.i2p");
i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey);
std::ofstream f1 (path, std::ofstream::binary | std::ofstream::out);
if (f1) {
f1.write ((char *)m_EncryptionPublicKey, 256);
f1.write ((char *)m_EncryptionPrivateKey, 256);
return;
}
LogPrint(eLogError, "Destinations: Can't save keys to ", path);
}
}
}

View File

@@ -26,6 +26,8 @@ namespace client
const uint8_t PROTOCOL_TYPE_DATAGRAM = 17;
const uint8_t PROTOCOL_TYPE_RAW = 18;
const int PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds
const int PUBLISH_VERIFICATION_TIMEOUT = 10; // in seconds after successfull publish
const int PUBLISH_REGULAR_VERIFICATION_INTERNAL = 100; // in seconds periodically
const int LEASESET_REQUEST_TIMEOUT = 5; // in seconds
const int MAX_LEASESET_REQUEST_TIMEOUT = 40; // in seconds
const int DESTINATION_CLEANUP_TIMEOUT = 3; // in minutes
@@ -44,7 +46,7 @@ namespace client
const int STREAM_REQUEST_TIMEOUT = 60; //in seconds
const char I2CP_PARAM_TAGS_TO_SEND[] = "crypto.tagsToSend";
const int DEFAULT_TAGS_TO_SEND = 40;
typedef std::function<void (std::shared_ptr<i2p::stream::Stream> stream)> StreamRequestComplete;
class ClientDestination: public i2p::garlic::GarlicDestination,
@@ -59,6 +61,8 @@ namespace client
uint64_t requestTime;
boost::asio::deadline_timer requestTimeoutTimer;
RequestComplete requestComplete;
std::shared_ptr<i2p::tunnel::OutboundTunnel> outboundTunnel;
std::shared_ptr<i2p::tunnel::InboundTunnel> replyTunnel;
};
@@ -72,13 +76,13 @@ namespace client
bool IsRunning () const { return m_IsRunning; };
boost::asio::io_service& GetService () { return m_Service; };
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () { return m_Pool; };
bool IsReady () const { return m_LeaseSet && m_LeaseSet->HasNonExpiredLeases () && m_Pool->GetOutboundTunnels ().size () > 0; };
bool IsReady () const { return m_LeaseSet && !m_LeaseSet->IsExpired () && m_Pool->GetOutboundTunnels ().size () > 0; };
std::shared_ptr<const i2p::data::LeaseSet> FindLeaseSet (const i2p::data::IdentHash& ident);
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
std::shared_ptr<i2p::stream::StreamingDestination> CreateStreamingDestination (int port, bool gzip = true); // additional
std::shared_ptr<i2p::stream::StreamingDestination> GetStreamingDestination (int port = 0) const;
// following methods operate with default streaming destination
void CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port = 0);
@@ -116,6 +120,7 @@ namespace client
void UpdateLeaseSet ();
void Publish ();
void HandlePublishConfirmationTimer (const boost::system::error_code& ecode);
void HandlePublishVerificationTimer (const boost::system::error_code& ecode);
void HandleDatabaseStoreMessage (const uint8_t * buf, size_t len);
void HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len);
void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
@@ -148,7 +153,7 @@ namespace client
std::map<uint16_t, std::shared_ptr<i2p::stream::StreamingDestination> > m_StreamingDestinationsByPorts;
i2p::datagram::DatagramDestination * m_DatagramDestination;
boost::asio::deadline_timer m_PublishConfirmationTimer, m_CleanupTimer;
boost::asio::deadline_timer m_PublishConfirmationTimer, m_PublishVerificationTimer, m_CleanupTimer;
public:

158
FS.cpp Normal file
View File

@@ -0,0 +1,158 @@
/*
* Copyright (c) 2013-2016, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include <algorithm>
#include <boost/filesystem.hpp>
#ifdef WIN32
#include <shlobj.h>
#endif
#include "Base.h"
#include "FS.h"
#include "Log.h"
namespace i2p {
namespace fs {
std::string appName = "i2pd";
std::string dataDir = "";
#ifdef _WIN32
std::string dirSep = "\\";
#else
std::string dirSep = "/";
#endif
const std::string & GetAppName () {
return appName;
}
void SetAppName (const std::string& name) {
appName = name;
}
const std::string & GetDataDir () {
return dataDir;
}
void DetectDataDir(const std::string & cmdline_param, bool isService) {
if (cmdline_param != "") {
dataDir = cmdline_param;
return;
}
#if defined(WIN32) || defined(_WIN32)
char localAppData[MAX_PATH];
SHGetFolderPath(NULL, CSIDL_APPDATA, 0, NULL, localAppData);
dataDir = std::string(localAppData) + "\\" + appName;
return;
#elif defined(MAC_OSX)
char *home = getenv("HOME");
dataDir = (home != NULL && strlen(home) > 0) ? home : "";
dataDir += "/Library/Application Support/" + appName;
return;
#else /* other unix */
char *home = getenv("HOME");
if (isService) {
dataDir = "/var/lib/" + appName;
} else if (home != NULL && strlen(home) > 0) {
dataDir = std::string(home) + "/." + appName;
} else {
dataDir = "/tmp/" + appName;
}
return;
#endif
}
bool Init() {
if (!boost::filesystem::exists(dataDir))
boost::filesystem::create_directory(dataDir);
std::string destinations = DataDirPath("destinations");
if (!boost::filesystem::exists(destinations))
boost::filesystem::create_directory(destinations);
return true;
}
bool ReadDir(const std::string & path, std::vector<std::string> & files) {
if (!boost::filesystem::exists(path))
return false;
boost::filesystem::directory_iterator it(path);
boost::filesystem::directory_iterator end;
for ( ; it != end; it++) {
if (!boost::filesystem::is_regular_file(it->status()))
continue;
files.push_back(it->path().string());
}
return true;
}
bool Exists(const std::string & path) {
return boost::filesystem::exists(path);
}
bool Remove(const std::string & path) {
if (!boost::filesystem::exists(path))
return false;
return boost::filesystem::remove(path);
}
void HashedStorage::SetPlace(const std::string &path) {
root = path + i2p::fs::dirSep + name;
}
bool HashedStorage::Init(const char * chars, size_t count) {
if (!boost::filesystem::exists(root)) {
boost::filesystem::create_directory(root);
}
for (size_t i = 0; i < count; i++) {
auto p = root + i2p::fs::dirSep + prefix1 + chars[i];
if (boost::filesystem::exists(p))
continue;
if (boost::filesystem::create_directory(p))
continue; /* ^ throws exception on failure */
return false;
}
return true;
}
std::string HashedStorage::Path(const std::string & ident) const {
std::string safe_ident = ident;
std::replace(safe_ident.begin(), safe_ident.end(), '/', '-');
std::replace(safe_ident.begin(), safe_ident.end(), '\\', '-');
std::stringstream t("");
t << this->root << i2p::fs::dirSep;
t << prefix1 << safe_ident[0] << i2p::fs::dirSep;
t << prefix2 << safe_ident << "." << suffix;
return t.str();
}
void HashedStorage::Remove(const std::string & ident) {
std::string path = Path(ident);
if (!boost::filesystem::exists(path))
return;
boost::filesystem::remove(path);
}
void HashedStorage::Traverse(std::vector<std::string> & files) {
boost::filesystem::path p(root);
boost::filesystem::recursive_directory_iterator it(p);
boost::filesystem::recursive_directory_iterator end;
for ( ; it != end; it++) {
if (!boost::filesystem::is_regular_file( it->status() ))
continue;
const std::string & t = it->path().string();
files.push_back(t);
}
}
} // fs
} // i2p

142
FS.h Normal file
View File

@@ -0,0 +1,142 @@
/*
* Copyright (c) 2013-2016, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef FS_H__
#define FS_H__
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
namespace i2p {
namespace fs {
extern std::string dirSep;
/**
* @brief Class to work with NetDb & Router profiles
*
* Usage:
*
* const char alphabet[8] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'};
* auto h = HashedStorage("name", "y", "z-", ".txt");
* h.SetPlace("/tmp/hs-test");
* h.GetName() -> gives "name"
* h.GetRoot() -> gives "/tmp/hs-test/name"
* h.Init(alphabet, 8); <- creates needed dirs, 8 is size of alphabet
* h.Path("abcd"); <- returns /tmp/hs-test/name/ya/z-abcd.txt
* h.Remove("abcd"); <- removes /tmp/hs-test/name/ya/z-abcd.txt, if it exists
* std::vector<std::string> files;
* h.Traverse(files); <- finds all files in storage and saves in given vector
*/
class HashedStorage {
protected:
std::string root; /**< path to storage with it's name included */
std::string name; /**< name of the storage */
std::string prefix1; /**< hashed directory prefix */
std::string prefix2; /**< prefix of file in storage */
std::string suffix; /**< suffix of file in storage (extension) */
public:
HashedStorage(const char *n, const char *p1, const char *p2, const char *s):
name(n), prefix1(p1), prefix2(p2), suffix(s) {};
/** create subdirs in storage */
bool Init(const char* chars, size_t cnt);
const std::string & GetRoot() const { return this->root; }
const std::string & GetName() const { return this->name; }
/** set directory where to place storage directory */
void SetPlace(const std::string & path);
/** path to file with given ident */
std::string Path(const std::string & ident) const;
/** remove file by ident */
void Remove(const std::string & ident);
/** find all files in storage and store list in provided vector */
void Traverse(std::vector<std::string> & files);
};
/** @brief Returns current application name, default 'i2pd' */
const std::string & GetAppName ();
/** @brief Set applicaton name, affects autodetection of datadir */
void SetAppName (const std::string& name);
/** @brief Returns datadir path */
const std::string & GetDataDir();
/**
* @brief Set datadir either from cmdline option or using autodetection
* @param cmdline_param Value of cmdline parameter --datadir=<something>
* @param isService Value of cmdline parameter --service
*
* Examples of autodetected paths:
*
* Windows < Vista: C:\Documents and Settings\Username\Application Data\i2pd\
* Windows >= Vista: C:\Users\Username\AppData\Roaming\i2pd\
* Mac: /Library/Application Support/i2pd/ or ~/Library/Application Support/i2pd/
* Unix: /var/lib/i2pd/ (system=1) >> ~/.i2pd/ or /tmp/i2pd/
*/
void DetectDataDir(const std::string & cmdline_datadir, bool isService = false);
/**
* @brief Create subdirectories inside datadir
*/
bool Init();
/**
* @brief Get list of files in directory
* @param path Path to directory
* @param files Vector to store found files
* @return true on success and false if directory not exists
*/
bool ReadDir(const std::string & path, std::vector<std::string> & files);
/**
* @brief Remove file with given path
* @param path Absolute path to file
* @return true on success, false if file not exists, throws exception on error
*/
bool Remove(const std::string & path);
/**
* @brief Check existence of file
* @param path Absolute path to file
* @return true if file exists, false otherwise
*/
bool Exists(const std::string & path);
template<typename T>
void _ExpandPath(std::stringstream & path, T c) {
path << i2p::fs::dirSep << c;
}
template<typename T, typename ... Other>
void _ExpandPath(std::stringstream & path, T c, Other ... other) {
_ExpandPath(path, c);
_ExpandPath(path, other ...);
}
/**
* @brief Get path relative to datadir
*
* Examples (with datadir = "/tmp/i2pd"):
*
* i2p::fs::Path("test") -> '/tmp/i2pd/test'
* i2p::fs::Path("test", "file.txt") -> '/tmp/i2pd/test/file.txt'
*/
template<typename ... Other>
std::string DataDirPath(Other ... components) {
std::stringstream s("");
s << i2p::fs::GetDataDir();
_ExpandPath(s, components ...);
return s.str();
}
} // fs
} // i2p
#endif // /* FS_H__ */

175
Family.cpp Normal file
View File

@@ -0,0 +1,175 @@
#include <string.h>
#include <openssl/evp.h>
#include <openssl/ssl.h>
#include "FS.h"
#include "Log.h"
#include "Crypto.h"
#include "Family.h"
namespace i2p
{
namespace data
{
Families::Families ()
{
}
Families::~Families ()
{
}
void Families::LoadCertificate (const std::string& filename)
{
SSL_CTX * ctx = SSL_CTX_new (TLSv1_method ());
int ret = SSL_CTX_use_certificate_file (ctx, filename.c_str (), SSL_FILETYPE_PEM);
if (ret)
{
SSL * ssl = SSL_new (ctx);
X509 * cert = SSL_get_certificate (ssl);
if (cert)
{
std::shared_ptr<i2p::crypto::Verifier> verifier;
// extract issuer name
char name[100];
X509_NAME_oneline (X509_get_issuer_name(cert), name, 100);
char * cn = strstr (name, "CN=");
if (cn)
{
cn += 3;
char * family = strstr (cn, ".family");
if (family) family[0] = 0;
}
auto pkey = X509_get_pubkey (cert);
int keyType = EVP_PKEY_type(pkey->type);
switch (keyType)
{
case EVP_PKEY_DSA:
// TODO:
break;
case EVP_PKEY_EC:
{
EC_KEY * ecKey = EVP_PKEY_get1_EC_KEY (pkey);
if (ecKey)
{
auto group = EC_KEY_get0_group (ecKey);
if (group)
{
int curve = EC_GROUP_get_curve_name (group);
if (curve == NID_X9_62_prime256v1)
{
uint8_t signingKey[64];
BIGNUM * x = BN_new(), * y = BN_new();
EC_POINT_get_affine_coordinates_GFp (group,
EC_KEY_get0_public_key (ecKey), x, y, NULL);
i2p::crypto::bn2buf (x, signingKey, 32);
i2p::crypto::bn2buf (y, signingKey + 32, 32);
BN_free (x); BN_free (y);
verifier = std::make_shared<i2p::crypto::ECDSAP256Verifier>(signingKey);
}
else
LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported");
}
EC_KEY_free (ecKey);
}
break;
}
default:
LogPrint (eLogWarning, "Family: Certificate key type ", keyType, " is not supported");
}
EVP_PKEY_free (pkey);
if (verifier && cn)
m_SigningKeys[cn] = verifier;
}
SSL_free (ssl);
}
else
LogPrint (eLogError, "Family: Can't open certificate file ", filename);
SSL_CTX_free (ctx);
}
void Families::LoadCertificates ()
{
std::string certDir = i2p::fs::DataDirPath("certificates", "family");
std::vector<std::string> files;
int numCertificates = 0;
if (!i2p::fs::ReadDir(certDir, files)) {
LogPrint(eLogWarning, "Reseed: Can't load reseed certificates from ", certDir);
return;
}
for (const std::string & file : files) {
if (file.compare(file.size() - 4, 4, ".crt") != 0) {
LogPrint(eLogWarning, "Family: ignoring file ", file);
continue;
}
LoadCertificate (file);
numCertificates++;
}
LogPrint (eLogInfo, "Family: ", numCertificates, " certificates loaded");
}
bool Families::VerifyFamily (const std::string& family, const IdentHash& ident,
const char * signature, const char * key)
{
uint8_t buf[50], signatureBuf[64];
size_t len = family.length (), signatureLen = strlen (signature);
memcpy (buf, family.c_str (), len);
memcpy (buf + len, (const uint8_t *)ident, 32);
len += 32;
Base64ToByteStream (signature, signatureLen, signatureBuf, 64);
auto it = m_SigningKeys.find (family);
if (it != m_SigningKeys.end ())
return it->second->Verify (buf, len, signatureBuf);
// TODO: process key
return true;
}
std::string CreateFamilySignature (const std::string& family, const IdentHash& ident)
{
auto filename = i2p::fs::DataDirPath("family", (family + ".key"));
std::string sig;
SSL_CTX * ctx = SSL_CTX_new (TLSv1_method ());
int ret = SSL_CTX_use_PrivateKey_file (ctx, filename.c_str (), SSL_FILETYPE_PEM);
if (ret)
{
SSL * ssl = SSL_new (ctx);
EVP_PKEY * pkey = SSL_get_privatekey (ssl);
EC_KEY * ecKey = EVP_PKEY_get1_EC_KEY (pkey);
if (ecKey)
{
auto group = EC_KEY_get0_group (ecKey);
if (group)
{
int curve = EC_GROUP_get_curve_name (group);
if (curve == NID_X9_62_prime256v1)
{
uint8_t signingPrivateKey[32], buf[50], signature[64];
i2p::crypto::bn2buf (EC_KEY_get0_private_key (ecKey), signingPrivateKey, 32);
i2p::crypto::ECDSAP256Signer signer (signingPrivateKey);
size_t len = family.length ();
memcpy (buf, family.c_str (), len);
memcpy (buf + len, (const uint8_t *)ident, 32);
len += 32;
signer.Sign (buf, len, signature);
len = Base64EncodingBufferSize (64);
char * b64 = new char[len+1];
len = ByteStreamToBase64 (signature, 64, b64, len);
b64[len] = 0;
sig = b64;
delete[] b64;
}
else
LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported");
}
}
SSL_free (ssl);
}
else
LogPrint (eLogError, "Family: Can't open keys file: ", filename);
SSL_CTX_free (ctx);
return sig;
}
}
}

38
Family.h Normal file
View File

@@ -0,0 +1,38 @@
#ifndef FAMILY_H__
#define FAMILY_H__
#include <map>
#include <string>
#include <memory>
#include "Signature.h"
#include "Identity.h"
namespace i2p
{
namespace data
{
class Families
{
public:
Families ();
~Families ();
void LoadCertificates ();
bool VerifyFamily (const std::string& family, const IdentHash& ident,
const char * signature, const char * key = nullptr);
private:
void LoadCertificate (const std::string& filename);
private:
std::map<std::string, std::shared_ptr<i2p::crypto::Verifier> > m_SigningKeys;
};
std::string CreateFamilySignature (const std::string& family, const IdentHash& ident);
// return base64 signature of empty string in case of failure
}
}
#endif

View File

@@ -42,7 +42,32 @@ namespace garlic
delete it.second;
m_UnconfirmedTagsMsgs.clear ();
}
std::shared_ptr<GarlicRoutingPath> GarlicRoutingSession::GetSharedRoutingPath ()
{
if (!m_SharedRoutingPath) return nullptr;
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
if (m_SharedRoutingPath->numTimesUsed >= ROUTING_PATH_MAX_NUM_TIMES_USED ||
!m_SharedRoutingPath->outboundTunnel->IsEstablished () ||
ts*1000LL > m_SharedRoutingPath->remoteLease->endDate ||
ts > m_SharedRoutingPath->updateTime + ROUTING_PATH_EXPIRATION_TIMEOUT)
m_SharedRoutingPath = nullptr;
if (m_SharedRoutingPath) m_SharedRoutingPath->numTimesUsed++;
return m_SharedRoutingPath;
}
void GarlicRoutingSession::SetSharedRoutingPath (std::shared_ptr<GarlicRoutingPath> path)
{
if (path && path->outboundTunnel && path->remoteLease)
{
path->updateTime = i2p::util::GetSecondsSinceEpoch ();
path->numTimesUsed = 0;
}
else
path = nullptr;
m_SharedRoutingPath = path;
}
GarlicRoutingSession::UnconfirmedTags * GarlicRoutingSession::GenerateSessionTags ()
{
auto tags = new UnconfirmedTags (m_NumTags);
@@ -139,7 +164,7 @@ namespace garlic
// create message
if (!tagFound) // new session
{
LogPrint (eLogWarning, "Garlic: No tags available. Use ElGamal");
LogPrint (eLogWarning, "Garlic: No tags available, will use ElGamal");
if (!m_Destination)
{
LogPrint (eLogError, "Garlic: Can't use ElGamal for unknown destination");
@@ -409,28 +434,6 @@ namespace garlic
else
LogPrint (eLogError, "Garlic: Failed to decrypt message");
}
// cleanup expired tags
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
if (ts > m_LastTagsCleanupTime + INCOMING_TAGS_EXPIRATION_TIMEOUT)
{
if (m_LastTagsCleanupTime)
{
int numExpiredTags = 0;
for (auto it = m_Tags.begin (); it != m_Tags.end ();)
{
if (ts > it->first.creationTime + INCOMING_TAGS_EXPIRATION_TIMEOUT)
{
numExpiredTags++;
it = m_Tags.erase (it);
}
else
it++;
}
LogPrint (eLogDebug, "Garlic: ", numExpiredTags, " tags expired for ", GetIdentHash().ToBase64 ());
}
m_LastTagsCleanupTime = ts;
}
}
void GarlicDestination::HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr<i2p::crypto::CBCDecryption> decryption,
@@ -570,11 +573,29 @@ namespace garlic
return session;
}
void GarlicDestination::CleanupRoutingSessions ()
void GarlicDestination::CleanupExpiredTags ()
{
// incoming
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
int numExpiredTags = 0;
for (auto it = m_Tags.begin (); it != m_Tags.end ();)
{
if (ts > it->first.creationTime + INCOMING_TAGS_EXPIRATION_TIMEOUT)
{
numExpiredTags++;
it = m_Tags.erase (it);
}
else
it++;
}
if (numExpiredTags > 0)
LogPrint (eLogDebug, "Garlic: ", numExpiredTags, " tags expired for ", GetIdentHash().ToBase64 ());
// outgoing
std::unique_lock<std::mutex> l(m_SessionsMutex);
for (auto it = m_Sessions.begin (); it != m_Sessions.end ();)
{
it->second->GetSharedRoutingPath (); // delete shared path if necessary
if (!it->second->CleanupExpiredTags ())
{
LogPrint (eLogInfo, "Routing session to ", it->first.ToBase32 (), " deleted");

View File

@@ -15,7 +15,12 @@
#include "Identity.h"
namespace i2p
{
{
namespace tunnel
{
class OutboundTunnel;
}
namespace garlic
{
@@ -27,19 +32,19 @@ namespace garlic
eGarlicDeliveryTypeTunnel = 3
};
#pragma pack(1)
struct ElGamalBlock
{
uint8_t sessionKey[32];
uint8_t preIV[32];
uint8_t padding[158];
};
#pragma pack()
const int INCOMING_TAGS_EXPIRATION_TIMEOUT = 960; // 16 minutes
const int OUTGOING_TAGS_EXPIRATION_TIMEOUT = 720; // 12 minutes
const int OUTGOING_TAGS_CONFIRMATION_TIMEOUT = 10; // 10 seconds
const int LEASET_CONFIRMATION_TIMEOUT = 4000; // in milliseconds
const int ROUTING_PATH_EXPIRATION_TIMEOUT = 30; // 30 seconds
const int ROUTING_PATH_MAX_NUM_TIMES_USED = 100; // how many times might be used
struct SessionTag: public i2p::data::Tag<32>
{
@@ -53,7 +58,16 @@ namespace garlic
#endif
uint32_t creationTime; // seconds since epoch
};
struct GarlicRoutingPath
{
std::shared_ptr<i2p::tunnel::OutboundTunnel> outboundTunnel;
std::shared_ptr<const i2p::data::Lease> remoteLease;
int rtt; // RTT
uint32_t updateTime; // seconds since epoch
int numTimesUsed;
};
class GarlicDestination;
class GarlicRoutingSession: public std::enable_shared_from_this<GarlicRoutingSession>
{
@@ -88,6 +102,9 @@ namespace garlic
{
if (m_LeaseSetUpdateStatus != eLeaseSetDoNotSend) m_LeaseSetUpdateStatus = eLeaseSetUpdated;
};
std::shared_ptr<GarlicRoutingPath> GetSharedRoutingPath ();
void SetSharedRoutingPath (std::shared_ptr<GarlicRoutingPath> path);
private:
@@ -115,22 +132,25 @@ namespace garlic
i2p::crypto::CBCEncryption m_Encryption;
std::unique_ptr<const i2p::crypto::ElGamalEncryption> m_ElGamalEncryption;
std::shared_ptr<GarlicRoutingPath> m_SharedRoutingPath;
public:
// for HTTP only
size_t GetNumOutgoingTags () const { return m_SessionTags.size (); };
};
using GarlicRoutingSessionPtr = std::shared_ptr<GarlicRoutingSession>;
//using GarlicRoutingSessionPtr = std::shared_ptr<GarlicRoutingSession>;
typedef std::shared_ptr<GarlicRoutingSession> GarlicRoutingSessionPtr; // TODO: replace to using after switch to 4.8
class GarlicDestination: public i2p::data::LocalDestination
{
public:
GarlicDestination (): m_NumTags (32), m_LastTagsCleanupTime (0) {}; // 32 tags by default
GarlicDestination (): m_NumTags (32) {}; // 32 tags by default
~GarlicDestination ();
void SetNumTags (int numTags) { m_NumTags = numTags; };
std::shared_ptr<GarlicRoutingSession> GetRoutingSession (std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet);
void CleanupRoutingSessions ();
void CleanupExpiredTags ();
void RemoveDeliveryStatusSession (uint32_t msgID);
std::shared_ptr<I2NPMessage> WrapMessage (std::shared_ptr<const i2p::data::RoutingDestination> destination,
std::shared_ptr<I2NPMessage> msg, bool attachLeaseSet = false);
@@ -166,7 +186,6 @@ namespace garlic
std::map<i2p::data::IdentHash, GarlicRoutingSessionPtr> m_Sessions;
// incoming
std::map<SessionTag, std::shared_ptr<i2p::crypto::CBCDecryption>> m_Tags;
uint32_t m_LastTagsCleanupTime;
// DeliveryStatus
std::map<uint32_t, GarlicRoutingSessionPtr> m_DeliveryStatusSessions; // msgID -> session

View File

@@ -65,13 +65,13 @@ namespace proxy
void HTTPProxyHandler::AsyncSockRead()
{
LogPrint(eLogDebug,"--- HTTP Proxy async sock read");
LogPrint(eLogDebug, "HTTPProxy: async sock read");
if(m_sock) {
m_sock->async_receive(boost::asio::buffer(m_http_buff, http_buffer_size),
std::bind(&HTTPProxyHandler::HandleSockRecv, shared_from_this(),
std::placeholders::_1, std::placeholders::_2));
} else {
LogPrint(eLogError,"--- HTTP Proxy no socket for read");
LogPrint(eLogError, "HTTPProxy: no socket for read");
}
}
@@ -79,7 +79,7 @@ namespace proxy
if (Kill()) return;
if (m_sock)
{
LogPrint(eLogDebug,"--- HTTP Proxy close sock");
LogPrint(eLogDebug, "HTTPProxy: close sock");
m_sock->close();
m_sock = nullptr;
}
@@ -102,7 +102,7 @@ namespace proxy
void HTTPProxyHandler::ExtractRequest()
{
LogPrint(eLogDebug,"--- HTTP Proxy method is: ", m_method, "\nRequest is: ", m_url);
LogPrint(eLogDebug, "HTTPProxy: request: ", m_method, " ", m_url);
std::string server="";
std::string port="80";
boost::regex rHTTP("http://(.*?)(:(\\d+))?(/.*)");
@@ -114,7 +114,7 @@ namespace proxy
if (m[2].str() != "") port=m[3].str();
path=m[4].str();
}
LogPrint(eLogDebug,"--- HTTP Proxy server is: ",server, " port is: ", port, "\n path is: ",path);
LogPrint(eLogDebug, "HTTPProxy: server: ", server, ", port: ", port, ", path: ", path);
m_address = server;
m_port = boost::lexical_cast<int>(port);
m_path = path;
@@ -124,7 +124,7 @@ namespace proxy
{
if ( m_version != "HTTP/1.0" && m_version != "HTTP/1.1" )
{
LogPrint(eLogError,"--- HTTP Proxy unsupported version: ", m_version);
LogPrint(eLogError, "HTTPProxy: unsupported version: ", m_version);
HTTPRequestFailed(); //TODO: send right stuff
return false;
}
@@ -156,7 +156,7 @@ namespace proxy
}
auto base64 = m_path.substr (addressHelperPos + strlen(helpermark1));
base64 = i2p::util::http::urlDecode(base64); //Some of the symbols may be urlencoded
LogPrint (eLogDebug,"Jump service for ", m_address, " found at ", base64, ". Inserting to address book");
LogPrint (eLogInfo, "HTTPProxy: jump service for ", m_address, ", inserting to address book");
//TODO: this is very dangerous and broken. We should ask the user before doing anything see http://pastethis.i2p/raw/pn5fL4YNJL7OSWj3Sc6N/
//TODO: we could redirect the user again to avoid dirtiness in the browser
i2p::client::context.GetAddressBook ().InsertAddress (m_address, base64);
@@ -176,28 +176,39 @@ namespace proxy
m_request.push_back('\r');
m_request.push_back('\n');
m_request.append("Connection: close\r\n");
m_request.append(reinterpret_cast<const char *>(http_buff),len);
// TODO: temporary shortcut. Must be implemented properly
uint8_t * eol = nullptr;
bool isEndOfHeader = false;
while (!isEndOfHeader && len && (eol = (uint8_t *)memchr (http_buff, '\r', len)))
{
if (eol)
{
*eol = 0; eol++;
if (strncmp ((const char *)http_buff, "Referer", 7)) // strip out referer
{
if (!strncmp ((const char *)http_buff, "User-Agent", 10)) // replace UserAgent
m_request.append("User-Agent: MYOB/6.66 (AN/ON)");
else
m_request.append ((const char *)http_buff);
m_request.append ("\r\n");
}
isEndOfHeader = !http_buff[0];
auto l = eol - http_buff;
http_buff = eol;
len -= l;
if (len > 0) // \r
{
http_buff++;
len--;
}
}
}
m_request.append(reinterpret_cast<const char *>(http_buff),len);
return true;
}
bool HTTPProxyHandler::HandleData(uint8_t *http_buff, std::size_t len)
{
// TODO: we should srtrip 'Referer' better, because it might be inside message body
/*assert(len); // This should always be called with a least a byte left to parse
// remove "Referer" from http requst
http_buff[len] = 0;
auto start = strstr((char *)http_buff, "\nReferer:");
if (start)
{
auto end = strchr (start + 1, '\n');
if (end)
{
strncpy(start, end, (char *)(http_buff + len) - end);
len -= (end - start);
}
}*/
while (len > 0)
{
//TODO: fallback to finding HOst: header if needed
@@ -229,13 +240,13 @@ namespace proxy
{
case '\n': EnterState(DONE); break;
default:
LogPrint(eLogError,"--- HTTP Proxy rejected invalid request ending with: ", ((int)*http_buff));
LogPrint(eLogError, "HTTPProxy: rejected invalid request ending with: ", ((int)*http_buff));
HTTPRequestFailed(); //TODO: add correct code
return false;
}
break;
default:
LogPrint(eLogError,"--- HTTP Proxy invalid state: ", m_state);
LogPrint(eLogError, "HTTPProxy: invalid state: ", m_state);
HTTPRequestFailed(); //TODO: add correct code 500
return false;
}
@@ -249,11 +260,11 @@ namespace proxy
void HTTPProxyHandler::HandleSockRecv(const boost::system::error_code & ecode, std::size_t len)
{
LogPrint(eLogDebug,"--- HTTP Proxy sock recv: ", len);
LogPrint(eLogDebug, "HTTPProxy: sock recv: ", len, " bytes");
if(ecode)
{
LogPrint(eLogWarning," --- HTTP Proxy sock recv got error: ", ecode);
Terminate();
LogPrint(eLogWarning, "HTTPProxy: sock recv got error: ", ecode);
Terminate();
return;
}
@@ -261,7 +272,7 @@ namespace proxy
{
if (m_state == DONE)
{
LogPrint(eLogInfo,"--- HTTP Proxy requested: ", m_url);
LogPrint(eLogDebug, "HTTPProxy: requested: ", m_url);
GetOwner()->CreateStream (std::bind (&HTTPProxyHandler::HandleStreamRequestComplete,
shared_from_this(), std::placeholders::_1), m_address, m_port);
}
@@ -273,13 +284,9 @@ namespace proxy
void HTTPProxyHandler::SentHTTPFailed(const boost::system::error_code & ecode)
{
if (!ecode)
Terminate();
else
{
LogPrint (eLogError,"--- HTTP Proxy Closing socket after sending failure because: ", ecode.message ());
Terminate();
}
if (ecode)
LogPrint (eLogError, "HTTPProxy: Closing socket after sending failure because: ", ecode.message ());
Terminate();
}
void HTTPProxyHandler::HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream)
@@ -287,7 +294,7 @@ namespace proxy
if (stream)
{
if (Kill()) return;
LogPrint (eLogInfo,"--- HTTP Proxy New I2PTunnel connection");
LogPrint (eLogInfo, "HTTPProxy: New I2PTunnel connection");
auto connection = std::make_shared<i2p::client::I2PTunnelConnection>(GetOwner(), m_sock, stream);
GetOwner()->AddHandler (connection);
connection->I2PConnect (reinterpret_cast<const uint8_t*>(m_request.data()), m_request.size());
@@ -295,7 +302,7 @@ namespace proxy
}
else
{
LogPrint (eLogError,"--- HTTP Proxy Issue when creating the stream, check the previous warnings for more info.");
LogPrint (eLogError, "HTTPProxy: error when creating the stream, check the previous warnings for more info");
HTTPRequestFailed(); // TODO: Send correct error message host unreachable
}
}

View File

@@ -4,6 +4,7 @@
#include <boost/lexical_cast.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include "Base.h"
#include "FS.h"
#include "Log.h"
#include "Tunnel.h"
#include "TransitTunnel.h"
@@ -420,7 +421,7 @@ namespace util
s << " (" << i2p::transport::transports.GetInBandwidth () <<" Bps)<br>\r\n";
s << "<b>Sent:</b> " << i2p::transport::transports.GetTotalSentBytes ()/1000 << "K";
s << " (" << i2p::transport::transports.GetOutBandwidth () <<" Bps)<br>\r\n";
s << "<b>Data path:</b> " << i2p::util::filesystem::GetDataDir().string() << "<br>\r\n<br>\r\n";
s << "<b>Data path:</b> " << i2p::fs::GetDataDir() << "<br>\r\n<br>\r\n";
s << "<b>Our external address:</b>" << "<br>\r\n" ;
for (auto& address : i2p::context.GetRouterInfo().GetAddresses())
{
@@ -446,6 +447,13 @@ namespace util
s << "<br>\r\n<b>Routers:</b> " << i2p::data::netdb.GetNumRouters () << " ";
s << "<b>Floodfills:</b> " << i2p::data::netdb.GetNumFloodfills () << " ";
s << "<b>LeaseSets:</b> " << i2p::data::netdb.GetNumLeaseSets () << "<br>\r\n";
size_t clientTunnelCount = i2p::tunnel::tunnels.CountOutboundTunnels();
clientTunnelCount += i2p::tunnel::tunnels.CountInboundTunnels();
size_t transitTunnelCount = i2p::tunnel::tunnels.CountTransitTunnels();
s << "<b>Client Tunnels:</b> " << std::to_string(clientTunnelCount) << " ";
s << "<b>Transit Tunnels:</b> " << std::to_string(transitTunnelCount) << "<br>\r\n";
}
void HTTPConnection::HandleCommand (const std::string& command, std::stringstream& s)
@@ -602,13 +610,13 @@ namespace util
for (auto it: i2p::tunnel::tunnels.GetInboundTunnels ())
{
it.second->Print (s);
auto state = it.second->GetState ();
it->Print (s);
auto state = it->GetState ();
if (state == i2p::tunnel::eTunnelStateFailed)
s << "<span class=failed_tunnel> " << "Failed</span>";
else if (state == i2p::tunnel::eTunnelStateExpiring)
s << "<span class=expiring_tunnel> " << "Exp</span>";
s << " " << (int)it.second->GetNumReceivedBytes () << "<br>\r\n";
s << " " << (int)it->GetNumReceivedBytes () << "<br>\r\n";
s << std::endl;
}
}
@@ -618,13 +626,13 @@ namespace util
s << "<b>Transit tunnels:</b><br>\r\n<br>\r\n";
for (auto it: i2p::tunnel::tunnels.GetTransitTunnels ())
{
if (dynamic_cast<i2p::tunnel::TransitTunnelGateway *>(it.second))
s << it.second->GetTunnelID () << "";
else if (dynamic_cast<i2p::tunnel::TransitTunnelEndpoint *>(it.second))
s << "" << it.second->GetTunnelID ();
if (std::dynamic_pointer_cast<i2p::tunnel::TransitTunnelGateway>(it))
s << it->GetTunnelID () << "";
else if (std::dynamic_pointer_cast<i2p::tunnel::TransitTunnelEndpoint>(it))
s << "" << it->GetTunnelID ();
else
s << "" << it.second->GetTunnelID () << "";
s << " " << it.second->GetNumTransmittedBytes () << "<br>\r\n";
s << "" << it->GetTunnelID () << "";
s << " " << it->GetNumTransmittedBytes () << "<br>\r\n";
}
}
@@ -793,7 +801,7 @@ namespace util
}
auto leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (destination);
if (leaseSet && leaseSet->HasNonExpiredLeases ())
if (leaseSet && !leaseSet->IsExpired ())
SendToDestination (leaseSet, port, buf, len);
else
{
@@ -812,7 +820,7 @@ namespace util
if (ecode != boost::asio::error::operation_aborted)
{
auto leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (destination);
if (leaseSet && leaseSet->HasNonExpiredLeases ())
if (leaseSet && !leaseSet->IsExpired ())
SendToDestination (leaseSet, port, buf, len);
else
// still no LeaseSet

View File

@@ -157,7 +157,7 @@ namespace i2p
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
const std::set<i2p::data::IdentHash>& excludedFloodfills,
const i2p::tunnel::InboundTunnel * replyTunnel, const uint8_t * replyKey, const uint8_t * replyTag)
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, const uint8_t * replyKey, const uint8_t * replyTag)
{
int cnt = excludedFloodfills.size ();
auto m = cnt > 0 ? NewI2NPMessage () : NewI2NPShortMessage ();
@@ -265,9 +265,9 @@ namespace i2p
auto leases = leaseSet->GetNonExpiredLeases ();
if (leases.size () > 0)
{
htobe32buf (payload + size, leases[0].tunnelID);
htobe32buf (payload + size, leases[0]->tunnelID);
size += 4; // reply tunnelID
memcpy (payload + size, leases[0].tunnelGateway, 32);
memcpy (payload + size, leases[0]->tunnelGateway, 32);
size += 32; // reply tunnel gateway
}
else
@@ -301,8 +301,7 @@ namespace i2p
i2p::tunnel::tunnels.GetTransitTunnels ().size () <= MAX_NUM_TRANSIT_TUNNELS &&
!i2p::transport::transports.IsBandwidthExceeded ())
{
i2p::tunnel::TransitTunnel * transitTunnel =
i2p::tunnel::CreateTransitTunnel (
auto transitTunnel = i2p::tunnel::CreateTransitTunnel (
bufbe32toh (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),

View File

@@ -222,7 +222,7 @@ namespace tunnel
uint32_t replyTunnelID, bool exploratory = false, std::set<i2p::data::IdentHash> * excludedPeers = nullptr);
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
const std::set<i2p::data::IdentHash>& excludedFloodfills,
const i2p::tunnel::InboundTunnel * replyTunnel, const uint8_t * replyKey, const uint8_t * replyTag);
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, const uint8_t * replyKey, const uint8_t * replyTag);
std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector<i2p::data::IdentHash> routers);
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router = nullptr, uint32_t replyToken = 0);

View File

@@ -13,6 +13,7 @@
#include <boost/property_tree/json_parser.hpp>
#endif
#include "FS.h"
#include "Log.h"
#include "Config.h"
#include "NetDb.h"
@@ -39,15 +40,12 @@ namespace client
// certificate / keys
std::string i2pcp_crt; i2p::config::GetOption("i2pcontrol.cert", i2pcp_crt);
std::string i2pcp_key; i2p::config::GetOption("i2pcontrol.key", i2pcp_key);
auto path = GetPath ();
// TODO: move this to i2p::fs::expand
if (i2pcp_crt.at(0) != '/')
i2pcp_crt.insert(0, (path / "/").string());
i2pcp_crt = i2p::fs::DataDirPath(i2pcp_crt);
if (i2pcp_key.at(0) != '/')
i2pcp_key.insert(0, (path / "/").string());
if (!boost::filesystem::exists (i2pcp_crt) ||
!boost::filesystem::exists (i2pcp_key))
{
i2pcp_key = i2p::fs::DataDirPath(i2pcp_key);
if (!i2p::fs::Exists (i2pcp_crt) || !i2p::fs::Exists (i2pcp_key)) {
LogPrint (eLogInfo, "I2PControl: creating new certificate for control connection");
CreateCertificate (i2pcp_crt.c_str(), i2pcp_key.c_str());
} else {
@@ -205,7 +203,7 @@ namespace client
}
if (ss.eof ())
{
LogPrint (eLogError, "Malformed I2PControl request. HTTP header expected");
LogPrint (eLogError, "I2PControl: malformed request, HTTP header expected");
return; // TODO:
}
std::streamoff rem = contentLength + ss.tellg () - bytes_transferred; // more bytes to read
@@ -215,8 +213,12 @@ namespace client
ss.write (buf->data (), bytes_transferred);
}
}
std::ostringstream response;
#if GCC47_BOOST149
LogPrint (eLogError, "json_read is not supported due bug in boost 1.49 with gcc 4.7");
LogPrint (eLogError, "I2PControl: json_read is not supported due bug in boost 1.49 with gcc 4.7");
response << "{\"id\":null,\"error\":";
response << "{\"code\":-32603,\"message\":\"JSON requests is not supported with this version of boost\"},";
response << "\"jsonrpc\":\"2.0\"}";
#else
boost::property_tree::ptree pt;
boost::property_tree::read_json (ss, pt);
@@ -226,23 +228,25 @@ namespace client
auto it = m_MethodHandlers.find (method);
if (it != m_MethodHandlers.end ())
{
std::ostringstream response;
response << "{\"id\":" << id << ",\"result\":{";
(this->*(it->second))(pt.get_child ("params"), response);
response << "},\"jsonrpc\":\"2.0\"}";
SendResponse (socket, buf, response, isHtml);
} else {
LogPrint (eLogWarning, "I2PControl: unknown method ", method);
response << "{\"id\":null,\"error\":";
response << "{\"code\":-32601,\"message\":\"Method not found\"},";
response << "\"jsonrpc\":\"2.0\"}";
}
else
LogPrint (eLogWarning, "Unknown I2PControl method ", method);
#endif
SendResponse (socket, buf, response, isHtml);
}
catch (std::exception& ex)
{
LogPrint (eLogError, "I2PControl handle request: ", ex.what ());
LogPrint (eLogError, "I2PControl: exception when handle request: ", ex.what ());
}
catch (...)
{
LogPrint (eLogError, "I2PControl handle request unknown exception");
LogPrint (eLogError, "I2PControl: handle request unknown exception");
}
}
}
@@ -527,7 +531,7 @@ namespace client
// save key
if ((f = fopen (key_path, "wb")) != NULL) {
LogPrint (eLogInfo, "I2PControl: saving cert key to : ", key_path);
LogPrint (eLogInfo, "I2PControl: saving cert key to ", key_path);
PEM_write_PrivateKey (f, pkey, NULL, NULL, 0, NULL, NULL);
fclose (f);
} else {

View File

@@ -12,8 +12,6 @@
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/filesystem.hpp>
#include "util.h"
namespace i2p
{
@@ -52,7 +50,6 @@ namespace client
void HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred,
std::shared_ptr<ssl_socket> socket, std::shared_ptr<I2PControlBuffer> buf);
boost::filesystem::path GetPath () const { return i2p::util::filesystem::GetDefaultDataDir(); };
void CreateCertificate (const char *crt_path, const char *key_path);
private:

View File

@@ -28,11 +28,143 @@ namespace client
m_LocalDestination->CreateStream (streamRequestComplete, identHash, port);
else
{
LogPrint (eLogWarning, "Remote destination ", dest, " not found");
LogPrint (eLogWarning, "I2PService: Remote destination ", dest, " not found");
streamRequestComplete (nullptr);
}
}
TCPIPPipe::TCPIPPipe(I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> upstream, std::shared_ptr<boost::asio::ip::tcp::socket> downstream) : I2PServiceHandler(owner), m_up(upstream), m_down(downstream) {}
TCPIPPipe::~TCPIPPipe()
{
Terminate();
}
void TCPIPPipe::Start()
{
AsyncReceiveUpstream();
AsyncReceiveDownstream();
}
void TCPIPPipe::Terminate()
{
if(Kill()) return;
Done(shared_from_this());
if (m_up) {
if (m_up->is_open()) {
m_up->close();
}
m_up = nullptr;
}
if (m_down) {
if (m_down->is_open()) {
m_down->close();
}
m_down = nullptr;
}
}
void TCPIPPipe::AsyncReceiveUpstream()
{
if (m_up) {
m_up->async_read_some(boost::asio::buffer(m_upstream_to_down_buf, TCP_IP_PIPE_BUFFER_SIZE),
std::bind(&TCPIPPipe::HandleUpstreamReceived, shared_from_this(),
std::placeholders::_1, std::placeholders::_2));
} else {
LogPrint(eLogError, "TCPIPPipe: no upstream socket for read");
}
}
void TCPIPPipe::AsyncReceiveDownstream()
{
if (m_down) {
m_down->async_read_some(boost::asio::buffer(m_downstream_to_up_buf, TCP_IP_PIPE_BUFFER_SIZE),
std::bind(&TCPIPPipe::HandleDownstreamReceived, shared_from_this(),
std::placeholders::_1, std::placeholders::_2));
} else {
LogPrint(eLogError, "TCPIPPipe: no downstream socket for read");
}
}
void TCPIPPipe::UpstreamWrite(const uint8_t * buf, size_t len)
{
if (m_up) {
LogPrint(eLogDebug, "TCPIPPipe: write upstream ", (int)len);
boost::asio::async_write(*m_up, boost::asio::buffer(buf, len),
boost::asio::transfer_all(),
std::bind(&TCPIPPipe::HandleUpstreamWrite,
shared_from_this(),
std::placeholders::_1)
);
} else {
LogPrint(eLogError, "tcpip pipe upstream socket null");
}
}
void TCPIPPipe::DownstreamWrite(const uint8_t * buf, size_t len)
{
if (m_down) {
LogPrint(eLogDebug, "TCPIPPipe: write downstream ", (int)len);
boost::asio::async_write(*m_down, boost::asio::buffer(buf, len),
boost::asio::transfer_all(),
std::bind(&TCPIPPipe::HandleDownstreamWrite,
shared_from_this(),
std::placeholders::_1)
);
} else {
LogPrint(eLogError, "tcpip pipe downstream socket null");
}
}
void TCPIPPipe::HandleDownstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transfered)
{
LogPrint(eLogDebug, "TCPIPPipe downstream got ", (int) bytes_transfered);
if (ecode) {
LogPrint(eLogError, "TCPIPPipe Downstream read error:" , ecode.message());
if (ecode != boost::asio::error::operation_aborted)
Terminate();
} else {
if (bytes_transfered > 0 ) {
memcpy(m_upstream_buf, m_downstream_to_up_buf, bytes_transfered);
UpstreamWrite(m_upstream_buf, bytes_transfered);
}
AsyncReceiveDownstream();
}
}
void TCPIPPipe::HandleDownstreamWrite(const boost::system::error_code & ecode) {
if (ecode) {
LogPrint(eLogError, "TCPIPPipe Downstream write error:" , ecode.message());
if (ecode != boost::asio::error::operation_aborted)
Terminate();
}
}
void TCPIPPipe::HandleUpstreamWrite(const boost::system::error_code & ecode) {
if (ecode) {
LogPrint(eLogError, "TCPIPPipe Upstream write error:" , ecode.message());
if (ecode != boost::asio::error::operation_aborted)
Terminate();
}
}
void TCPIPPipe::HandleUpstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transfered)
{
LogPrint(eLogDebug, "TCPIPPipe upstream got ", (int) bytes_transfered);
if (ecode) {
LogPrint(eLogError, "TCPIPPipe Upstream read error:" , ecode.message());
if (ecode != boost::asio::error::operation_aborted)
Terminate();
} else {
if (bytes_transfered > 0 ) {
memcpy(m_upstream_buf, m_upstream_to_down_buf, bytes_transfered);
DownstreamWrite(m_upstream_buf, bytes_transfered);
}
AsyncReceiveUpstream();
}
}
void TCPIPAcceptor::Start ()
{
m_Acceptor.listen ();
@@ -57,7 +189,7 @@ namespace client
{
if (!ecode)
{
LogPrint(eLogDebug,"--- ",GetName()," accepted");
LogPrint(eLogDebug, "I2PService: ", GetName(), " accepted");
auto handler = CreateHandler(socket);
if (handler)
{
@@ -71,7 +203,7 @@ namespace client
else
{
if (ecode != boost::asio::error::operation_aborted)
LogPrint (eLogError,"--- ",GetName()," Closing socket on accept because: ", ecode.message ());
LogPrint (eLogError, "I2PService: ", GetName(), " closing socket on accept because: ", ecode.message ());
}
}

View File

@@ -76,6 +76,30 @@ namespace client
std::atomic<bool> m_Dead; //To avoid cleaning up multiple times
};
const size_t TCP_IP_PIPE_BUFFER_SIZE = 8192;
// bidirectional pipe for 2 tcp/ip sockets
class TCPIPPipe: public I2PServiceHandler, public std::enable_shared_from_this<TCPIPPipe> {
public:
TCPIPPipe(I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> upstream, std::shared_ptr<boost::asio::ip::tcp::socket> downstream);
~TCPIPPipe();
void Start();
protected:
void Terminate();
void AsyncReceiveUpstream();
void AsyncReceiveDownstream();
void HandleUpstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transferred);
void HandleDownstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transferred);
void HandleUpstreamWrite(const boost::system::error_code & ecode);
void HandleDownstreamWrite(const boost::system::error_code & ecode);
void UpstreamWrite(const uint8_t * buf, size_t len);
void DownstreamWrite(const uint8_t * buf, size_t len);
private:
uint8_t m_upstream_to_down_buf[TCP_IP_PIPE_BUFFER_SIZE], m_downstream_to_up_buf[TCP_IP_PIPE_BUFFER_SIZE];
uint8_t m_upstream_buf[TCP_IP_PIPE_BUFFER_SIZE], m_downstream_buf[TCP_IP_PIPE_BUFFER_SIZE];
std::shared_ptr<boost::asio::ip::tcp::socket> m_up, m_down;
};
/* TODO: support IPv6 too */
//This is a service that listens for connections on the IP network and interacts with I2P
class TCPIPAcceptor: public I2PService

View File

@@ -114,10 +114,25 @@ namespace client
void I2PTunnelConnection::StreamReceive ()
{
if (m_Stream)
m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE),
std::bind (&I2PTunnelConnection::HandleStreamReceive, shared_from_this (),
std::placeholders::_1, std::placeholders::_2),
I2P_TUNNEL_CONNECTION_MAX_IDLE);
{
if (m_Stream->GetStatus () == i2p::stream::eStreamStatusNew ||
m_Stream->GetStatus () == i2p::stream::eStreamStatusOpen) // regular
{
m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE),
std::bind (&I2PTunnelConnection::HandleStreamReceive, shared_from_this (),
std::placeholders::_1, std::placeholders::_2),
I2P_TUNNEL_CONNECTION_MAX_IDLE);
}
else // closed by peer
{
// get remaning data
auto len = m_Stream->ReadSome (m_StreamBuffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE);
if (len > 0) // still some data
Write (m_StreamBuffer, len);
else // no more data
Terminate ();
}
}
}
void I2PTunnelConnection::HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred)
@@ -126,7 +141,12 @@ namespace client
{
LogPrint (eLogError, "I2PTunnel: stream read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
{
if (bytes_transferred > 0)
Write (m_StreamBuffer, bytes_transferred); // postpone termination
else
Terminate ();
}
}
else
Write (m_StreamBuffer, bytes_transferred);
@@ -214,6 +234,53 @@ namespace client
}
}
I2PTunnelConnectionIRC::I2PTunnelConnectionIRC (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& webircpass):
I2PTunnelConnection (owner, stream, socket, target), m_From (stream->GetRemoteIdentity ()),
m_NeedsWebIrc (webircpass.length() ? true : false), m_WebircPass (webircpass)
{
}
void I2PTunnelConnectionIRC::Write (const uint8_t * buf, size_t len)
{
if (m_NeedsWebIrc) {
m_NeedsWebIrc = false;
m_OutPacket.str ("");
m_OutPacket << "WEBIRC " << this->m_WebircPass << " cgiirc " << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ()) << " 127.0.0.1\n";
I2PTunnelConnection::Write ((uint8_t *)m_OutPacket.str ().c_str (), m_OutPacket.str ().length ());
}
std::string line;
m_OutPacket.str ("");
m_InPacket.clear ();
m_InPacket.write ((const char *)buf, len);
while (!m_InPacket.eof () && !m_InPacket.fail ())
{
std::getline (m_InPacket, line);
if (line.length () == 0 && m_InPacket.eof ()) {
m_InPacket.str ("");
}
auto pos = line.find ("USER");
if (pos != std::string::npos && pos == 0)
{
pos = line.find (" ");
pos++;
pos = line.find (" ", pos);
pos++;
auto nextpos = line.find (" ", pos);
m_OutPacket << line.substr (0, pos);
m_OutPacket << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ());
m_OutPacket << line.substr (nextpos) << '\n';
} else {
m_OutPacket << line << '\n';
}
}
I2PTunnelConnection::Write ((uint8_t *)m_OutPacket.str ().c_str (), m_OutPacket.str ().length ());
}
/* This handler tries to stablish a connection with the desired server and dies if it fails to do so */
class I2PClientTunnelHandler: public I2PServiceHandler, public std::enable_shared_from_this<I2PClientTunnelHandler>
{
@@ -312,10 +379,10 @@ namespace client
}
I2PServerTunnel::I2PServerTunnel (const std::string& name, const std::string& address,
int port, std::shared_ptr<ClientDestination> localDestination, int inport):
int port, std::shared_ptr<ClientDestination> localDestination, int inport, bool gzip):
I2PService (localDestination), m_Name (name), m_Address (address), m_Port (port), m_IsAccessList (false)
{
m_PortDestination = localDestination->CreateStreamingDestination (inport > 0 ? inport : port);
m_PortDestination = localDestination->CreateStreamingDestination (inport > 0 ? inport : port, gzip);
}
void I2PServerTunnel::Start ()
@@ -402,16 +469,35 @@ namespace client
}
I2PServerTunnelHTTP::I2PServerTunnelHTTP (const std::string& name, const std::string& address,
int port, std::shared_ptr<ClientDestination> localDestination, int inport):
I2PServerTunnel (name, address, port, localDestination, inport)
int port, std::shared_ptr<ClientDestination> localDestination,
const std::string& host, int inport, bool gzip):
I2PServerTunnel (name, address, port, localDestination, inport, gzip),
m_Host (host.length () > 0 ? host : address)
{
}
void I2PServerTunnelHTTP::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
{
auto conn = std::make_shared<I2PTunnelConnectionHTTP> (this, stream, std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), GetEndpoint (), GetAddress ());
auto conn = std::make_shared<I2PTunnelConnectionHTTP> (this, stream,
std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), GetEndpoint (), m_Host);
AddHandler (conn);
conn->Connect ();
}
I2PServerTunnelIRC::I2PServerTunnelIRC (const std::string& name, const std::string& address,
int port, std::shared_ptr<ClientDestination> localDestination,
const std::string& webircpass, int inport, bool gzip):
I2PServerTunnel (name, address, port, localDestination, inport, gzip),
m_WebircPass (webircpass)
{
}
void I2PServerTunnelIRC::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
{
auto conn = std::make_shared<I2PTunnelConnectionIRC> (this, stream, std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), GetEndpoint (), this->m_WebircPass);
AddHandler (conn);
conn->Connect ();
}
}
}

View File

@@ -80,6 +80,27 @@ namespace client
std::shared_ptr<const i2p::data::IdentityEx> m_From;
};
class I2PTunnelConnectionIRC: public I2PTunnelConnection
{
public:
I2PTunnelConnectionIRC (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& m_WebircPass);
protected:
void Write (const uint8_t * buf, size_t len);
private:
std::shared_ptr<const i2p::data::IdentityEx> m_From;
std::stringstream m_OutPacket, m_InPacket;
bool m_NeedsWebIrc;
std::string m_WebircPass;
};
class I2PClientTunnel: public TCPIPAcceptor
{
protected:
@@ -114,7 +135,7 @@ namespace client
public:
I2PServerTunnel (const std::string& name, const std::string& address, int port,
std::shared_ptr<ClientDestination> localDestination, int inport = 0);
std::shared_ptr<ClientDestination> localDestination, int inport = 0, bool gzip = true);
void Start ();
void Stop ();
@@ -152,12 +173,35 @@ namespace client
public:
I2PServerTunnelHTTP (const std::string& name, const std::string& address, int port,
std::shared_ptr<ClientDestination> localDestination, int inport = 0);
std::shared_ptr<ClientDestination> localDestination, const std::string& host,
int inport = 0, bool gzip = true);
private:
void CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream);
void CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream);
private:
std::string m_Host;
};
class I2PServerTunnelIRC: public I2PServerTunnel
{
public:
I2PServerTunnelIRC (const std::string& name, const std::string& address, int port,
std::shared_ptr<ClientDestination> localDestination, const std::string& webircpass,
int inport = 0, bool gzip = true);
private:
void CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream);
private:
std::string m_WebircPass;
};
}
}

View File

@@ -22,6 +22,10 @@ namespace data
size_t Identity::FromBuffer (const uint8_t * buf, size_t len)
{
if ( len < DEFAULT_IDENTITY_SIZE ) {
// buffer too small, don't overflow
return 0;
}
memcpy (publicKey, buf, DEFAULT_IDENTITY_SIZE);
return DEFAULT_IDENTITY_SIZE;
}
@@ -228,26 +232,31 @@ namespace data
}
size_t IdentityEx::ToBuffer (uint8_t * buf, size_t len) const
{
{
const size_t fullLen = GetFullLen();
if (fullLen > len) return 0; // buffer is too small and may overflow somewhere else
memcpy (buf, &m_StandardIdentity, DEFAULT_IDENTITY_SIZE);
if (m_ExtendedLen > 0 && m_ExtendedBuffer)
memcpy (buf + DEFAULT_IDENTITY_SIZE, m_ExtendedBuffer, m_ExtendedLen);
return GetFullLen ();
return fullLen;
}
size_t IdentityEx::FromBase64(const std::string& s)
{
uint8_t buf[1024];
auto len = Base64ToByteStream (s.c_str(), s.length(), buf, 1024);
const size_t slen = s.length();
uint8_t buf[slen]; // binary data can't exceed base64
const size_t len = Base64ToByteStream (s.c_str(), slen, buf, slen);
return FromBuffer (buf, len);
}
std::string IdentityEx::ToBase64 () const
{
uint8_t buf[1024];
char str[1536];
size_t l = ToBuffer (buf, 1024);
size_t l1 = i2p::data::ByteStreamToBase64 (buf, l, str, 1536);
const size_t bufLen = GetFullLen();
const size_t strLen = Base64EncodingBufferSize(bufLen);
uint8_t buf[bufLen];
char str[strLen];
size_t l = ToBuffer (buf, bufLen);
size_t l1 = i2p::data::ByteStreamToBase64 (buf, l, str, strLen);
str[l1] = 0;
return std::string (str);
}

View File

@@ -12,8 +12,8 @@ namespace i2p
namespace data
{
LeaseSet::LeaseSet (const uint8_t * buf, size_t len):
m_IsValid (true)
LeaseSet::LeaseSet (const uint8_t * buf, size_t len, bool storeLeases):
m_IsValid (true), m_StoreLeases (storeLeases), m_ExpirationTime (0)
{
m_Buffer = new uint8_t[len];
memcpy (m_Buffer, buf, len);
@@ -22,7 +22,7 @@ namespace data
}
LeaseSet::LeaseSet (std::shared_ptr<const i2p::tunnel::TunnelPool> pool):
m_IsValid (true)
m_IsValid (true), m_StoreLeases (true), m_ExpirationTime (0)
{
if (!pool) return;
// header
@@ -42,10 +42,13 @@ 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
int numTunnels = pool->GetNumInboundTunnels () + 2; // 2 backup tunnels
if (numTunnels > 16) numTunnels = 16; // 16 tunnels maximum
auto tunnels = pool->GetInboundTunnels (numTunnels);
m_Buffer[m_BufferLen] = tunnels.size (); // num leases
m_BufferLen++;
// leases
auto currentTime = i2p::util::GetMillisecondsSinceEpoch ();
for (auto it: tunnels)
{
memcpy (m_Buffer + m_BufferLen, it->GetNextIdentHash (), 32);
@@ -54,7 +57,9 @@ namespace data
m_BufferLen += 4; // tunnel id
uint64_t ts = it->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD; // 1 minute before expiration
ts *= 1000; // in milliseconds
ts += rand () % 6; // + random milliseconds 0-5
if (ts > m_ExpirationTime) m_ExpirationTime = ts;
// make sure leaseset is newer than previous, but adding some time to expiration date
ts += (currentTime - it->GetCreationTime ()*1000LL)*2/i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT; // up to 2 secs
htobe64buf (m_Buffer + m_BufferLen, ts);
m_BufferLen += 8; // end date
}
@@ -68,7 +73,6 @@ namespace data
void LeaseSet::Update (const uint8_t * buf, size_t len)
{
m_Leases.clear ();
if (len > m_BufferLen)
{
auto oldBuffer = m_Buffer;
@@ -79,7 +83,13 @@ namespace data
m_BufferLen = len;
ReadFromBuffer (false);
}
void LeaseSet::PopulateLeases ()
{
m_StoreLeases = true;
ReadFromBuffer (false);
}
void LeaseSet::ReadFromBuffer (bool readIdentity)
{
if (readIdentity || !m_Identity)
@@ -104,7 +114,16 @@ namespace data
return;
}
// reset existing leases
if (m_StoreLeases)
for (auto it: m_Leases)
it->isUpdated = false;
else
m_Leases.clear ();
// process leases
m_ExpirationTime = 0;
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
const uint8_t * leases = m_Buffer + size;
for (int i = 0; i < num; i++)
{
@@ -113,19 +132,51 @@ namespace data
leases += 32; // gateway
lease.tunnelID = bufbe32toh (leases);
leases += 4; // tunnel ID
lease.endDate = bufbe64toh (leases);
lease.endDate = bufbe64toh (leases);
leases += 8; // end date
m_Leases.push_back (lease);
// check if lease's gateway is in our netDb
if (!netdb.FindRouter (lease.tunnelGateway))
{
// if not found request it
LogPrint (eLogInfo, "LeaseSet: Lease's tunnel gateway not found, requesting");
netdb.RequestDestination (lease.tunnelGateway);
}
if (ts < lease.endDate + LEASE_ENDDATE_THRESHOLD)
{
if (lease.endDate > m_ExpirationTime)
m_ExpirationTime = lease.endDate;
if (m_StoreLeases)
{
auto ret = m_Leases.insert (std::make_shared<Lease>(lease));
if (!ret.second) *(*ret.first) = lease; // update existing
(*ret.first)->isUpdated = true;
// check if lease's gateway is in our netDb
if (!netdb.FindRouter (lease.tunnelGateway))
{
// if not found request it
LogPrint (eLogInfo, "LeaseSet: Lease's tunnel gateway not found, requesting");
netdb.RequestDestination (lease.tunnelGateway);
}
}
}
else
LogPrint (eLogWarning, "LeaseSet: Lease is expired already ");
}
if (!m_ExpirationTime)
{
LogPrint (eLogWarning, "LeaseSet: all leases are expired. Dropped");
m_IsValid = false;
return;
}
m_ExpirationTime += LEASE_ENDDATE_THRESHOLD;
// delete old leases
if (m_StoreLeases)
{
for (auto it = m_Leases.begin (); it != m_Leases.end ();)
{
if (!(*it)->isUpdated)
{
(*it)->endDate = 0; // somebody might still hold it
m_Leases.erase (it++);
}
else
it++;
}
}
// verify
if (!m_Identity->Verify (m_Buffer, leases - m_Buffer, leases))
{
@@ -133,16 +184,46 @@ namespace data
m_IsValid = false;
}
}
const std::vector<Lease> LeaseSet::GetNonExpiredLeases (bool withThreshold) const
uint64_t LeaseSet::ExtractTimestamp (const uint8_t * buf, size_t len) const
{
if (!m_Identity) return 0;
size_t size = m_Identity->GetFullLen ();
if (size > len) return 0;
size += 256; // encryption key
size += m_Identity->GetSigningPublicKeyLen (); // unused signing key
if (size > len) return 0;
uint8_t num = buf[size];
size++; // num
if (size + num*44 > len) return 0;
uint64_t timestamp= 0 ;
for (int i = 0; i < num; i++)
{
size += 36; // gateway (32) + tunnelId(4)
auto endDate = bufbe64toh (buf + size);
size += 8; // end date
if (!timestamp || endDate < timestamp)
timestamp = endDate;
}
return timestamp;
}
bool LeaseSet::IsNewer (const uint8_t * buf, size_t len) const
{
return ExtractTimestamp (buf, len) > ExtractTimestamp (m_Buffer, m_BufferLen);
}
const std::vector<std::shared_ptr<const Lease> > LeaseSet::GetNonExpiredLeases (bool withThreshold) const
{
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
std::vector<Lease> leases;
for (auto& it: m_Leases)
std::vector<std::shared_ptr<const Lease> > leases;
for (auto it: m_Leases)
{
auto endDate = it.endDate;
if (!withThreshold)
endDate -= i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD*1000;
auto endDate = it->endDate;
if (withThreshold)
endDate += LEASE_ENDDATE_THRESHOLD;
else
endDate -= LEASE_ENDDATE_THRESHOLD;
if (ts < endDate)
leases.push_back (it);
}
@@ -150,19 +231,18 @@ namespace data
}
bool LeaseSet::HasExpiredLeases () const
{
{
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
for (auto& it: m_Leases)
if (ts >= it.endDate) return true;
for (auto it: m_Leases)
if (ts >= it->endDate) return true;
return false;
}
}
bool LeaseSet::HasNonExpiredLeases () const
bool LeaseSet::IsExpired () const
{
if (IsEmpty ()) return true;
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
for (auto& it: m_Leases)
if (ts < it.endDate) return true;
return false;
return ts > m_ExpirationTime;
}
}
}

View File

@@ -4,6 +4,7 @@
#include <inttypes.h>
#include <string.h>
#include <vector>
#include <memory>
#include "Identity.h"
namespace i2p
@@ -16,19 +17,24 @@ namespace tunnel
namespace data
{
const int LEASE_ENDDATE_THRESHOLD = 51000; // in milliseconds
struct Lease
{
IdentHash tunnelGateway;
uint32_t tunnelID;
uint64_t endDate;
uint64_t endDate; // 0 means invalid
bool isUpdated; // trasient
};
bool operator< (const Lease& other) const
{
if (endDate != other.endDate)
return endDate > other.endDate;
struct LeaseCmp
{
bool operator() (std::shared_ptr<const Lease> l1, std::shared_ptr<const Lease> l2) const
{
if (l1->tunnelID != l2->tunnelID)
return l1->tunnelID < l2->tunnelID;
else
return tunnelID < other.tunnelID;
}
return l1->tunnelGateway < l2->tunnelGateway;
};
};
const int MAX_LS_BUFFER_SIZE = 3072;
@@ -37,33 +43,40 @@ namespace data
{
public:
LeaseSet (const uint8_t * buf, size_t len);
LeaseSet (const uint8_t * buf, size_t len, bool storeLeases = true);
LeaseSet (std::shared_ptr<const i2p::tunnel::TunnelPool> pool);
~LeaseSet () { delete[] m_Buffer; };
void Update (const uint8_t * buf, size_t len);
bool IsNewer (const uint8_t * buf, size_t len) const;
void PopulateLeases (); // from buffer
std::shared_ptr<const IdentityEx> GetIdentity () const { return m_Identity; };
const uint8_t * GetBuffer () const { return m_Buffer; };
size_t GetBufferLen () const { return m_BufferLen; };
bool IsValid () const { return m_IsValid; };
const std::vector<std::shared_ptr<const Lease> > GetNonExpiredLeases (bool withThreshold = true) const;
bool HasExpiredLeases () const;
bool IsExpired () const;
bool IsEmpty () const { return m_Leases.empty (); };
uint64_t GetExpirationTime () const { return m_ExpirationTime; };
bool operator== (const LeaseSet& other) const
{ return m_BufferLen == other.m_BufferLen && !memcmp (m_Buffer, other.m_Buffer, m_BufferLen); };
// implements RoutingDestination
const IdentHash& GetIdentHash () const { return m_Identity->GetIdentHash (); };
const std::vector<Lease>& GetLeases () const { return m_Leases; };
const std::vector<Lease> GetNonExpiredLeases (bool withThreshold = true) const;
bool HasExpiredLeases () const;
bool HasNonExpiredLeases () const;
const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionKey; };
bool IsDestination () const { return true; };
private:
void ReadFromBuffer (bool readIdentity = true);
uint64_t ExtractTimestamp (const uint8_t * buf, size_t len) const; // min expiration time
private:
bool m_IsValid;
std::vector<Lease> m_Leases;
bool m_IsValid, m_StoreLeases; // we don't need to store leases for floodfill
std::set<std::shared_ptr<Lease>, LeaseCmp> m_Leases;
uint64_t m_ExpirationTime; // in milliseconds
std::shared_ptr<const IdentityEx> m_Identity;
uint8_t m_EncryptionKey[256];
uint8_t * m_Buffer;

27
Log.cpp
View File

@@ -13,7 +13,8 @@ static const char * g_LogLevelStr[eNumLogLevels] =
void LogMsg::Process()
{
auto& output = (log && log->GetLogStream ()) ? *log->GetLogStream () : std::cerr;
auto stream = log ? log->GetLogStream () : nullptr;
auto& output = stream ? *stream : std::cout;
if (log)
output << log->GetTimestamp ();
else
@@ -43,18 +44,29 @@ void Log::Flush ()
m_LogStream->flush();
}
void Log::SetLogFile (const std::string& fullFilePath)
void Log::SetLogFile (const std::string& fullFilePath, bool truncate)
{
auto logFile = new std::ofstream (fullFilePath, std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
m_FullFilePath = fullFilePath;
auto mode = std::ofstream::out | std::ofstream::binary;
mode |= truncate ? std::ofstream::trunc : std::ofstream::app;
auto logFile = std::make_shared<std::ofstream> (fullFilePath, mode);
if (logFile->is_open ())
{
SetLogStream (logFile);
LogPrint(eLogInfo, "Log: will send messages to ", fullFilePath);
}
else
delete logFile;
}
void Log::ReopenLogFile ()
{
if (m_FullFilePath.length () > 0)
{
SetLogFile (m_FullFilePath, false); // don't truncate
LogPrint(eLogInfo, "Log: file ", m_FullFilePath, " reopen");
}
}
void Log::SetLogLevel (const std::string& level)
{
if (level == "error") { m_MinLevel = eLogError; }
@@ -65,11 +77,10 @@ void Log::SetLogLevel (const std::string& level)
LogPrint(eLogError, "Log: Unknown loglevel: ", level);
return;
}
LogPrint(eLogInfo, "Log: min messages level set to ", level);
LogPrint(eLogInfo, "Log: min msg level set to ", level);
}
void Log::SetLogStream (std::ostream * logStream)
void Log::SetLogStream (std::shared_ptr<std::ostream> logStream)
{
if (m_LogStream) delete m_LogStream;
m_LogStream = logStream;
}

29
Log.h
View File

@@ -7,6 +7,7 @@
#include <fstream>
#include <functional>
#include <chrono>
#include <memory>
#include "Queue.h"
enum LogLevel
@@ -34,15 +35,17 @@ class Log: public i2p::util::MsgQueue<LogMsg>
{
public:
Log (): m_LogStream (nullptr) { SetOnEmpty (std::bind (&Log::Flush, this)); };
~Log () { delete m_LogStream; };
Log () { SetOnEmpty (std::bind (&Log::Flush, this)); };
~Log () {};
void SetLogFile (const std::string& fullFilePath);
void SetLogFile (const std::string& fullFilePath, bool truncate = true);
void ReopenLogFile ();
void SetLogLevel (const std::string& level);
void SetLogStream (std::ostream * logStream);
std::ostream * GetLogStream () const { return m_LogStream; };
void SetLogStream (std::shared_ptr<std::ostream> logStream);
std::shared_ptr<std::ostream> GetLogStream () const { return m_LogStream; };
const std::string& GetTimestamp ();
LogLevel GetLogLevel () { return m_MinLevel; };
const std::string& GetFullFilePath () const { return m_FullFilePath; };
private:
@@ -50,7 +53,8 @@ class Log: public i2p::util::MsgQueue<LogMsg>
private:
std::ostream * m_LogStream;
std::string m_FullFilePath; // empty if stream
std::shared_ptr<std::ostream> m_LogStream;
enum LogLevel m_MinLevel;
std::string m_Timestamp;
#if (__GNUC__ == 4) && (__GNUC_MINOR__ <= 6) && !defined(__clang__) // gcc 4.6
@@ -73,7 +77,7 @@ inline void StartLog (const std::string& fullFilePath)
}
}
inline void StartLog (std::ostream * s)
inline void StartLog (std::shared_ptr<std::ostream> s)
{
if (!g_Log)
{
@@ -101,6 +105,17 @@ inline void SetLogLevel (const std::string& level)
g_Log->SetLogLevel(level);
}
inline void ReopenLogFile ()
{
if (g_Log)
g_Log->ReopenLogFile ();
}
inline bool IsLogToFile ()
{
return g_Log ? !g_Log->GetFullFilePath ().empty () : false;
}
template<typename TValue>
void LogPrint (std::stringstream& s, TValue arg)
{

183
Makefile
View File

@@ -1,92 +1,91 @@
UNAME := $(shell uname -s)
SHLIB := libi2pd.so
ARLIB := libi2pd.a
SHLIB_CLIENT := libi2pdclient.so
ARLIB_CLIENT := libi2pdclient.a
I2PD := i2pd
GREP := fgrep
DEPS := obj/make.dep
include filelist.mk
USE_AESNI := yes
USE_STATIC := no
ifeq ($(UNAME),Darwin)
DAEMON_SRC += DaemonLinux.cpp
include Makefile.osx
else ifeq ($(shell echo $(UNAME) | $(GREP) -c FreeBSD),1)
DAEMON_SRC += DaemonLinux.cpp
include Makefile.bsd
else ifeq ($(UNAME),Linux)
DAEMON_SRC += DaemonLinux.cpp
include Makefile.linux
else # win32 mingw
DAEMON_SRC += DaemonWin32.cpp Win32/Win32Service.cpp
WINDIR := True
include Makefile.mingw
endif
all: mk_build_dir $(ARLIB) $(ARLIB_CLIENT) $(I2PD)
mk_build_dir:
mkdir -p obj
ifeq ($(WINDIR),True)
mkdir -p obj/Win32
endif
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.
## For example, when adding 'hardening flags' to the build
## (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.
deps:
@mkdir -p obj
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) -MM *.cpp > $(DEPS)
@sed -i -e '/\.o:/ s/^/obj\//' $(DEPS)
obj/%.o : %.cpp
@mkdir -p obj
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(CPU_FLAGS) -c -o $@ $<
# '-' is 'ignore if missing' on first run
-include $(DEPS)
$(I2PD): $(patsubst %.cpp,obj/%.o,$(DAEMON_SRC)) $(ARLIB) $(ARLIB_CLIENT)
$(CXX) -o $@ $^ $(LDLIBS) $(LDFLAGS)
$(SHLIB): $(patsubst %.cpp,obj/%.o,$(LIB_SRC))
ifneq ($(USE_STATIC),yes)
$(CXX) $(LDFLAGS) $(LDLIBS) -shared -o $@ $^
endif
$(SHLIB_CLIENT): $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC))
$(CXX) $(LDFLAGS) $(LDLIBS) -shared -o $@ $^
$(ARLIB): $(patsubst %.cpp,obj/%.o,$(LIB_SRC))
ar -r $@ $^
$(ARLIB_CLIENT): $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC))
ar -r $@ $^
clean:
rm -rf obj
$(RM) $(I2PD) $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT)
LATEST_TAG=$(shell git describe --tags --abbrev=0 master)
dist:
git archive --format=tar.gz -9 --worktree-attributes \
--prefix=i2pd_$(LATEST_TAG)/ $(LATEST_TAG) -o i2pd_$(LATEST_TAG).tar.gz
.PHONY: all
.PHONY: clean
.PHONY: deps
.PHONY: dist
.PHONY: api
.PHONY: api_client
.PHONY: mk_build_dir
UNAME := $(shell uname -s)
SHLIB := libi2pd.so
ARLIB := libi2pd.a
SHLIB_CLIENT := libi2pdclient.so
ARLIB_CLIENT := libi2pdclient.a
I2PD := i2pd
GREP := fgrep
DEPS := obj/make.dep
include filelist.mk
USE_AESNI := yes
USE_STATIC := no
ifeq ($(UNAME),Darwin)
DAEMON_SRC += DaemonLinux.cpp
include Makefile.osx
else ifeq ($(shell echo $(UNAME) | $(GREP) -c FreeBSD),1)
DAEMON_SRC += DaemonLinux.cpp
include Makefile.bsd
else ifeq ($(UNAME),Linux)
DAEMON_SRC += DaemonLinux.cpp
include Makefile.linux
else # win32 mingw
DAEMON_SRC += DaemonWin32.cpp Win32/Win32App.cpp
include Makefile.mingw
endif
all: mk_obj_dir $(ARLIB) $(ARLIB_CLIENT) $(I2PD)
mk_obj_dir:
@mkdir -p obj
@mkdir -p obj/Win32
api: mk_obj_dir $(SHLIB) $(ARLIB)
api_client: mk_obj_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.
## For example, when adding 'hardening flags' to the build
## (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.
deps: mk_obj_dir
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) -MM *.cpp > $(DEPS)
@sed -i -e '/\.o:/ s/^/obj\//' $(DEPS)
obj/%.o: %.cpp
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(CPU_FLAGS) -c -o $@ $<
# '-' is 'ignore if missing' on first run
-include $(DEPS)
DAEMON_OBJS += $(patsubst %.cpp,obj/%.o,$(DAEMON_SRC))
$(I2PD): $(DAEMON_OBJS) $(ARLIB) $(ARLIB_CLIENT)
$(CXX) -o $@ $^ $(LDLIBS) $(LDFLAGS)
$(SHLIB): $(patsubst %.cpp,obj/%.o,$(LIB_SRC))
ifneq ($(USE_STATIC),yes)
$(CXX) $(LDFLAGS) $(LDLIBS) -shared -o $@ $^
endif
$(SHLIB_CLIENT): $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC))
$(CXX) $(LDFLAGS) $(LDLIBS) -shared -o $@ $^
$(ARLIB): $(patsubst %.cpp,obj/%.o,$(LIB_SRC))
ar -r $@ $^
$(ARLIB_CLIENT): $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC))
ar -r $@ $^
clean:
rm -rf obj
$(RM) $(I2PD) $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT)
strip: $(I2PD) $(SHLIB_CLIENT) $(SHLIB)
strip $^
LATEST_TAG=$(shell git describe --tags --abbrev=0 master)
dist:
git archive --format=tar.gz -9 --worktree-attributes \
--prefix=i2pd_$(LATEST_TAG)/ $(LATEST_TAG) -o i2pd_$(LATEST_TAG).tar.gz
.PHONY: all
.PHONY: clean
.PHONY: deps
.PHONY: dist
.PHONY: api
.PHONY: api_client
.PHONY: mk_obj_dir

View File

@@ -1,7 +1,38 @@
CXX = g++
CXXFLAGS = -O2 -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN
WINDRES = windres
CXXFLAGS = -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN
NEEDED_CXXFLAGS = -std=c++11
BOOST_SUFFIX = -mt
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 = -Wl,-Bstatic -lboost_system$(BOOST_SUFFIX) -Wl,-Bstatic -lboost_date_time$(BOOST_SUFFIX) -Wl,-Bstatic -lboost_filesystem$(BOOST_SUFFIX) -Wl,-Bstatic -lboost_regex$(BOOST_SUFFIX) -Wl,-Bstatic -lboost_program_options$(BOOST_SUFFIX) -Wl,-Bstatic -lssl -Wl,-Bstatic -lcrypto -Wl,-Bstatic -lz -Wl,-Bstatic -lwsock32 -Wl,-Bstatic -lws2_32 -Wl,-Bstatic -lgdi32 -Wl,-Bstatic -liphlpapi -static-libgcc -static-libstdc++ -Wl,-Bstatic -lstdc++ -Wl,-Bstatic -lpthread
INCFLAGS = -I/usr/include/ -I/usr/local/include/
LDFLAGS = -mwindows -Wl,-rpath,/usr/local/lib \
-L/usr/local/lib \
-L/c/dev/openssl \
-L/c/dev/boost/lib
LDLIBS = \
-Wl,-Bstatic -lboost_system$(BOOST_SUFFIX) \
-Wl,-Bstatic -lboost_date_time$(BOOST_SUFFIX) \
-Wl,-Bstatic -lboost_filesystem$(BOOST_SUFFIX) \
-Wl,-Bstatic -lboost_regex$(BOOST_SUFFIX) \
-Wl,-Bstatic -lboost_program_options$(BOOST_SUFFIX) \
-Wl,-Bstatic -lssl \
-Wl,-Bstatic -lcrypto \
-Wl,-Bstatic -lz \
-Wl,-Bstatic -lwsock32 \
-Wl,-Bstatic -lws2_32 \
-Wl,-Bstatic -lgdi32 \
-Wl,-Bstatic -liphlpapi \
-static-libgcc -static-libstdc++ \
-Wl,-Bstatic -lstdc++ \
-Wl,-Bstatic -lpthread
DAEMON_RC += Win32/Resource.rc
DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC))
ifeq ($(USE_AESNI),1)
CPU_FLAGS = -maes -DAESNI
else
CPU_FLAGS = -msse
endif
obj/%.o : %.rc
$(WINDRES) -i $< -o $@

View File

@@ -25,7 +25,6 @@ namespace transport
m_TerminationTimer (m_Server.GetService ()), m_IsEstablished (false), m_IsTerminated (false),
m_ReceiveBufferOffset (0), m_NextMessage (nullptr), m_IsSending (false)
{
m_DHKeysPair = transports.GetNextDHKeysPair ();
m_Establisher = new Establisher;
}
@@ -134,6 +133,7 @@ namespace transport
void NTCPSession::HandlePhase1Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred)
{
(void) bytes_transferred;
if (ecode)
{
LogPrint (eLogInfo, "NTCP: couldn't send Phase 1 message: ", ecode.message ());
@@ -150,6 +150,7 @@ namespace transport
void NTCPSession::HandlePhase1Received (const boost::system::error_code& ecode, std::size_t bytes_transferred)
{
(void) bytes_transferred;
if (ecode)
{
LogPrint (eLogInfo, "NTCP: phase 1 read error: ", ecode.message ());
@@ -205,6 +206,7 @@ namespace transport
void NTCPSession::HandlePhase2Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB)
{
(void) bytes_transferred;
if (ecode)
{
LogPrint (eLogInfo, "NTCP: Couldn't send Phase 2 message: ", ecode.message ());
@@ -221,6 +223,7 @@ namespace transport
void NTCPSession::HandlePhase2Received (const boost::system::error_code& ecode, std::size_t bytes_transferred)
{
(void) bytes_transferred;
if (ecode)
{
LogPrint (eLogInfo, "NTCP: Phase 2 read error: ", ecode.message (), ". Wrong ident assumed");
@@ -277,7 +280,8 @@ namespace transport
if (paddingSize > 0)
{
paddingSize = 16 - paddingSize;
// TODO: fill padding with random data
// fill padding with random data
RAND_bytes(buf, paddingSize);
buf += paddingSize;
len += paddingSize;
}
@@ -297,6 +301,7 @@ namespace transport
void NTCPSession::HandlePhase3Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsA)
{
(void) bytes_transferred;
if (ecode)
{
LogPrint (eLogInfo, "NTCP: Couldn't send Phase 3 message: ", ecode.message ());
@@ -420,6 +425,7 @@ namespace transport
void NTCPSession::HandlePhase4Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred)
{
(void) bytes_transferred;
if (ecode)
{
LogPrint (eLogWarning, "NTCP: Couldn't send Phase 4 message: ", ecode.message ());
@@ -496,12 +502,13 @@ namespace transport
void NTCPSession::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
{
if (ecode)
{
LogPrint (eLogInfo, "NTCP: Read error: ", ecode.message ());
if (!m_NumReceivedBytes) m_Server.Ban (m_ConnectedFrom);
if (ecode) {
if (ecode != boost::asio::error::operation_aborted)
LogPrint (eLogDebug, "NTCP: Read error: ", ecode.message ());
if (!m_NumReceivedBytes)
m_Server.Ban (m_ConnectedFrom);
//if (ecode != boost::asio::error::operation_aborted)
Terminate ();
Terminate ();
}
else
{
@@ -645,8 +652,11 @@ namespace transport
}
int rem = (len + 6) & 0x0F; // %16
int padding = 0;
if (rem > 0) padding = 16 - rem;
// TODO: fill padding
if (rem > 0) {
padding = 16 - rem;
// fill with random padding
RAND_bytes(sendBuffer + len + 2, padding);
}
htobe32buf (sendBuffer + len + 2 + padding, adler32 (adler32 (0, Z_NULL, 0), sendBuffer, len + 2+ padding));
int l = len + padding + 6;
@@ -667,6 +677,7 @@ namespace transport
void NTCPSession::HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::vector<std::shared_ptr<I2NPMessage> > msgs)
{
(void) msgs;
m_IsSending = false;
if (ecode)
{
@@ -725,7 +736,7 @@ namespace transport
{
if (ecode != boost::asio::error::operation_aborted)
{
LogPrint (eLogWarning, "NTCP: No activity fo ", NTCP_TERMINATION_TIMEOUT, " seconds");
LogPrint (eLogDebug, "NTCP: No activity for ", NTCP_TERMINATION_TIMEOUT, " seconds");
//Terminate ();
m_Socket.close ();// invoke Terminate () from HandleReceive
}

363
NetDb.cpp
View File

@@ -1,10 +1,10 @@
#include <string.h>
#include "I2PEndian.h"
#include <fstream>
#include <vector>
#include <boost/asio.hpp>
#include <openssl/rand.h>
#include <zlib.h>
#include "I2PEndian.h"
#include "Base.h"
#include "Log.h"
#include "Timestamp.h"
@@ -22,10 +22,9 @@ namespace i2p
{
namespace data
{
const char NetDb::m_NetDbPath[] = "netDb";
NetDb netdb;
NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr)
NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat")
{
}
@@ -37,6 +36,10 @@ namespace data
void NetDb::Start ()
{
m_Storage.SetPlace(i2p::fs::GetDataDir());
m_Storage.Init(i2p::data::GetBase64SubstitutionTable(), 64);
InitProfilesStorage ();
m_Families.LoadCertificates ();
Load ();
if (m_RouterInfos.size () < 25) // reseed if # of router less than 50
Reseed ();
@@ -149,22 +152,31 @@ namespace data
}
}
void NetDb::AddRouterInfo (const uint8_t * buf, int len)
bool NetDb::AddRouterInfo (const uint8_t * buf, int len)
{
IdentityEx identity;
if (identity.FromBuffer (buf, len))
AddRouterInfo (identity.GetIdentHash (), buf, len);
return AddRouterInfo (identity.GetIdentHash (), buf, len);
return false;
}
void NetDb::AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len)
bool NetDb::AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len)
{
bool updated = true;
auto r = FindRouter (ident);
if (r)
{
auto ts = r->GetTimestamp ();
r->Update (buf, len);
if (r->GetTimestamp () > ts)
if (r->IsNewer (buf, len))
{
r->Update (buf, len);
LogPrint (eLogInfo, "NetDb: RouterInfo updated: ", ident.ToBase64());
// TODO: check if floodfill has been changed
}
else
{
LogPrint (eLogDebug, "NetDb: RouterInfo is older: ", ident.ToBase64());
updated = false;
}
}
else
{
@@ -176,46 +188,60 @@ namespace data
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
m_RouterInfos[r->GetIdentHash ()] = r;
}
if (r->IsFloodfill ())
if (r->IsFloodfill () && r->IsReachable ()) // floodfill must be reachable
{
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
m_Floodfills.push_back (r);
}
}
else
updated = false;
}
// take care about requested destination
m_Requests.RequestComplete (ident, r);
return updated;
}
void NetDb::AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len,
bool NetDb::AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len,
std::shared_ptr<i2p::tunnel::InboundTunnel> from)
{
bool updated = false;
if (!from) // unsolicited LS must be received directly
{
auto it = m_LeaseSets.find(ident);
if (it != m_LeaseSets.end ())
{
it->second->Update (buf, len);
if (it->second->IsValid ())
LogPrint (eLogInfo, "NetDb: LeaseSet updated: ", ident.ToBase64());
else
if (it->second->IsNewer (buf, len))
{
LogPrint (eLogWarning, "NetDb: LeaseSet update failed: ", ident.ToBase64());
m_LeaseSets.erase (it);
}
it->second->Update (buf, len);
if (it->second->IsValid ())
{
LogPrint (eLogInfo, "NetDb: LeaseSet updated: ", ident.ToBase64());
updated = true;
}
else
{
LogPrint (eLogWarning, "NetDb: LeaseSet update failed: ", ident.ToBase64());
m_LeaseSets.erase (it);
}
}
else
LogPrint (eLogDebug, "NetDb: LeaseSet is older: ", ident.ToBase64());
}
else
{
auto leaseSet = std::make_shared<LeaseSet> (buf, len);
auto leaseSet = std::make_shared<LeaseSet> (buf, len, false); // we don't need leases in netdb
if (leaseSet->IsValid ())
{
LogPrint (eLogInfo, "NetDb: LeaseSet added: ", ident.ToBase64());
m_LeaseSets[ident] = leaseSet;
updated = true;
}
else
LogPrint (eLogError, "NetDb: new LeaseSet validation failed: ", ident.ToBase64());
}
}
return updated;
}
std::shared_ptr<RouterInfo> NetDb::FindRouter (const IdentHash& ident) const
@@ -250,30 +276,6 @@ namespace data
return it->second->SetUnreachable (unreachable);
}
// 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 (eLogInfo, "NetDb: storage directory doesn't exist, trying to create it.");
if (!boost::filesystem::create_directory (directory))
{
LogPrint (eLogError, "NetDb: failed to create directory ", directory);
return false;
}
// list of chars might appear in base64 string
const char * chars = GetBase64SubstitutionTable (); // 64 bytes
for (int i = 0; i < 64; i++)
{
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;
}
void NetDb::Reseed ()
{
if (!m_Reseeder)
@@ -288,145 +290,113 @@ namespace data
LogPrint (eLogWarning, "NetDb: failed to reseed after 10 attempts");
}
bool NetDb::LoadRouterInfo (const std::string & path)
{
auto r = std::make_shared<RouterInfo>(path);
if (r->GetRouterIdentity () && !r->IsUnreachable () &&
(!r->UsesIntroducer () || m_LastLoad < r->GetTimestamp () + NETDB_INTRODUCEE_EXPIRATION_TIMEOUT*1000LL)) // 1 hour
{
r->DeleteBuffer ();
r->ClearProperties (); // properties are not used for regular routers
m_RouterInfos[r->GetIdentHash ()] = r;
if (r->IsFloodfill () && r->IsReachable ()) // floodfill must be reachable
m_Floodfills.push_back (r);
}
else
{
LogPrint(eLogWarning, "NetDb: RI from ", path, " is invalid. Delete");
i2p::fs::Remove(path);
}
return true;
}
void NetDb::Load ()
{
boost::filesystem::path p(i2p::util::filesystem::GetDataDir() / m_NetDbPath);
if (!boost::filesystem::exists (p))
{
// seems netDb doesn't exist yet
if (!CreateNetDb(p)) return;
}
// make sure we cleanup netDb from previous attempts
m_RouterInfos.clear ();
m_Floodfills.clear ();
// load routers now
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
int numRouters = 0;
boost::filesystem::directory_iterator end;
for (boost::filesystem::directory_iterator it (p); it != end; ++it)
{
if (boost::filesystem::is_directory (it->status()))
{
for (boost::filesystem::directory_iterator it1 (it->path ()); it1 != end; ++it1)
{
#if BOOST_VERSION > 10500
const std::string& fullPath = it1->path().string();
#else
const std::string& fullPath = it1->path();
#endif
auto r = std::make_shared<RouterInfo>(fullPath);
if (!r->IsUnreachable () && (!r->UsesIntroducer () || ts < r->GetTimestamp () + 3600*1000LL)) // 1 hour
{
r->DeleteBuffer ();
r->ClearProperties (); // properties are not used for regular routers
m_RouterInfos[r->GetIdentHash ()] = r;
if (r->IsFloodfill ())
m_Floodfills.push_back (r);
numRouters++;
}
else
{
if (boost::filesystem::exists (fullPath))
boost::filesystem::remove (fullPath);
}
}
}
}
LogPrint (eLogInfo, "NetDb: ", numRouters, " routers loaded (", m_Floodfills.size (), " floodfils)");
m_LastLoad = i2p::util::GetSecondsSinceEpoch();
std::vector<std::string> files;
m_Storage.Traverse(files);
for (auto path : files)
LoadRouterInfo(path);
LogPrint (eLogInfo, "NetDb: ", m_RouterInfos.size(), " routers loaded (", m_Floodfills.size (), " floodfils)");
}
void NetDb::SaveUpdated ()
{
auto GetFilePath = [](const boost::filesystem::path& directory, const RouterInfo * routerInfo)
{
std::string s(routerInfo->GetIdentHashBase64());
return directory / (std::string("r") + s[0]) / ("routerInfo-" + s + ".dat");
};
boost::filesystem::path fullDirectory (i2p::util::filesystem::GetDataDir() / m_NetDbPath);
int count = 0, deletedCount = 0;
int updatedCount = 0, deletedCount = 0;
auto total = m_RouterInfos.size ();
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
uint64_t expirationTimeout = NETDB_MAX_EXPIRATION_TIMEOUT*1000LL;
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch();
// routers don't expire if less than 90 or uptime is less than 1 hour
bool checkForExpiration = total > NETDB_MIN_ROUTERS && ts > (i2p::context.GetStartupTime () + 600)*1000LL; // 10 minutes
if (checkForExpiration && ts > (i2p::context.GetStartupTime () + 3600)*1000LL) // 1 hour
expirationTimeout = i2p::context.IsFloodfill () ? NETDB_FLOODFILL_EXPIRATION_TIMEOUT*1000LL :
NETDB_MIN_EXPIRATION_TIMEOUT*1000LL + (NETDB_MAX_EXPIRATION_TIMEOUT - NETDB_MIN_EXPIRATION_TIMEOUT)*1000LL*NETDB_MIN_ROUTERS/total;
for (auto it: m_RouterInfos)
{
if (it.second->IsUpdated ())
std::string ident = it.second->GetIdentHashBase64();
std::string path = m_Storage.Path(ident);
if (it.second->IsUpdated ())
{
std::string f = GetFilePath(fullDirectory, it.second.get()).string();
it.second->SaveToFile (f);
it.second->SaveToFile (path);
it.second->SetUpdated (false);
it.second->SetUnreachable (false);
it.second->DeleteBuffer ();
count++;
updatedCount++;
continue;
}
else
// find & mark expired routers
if (it.second->UsesIntroducer ())
{
if (ts > it.second->GetTimestamp () + NETDB_INTRODUCEE_EXPIRATION_TIMEOUT*1000LL)
// RouterInfo expires after 1 hour if uses introducer
if (it.second->UsesIntroducer () && ts > it.second->GetTimestamp () + 3600*1000LL) // 1 hour
it.second->SetUnreachable (true);
else if (total > 75 && ts > (i2p::context.GetStartupTime () + 600)*1000LL) // routers don't expire if less than 25 or uptime is less than 10 minutes
{
if (i2p::context.IsFloodfill ())
{
if (ts > it.second->GetTimestamp () + 3600*1000LL) // 1 hours
{
it.second->SetUnreachable (true);
total--;
}
}
else if (total > 300)
{
if (ts > it.second->GetTimestamp () + 30*3600*1000LL) // 30 hours
{
it.second->SetUnreachable (true);
total--;
}
}
else if (total > 120)
{
if (ts > it.second->GetTimestamp () + 72*3600*1000LL) // 72 hours
{
it.second->SetUnreachable (true);
total--;
}
}
}
if (it.second->IsUnreachable ())
{
total--;
// delete RI file
if (boost::filesystem::exists (GetFilePath (fullDirectory, it.second.get ())))
{
boost::filesystem::remove (GetFilePath (fullDirectory, it.second.get ()));
deletedCount++;
}
// delete from floodfills list
if (it.second->IsFloodfill ())
{
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
m_Floodfills.remove (it.second);
}
}
}
}
if (count > 0)
LogPrint (eLogInfo, "NetDb: ", count, " new/updated routers saved");
}
else if (checkForExpiration && ts > it.second->GetTimestamp () + expirationTimeout)
it.second->SetUnreachable (true);
if (it.second->IsUnreachable ())
{
// delete RI file
m_Storage.Remove(ident);
deletedCount++;
if (total - deletedCount < NETDB_MIN_ROUTERS) checkForExpiration = false;
}
} // m_RouterInfos iteration
if (updatedCount > 0)
LogPrint (eLogInfo, "NetDb: saved ", updatedCount, " new/updated routers");
if (deletedCount > 0)
{
LogPrint (eLogDebug, "NetDb: ", deletedCount, " routers deleted");
LogPrint (eLogInfo, "NetDb: deleting ", deletedCount, " unreachable routers");
// clean up RouterInfos table
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
for (auto it = m_RouterInfos.begin (); it != m_RouterInfos.end ();)
{
if (it->second->IsUnreachable ())
{
it->second->SaveProfile ();
it = m_RouterInfos.erase (it);
}
else
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
for (auto it = m_RouterInfos.begin (); it != m_RouterInfos.end ();)
{
if (it->second->IsUnreachable ())
{
it->second->SaveProfile ();
it = m_RouterInfos.erase (it);
continue;
}
it++;
}
}
}
// clean up expired floodfiils
{
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
for (auto it = m_Floodfills.begin (); it != m_Floodfills.end ();)
if ((*it)->IsUnreachable ())
it = m_Floodfills.erase (it);
else
it++;
}
}
}
@@ -478,37 +448,14 @@ namespace data
LogPrint (eLogError, "NetDb: no outbound tunnels for DatabaseStore reply found");
}
offset += 32;
if (context.IsFloodfill ())
{
// flood it
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
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);
}
}
size_t payloadOffset = offset;
bool updated = false;
if (buf[DATABASE_STORE_TYPE_OFFSET]) // type
{
LogPrint (eLogDebug, "NetDb: store request: LeaseSet");
AddLeaseSet (ident, buf + offset, len - offset, m->from);
updated = AddLeaseSet (ident, buf + offset, len - offset, m->from);
}
else
{
@@ -523,7 +470,34 @@ namespace data
uint8_t uncompressed[2048];
size_t uncompressedSize = m_Inflator.Inflate (buf + offset, size, uncompressed, 2048);
if (uncompressedSize)
AddRouterInfo (ident, uncompressed, uncompressedSize);
updated = AddRouterInfo (ident, uncompressed, uncompressedSize);
}
if (replyToken && context.IsFloodfill () && updated)
{
// flood updated
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
auto msgLen = len - payloadOffset;
floodMsg->len += DATABASE_STORE_HEADER_SIZE + msgLen;
if (floodMsg->len < floodMsg->maxLen)
{
memcpy (payload + DATABASE_STORE_HEADER_SIZE, buf + payloadOffset, 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
break;
}
}
else
LogPrint (eLogError, "Database store message is too long ", floodMsg->len);
}
}
@@ -687,7 +661,7 @@ namespace data
lookupType == DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP))
{
auto leaseSet = FindLeaseSet (ident);
if (leaseSet) // we don't send back our LeaseSets
if (leaseSet && !leaseSet->IsExpired ()) // we don't send back our LeaseSets
{
LogPrint (eLogDebug, "NetDb: requested LeaseSet ", key, " found");
replyMsg = CreateDatabaseStoreMsg (leaseSet);
@@ -703,7 +677,7 @@ namespace data
excludedRouters.insert (excluded);
excluded += 32;
}
replyMsg = CreateDatabaseSearchReply (ident, GetClosestFloodfills (ident, 3, excludedRouters));
replyMsg = CreateDatabaseSearchReply (ident, GetClosestFloodfills (ident, 3, excludedRouters, true));
}
}
@@ -884,12 +858,15 @@ namespace data
}
std::shared_ptr<const RouterInfo> NetDb::GetClosestFloodfill (const IdentHash& destination,
const std::set<IdentHash>& excluded) const
const std::set<IdentHash>& excluded, bool closeThanUsOnly) const
{
std::shared_ptr<const RouterInfo> r;
XORMetric minMetric;
IdentHash destKey = CreateRoutingKey (destination);
minMetric.SetMax ();
if (closeThanUsOnly)
minMetric = destKey ^ i2p::context.GetIdentHash ();
else
minMetric.SetMax ();
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
for (auto it: m_Floodfills)
{
@@ -907,7 +884,7 @@ namespace data
}
std::vector<IdentHash> NetDb::GetClosestFloodfills (const IdentHash& destination, size_t num,
std::set<IdentHash>& excluded) const
std::set<IdentHash>& excluded, bool closeThanUsOnly) const
{
struct Sorted
{
@@ -918,6 +895,8 @@ namespace data
std::set<Sorted> sorted;
IdentHash destKey = CreateRoutingKey (destination);
XORMetric ourMetric;
if (closeThanUsOnly) ourMetric = destKey ^ i2p::context.GetIdentHash ();
{
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
for (auto it: m_Floodfills)
@@ -925,6 +904,7 @@ namespace data
if (!it->IsUnreachable ())
{
XORMetric m = destKey ^ it->GetIdentHash ();
if (closeThanUsOnly && ourMetric < m) continue;
if (sorted.size () < num)
sorted.insert ({it, m});
else if (m < sorted.rbegin ()->metric)
@@ -980,11 +960,12 @@ namespace data
void NetDb::ManageLeaseSets ()
{
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
for (auto it = m_LeaseSets.begin (); it != m_LeaseSets.end ();)
{
if (!it->second->HasNonExpiredLeases ()) // all leases expired
if (ts > it->second->GetExpirationTime () - LEASE_ENDDATE_THRESHOLD)
{
LogPrint (eLogWarning, "NetDb: LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired");
LogPrint (eLogInfo, "NetDb: LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired");
it = m_LeaseSets.erase (it);
}
else

26
NetDb.h
View File

@@ -8,8 +8,8 @@
#include <string>
#include <thread>
#include <mutex>
#include <boost/filesystem.hpp>
#include "Base.h"
#include "FS.h"
#include "Queue.h"
#include "I2NPProtocol.h"
#include "RouterInfo.h"
@@ -18,11 +18,17 @@
#include "TunnelPool.h"
#include "Reseed.h"
#include "NetDbRequests.h"
#include "Family.h"
namespace i2p
{
namespace data
{
const int NETDB_MIN_ROUTERS = 90;
const int NETDB_FLOODFILL_EXPIRATION_TIMEOUT = 60*60; // 1 hour, in seconds
const int NETDB_INTRODUCEE_EXPIRATION_TIMEOUT = 65*60;
const int NETDB_MIN_EXPIRATION_TIMEOUT = 90*60; // 1.5 hours
const int NETDB_MAX_EXPIRATION_TIMEOUT = 27*60*60; // 27 hours
class NetDb
{
@@ -34,9 +40,9 @@ namespace data
void Start ();
void Stop ();
void AddRouterInfo (const uint8_t * buf, int len);
void AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len);
void AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
bool AddRouterInfo (const uint8_t * buf, int len);
bool AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len);
bool AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
std::shared_ptr<RouterInfo> FindRouter (const IdentHash& ident) const;
std::shared_ptr<LeaseSet> FindLeaseSet (const IdentHash& destination) const;
std::shared_ptr<RouterProfile> FindRouterProfile (const IdentHash& ident) const;
@@ -52,15 +58,16 @@ namespace data
std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const;
std::shared_ptr<const RouterInfo> GetRandomPeerTestRouter () const;
std::shared_ptr<const RouterInfo> GetRandomIntroducer () const;
std::shared_ptr<const RouterInfo> GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
std::shared_ptr<const RouterInfo> GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
std::vector<IdentHash> GetClosestFloodfills (const IdentHash& destination, size_t num,
std::set<IdentHash>& excluded) const;
std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
void SetUnreachable (const IdentHash& ident, bool unreachable);
void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg);
void Reseed ();
Families& GetFamilies () { return m_Families; };
// for web interface
int GetNumRouters () const { return m_RouterInfos.size (); };
@@ -69,8 +76,8 @@ namespace data
private:
bool CreateNetDb(boost::filesystem::path directory);
void Load ();
bool LoadRouterInfo (const std::string & path);
void SaveUpdated ();
void Run (); // exploratory thread
void Explore (int numDestinations);
@@ -90,16 +97,17 @@ namespace data
std::list<std::shared_ptr<RouterInfo> > m_Floodfills;
bool m_IsRunning;
uint64_t m_LastLoad;
std::thread * m_Thread;
i2p::util::Queue<std::shared_ptr<const I2NPMessage> > m_Queue; // of I2NPDatabaseStoreMsg
GzipInflator m_Inflator;
Reseeder * m_Reseeder;
Families m_Families;
i2p::fs::HashedStorage m_Storage;
friend class NetDbRequests;
NetDbRequests m_Requests;
static const char m_NetDbPath[];
};
extern NetDb netdb;

View File

@@ -1,8 +1,8 @@
#include <boost/filesystem.hpp>
#include <sys/stat.h>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include "Base.h"
#include "util.h"
#include "FS.h"
#include "Log.h"
#include "Profiling.h"
@@ -10,6 +10,8 @@ namespace i2p
{
namespace data
{
i2p::fs::HashedStorage m_ProfilesStorage("peerProfiles", "p", "profile-", "txt");
RouterProfile::RouterProfile (const IdentHash& identHash):
m_IdentHash (identHash), m_LastUpdateTime (boost::posix_time::second_clock::local_time()),
m_NumTunnelsAgreed (0), m_NumTunnelsDeclined (0), m_NumTunnelsNonReplied (0),
@@ -41,101 +43,69 @@ namespace data
boost::property_tree::ptree pt;
pt.put (PEER_PROFILE_LAST_UPDATE_TIME, boost::posix_time::to_simple_string (m_LastUpdateTime));
pt.put_child (PEER_PROFILE_SECTION_PARTICIPATION, participation);
pt.put_child (PEER_PROFILE_SECTION_USAGE, usage);
pt.put_child (PEER_PROFILE_SECTION_USAGE, usage);
// save to file
auto path = i2p::util::filesystem::GetDefaultDataDir() / PEER_PROFILES_DIRECTORY;
if (!boost::filesystem::exists (path))
{
// Create directory is necessary
if (!boost::filesystem::create_directory (path))
{
LogPrint (eLogError, "Failed to create directory ", path);
return;
}
const char * chars = GetBase64SubstitutionTable (); // 64 bytes
for (int i = 0; i < 64; i++)
{
auto path1 = path / (std::string ("p") + chars[i]);
if (!boost::filesystem::exists (path1) && !boost::filesystem::create_directory (path1))
{
LogPrint (eLogError, "Failed to create directory ", path1);
return;
}
}
std::string ident = m_IdentHash.ToBase64 ();
std::string path = m_ProfilesStorage.Path(ident);
try {
boost::property_tree::write_ini (path, pt);
} catch (std::exception& ex) {
/* boost exception verbose enough */
LogPrint (eLogError, "Profiling: ", ex.what ());
}
std::string base64 = m_IdentHash.ToBase64 ();
path = path / (std::string ("p") + base64[0]);
auto filename = path / (std::string (PEER_PROFILE_PREFIX) + base64 + ".txt");
try
{
boost::property_tree::write_ini (filename.string (), pt);
}
catch (std::exception& ex)
{
LogPrint (eLogError, "Can't write ", filename, ": ", ex.what ());
}
}
}
void RouterProfile::Load ()
{
std::string base64 = m_IdentHash.ToBase64 ();
auto path = i2p::util::filesystem::GetDefaultDataDir() / PEER_PROFILES_DIRECTORY;
path /= std::string ("p") + base64[0];
auto filename = path / (std::string (PEER_PROFILE_PREFIX) + base64 + ".txt");
if (boost::filesystem::exists (filename))
{
boost::property_tree::ptree pt;
try
{
boost::property_tree::read_ini (filename.string (), pt);
}
catch (std::exception& ex)
{
LogPrint (eLogError, "Can't read ", filename, ": ", ex.what ());
return;
}
try
{
auto t = pt.get (PEER_PROFILE_LAST_UPDATE_TIME, "");
if (t.length () > 0)
m_LastUpdateTime = boost::posix_time::time_from_string (t);
if ((GetTime () - m_LastUpdateTime).hours () < PEER_PROFILE_EXPIRATION_TIMEOUT)
{
try
{
// read participations
auto participations = pt.get_child (PEER_PROFILE_SECTION_PARTICIPATION);
m_NumTunnelsAgreed = participations.get (PEER_PROFILE_PARTICIPATION_AGREED, 0);
m_NumTunnelsDeclined = participations.get (PEER_PROFILE_PARTICIPATION_DECLINED, 0);
m_NumTunnelsNonReplied = participations.get (PEER_PROFILE_PARTICIPATION_NON_REPLIED, 0);
}
catch (boost::property_tree::ptree_bad_path& ex)
{
LogPrint (eLogWarning, "Missing section ", PEER_PROFILE_SECTION_PARTICIPATION);
}
try
{
// read usage
auto usage = pt.get_child (PEER_PROFILE_SECTION_USAGE);
m_NumTimesTaken = usage.get (PEER_PROFILE_USAGE_TAKEN, 0);
m_NumTimesRejected = usage.get (PEER_PROFILE_USAGE_REJECTED, 0);
}
catch (boost::property_tree::ptree_bad_path& ex)
{
LogPrint (eLogWarning, "Missing section ", PEER_PROFILE_SECTION_USAGE);
}
std::string ident = m_IdentHash.ToBase64 ();
std::string path = m_ProfilesStorage.Path(ident);
boost::property_tree::ptree pt;
if (!i2p::fs::Exists(path)) {
LogPrint(eLogWarning, "Profiling: no profile yet for ", ident);
return;
}
try {
boost::property_tree::read_ini (path, pt);
} catch (std::exception& ex) {
/* boost exception verbose enough */
LogPrint (eLogError, "Profiling: ", ex.what ());
return;
}
try {
auto t = pt.get (PEER_PROFILE_LAST_UPDATE_TIME, "");
if (t.length () > 0)
m_LastUpdateTime = boost::posix_time::time_from_string (t);
if ((GetTime () - m_LastUpdateTime).hours () < PEER_PROFILE_EXPIRATION_TIMEOUT) {
try {
// read participations
auto participations = pt.get_child (PEER_PROFILE_SECTION_PARTICIPATION);
m_NumTunnelsAgreed = participations.get (PEER_PROFILE_PARTICIPATION_AGREED, 0);
m_NumTunnelsDeclined = participations.get (PEER_PROFILE_PARTICIPATION_DECLINED, 0);
m_NumTunnelsNonReplied = participations.get (PEER_PROFILE_PARTICIPATION_NON_REPLIED, 0);
} catch (boost::property_tree::ptree_bad_path& ex) {
LogPrint (eLogWarning, "Profiling: Missing section ", PEER_PROFILE_SECTION_PARTICIPATION, " in profile for ", ident);
}
else
*this = RouterProfile (m_IdentHash);
}
catch (std::exception& ex)
{
LogPrint (eLogError, "Can't read profile ", base64, " :", ex.what ());
}
}
}
try {
// read usage
auto usage = pt.get_child (PEER_PROFILE_SECTION_USAGE);
m_NumTimesTaken = usage.get (PEER_PROFILE_USAGE_TAKEN, 0);
m_NumTimesRejected = usage.get (PEER_PROFILE_USAGE_REJECTED, 0);
} catch (boost::property_tree::ptree_bad_path& ex) {
LogPrint (eLogWarning, "Missing section ", PEER_PROFILE_SECTION_USAGE, " in profile for ", ident);
}
} else {
*this = RouterProfile (m_IdentHash);
}
} catch (std::exception& ex) {
LogPrint (eLogError, "Profiling: Can't read profile ", ident, " :", ex.what ());
}
}
void RouterProfile::TunnelBuildResponse (uint8_t ret)
{
UpdateTime ();
@@ -184,31 +154,29 @@ namespace data
return profile;
}
void InitProfilesStorage ()
{
m_ProfilesStorage.SetPlace(i2p::fs::GetDataDir());
m_ProfilesStorage.Init(i2p::data::GetBase64SubstitutionTable(), 64);
}
void DeleteObsoleteProfiles ()
{
int num = 0;
auto ts = boost::posix_time::second_clock::local_time();
boost::filesystem::path p (i2p::util::filesystem::GetDataDir()/PEER_PROFILES_DIRECTORY);
if (boost::filesystem::exists (p))
{
boost::filesystem::directory_iterator end;
for (boost::filesystem::directory_iterator it (p); it != end; ++it)
{
if (boost::filesystem::is_directory (it->status()))
{
for (boost::filesystem::directory_iterator it1 (it->path ()); it1 != end; ++it1)
{
auto lastModified = boost::posix_time::from_time_t (boost::filesystem::last_write_time (it1->path ()));
if ((ts - lastModified).hours () >= PEER_PROFILE_EXPIRATION_TIMEOUT)
{
boost::filesystem::remove (it1->path ());
num++;
}
}
}
}
struct stat st;
std::time_t now = std::time(nullptr);
std::vector<std::string> files;
m_ProfilesStorage.Traverse(files);
for (auto path: files) {
if (stat(path.c_str(), &st) != 0) {
LogPrint(eLogWarning, "Profiling: Can't stat(): ", path);
continue;
}
if (((now - st.st_mtime) / 3600) >= PEER_PROFILE_EXPIRATION_TIMEOUT) {
LogPrint(eLogDebug, "Profiling: removing expired peer profile: ", path);
i2p::fs::Remove(path);
}
}
LogPrint (eLogInfo, num, " obsolete profiles deleted");
}
}
}
}

View File

@@ -9,8 +9,6 @@ namespace i2p
{
namespace data
{
const char PEER_PROFILES_DIRECTORY[] = "peerProfiles";
const char PEER_PROFILE_PREFIX[] = "profile-";
// sections
const char PEER_PROFILE_SECTION_PARTICIPATION[] = "participation";
const char PEER_PROFILE_SECTION_USAGE[] = "usage";
@@ -62,6 +60,7 @@ namespace data
};
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash);
void InitProfilesStorage ();
void DeleteObsoleteProfiles ();
}
}

View File

@@ -2,15 +2,16 @@
#include <fstream>
#include <sstream>
#include <boost/regex.hpp>
#include <boost/filesystem.hpp>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <openssl/bn.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <zlib.h>
#include "I2PEndian.h"
#include "Reseed.h"
#include "FS.h"
#include "Log.h"
#include "Identity.h"
#include "Crypto.h"
@@ -25,15 +26,16 @@ namespace data
static std::vector<std::string> httpsReseedHostList =
{
"https://reseed.i2p-projekt.de/", // Only HTTPS
"https://i2pseed.zarrenspry.info/", // Only HTTPS and SU3 (v3) support
//"https://i2pseed.zarrenspry.info/", // Only HTTPS and SU3 (v3) support
"https://i2p.mooo.com/netDb/",
"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://www.torontocrypto.org:8443/",
"https://i2p-0.manas.ca: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
"https://download.xxlspeed.com/" // Only HTTPS and SU3 (v3) support
};
Reseeder::Reseeder()
@@ -208,6 +210,11 @@ namespace data
uint16_t fileNameLength, extraFieldLength;
s.read ((char *)&fileNameLength, 2);
fileNameLength = le16toh (fileNameLength);
if ( fileNameLength > 255 ) {
// too big
LogPrint(eLogError, "Reseed: SU3 fileNameLength too large: ", fileNameLength);
return numFiles;
}
s.read ((char *)&extraFieldLength, 2);
extraFieldLength = le16toh (extraFieldLength);
char localFileName[255];
@@ -341,23 +348,22 @@ namespace data
void Reseeder::LoadCertificates ()
{
boost::filesystem::path reseedDir = i2p::util::filesystem::GetCertificatesDir() / "reseed";
if (!boost::filesystem::exists (reseedDir))
{
LogPrint (eLogWarning, "Reseed: certificates not loaded, ", reseedDir, " doesn't exist");
std::string certDir = i2p::fs::DataDirPath("certificates", "reseed");
std::vector<std::string> files;
int numCertificates = 0;
if (!i2p::fs::ReadDir(certDir, files)) {
LogPrint(eLogWarning, "Reseed: Can't load reseed certificates from ", certDir);
return;
}
int numCertificates = 0;
boost::filesystem::directory_iterator end; // empty
for (boost::filesystem::directory_iterator it (reseedDir); it != end; ++it)
{
if (boost::filesystem::is_regular_file (it->status()) && it->path ().extension () == ".crt")
{
LoadCertificate (it->path ().string ());
numCertificates++;
}
for (const std::string & file : files) {
if (file.compare(file.size() - 4, 4, ".crt") != 0) {
LogPrint(eLogWarning, "Reseed: ignoring file ", file);
continue;
}
LoadCertificate (file);
numCertificates++;
}
LogPrint (eLogInfo, "Reseed: ", numCertificates, " certificates loaded");
}

View File

@@ -5,9 +5,11 @@
#include "Timestamp.h"
#include "I2NPProtocol.h"
#include "NetDb.h"
#include "FS.h"
#include "util.h"
#include "version.h"
#include "Log.h"
#include "Family.h"
#include "RouterContext.h"
namespace i2p
@@ -48,7 +50,7 @@ namespace i2p
if (!port)
port = rand () % (30777 - 9111) + 9111; // I2P network ports range
std::string host; i2p::config::GetOption("host", host);
if (host == "0.0.0.0")
if (i2p::config::IsDefault("host"))
host = "127.0.0.1"; // replace default address with safe value
routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ());
routerInfo.AddNTCPAddress (host.c_str(), port);
@@ -64,7 +66,7 @@ namespace i2p
void RouterContext::UpdateRouterInfo ()
{
m_RouterInfo.CreateBuffer (m_Keys);
m_RouterInfo.SaveToFile (i2p::util::filesystem::GetFullPath (ROUTER_INFO));
m_RouterInfo.SaveToFile (i2p::fs::DataDirPath (ROUTER_INFO));
m_LastUpdateTime = i2p::util::GetSecondsSinceEpoch ();
}
@@ -141,12 +143,29 @@ namespace i2p
{
m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () & ~i2p::data::RouterInfo::eFloodfill);
// we don't publish number of routers and leaseset for non-floodfill
m_RouterInfo.DeleteProperty (ROUTER_INFO_PROPERTY_LEASESETS);
m_RouterInfo.DeleteProperty (ROUTER_INFO_PROPERTY_ROUTERS);
m_RouterInfo.DeleteProperty (i2p::data::ROUTER_INFO_PROPERTY_LEASESETS);
m_RouterInfo.DeleteProperty (i2p::data::ROUTER_INFO_PROPERTY_ROUTERS);
}
UpdateRouterInfo ();
}
void RouterContext::SetFamily (const std::string& family)
{
std::string signature;
if (family.length () > 0)
signature = i2p::data::CreateFamilySignature (family, GetIdentHash ());
if (signature.length () > 0)
{
m_RouterInfo.SetProperty (i2p::data::ROUTER_INFO_PROPERTY_FAMILY, family);
m_RouterInfo.SetProperty (i2p::data::ROUTER_INFO_PROPERTY_FAMILY_SIG, signature);
}
else
{
m_RouterInfo.DeleteProperty (i2p::data::ROUTER_INFO_PROPERTY_FAMILY);
m_RouterInfo.DeleteProperty (i2p::data::ROUTER_INFO_PROPERTY_FAMILY_SIG);
}
}
void RouterContext::SetHighBandwidth ()
{
if (!m_RouterInfo.IsHighBandwidth () || m_RouterInfo.IsExtraBandwidth ())
@@ -284,15 +303,15 @@ namespace i2p
if (m_IsFloodfill)
{
// update routers and leasesets
m_RouterInfo.SetProperty (ROUTER_INFO_PROPERTY_LEASESETS, boost::lexical_cast<std::string>(i2p::data::netdb.GetNumLeaseSets ()));
m_RouterInfo.SetProperty (ROUTER_INFO_PROPERTY_ROUTERS, boost::lexical_cast<std::string>(i2p::data::netdb.GetNumRouters ()));
m_RouterInfo.SetProperty (i2p::data::ROUTER_INFO_PROPERTY_LEASESETS, boost::lexical_cast<std::string>(i2p::data::netdb.GetNumLeaseSets ()));
m_RouterInfo.SetProperty (i2p::data::ROUTER_INFO_PROPERTY_ROUTERS, boost::lexical_cast<std::string>(i2p::data::netdb.GetNumRouters ()));
UpdateRouterInfo ();
}
}
bool RouterContext::Load ()
{
std::ifstream fk (i2p::util::filesystem::GetFullPath (ROUTER_KEYS).c_str (), std::ifstream::binary | std::ofstream::in);
std::ifstream fk (i2p::fs::DataDirPath (ROUTER_KEYS), std::ifstream::in | std::ifstream::binary);
if (!fk.is_open ()) return false;
fk.seekg (0, std::ios::end);
size_t len = fk.tellg();
@@ -312,7 +331,7 @@ namespace i2p
delete[] buf;
}
i2p::data::RouterInfo routerInfo(i2p::util::filesystem::GetFullPath (ROUTER_INFO)); // TODO
i2p::data::RouterInfo routerInfo(i2p::fs::DataDirPath (ROUTER_INFO)); // TODO
m_RouterInfo.SetRouterIdentity (GetIdentity ());
m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ());
m_RouterInfo.SetProperty ("coreVersion", I2P_VERSION);
@@ -331,7 +350,7 @@ namespace i2p
void RouterContext::SaveKeys ()
{
// save in the same format as .dat files
std::ofstream fk (i2p::util::filesystem::GetFullPath (ROUTER_KEYS).c_str (), std::ofstream::binary | std::ofstream::out);
std::ofstream fk (i2p::fs::DataDirPath (ROUTER_KEYS), std::ofstream::binary | std::ofstream::out);
size_t len = m_Keys.GetFullLen ();
uint8_t * buf = new uint8_t[len];
m_Keys.ToBuffer (buf, len);

View File

@@ -15,9 +15,6 @@ namespace i2p
const char ROUTER_INFO[] = "router.info";
const char ROUTER_KEYS[] = "router.keys";
const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes
const char ROUTER_INFO_PROPERTY_LEASESETS[] = "netdb.knownLeaseSets";
const char ROUTER_INFO_PROPERTY_ROUTERS[] = "netdb.knownRouters";
enum RouterStatus
{
@@ -60,6 +57,7 @@ namespace i2p
void SetReachable ();
bool IsFloodfill () const { return m_IsFloodfill; };
void SetFloodfill (bool floodfill);
void SetFamily (const std::string& family);
void SetHighBandwidth ();
void SetLowBandwidth ();
void SetExtraBandwidth ();

View File

@@ -8,6 +8,7 @@
#include "Base.h"
#include "Timestamp.h"
#include "Log.h"
#include "NetDb.h"
#include "RouterInfo.h"
namespace i2p
@@ -146,6 +147,7 @@ namespace data
bool introducers = false;
for (int i = 0; i < numAddresses; i++)
{
uint8_t supportedTransports = 0;
bool isValidAddress = true;
Address address;
s.read ((char *)&address.cost, sizeof (address.cost));
@@ -178,12 +180,12 @@ namespace data
{
if (address.transportStyle == eTransportNTCP)
{
m_SupportedTransports |= eNTCPV4; // TODO:
supportedTransports |= eNTCPV4; // TODO:
address.addressString = value;
}
else
{
m_SupportedTransports |= eSSUV4; // TODO:
supportedTransports |= eSSUV4; // TODO:
address.addressString = value;
}
}
@@ -191,9 +193,9 @@ namespace data
{
// add supported protocol
if (address.host.is_v4 ())
m_SupportedTransports |= (address.transportStyle == eTransportNTCP) ? eNTCPV4 : eSSUV4;
supportedTransports |= (address.transportStyle == eTransportNTCP) ? eNTCPV4 : eSSUV4;
else
m_SupportedTransports |= (address.transportStyle == eTransportNTCP) ? eNTCPV6 : eSSUV6;
supportedTransports |= (address.transportStyle == eTransportNTCP) ? eNTCPV6 : eSSUV6;
}
}
else if (!strcmp (key, "port"))
@@ -229,7 +231,10 @@ namespace data
if (!s) return;
}
if (isValidAddress)
{
m_Addresses.push_back(address);
m_SupportedTransports |= supportedTransports;
}
}
// read peers
uint8_t numPeers;
@@ -258,11 +263,26 @@ namespace data
if (!strcmp (key, "caps"))
ExtractCaps (value);
// check netId
if (!strcmp (key, "netId") && atoi (value) != I2PD_NET_ID)
else if (!strcmp (key, ROUTER_INFO_PROPERTY_NETID) && atoi (value) != I2PD_NET_ID)
{
LogPrint (eLogError, "Unexpected netid=", value);
LogPrint (eLogError, "Unexpected ", ROUTER_INFO_PROPERTY_NETID, "=", value);
m_IsUnreachable = true;
}
// family
else if (!strcmp (key, ROUTER_INFO_PROPERTY_FAMILY))
{
m_Family = value;
boost::to_lower (m_Family);
}
else if (!strcmp (key, ROUTER_INFO_PROPERTY_FAMILY_SIG))
{
if (!netdb.GetFamilies ().VerifyFamily (m_Family, GetIdentHash (), value))
{
LogPrint (eLogWarning, "RouterInfo: family signature verification failed");
m_Family.clear ();
}
}
if (!s) return;
}
@@ -455,6 +475,14 @@ namespace data
s.write (properties.str ().c_str (), properties.str ().size ());
}
bool RouterInfo::IsNewer (const uint8_t * buf, size_t len) const
{
if (!m_RouterIdentity) return false;
size_t size = m_RouterIdentity->GetFullLen ();
if (size + 8 > len) return false;
return bufbe64toh (buf + size) > m_Timestamp;
}
const uint8_t * RouterInfo::LoadBuffer ()
{
if (!m_Buffer)
@@ -601,11 +629,6 @@ namespace data
m_Properties.erase (key);
}
bool RouterInfo::IsFloodfill () const
{
return m_Caps & Caps::eFloodfill;
}
bool RouterInfo::IsNTCP (bool v4only) const
{
if (v4only)

View File

@@ -14,6 +14,12 @@ namespace i2p
{
namespace data
{
const char ROUTER_INFO_PROPERTY_LEASESETS[] = "netdb.knownLeaseSets";
const char ROUTER_INFO_PROPERTY_ROUTERS[] = "netdb.knownRouters";
const char ROUTER_INFO_PROPERTY_NETID[] = "netId";
const char ROUTER_INFO_PROPERTY_FAMILY[] = "family";
const char ROUTER_INFO_PROPERTY_FAMILY_SIG[] = "family.sig";
const char CAPS_FLAG_FLOODFILL = 'f';
const char CAPS_FLAG_HIDDEN = 'H';
const char CAPS_FLAG_REACHABLE = 'R';
@@ -122,7 +128,8 @@ namespace data
void SetProperty (const std::string& key, const std::string& value); // called from RouterContext only
void DeleteProperty (const std::string& key); // called from RouterContext only
void ClearProperties () { m_Properties.clear (); };
bool IsFloodfill () const;
bool IsFloodfill () const { return m_Caps & Caps::eFloodfill; };
bool IsReachable () const { return m_Caps & Caps::eReachable; };
bool IsNTCP (bool v4only = true) const;
bool IsSSU (bool v4only = true) const;
bool IsV6 () const;
@@ -157,7 +164,8 @@ namespace data
void Update (const uint8_t * buf, int len);
void DeleteBuffer () { delete[] m_Buffer; m_Buffer = nullptr; };
bool IsNewer (const uint8_t * buf, size_t len) const;
// implements RoutingDestination
const IdentHash& GetIdentHash () const { return m_RouterIdentity->GetIdentHash (); };
const uint8_t * GetEncryptionPublicKey () const { return m_RouterIdentity->GetStandardIdentity ().publicKey; };
@@ -179,7 +187,7 @@ namespace data
private:
std::string m_FullPath;
std::string m_FullPath, m_Family;
std::shared_ptr<const IdentityEx> m_RouterIdentity;
uint8_t * m_Buffer;
size_t m_BufferLen;

13
SAM.cpp
View File

@@ -631,10 +631,15 @@ namespace client
m_SocketType = eSAMSocketTypeStream;
if (!m_IsSilent)
{
// send remote peer address
uint8_t ident[1024];
size_t l = stream->GetRemoteIdentity ()->ToBuffer (ident, 1024);
size_t l1 = i2p::data::ByteStreamToBase64 (ident, l, (char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE);
// get remote peer address
auto ident_ptr = stream->GetRemoteIdentity();
const size_t ident_len = ident_ptr->GetFullLen();
uint8_t* ident = new uint8_t[ident_len];
// send remote peer address as base64
const size_t l = ident_ptr->ToBuffer (ident, ident_len);
const size_t l1 = i2p::data::ByteStreamToBase64 (ident, l, (char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE);
delete[] ident;
m_StreamBuffer[l1] = '\n';
HandleI2PReceive (boost::system::error_code (), l1 +1); // we send identity like it has been received from stream
}

279
SOCKS.cpp
View File

@@ -9,6 +9,7 @@
#include "ClientContext.h"
#include "I2PEndian.h"
#include "I2PTunnel.h"
#include "I2PService.h"
namespace i2p
{
@@ -17,6 +18,10 @@ namespace proxy
static const size_t socks_buffer_size = 8192;
static const size_t max_socks_hostname_size = 255; // Limit for socks5 and bad idea to traverse
static const size_t SOCKS_FORWARDER_BUFFER_SIZE = 8192;
static const size_t SOCKS_UPSTREAM_SOCKS4A_REPLY_SIZE = 8;
struct SOCKSDnsAddress
{
uint8_t size;
@@ -51,7 +56,10 @@ namespace proxy
GET5_IPV6,
GET5_HOST_SIZE,
GET5_HOST,
DONE
READY,
UPSTREAM_RESOLVE,
UPSTREAM_CONNECT,
UPSTREAM_HANDSHAKE
};
enum authMethods
{
@@ -109,6 +117,7 @@ namespace proxy
boost::asio::const_buffers_1 GenerateSOCKS5SelectAuth(authMethods method);
boost::asio::const_buffers_1 GenerateSOCKS4Response(errTypes error, uint32_t ip, uint16_t port);
boost::asio::const_buffers_1 GenerateSOCKS5Response(errTypes error, addrTypes type, const address &addr, uint16_t port);
boost::asio::const_buffers_1 GenerateUpstreamRequest();
bool Socks5ChooseAuth();
void SocksRequestFailed(errTypes error);
void SocksRequestSuccess();
@@ -116,12 +125,29 @@ namespace proxy
void SentSocksDone(const boost::system::error_code & ecode);
void SentSocksResponse(const boost::system::error_code & ecode);
void HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream);
void ForwardSOCKS();
uint8_t m_sock_buff[socks_buffer_size];
std::shared_ptr<boost::asio::ip::tcp::socket> m_sock;
void SocksUpstreamSuccess();
void AsyncUpstreamSockRead();
void SendUpstreamRequest();
void HandleUpstreamData(uint8_t * buff, std::size_t len);
void HandleUpstreamSockSend(const boost::system::error_code & ecode, std::size_t bytes_transfered);
void HandleUpstreamSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered);
void HandleUpstreamConnected(const boost::system::error_code & ecode,
boost::asio::ip::tcp::resolver::iterator itr);
void HandleUpstreamResolved(const boost::system::error_code & ecode,
boost::asio::ip::tcp::resolver::iterator itr);
boost::asio::ip::tcp::resolver m_proxy_resolver;
uint8_t m_sock_buff[socks_buffer_size];
std::shared_ptr<boost::asio::ip::tcp::socket> m_sock, m_upstreamSock;
std::shared_ptr<i2p::stream::Stream> m_stream;
uint8_t *m_remaining_data; //Data left to be sent
uint8_t *m_remaining_upstream_data; //upstream data left to be forwarded
uint8_t m_response[7+max_socks_hostname_size];
uint8_t m_upstream_response[SOCKS_UPSTREAM_SOCKS4A_REPLY_SIZE];
uint8_t m_upstream_request[14+max_socks_hostname_size];
std::size_t m_upstream_response_len;
address m_address; //Address
std::size_t m_remaining_data_len; //Size of the data left to be sent
uint32_t m_4aip; //Used in 4a requests
@@ -133,16 +159,25 @@ namespace proxy
socksVersions m_socksv; //Socks version
cmdTypes m_cmd; // Command requested
state m_state;
const bool m_UseUpstreamProxy; // do we want to use the upstream proxy for non i2p addresses?
const std::string m_UpstreamProxyAddress;
const uint16_t m_UpstreamProxyPort;
public:
SOCKSHandler(SOCKSServer * parent, std::shared_ptr<boost::asio::ip::tcp::socket> sock) :
I2PServiceHandler(parent), m_sock(sock), m_stream(nullptr),
m_authchosen(AUTH_UNACCEPTABLE), m_addrtype(ADDR_IPV4)
SOCKSHandler(SOCKSServer * parent, std::shared_ptr<boost::asio::ip::tcp::socket> sock, const std::string & upstreamAddr, const uint16_t upstreamPort, const bool useUpstream) :
I2PServiceHandler(parent),
m_proxy_resolver(parent->GetService()),
m_sock(sock), m_stream(nullptr),
m_authchosen(AUTH_UNACCEPTABLE), m_addrtype(ADDR_IPV4),
m_UseUpstreamProxy(useUpstream),
m_UpstreamProxyAddress(upstreamAddr),
m_UpstreamProxyPort(upstreamPort)
{ m_address.ip = 0; EnterState(GET_SOCKSV); }
~SOCKSHandler() { Terminate(); }
void Handle() { AsyncSockRead(); }
};
void SOCKSHandler::AsyncSockRead()
{
LogPrint(eLogDebug, "SOCKS: async sock read");
@@ -164,6 +199,12 @@ namespace proxy
m_sock->close();
m_sock = nullptr;
}
if (m_upstreamSock)
{
LogPrint(eLogDebug, "SOCKS: closing upstream socket");
m_upstreamSock->close();
m_upstreamSock = nullptr;
}
if (m_stream)
{
LogPrint(eLogDebug, "SOCKS: closing stream");
@@ -210,6 +251,37 @@ namespace proxy
return boost::asio::const_buffers_1(m_response,size);
}
boost::asio::const_buffers_1 SOCKSHandler::GenerateUpstreamRequest()
{
size_t upstreamRequestSize = 0;
// TODO: negotiate with upstream
// SOCKS 4a
m_upstream_request[0] = '\x04'; //version
m_upstream_request[1] = m_cmd;
htobe16buf(m_upstream_request+2, m_port);
m_upstream_request[4] = 0;
m_upstream_request[5] = 0;
m_upstream_request[6] = 0;
m_upstream_request[7] = 1;
// user id
m_upstream_request[8] = 'i';
m_upstream_request[9] = '2';
m_upstream_request[10] = 'p';
m_upstream_request[11] = 'd';
m_upstream_request[12] = 0;
upstreamRequestSize += 13;
if (m_address.dns.size <= max_socks_hostname_size - ( upstreamRequestSize + 1) ) {
// bounds check okay
memcpy(m_upstream_request + upstreamRequestSize, m_address.dns.value, m_address.dns.size);
upstreamRequestSize += m_address.dns.size;
// null terminate
m_upstream_request[++upstreamRequestSize] = 0;
} else {
LogPrint(eLogError, "SOCKS: BUG!!! m_addr.dns.sizs > max_socks_hostname - ( upstreamRequestSize + 1 ) )");
}
return boost::asio::const_buffers_1(m_upstream_request, upstreamRequestSize);
}
bool SOCKSHandler::Socks5ChooseAuth()
{
m_response[0] = '\x05'; //Version
@@ -219,14 +291,14 @@ namespace proxy
{
LogPrint(eLogWarning, "SOCKS: v5 authentication negotiation failed");
boost::asio::async_write(*m_sock, response, std::bind(&SOCKSHandler::SentSocksFailed,
shared_from_this(), std::placeholders::_1));
shared_from_this(), std::placeholders::_1));
return false;
}
else
{
LogPrint(eLogDebug, "SOCKS: v5 choosing authentication method: ", m_authchosen);
boost::asio::async_write(*m_sock, response, std::bind(&SOCKSHandler::SentSocksResponse,
shared_from_this(), std::placeholders::_1));
shared_from_this(), std::placeholders::_1));
return true;
}
}
@@ -249,7 +321,7 @@ namespace proxy
break;
}
boost::asio::async_write(*m_sock, response, std::bind(&SOCKSHandler::SentSocksFailed,
shared_from_this(), std::placeholders::_1));
shared_from_this(), std::placeholders::_1));
}
void SOCKSHandler::SocksRequestSuccess()
@@ -271,7 +343,7 @@ namespace proxy
break;
}
boost::asio::async_write(*m_sock, response, std::bind(&SOCKSHandler::SentSocksDone,
shared_from_this(), std::placeholders::_1));
shared_from_this(), std::placeholders::_1));
}
void SOCKSHandler::EnterState(SOCKSHandler::state nstate, uint8_t parseleft) {
@@ -313,13 +385,6 @@ namespace proxy
SocksRequestFailed(SOCKS5_ADDR_UNSUP);
return false;
}
//TODO: we may want to support other domains
if(m_addrtype == ADDR_DNS && m_address.dns.ToString().find(".i2p") == std::string::npos)
{
LogPrint(eLogError, "SOCKS: invalid hostname: ", m_address.dns.ToString());
SocksRequestFailed(SOCKS5_ADDR_UNSUP);
return false;
}
return true;
}
@@ -386,7 +451,7 @@ namespace proxy
{
switch (m_socksv)
{
case SOCKS5: EnterState(DONE); break;
case SOCKS5: EnterState(READY); break;
case SOCKS4: EnterState(GET_IPV4); break;
}
}
@@ -407,7 +472,7 @@ namespace proxy
if (!*sock_buff)
{
if( m_4aip == 0 || m_4aip > 255 )
EnterState(DONE);
EnterState(READY);
else
EnterState(GET4A_HOST);
}
@@ -415,7 +480,7 @@ namespace proxy
case GET4A_HOST:
if (!*sock_buff)
{
EnterState(DONE);
EnterState(READY);
break;
}
if (m_address.dns.size >= max_socks_hostname_size)
@@ -476,7 +541,7 @@ namespace proxy
}
sock_buff++;
len--;
if (m_state == DONE)
if (m_state == READY)
{
m_remaining_data_len = len;
m_remaining_data = sock_buff;
@@ -498,11 +563,23 @@ namespace proxy
if (HandleData(m_sock_buff, len))
{
if (m_state == DONE)
if (m_state == READY)
{
LogPrint(eLogInfo, "SOCKS: requested ", m_address.dns.ToString(), ":" , m_port);
GetOwner()->CreateStream ( std::bind (&SOCKSHandler::HandleStreamRequestComplete,
shared_from_this(), std::placeholders::_1), m_address.dns.ToString(), m_port);
const std::string addr = m_address.dns.ToString();
LogPrint(eLogInfo, "SOCKS: requested ", addr, ":" , m_port);
const size_t addrlen = addr.size();
// does it end with .i2p?
if ( addr.rfind(".i2p") == addrlen - 4) {
// yes it does, make an i2p session
GetOwner()->CreateStream ( std::bind (&SOCKSHandler::HandleStreamRequestComplete,
shared_from_this(), std::placeholders::_1), m_address.dns.ToString(), m_port);
} else if (m_UseUpstreamProxy) {
// forward it to upstream proxy
ForwardSOCKS();
} else {
// no upstream proxy
SocksRequestFailed(SOCKS5_ADDR_UNSUP);
}
}
else
AsyncSockRead();
@@ -556,17 +633,159 @@ namespace proxy
SocksRequestFailed(SOCKS5_HOST_UNREACH);
}
}
void SOCKSHandler::ForwardSOCKS()
{
LogPrint(eLogInfo, "SOCKS: forwarding to upstream");
EnterState(UPSTREAM_RESOLVE);
boost::asio::ip::tcp::resolver::query q(m_UpstreamProxyAddress,boost::lexical_cast<std::string>(m_UpstreamProxyPort) );
m_proxy_resolver.async_resolve(q, std::bind(&SOCKSHandler::HandleUpstreamResolved, shared_from_this(),
std::placeholders::_1, std::placeholders::_2));
}
SOCKSServer::SOCKSServer(const std::string& address, int port, const std::string& outAddress, int outPort,
std::shared_ptr<i2p::client::ClientDestination> localDestination) :
void SOCKSHandler::AsyncUpstreamSockRead()
{
LogPrint(eLogDebug, "SOCKS: async upstream sock read");
if (m_upstreamSock) {
m_upstreamSock->async_read_some(boost::asio::buffer(m_upstream_response, SOCKS_UPSTREAM_SOCKS4A_REPLY_SIZE),
std::bind(&SOCKSHandler::HandleUpstreamSockRecv, shared_from_this(),
std::placeholders::_1, std::placeholders::_2));
} else {
LogPrint(eLogError, "SOCKS: no upstream socket for read");
SocksRequestFailed(SOCKS5_GEN_FAIL);
}
}
void SOCKSHandler::HandleUpstreamSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered)
{
if (ecode) {
if (m_state == UPSTREAM_HANDSHAKE ) {
// we are trying to handshake but it failed
SocksRequestFailed(SOCKS5_NET_UNREACH);
} else {
LogPrint(eLogError, "SOCKS: bad state when reading from upstream: ", (int) m_state);
}
return;
}
HandleUpstreamData(m_upstream_response, bytes_transfered);
}
void SOCKSHandler::SocksUpstreamSuccess()
{
LogPrint(eLogInfo, "SOCKS: upstream success");
boost::asio::const_buffers_1 response(nullptr, 0);
switch (m_socksv)
{
case SOCKS4:
LogPrint(eLogInfo, "SOCKS: v4 connection success");
response = GenerateSOCKS4Response(SOCKS4_OK, m_4aip, m_port);
break;
case SOCKS5:
LogPrint(eLogInfo, "SOCKS: v5 connection success");
//HACK only 16 bits passed in port as SOCKS5 doesn't allow for more
response = GenerateSOCKS5Response(SOCKS5_OK, ADDR_DNS, m_address, m_port);
break;
}
m_sock->send(response);
auto forwarder = std::make_shared<i2p::client::TCPIPPipe>(GetOwner(), m_sock, m_upstreamSock);
m_upstreamSock = nullptr;
m_sock = nullptr;
GetOwner()->AddHandler(forwarder);
forwarder->Start();
Terminate();
}
void SOCKSHandler::HandleUpstreamData(uint8_t * dataptr, std::size_t len)
{
if (m_state == UPSTREAM_HANDSHAKE) {
m_upstream_response_len += len;
// handle handshake data
if (m_upstream_response_len < SOCKS_UPSTREAM_SOCKS4A_REPLY_SIZE) {
// too small, continue reading
AsyncUpstreamSockRead();
} else if (len == SOCKS_UPSTREAM_SOCKS4A_REPLY_SIZE) {
// just right
uint8_t resp = m_upstream_response[1];
if (resp == SOCKS4_OK) {
// we have connected !
SocksUpstreamSuccess();
} else {
// upstream failure
LogPrint(eLogError, "SOCKS: upstream proxy failure: ", (int) resp);
// TODO: runtime error?
SocksRequestFailed(SOCKS5_GEN_FAIL);
}
} else {
// too big
SocksRequestFailed(SOCKS5_GEN_FAIL);
}
} else {
// invalid state
LogPrint(eLogError, "SOCKS: invalid state reading from upstream: ", (int) m_state);
}
}
void SOCKSHandler::SendUpstreamRequest()
{
LogPrint(eLogInfo, "SOCKS: negotiating with upstream proxy");
EnterState(UPSTREAM_HANDSHAKE);
if (m_upstreamSock) {
boost::asio::write(*m_upstreamSock,
GenerateUpstreamRequest());
AsyncUpstreamSockRead();
} else {
LogPrint(eLogError, "SOCKS: no upstream socket to send handshake to");
}
}
void SOCKSHandler::HandleUpstreamConnected(const boost::system::error_code & ecode, boost::asio::ip::tcp::resolver::iterator itr)
{
if (ecode) {
LogPrint(eLogWarning, "SOCKS: could not connect to upstream proxy: ", ecode.message());
SocksRequestFailed(SOCKS5_NET_UNREACH);
return;
}
LogPrint(eLogInfo, "SOCKS: connected to upstream proxy");
SendUpstreamRequest();
}
void SOCKSHandler::HandleUpstreamResolved(const boost::system::error_code & ecode, boost::asio::ip::tcp::resolver::iterator itr)
{
if (ecode) {
// error resolving
LogPrint(eLogWarning, "SOCKS: upstream proxy", m_UpstreamProxyAddress, " not resolved: ", ecode.message());
SocksRequestFailed(SOCKS5_NET_UNREACH);
return;
}
LogPrint(eLogInfo, "SOCKS: upstream proxy resolved");
EnterState(UPSTREAM_CONNECT);
auto & service = GetOwner()->GetService();
m_upstreamSock = std::make_shared<boost::asio::ip::tcp::socket>(service);
boost::asio::async_connect(*m_upstreamSock, itr,
std::bind(&SOCKSHandler::HandleUpstreamConnected,
shared_from_this(), std::placeholders::_1, std::placeholders::_2));
}
SOCKSServer::SOCKSServer(const std::string& address, int port, const std::string& outAddress, uint16_t outPort,
std::shared_ptr<i2p::client::ClientDestination> localDestination) :
TCPIPAcceptor (address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ())
{
m_UseUpstreamProxy = false;
if (outAddress.length() > 0)
SetUpstreamProxy(outAddress, outPort);
}
std::shared_ptr<i2p::client::I2PServiceHandler> SOCKSServer::CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket)
{
return std::make_shared<SOCKSHandler> (this, socket);
return std::make_shared<SOCKSHandler> (this, socket, m_UpstreamProxyAddress, m_UpstreamProxyPort, m_UseUpstreamProxy);
}
void SOCKSServer::SetUpstreamProxy(const std::string & addr, const uint16_t port)
{
m_UpstreamProxyAddress = addr;
m_UpstreamProxyPort = port;
m_UseUpstreamProxy = true;
}
}
}

View File

@@ -15,14 +15,21 @@ namespace proxy
{
public:
SOCKSServer(const std::string& address, int port, const std::string& outAddress, int outPort,
SOCKSServer(const std::string& address, int port, const std::string& outAddress, uint16_t outPort,
std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr);
~SOCKSServer() {};
void SetUpstreamProxy(const std::string & addr, const uint16_t port);
protected:
// Implements TCPIPAcceptor
std::shared_ptr<i2p::client::I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket);
const char* GetName() { return "SOCKS"; }
private:
std::string m_UpstreamProxyAddress;
uint16_t m_UpstreamProxyPort;
bool m_UseUpstreamProxy;
};
typedef SOCKSServer SOCKSProxy;

View File

@@ -157,7 +157,7 @@ namespace transport
ProcessData (buf + headerSize, len - headerSize);
break;
case PAYLOAD_TYPE_SESSION_REQUEST:
ProcessSessionRequest (buf + headerSize, len - headerSize, senderEndpoint);
ProcessSessionRequest (buf, len, senderEndpoint); // buf with header
break;
case PAYLOAD_TYPE_SESSION_CREATED:
ProcessSessionCreated (buf, len); // buf with header
@@ -196,11 +196,29 @@ namespace transport
void SSUSession::ProcessSessionRequest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
{
LogPrint (eLogDebug, "SSU message: session request");
bool sendRelayTag = true;
auto headerSize = sizeof (SSUHeader);
if (((SSUHeader *)buf)->IsExtendedOptions ())
{
uint8_t extendedOptionsLen = buf[headerSize];
headerSize++;
if (extendedOptionsLen >= 3) // options are presented
{
uint16_t flags = bufbe16toh (buf + headerSize);
sendRelayTag = flags & EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG;
}
headerSize += extendedOptionsLen;
}
if (headerSize >= len)
{
LogPrint (eLogError, "Session reaquest header size ", headerSize, " exceeds packet length ", len);
return;
}
m_RemoteEndpoint = senderEndpoint;
if (!m_DHKeysPair)
m_DHKeysPair = transports.GetNextDHKeysPair ();
CreateAESandMacKey (buf);
SendSessionCreated (buf);
CreateAESandMacKey (buf + headerSize);
SendSessionCreated (buf + headerSize, sendRelayTag);
}
void SSUSession::ProcessSessionCreated (uint8_t * buf, size_t len)
@@ -306,6 +324,18 @@ namespace transport
{
uint8_t buf[320 + 18]; // 304 bytes for ipv4, 320 for ipv6
uint8_t * payload = buf + sizeof (SSUHeader);
uint8_t flag = 0;
// fill extended options, 3 bytes extended options don't change message size
if (i2p::context.GetStatus () == eRouterStatusOK) // we don't need relays
{
// tell out peer to now assign relay tag
flag = SSU_HEADER_EXTENDED_OPTIONS_INCLUDED;
*payload = 2; payload++; // 1 byte length
uint16_t flags = 0; // clear EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG
htobe16buf (payload, flags);
payload += 2;
}
// fill payload
memcpy (payload, m_DHKeysPair->GetPublicKey (), 256); // x
bool isV4 = m_RemoteEndpoint.address ().is_v4 ();
if (isV4)
@@ -318,10 +348,10 @@ namespace transport
payload[256] = 16;
memcpy (payload + 257, m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data(), 16);
}
// encrypt and send
uint8_t iv[16];
RAND_bytes (iv, 16); // random iv
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_REQUEST, buf, isV4 ? 304 : 320, m_IntroKey, iv, m_IntroKey);
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_REQUEST, buf, isV4 ? 304 : 320, m_IntroKey, iv, m_IntroKey, flag);
m_Server.Send (buf, isV4 ? 304 : 320, m_RemoteEndpoint);
}
@@ -357,7 +387,7 @@ namespace transport
m_Server.Send (buf, 96, m_RemoteEndpoint);
}
void SSUSession::SendSessionCreated (const uint8_t * x)
void SSUSession::SendSessionCreated (const uint8_t * x, bool sendRelayTag)
{
auto address = IsV6 () ? i2p::context.GetRouterInfo ().GetSSUV6Address () :
i2p::context.GetRouterInfo ().GetSSUAddress (true); //v4 only
@@ -401,7 +431,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 () && !IsV6 ())
if (sendRelayTag && i2p::context.GetRouterInfo ().IsIntroducer () && !IsV6 ())
{
RAND_bytes((uint8_t *)&relayTag, 4);
if (!relayTag) relayTag = 1;
@@ -648,7 +678,7 @@ namespace transport
}
void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len,
const i2p::crypto::AESKey& aesKey, const uint8_t * iv, const i2p::crypto::MACKey& macKey)
const i2p::crypto::AESKey& aesKey, const uint8_t * iv, const i2p::crypto::MACKey& macKey, uint8_t flag)
{
if (len < sizeof (SSUHeader))
{
@@ -657,7 +687,7 @@ namespace transport
}
SSUHeader * header = (SSUHeader *)buf;
memcpy (header->iv, iv, 16);
header->flag = payloadType << 4; // MSB is 0
header->flag = flag | (payloadType << 4); // MSB is 0
htobe32buf (header->time, i2p::util::GetSecondsSinceEpoch ());
uint8_t * encrypted = &header->flag;
uint16_t encryptedLen = len - (encrypted - buf);

View File

@@ -39,6 +39,9 @@ namespace transport
const uint8_t PAYLOAD_TYPE_PEER_TEST = 7;
const uint8_t PAYLOAD_TYPE_SESSION_DESTROYED = 8;
// extended options
const uint16_t EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG = 0x0001;
enum SessionState
{
eSessionStateUnknown,
@@ -101,7 +104,7 @@ namespace transport
void SendSessionRequest ();
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 SendSessionCreated (const uint8_t * x, bool sendRelayTag = true);
void ProcessSessionConfirmed (const uint8_t * buf, size_t len);
void SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, size_t ourAddressLen);
void ProcessRelayRequest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from);
@@ -121,7 +124,8 @@ namespace transport
void Send (uint8_t type, const uint8_t * payload, size_t len); // with session key
void Send (const uint8_t * buf, size_t size);
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey, const uint8_t * iv, const i2p::crypto::MACKey& macKey);
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey,
const uint8_t * iv, const i2p::crypto::MACKey& macKey, uint8_t flag = 0);
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len); // with session key
void Decrypt (uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey);
void DecryptSessionKey (uint8_t * buf, size_t len);

View File

@@ -22,7 +22,6 @@ namespace stream
{
RAND_bytes ((uint8_t *)&m_RecvStreamID, 4);
m_RemoteIdentity = remote->GetIdentity ();
m_CurrentRemoteLease.endDate = 0;
}
Stream::Stream (boost::asio::io_service& service, StreamingDestination& local):
@@ -89,7 +88,7 @@ namespace stream
}
LogPrint (eLogDebug, "Streaming: Received seqn=", receivedSeqn);
if (isSyn || receivedSeqn == m_LastReceivedSequenceNumber + 1)
if (receivedSeqn == m_LastReceivedSequenceNumber + 1)
{
// we have received next in sequence message
ProcessPacket (packet);
@@ -114,7 +113,9 @@ namespace stream
if (!m_IsAckSendScheduled)
{
m_IsAckSendScheduled = true;
m_AckSendTimer.expires_from_now (boost::posix_time::milliseconds(ACK_SEND_TIMEOUT));
auto ackTimeout = m_RTT/10;
if (ackTimeout > ACK_SEND_TIMEOUT) ackTimeout = ACK_SEND_TIMEOUT;
m_AckSendTimer.expires_from_now (boost::posix_time::milliseconds(ackTimeout));
m_AckSendTimer.async_wait (std::bind (&Stream::HandleAckSendTimer,
shared_from_this (), std::placeholders::_1));
}
@@ -272,6 +273,10 @@ namespace stream
m_LastWindowSizeIncreaseTime = ts;
}
}
if (!seqn && m_RoutingSession) // first message confirmed
m_RoutingSession->SetSharedRoutingPath (
std::make_shared<i2p::garlic::GarlicRoutingPath> (
i2p::garlic::GarlicRoutingPath{m_CurrentOutboundTunnel, m_CurrentRemoteLease, m_RTT, 0, 0}));
}
else
break;
@@ -590,6 +595,23 @@ namespace stream
return;
}
}
if (!m_CurrentOutboundTunnel) // first message to send
{
// try to get shared path first
if (!m_RoutingSession)
m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true);
if (m_RoutingSession)
{
auto routingPath = m_RoutingSession->GetSharedRoutingPath ();
if (routingPath)
{
m_CurrentOutboundTunnel = routingPath->outboundTunnel;
m_CurrentRemoteLease = routingPath->remoteLease;
m_RTT = routingPath->rtt;
m_RTO = m_RTT*1.5; // TODO: implement it better
}
}
}
if (!m_CurrentOutboundTunnel || !m_CurrentOutboundTunnel->IsEstablished ())
m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNewOutboundTunnel (m_CurrentOutboundTunnel);
if (!m_CurrentOutboundTunnel)
@@ -599,18 +621,18 @@ namespace stream
}
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
if (!m_CurrentRemoteLease.endDate || ts >= m_CurrentRemoteLease.endDate - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD*1000)
if (!m_CurrentRemoteLease || ts >= m_CurrentRemoteLease->endDate - i2p::data::LEASE_ENDDATE_THRESHOLD)
UpdateCurrentRemoteLease (true);
if (ts < m_CurrentRemoteLease.endDate)
if (m_CurrentRemoteLease && ts < m_CurrentRemoteLease->endDate + i2p::data::LEASE_ENDDATE_THRESHOLD)
{
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
for (auto it: packets)
{
auto msg = m_RoutingSession->WrapSingleMessage (CreateDataMessage (it->GetBuffer (), it->GetLength ()));
auto msg = m_RoutingSession->WrapSingleMessage (m_LocalDestination.CreateDataMessage (it->GetBuffer (), it->GetLength (), m_Port));
msgs.push_back (i2p::tunnel::TunnelMessageBlock
{
i2p::tunnel::eDeliveryTypeTunnel,
m_CurrentRemoteLease.tunnelGateway, m_CurrentRemoteLease.tunnelID,
m_CurrentRemoteLease->tunnelGateway, m_CurrentRemoteLease->tunnelID,
msg
});
m_NumSentBytes += it->GetLength ();
@@ -669,12 +691,14 @@ namespace stream
case 2:
m_RTO = INITIAL_RTO; // drop RTO to initial upon tunnels pair change first time
// no break here
case 4:
case 4:
if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr);
UpdateCurrentRemoteLease (); // pick another lease
LogPrint (eLogWarning, "Streaming: Another remote lease has been selected for stream");
break;
case 3:
// pick another outbound tunnel
if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr);
m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNextOutboundTunnel (m_CurrentOutboundTunnel);
LogPrint (eLogWarning, "Streaming: Another outbound tunnel has been selected for stream");
break;
@@ -705,11 +729,11 @@ namespace stream
void Stream::UpdateCurrentRemoteLease (bool expired)
{
if (!m_RemoteLeaseSet)
if (!m_RemoteLeaseSet || m_RemoteLeaseSet->IsExpired ())
{
m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ());
if (!m_RemoteLeaseSet)
LogPrint (eLogError, "Streaming: LeaseSet ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), " not found");
if (!m_RemoteLeaseSet)
LogPrint (eLogWarning, "Streaming: LeaseSet ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), " not found");
}
if (m_RemoteLeaseSet)
{
@@ -719,16 +743,16 @@ namespace stream
if (leases.empty ())
{
expired = false;
m_LocalDestination.GetOwner ()->RequestDestination (m_RemoteIdentity->GetIdentHash ()); // time to re-request
leases = m_RemoteLeaseSet->GetNonExpiredLeases (true); // then with threshold
m_LocalDestination.GetOwner ()->RequestDestination (m_RemoteIdentity->GetIdentHash ()); // time to request
leases = m_RemoteLeaseSet->GetNonExpiredLeases (true); // then with threshold
}
if (!leases.empty ())
{
bool updated = false;
if (expired)
if (expired && m_CurrentRemoteLease)
{
for (auto it: leases)
if ((it.tunnelGateway == m_CurrentRemoteLease.tunnelGateway) && (it.tunnelID != m_CurrentRemoteLease.tunnelID))
if ((it->tunnelGateway == m_CurrentRemoteLease->tunnelGateway) && (it->tunnelID != m_CurrentRemoteLease->tunnelID))
{
m_CurrentRemoteLease = it;
updated = true;
@@ -738,7 +762,7 @@ namespace stream
if (!updated)
{
uint32_t i = rand () % leases.size ();
if (m_CurrentRemoteLease.endDate && leases[i].tunnelID == m_CurrentRemoteLease.tunnelID)
if (m_CurrentRemoteLease && leases[i]->tunnelID == m_CurrentRemoteLease->tunnelID)
// make sure we don't select previous
i = (i + 1) % leases.size (); // if so, pick next
m_CurrentRemoteLease = leases[i];
@@ -747,46 +771,28 @@ namespace stream
else
{
m_RemoteLeaseSet = nullptr;
m_CurrentRemoteLease.endDate = 0;
// re-request expired
m_CurrentRemoteLease = nullptr;
// we have requested expired before, no need to do it twice
}
}
else
m_CurrentRemoteLease.endDate = 0;
m_CurrentRemoteLease = nullptr;
}
std::shared_ptr<I2NPMessage> Stream::CreateDataMessage (const uint8_t * payload, size_t len)
{
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)
{
htobe32buf (msg->GetPayload (), size); // length
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;
msg->FillI2NPMessageHeader (eI2NPData);
}
else
msg = nullptr;
return msg;
}
StreamingDestination::StreamingDestination (std::shared_ptr<i2p::client::ClientDestination> owner, uint16_t localPort):
m_Owner (owner), m_LocalPort (localPort), m_PendingIncomingTimer (m_Owner->GetService ())
StreamingDestination::StreamingDestination (std::shared_ptr<i2p::client::ClientDestination> owner, uint16_t localPort, bool gzip):
m_Owner (owner), m_LocalPort (localPort), m_Gzip (gzip),
m_PendingIncomingTimer (m_Owner->GetService ())
{
}
StreamingDestination::~StreamingDestination ()
{
for (auto it: m_SavedPackets)
{
for (auto it1: it.second) delete it1;
it.second.clear ();
}
m_SavedPackets.clear ();
}
void StreamingDestination::Start ()
@@ -822,7 +828,20 @@ namespace stream
if (packet->IsSYN () && !packet->GetSeqn ()) // new incoming stream
{
auto incomingStream = CreateNewIncomingStream ();
incomingStream->HandleNextPacket (packet);
uint32_t receiveStreamID = packet->GetReceiveStreamID ();
incomingStream->HandleNextPacket (packet); // SYN
// handle saved packets if any
{
auto it = m_SavedPackets.find (receiveStreamID);
if (it != m_SavedPackets.end ())
{
LogPrint (eLogDebug, "Streaming: Processing ", it->second.size (), " saved packets for receiveStreamID=", receiveStreamID);
for (auto it1: it->second)
incomingStream->HandleNextPacket (it1);
m_SavedPackets.erase (it);
}
}
// accept
if (m_Acceptor != nullptr)
m_Acceptor (incomingStream);
else
@@ -834,7 +853,7 @@ namespace stream
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));
shared_from_this (), std::placeholders::_1));
LogPrint (eLogDebug, "Streaming: Pending incoming stream added");
}
else
@@ -854,9 +873,30 @@ namespace stream
it.second->HandleNextPacket (packet);
return;
}
// TODO: should queue it up
LogPrint (eLogError, "Streaming: Unknown stream receiveStreamID=", receiveStreamID);
delete packet;
// save follow on packet
auto it = m_SavedPackets.find (receiveStreamID);
if (it != m_SavedPackets.end ())
it->second.push_back (packet);
else
{
m_SavedPackets[receiveStreamID] = std::list<Packet *>{ packet };
auto timer = std::make_shared<boost::asio::deadline_timer> (m_Owner->GetService ());
timer->expires_from_now (boost::posix_time::seconds(PENDING_INCOMING_TIMEOUT));
auto s = shared_from_this ();
timer->async_wait ([s,timer,receiveStreamID](const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
{
auto it = s->m_SavedPackets.find (receiveStreamID);
if (it != s->m_SavedPackets.end ())
{
for (auto it1: it->second) delete it1;
it->second.clear ();
s->m_SavedPackets.erase (it);
}
}
});
}
}
}
}
@@ -929,5 +969,30 @@ namespace stream
else
delete uncompressed;
}
std::shared_ptr<I2NPMessage> StreamingDestination::CreateDataMessage (const uint8_t * payload, size_t len, uint16_t toPort)
{
auto msg = NewI2NPShortMessage ();
if (!m_Gzip || len <= i2p::stream::COMPRESSION_THRESHOLD_SIZE)
m_Deflator.SetCompressionLevel (Z_NO_COMPRESSION);
else
m_Deflator.SetCompressionLevel (Z_DEFAULT_COMPRESSION);
uint8_t * buf = msg->GetPayload ();
buf += 4; // reserve for lengthlength
msg->len += 4;
size_t size = m_Deflator.Deflate (payload, len, buf, msg->maxLen - msg->len);
if (size)
{
htobe32buf (msg->GetPayload (), size); // length
htobe16buf (buf + 4, m_LocalPort); // source port
htobe16buf (buf + 6, toPort); // destination port
buf[9] = i2p::client::PROTOCOL_TYPE_STREAMING; // streaming protocol
msg->len += size;
msg->FillI2NPMessageHeader (eI2NPData);
}
else
msg = nullptr;
return msg;
}
}
}

View File

@@ -158,8 +158,6 @@ namespace stream
void ScheduleResend ();
void HandleResendTimer (const boost::system::error_code& ecode);
void HandleAckSendTimer (const boost::system::error_code& ecode);
std::shared_ptr<I2NPMessage> CreateDataMessage (const uint8_t * payload, size_t len);
private:
@@ -172,7 +170,7 @@ namespace stream
std::shared_ptr<const i2p::data::IdentityEx> m_RemoteIdentity;
std::shared_ptr<const i2p::data::LeaseSet> m_RemoteLeaseSet;
std::shared_ptr<i2p::garlic::GarlicRoutingSession> m_RoutingSession;
i2p::data::Lease m_CurrentRemoteLease;
std::shared_ptr<const i2p::data::Lease> m_CurrentRemoteLease;
std::shared_ptr<i2p::tunnel::OutboundTunnel> m_CurrentOutboundTunnel;
std::queue<Packet *> m_ReceiveQueue;
std::set<Packet *, PacketCmp> m_SavedPackets;
@@ -189,13 +187,13 @@ namespace stream
SendHandler m_SendHandler;
};
class StreamingDestination
class StreamingDestination: public std::enable_shared_from_this<StreamingDestination>
{
public:
typedef std::function<void (std::shared_ptr<Stream>)> Acceptor;
StreamingDestination (std::shared_ptr<i2p::client::ClientDestination> owner, uint16_t localPort = 0);
StreamingDestination (std::shared_ptr<i2p::client::ClientDestination> owner, uint16_t localPort = 0, bool gzip = true);
~StreamingDestination ();
void Start ();
@@ -210,6 +208,7 @@ namespace stream
uint16_t GetLocalPort () const { return m_LocalPort; };
void HandleDataMessagePayload (const uint8_t * buf, size_t len);
std::shared_ptr<I2NPMessage> CreateDataMessage (const uint8_t * payload, size_t len, uint16_t toPort);
private:
@@ -221,11 +220,13 @@ namespace stream
std::shared_ptr<i2p::client::ClientDestination> m_Owner;
uint16_t m_LocalPort;
bool m_Gzip; // gzip compression of data messages
std::mutex m_StreamsMutex;
std::map<uint32_t, std::shared_ptr<Stream> > m_Streams;
std::map<uint32_t, std::shared_ptr<Stream> > m_Streams; // sendStreamID->stream
Acceptor m_Acceptor;
std::list<std::shared_ptr<Stream> > m_PendingIncomingStreams;
boost::asio::deadline_timer m_PendingIncomingTimer;
std::map<uint32_t, std::list<Packet *> > m_SavedPackets; // receiveStreamID->packets, arrived before SYN
public:

View File

@@ -85,7 +85,7 @@ namespace tunnel
m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg);
}
TransitTunnel * CreateTransitTunnel (uint32_t receiveTunnelID,
std::shared_ptr<TransitTunnel> CreateTransitTunnel (uint32_t receiveTunnelID,
const uint8_t * nextIdent, uint32_t nextTunnelID,
const uint8_t * layerKey,const uint8_t * ivKey,
bool isGateway, bool isEndpoint)
@@ -93,17 +93,17 @@ namespace tunnel
if (isEndpoint)
{
LogPrint (eLogInfo, "TransitTunnel: endpoint ", receiveTunnelID, " created");
return new TransitTunnelEndpoint (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
return std::make_shared<TransitTunnelEndpoint> (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
}
else if (isGateway)
{
LogPrint (eLogInfo, "TransitTunnel: gateway ", receiveTunnelID, " created");
return new TransitTunnelGateway (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
return std::make_shared<TransitTunnelGateway> (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
}
else
{
LogPrint (eLogInfo, "TransitTunnel: ", receiveTunnelID, "->", nextTunnelID, " created");
return new TransitTunnelParticipant (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
return std::make_shared<TransitTunnelParticipant> (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
}
}
}

View File

@@ -93,7 +93,7 @@ namespace tunnel
TunnelEndpoint m_Endpoint;
};
TransitTunnel * CreateTransitTunnel (uint32_t receiveTunnelID,
std::shared_ptr<TransitTunnel> CreateTransitTunnel (uint32_t receiveTunnelID,
const uint8_t * nextIdent, uint32_t nextTunnelID,
const uint8_t * layerKey,const uint8_t * ivKey,
bool isGateway, bool isEndpoint);

View File

@@ -205,6 +205,26 @@ namespace tunnel
PrintHops (s);
s << "" << GetTunnelID () << ":me";
}
ZeroHopsInboundTunnel::ZeroHopsInboundTunnel ():
InboundTunnel (std::make_shared<ZeroHopsTunnelConfig> ()),
m_NumReceivedBytes (0)
{
}
void ZeroHopsInboundTunnel::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
{
if (msg)
{
m_NumReceivedBytes += msg->GetLength ();
HandleI2NPMessage (msg);
}
}
void ZeroHopsInboundTunnel::Print (std::stringstream& s) const
{
s << "" << GetTunnelID () << ":me";
}
void OutboundTunnel::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg)
{
@@ -224,8 +244,7 @@ namespace tunnel
block.deliveryType = eDeliveryTypeLocal;
block.data = msg;
std::unique_lock<std::mutex> l(m_SendMutex);
m_Gateway.SendTunnelDataMsg (block);
SendTunnelDataMsg ({block});
}
void OutboundTunnel::SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs)
@@ -248,6 +267,38 @@ namespace tunnel
s << "";
}
ZeroHopsOutboundTunnel::ZeroHopsOutboundTunnel ():
OutboundTunnel (std::make_shared<ZeroHopsTunnelConfig> ()),
m_NumSentBytes (0)
{
}
void ZeroHopsOutboundTunnel::SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs)
{
for (auto& msg : msgs)
{
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:
i2p::transport::transports.SendMessage (msg.hash, msg.data);
break;
default:
LogPrint (eLogError, "Tunnel: Unknown delivery type ", (int)msg.deliveryType);
}
}
}
void ZeroHopsOutboundTunnel::Print (std::stringstream& s) const
{
s << GetTunnelID () << ":me ⇒ ";
}
Tunnels tunnels;
Tunnels::Tunnels (): m_IsRunning (false), m_Thread (nullptr),
@@ -257,27 +308,16 @@ namespace tunnel
Tunnels::~Tunnels ()
{
for (auto& it : m_TransitTunnels)
delete it.second;
m_TransitTunnels.clear ();
}
std::shared_ptr<InboundTunnel> Tunnels::GetInboundTunnel (uint32_t tunnelID)
std::shared_ptr<TunnelBase> Tunnels::GetTunnel (uint32_t tunnelID)
{
auto it = m_InboundTunnels.find(tunnelID);
if (it != m_InboundTunnels.end ())
auto it = m_Tunnels.find(tunnelID);
if (it != m_Tunnels.end ())
return it->second;
return nullptr;
}
TransitTunnel * Tunnels::GetTransitTunnel (uint32_t tunnelID)
{
auto it = m_TransitTunnels.find(tunnelID);
if (it != m_TransitTunnels.end ())
return it->second;
return nullptr;
}
std::shared_ptr<InboundTunnel> Tunnels::GetPendingInboundTunnel (uint32_t replyMsgID)
{
return GetPendingTunnel (replyMsgID, m_PendingInboundTunnels);
@@ -306,11 +346,11 @@ namespace tunnel
size_t minReceived = 0;
for (auto it : m_InboundTunnels)
{
if (!it.second->IsEstablished ()) continue;
if (!tunnel || it.second->GetNumReceivedBytes () < minReceived)
if (!it->IsEstablished ()) continue;
if (!tunnel || it->GetNumReceivedBytes () < minReceived)
{
tunnel = it.second;
minReceived = it.second->GetNumReceivedBytes ();
tunnel = it;
minReceived = it->GetNumReceivedBytes ();
}
}
return tunnel;
@@ -363,14 +403,12 @@ namespace tunnel
}
}
void Tunnels::AddTransitTunnel (TransitTunnel * tunnel)
void Tunnels::AddTransitTunnel (std::shared_ptr<TransitTunnel> tunnel)
{
std::unique_lock<std::mutex> l(m_TransitTunnelsMutex);
if (!m_TransitTunnels.insert (std::make_pair (tunnel->GetTunnelID (), tunnel)).second)
{
LogPrint (eLogError, "Tunnel: transit tunnel with id ", tunnel->GetTunnelID (), " already exists");
delete tunnel;
}
if (m_Tunnels.emplace (tunnel->GetTunnelID (), tunnel).second)
m_TransitTunnels.push_back (tunnel);
else
LogPrint (eLogError, "Tunnel: tunnel with id ", tunnel->GetTunnelID (), " already exists");
}
void Tunnels::Start ()
@@ -404,10 +442,10 @@ namespace tunnel
if (msg)
{
uint32_t prevTunnelID = 0, tunnelID = 0;
TunnelBase * prevTunnel = nullptr;
std::shared_ptr<TunnelBase> prevTunnel;
do
{
TunnelBase * tunnel = nullptr;
std::shared_ptr<TunnelBase> tunnel;
uint8_t typeID = msg->GetTypeID ();
switch (typeID)
{
@@ -420,10 +458,8 @@ namespace tunnel
else if (prevTunnel)
prevTunnel->FlushTunnelDataMsgs ();
if (!tunnel && typeID == eI2NPTunnelData)
tunnel = GetInboundTunnel (tunnelID).get ();
if (!tunnel)
tunnel = GetTransitTunnel (tunnelID);
tunnel = GetTunnel (tunnelID);
if (tunnel)
{
if (typeID == eI2NPTunnelData)
@@ -471,7 +507,7 @@ namespace tunnel
}
}
void Tunnels::HandleTunnelGatewayMsg (TunnelBase * tunnel, std::shared_ptr<I2NPMessage> msg)
void Tunnels::HandleTunnelGatewayMsg (std::shared_ptr<TunnelBase> tunnel, std::shared_ptr<I2NPMessage> msg)
{
if (!tunnel)
{
@@ -580,6 +616,7 @@ namespace tunnel
auto pool = tunnel->GetTunnelPool ();
if (pool)
pool->TunnelExpired (tunnel);
// we don't have outbound tunnels in m_Tunnels
it = m_OutboundTunnels.erase (it);
}
else
@@ -621,13 +658,14 @@ namespace tunnel
{
for (auto it = m_InboundTunnels.begin (); it != m_InboundTunnels.end ();)
{
auto tunnel = it->second;
auto tunnel = *it;
if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
{
LogPrint (eLogDebug, "Tunnel: tunnel with id ", tunnel->GetTunnelID (), " expired");
auto pool = tunnel->GetTunnelPool ();
if (pool)
pool->TunnelExpired (tunnel);
m_Tunnels.erase (tunnel->GetTunnelID ());
it = m_InboundTunnels.erase (it);
}
else
@@ -654,6 +692,7 @@ namespace tunnel
{
LogPrint (eLogDebug, "Tunnel: Creating zero hops inbound tunnel");
CreateZeroHopsInboundTunnel ();
CreateZeroHopsOutboundTunnel ();
if (!m_ExploratoryPool)
{
m_ExploratoryPool = CreateTunnelPool (2, 2, 5, 5); // 2-hop exploratory, 5 tunnels
@@ -666,6 +705,10 @@ namespace tunnel
{
// trying to create one more inbound tunnel
auto router = i2p::data::netdb.GetRandomRouter ();
if (!router) {
LogPrint (eLogWarning, "Tunnel: can't find any router, skip creating tunnel");
return;
}
LogPrint (eLogDebug, "Tunnel: creating one hop inbound tunnel");
CreateTunnel<InboundTunnel> (
std::make_shared<TunnelConfig> (std::vector<std::shared_ptr<const i2p::data::IdentityEx> > { router->GetRouterIdentity () })
@@ -678,15 +721,12 @@ namespace tunnel
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
for (auto it = m_TransitTunnels.begin (); it != m_TransitTunnels.end ();)
{
if (ts > it->second->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
auto tunnel = *it;
if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
{
auto tmp = it->second;
LogPrint (eLogDebug, "Tunnel: Transit tunnel with id ", tmp->GetTunnelID (), " expired");
{
std::unique_lock<std::mutex> l(m_TransitTunnelsMutex);
it = m_TransitTunnels.erase (it);
}
delete tmp;
LogPrint (eLogDebug, "Tunnel: Transit tunnel with id ", tunnel->GetTunnelID (), " expired");
m_Tunnels.erase (tunnel->GetTunnelID ());
it = m_TransitTunnels.erase (it);
}
else
it++;
@@ -740,6 +780,7 @@ namespace tunnel
void Tunnels::AddOutboundTunnel (std::shared_ptr<OutboundTunnel> newTunnel)
{
// we don't need to insert it to m_Tunnels
m_OutboundTunnels.push_back (newTunnel);
auto pool = newTunnel->GetTunnelPool ();
if (pool && pool->IsActive ())
@@ -750,46 +791,76 @@ namespace tunnel
void Tunnels::AddInboundTunnel (std::shared_ptr<InboundTunnel> newTunnel)
{
m_InboundTunnels[newTunnel->GetTunnelID ()] = newTunnel;
auto pool = newTunnel->GetTunnelPool ();
if (!pool)
{
// build symmetric outbound tunnel
CreateTunnel<OutboundTunnel> (std::make_shared<TunnelConfig>(newTunnel->GetInvertedPeers (),
newTunnel->GetNextTunnelID (), newTunnel->GetNextIdentHash ()),
GetNextOutboundTunnel ());
if (m_Tunnels.emplace (newTunnel->GetTunnelID (), newTunnel).second)
{
m_InboundTunnels.push_back (newTunnel);
auto pool = newTunnel->GetTunnelPool ();
if (!pool)
{
// build symmetric outbound tunnel
CreateTunnel<OutboundTunnel> (std::make_shared<TunnelConfig>(newTunnel->GetInvertedPeers (),
newTunnel->GetNextTunnelID (), newTunnel->GetNextIdentHash ()),
GetNextOutboundTunnel ());
}
else
{
if (pool->IsActive ())
pool->TunnelCreated (newTunnel);
else
newTunnel->SetTunnelPool (nullptr);
}
}
else
{
if (pool->IsActive ())
pool->TunnelCreated (newTunnel);
else
newTunnel->SetTunnelPool (nullptr);
}
LogPrint (eLogError, "Tunnel: tunnel with id ", newTunnel->GetTunnelID (), " already exists");
}
void Tunnels::CreateZeroHopsInboundTunnel ()
{
CreateTunnel<InboundTunnel> (
std::make_shared<TunnelConfig> (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >
{
i2p::context.GetIdentity ()
}));
auto inboundTunnel = std::make_shared<ZeroHopsInboundTunnel> ();
inboundTunnel->SetState (eTunnelStateEstablished);
m_InboundTunnels.push_back (inboundTunnel);
m_Tunnels[inboundTunnel->GetTunnelID ()] = inboundTunnel;
}
void Tunnels::CreateZeroHopsOutboundTunnel ()
{
auto outboundTunnel = std::make_shared<ZeroHopsOutboundTunnel> ();
outboundTunnel->SetState (eTunnelStateEstablished);
m_OutboundTunnels.push_back (outboundTunnel);
// we don't insert into m_Tunnels
}
int Tunnels::GetTransitTunnelsExpirationTimeout ()
{
int timeout = 0;
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
std::unique_lock<std::mutex> l(m_TransitTunnelsMutex);
// TODO: possible race condition with I2PControl
for (auto it: m_TransitTunnels)
{
int t = it.second->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT - ts;
int t = it->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT - ts;
if (t > timeout) timeout = t;
}
return timeout;
}
}
size_t Tunnels::CountTransitTunnels() const
{
// TODO: locking
return m_TransitTunnels.size();
}
size_t Tunnels::CountInboundTunnels() const
{
// TODO: locking
return m_InboundTunnels.size();
}
size_t Tunnels::CountOutboundTunnels() const
{
// TODO: locking
return m_OutboundTunnels.size();
}
}
}

View File

@@ -3,6 +3,7 @@
#include <inttypes.h>
#include <map>
#include <unordered_map>
#include <list>
#include <vector>
#include <string>
@@ -71,6 +72,8 @@ namespace tunnel
void SetTunnelPool (std::shared_ptr<TunnelPool> pool) { m_Pool = pool; };
bool HandleTunnelBuildResponse (uint8_t * msg, size_t len);
virtual void Print (std::stringstream& s) const {};
// implements TunnelBase
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
@@ -97,9 +100,9 @@ namespace tunnel
Tunnel (config), m_Gateway (this), m_EndpointIdentHash (config->GetLastIdentHash ()) {};
void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg);
void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs); // multiple messages
virtual void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs); // multiple messages
const i2p::data::IdentHash& GetEndpointIdentHash () const { return m_EndpointIdentHash; };
size_t GetNumSentBytes () const { return m_Gateway.GetNumSentBytes (); };
virtual size_t GetNumSentBytes () const { return m_Gateway.GetNumSentBytes (); };
void Print (std::stringstream& s) const;
// implements TunnelBase
@@ -111,22 +114,49 @@ namespace tunnel
TunnelGateway m_Gateway;
i2p::data::IdentHash m_EndpointIdentHash;
};
class InboundTunnel: public Tunnel, public std::enable_shared_from_this<InboundTunnel>
{
public:
InboundTunnel (std::shared_ptr<const TunnelConfig> config): Tunnel (config), m_Endpoint (true) {};
void HandleTunnelDataMsg (std::shared_ptr<const I2NPMessage> msg);
size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); };
virtual size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); };
void Print (std::stringstream& s) const;
private:
TunnelEndpoint m_Endpoint;
};
class ZeroHopsInboundTunnel: public InboundTunnel
{
public:
ZeroHopsInboundTunnel ();
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
void Print (std::stringstream& s) const;
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
private:
size_t m_NumReceivedBytes;
};
class ZeroHopsOutboundTunnel: public OutboundTunnel
{
public:
ZeroHopsOutboundTunnel ();
void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs);
void Print (std::stringstream& s) const;
size_t GetNumSentBytes () const { return m_NumSentBytes; };
private:
size_t m_NumSentBytes;
};
class Tunnels
{
public:
@@ -136,15 +166,14 @@ namespace tunnel
void Start ();
void Stop ();
std::shared_ptr<InboundTunnel> GetInboundTunnel (uint32_t tunnelID);
std::shared_ptr<InboundTunnel> GetPendingInboundTunnel (uint32_t replyMsgID);
std::shared_ptr<OutboundTunnel> GetPendingOutboundTunnel (uint32_t replyMsgID);
std::shared_ptr<InboundTunnel> GetNextInboundTunnel ();
std::shared_ptr<OutboundTunnel> GetNextOutboundTunnel ();
std::shared_ptr<TunnelPool> GetExploratoryPool () const { return m_ExploratoryPool; };
TransitTunnel * GetTransitTunnel (uint32_t tunnelID);
std::shared_ptr<TunnelBase> GetTunnel (uint32_t tunnelID);
int GetTransitTunnelsExpirationTimeout ();
void AddTransitTunnel (TransitTunnel * tunnel);
void AddTransitTunnel (std::shared_ptr<TransitTunnel> tunnel);
void AddOutboundTunnel (std::shared_ptr<OutboundTunnel> newTunnel);
void AddInboundTunnel (std::shared_ptr<InboundTunnel> newTunnel);
void PostTunnelData (std::shared_ptr<I2NPMessage> msg);
@@ -163,7 +192,7 @@ namespace tunnel
template<class TTunnel>
std::shared_ptr<TTunnel> GetPendingTunnel (uint32_t replyMsgID, const std::map<uint32_t, std::shared_ptr<TTunnel> >& pendingTunnels);
void HandleTunnelGatewayMsg (TunnelBase * tunnel, std::shared_ptr<I2NPMessage> msg);
void HandleTunnelGatewayMsg (std::shared_ptr<TunnelBase> tunnel, std::shared_ptr<I2NPMessage> msg);
void Run ();
void ManageTunnels ();
@@ -176,17 +205,18 @@ namespace tunnel
void ManageTunnelPools ();
void CreateZeroHopsInboundTunnel ();
void CreateZeroHopsOutboundTunnel ();
private:
bool m_IsRunning;
std::thread * m_Thread;
std::map<uint32_t, std::shared_ptr<InboundTunnel> > m_PendingInboundTunnels; // by replyMsgID
std::map<uint32_t, std::shared_ptr<OutboundTunnel> > m_PendingOutboundTunnels; // by replyMsgID
std::map<uint32_t, std::shared_ptr<InboundTunnel> > m_InboundTunnels;
std::list<std::shared_ptr<InboundTunnel> > m_InboundTunnels;
std::list<std::shared_ptr<OutboundTunnel> > m_OutboundTunnels;
std::mutex m_TransitTunnelsMutex;
std::map<uint32_t, TransitTunnel *> m_TransitTunnels;
std::list<std::shared_ptr<TransitTunnel> > m_TransitTunnels;
std::unordered_map<uint32_t, std::shared_ptr<TunnelBase> > m_Tunnels; // tunnelID->tunnel known by this id
std::mutex m_PoolsMutex;
std::list<std::shared_ptr<TunnelPool>> m_Pools;
std::shared_ptr<TunnelPool> m_ExploratoryPool;
@@ -201,6 +231,11 @@ namespace tunnel
const decltype(m_OutboundTunnels)& GetOutboundTunnels () const { return m_OutboundTunnels; };
const decltype(m_InboundTunnels)& GetInboundTunnels () const { return m_InboundTunnels; };
const decltype(m_TransitTunnels)& GetTransitTunnels () const { return m_TransitTunnels; };
size_t CountTransitTunnels() const;
size_t CountInboundTunnels() const;
size_t CountOutboundTunnels() const;
int GetQueueSize () { return m_Queue.GetSize (); };
int GetTunnelCreationSuccessRate () const // in percents
{

View File

@@ -108,7 +108,7 @@ namespace tunnel
}
};
class TunnelConfig: public std::enable_shared_from_this<TunnelConfig>
class TunnelConfig
{
public:
@@ -160,26 +160,26 @@ namespace tunnel
return num;
}
bool IsInbound () const { return m_FirstHop->isGateway; }
virtual bool IsInbound () const { return m_FirstHop->isGateway; }
uint32_t GetTunnelID () const
virtual uint32_t GetTunnelID () const
{
if (!m_FirstHop) return 0;
return IsInbound () ? m_LastHop->nextTunnelID : m_FirstHop->tunnelID;
}
uint32_t GetNextTunnelID () const
virtual uint32_t GetNextTunnelID () const
{
if (!m_FirstHop) return 0;
return m_FirstHop->tunnelID;
}
const i2p::data::IdentHash& GetNextIdentHash () const
virtual const i2p::data::IdentHash& GetNextIdentHash () const
{
return m_FirstHop->ident->GetIdentHash ();
}
const i2p::data::IdentHash& GetLastIdentHash () const
virtual const i2p::data::IdentHash& GetLastIdentHash () const
{
return m_LastHop->ident->GetIdentHash ();
}
@@ -196,12 +196,14 @@ namespace tunnel
return peers;
}
private:
protected:
// this constructor can't be called from outside
TunnelConfig (): m_FirstHop (nullptr), m_LastHop (nullptr)
{
}
private:
template<class Peers>
void CreatePeers (const Peers& peers)
@@ -222,6 +224,24 @@ namespace tunnel
private:
TunnelHopConfig * m_FirstHop, * m_LastHop;
};
class ZeroHopsTunnelConfig: public TunnelConfig
{
public:
ZeroHopsTunnelConfig () { RAND_bytes ((uint8_t *)&m_TunnelID, 4);};
bool IsInbound () const { return true; }; // TODO:
uint32_t GetTunnelID () const { return m_TunnelID; };
uint32_t GetNextTunnelID () const { return m_TunnelID; };
const i2p::data::IdentHash& GetNextIdentHash () const { return i2p::context.GetIdentHash (); };
const i2p::data::IdentHash& GetLastIdentHash () const { return i2p::context.GetIdentHash (); };
private:
uint32_t m_TunnelID;
};
}
}

View File

@@ -201,7 +201,14 @@ namespace tunnel
void TunnelPool::TestTunnels ()
{
for (auto it: m_Tests)
decltype(m_Tests) tests;
{
std::unique_lock<std::mutex> l(m_TestsMutex);
tests = m_Tests;
m_Tests.clear ();
}
for (auto it: tests)
{
LogPrint (eLogWarning, "Tunnels: test of tunnel ", it.first, " failed");
// if test failed again with another tunnel we consider it failed
@@ -232,7 +239,7 @@ namespace tunnel
it.second.second->SetState (eTunnelStateTestFailed);
}
}
m_Tests.clear ();
// new tests
auto it1 = m_OutboundTunnels.begin ();
auto it2 = m_InboundTunnels.begin ();
@@ -253,7 +260,10 @@ namespace tunnel
{
uint32_t msgID;
RAND_bytes ((uint8_t *)&msgID, 4);
m_Tests[msgID] = std::make_pair (*it1, *it2);
{
std::unique_lock<std::mutex> l(m_TestsMutex);
m_Tests[msgID] = std::make_pair (*it1, *it2);
}
(*it1)->SendTunnelDataMsg ((*it2)->GetNextIdentHash (), (*it2)->GetNextTunnelID (),
CreateDeliveryStatusMsg (msgID));
it1++; it2++;
@@ -276,16 +286,26 @@ namespace tunnel
buf += 4;
uint64_t timestamp = bufbe64toh (buf);
auto it = m_Tests.find (msgID);
if (it != m_Tests.end ())
decltype(m_Tests)::mapped_type test;
bool found = false;
{
std::unique_lock<std::mutex> l(m_TestsMutex);
auto it = m_Tests.find (msgID);
if (it != m_Tests.end ())
{
found = true;
test = it->second;
m_Tests.erase (it);
}
}
if (found)
{
// restore from test failed state if any
if (it->second.first->GetState () == eTunnelStateTestFailed)
it->second.first->SetState (eTunnelStateEstablished);
if (it->second.second->GetState () == eTunnelStateTestFailed)
it->second.second->SetState (eTunnelStateEstablished);
LogPrint (eLogDebug, "Tunnels: test of ", it->first, " successful. ", i2p::util::GetMillisecondsSinceEpoch () - timestamp, " milliseconds");
m_Tests.erase (it);
if (test.first->GetState () == eTunnelStateTestFailed)
test.first->SetState (eTunnelStateEstablished);
if (test.second->GetState () == eTunnelStateTestFailed)
test.second->SetState (eTunnelStateEstablished);
LogPrint (eLogDebug, "Tunnels: test of ", msgID, " successful. ", i2p::util::GetMillisecondsSinceEpoch () - timestamp, " milliseconds");
}
else
{

View File

@@ -53,6 +53,9 @@ namespace tunnel
bool IsActive () const { return m_IsActive; };
void SetActive (bool isActive) { m_IsActive = isActive; };
void DetachTunnels ();
int GetNumInboundTunnels () const { return m_NumInboundTunnels; };
int GetNumOutboundTunnels () const { return m_NumOutboundTunnels; };
private:
@@ -74,6 +77,7 @@ namespace tunnel
std::set<std::shared_ptr<InboundTunnel>, TunnelCreationTimeCmp> m_InboundTunnels; // recent tunnel appears first
mutable std::mutex m_OutboundTunnelsMutex;
std::set<std::shared_ptr<OutboundTunnel>, TunnelCreationTimeCmp> m_OutboundTunnels;
mutable std::mutex m_TestsMutex;
std::map<uint32_t, std::pair<std::shared_ptr<OutboundTunnel>, std::shared_ptr<InboundTunnel> > > m_Tests;
bool m_IsActive;

View File

@@ -53,7 +53,7 @@ END
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
MAINICON ICON "ictoopie.ico"
IDI_ICON1 ICON "ictoopie_16.ico"
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////

162
Win32/Win32App.cpp Normal file
View File

@@ -0,0 +1,162 @@
#include <string.h>
#include <windows.h>
#include <shellapi.h>
//#include "../Daemon.h"
#include "resource.h"
#include "Win32App.h"
#define ID_ABOUT 2000
#define ID_EXIT 2001
#define ID_TRAY_ICON 2050
#define WM_TRAYICON (WM_USER + 1)
namespace i2p
{
namespace win32
{
static void ShowPopupMenu (HWND hWnd, POINT *curpos, int wDefaultItem)
{
HMENU hPopup = CreatePopupMenu();
InsertMenu (hPopup, 0, MF_BYPOSITION | MF_STRING, ID_ABOUT, "About...");
InsertMenu (hPopup, 1, MF_BYPOSITION | MF_STRING, ID_EXIT , "Exit");
SetMenuDefaultItem (hPopup, ID_ABOUT, FALSE);
SetFocus (hWnd);
SendMessage (hWnd, WM_INITMENUPOPUP, (WPARAM)hPopup, 0);
POINT p;
if (!curpos)
{
GetCursorPos (&p);
curpos = &p;
}
WORD cmd = TrackPopupMenu (hPopup, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_NONOTIFY, curpos->x, curpos->y, 0, hWnd, NULL);
SendMessage (hWnd, WM_COMMAND, cmd, 0);
DestroyMenu(hPopup);
}
static void AddTrayIcon (HWND hWnd)
{
NOTIFYICONDATA nid;
memset(&nid, 0, sizeof(nid));
nid.cbSize = sizeof(nid);
nid.hWnd = hWnd;
nid.uID = ID_TRAY_ICON;
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
nid.uCallbackMessage = WM_TRAYICON;
nid.hIcon = LoadIcon (GetModuleHandle(NULL), MAKEINTRESOURCE (IDI_ICON1));
strcpy (nid.szTip, "i2pd");
Shell_NotifyIcon(NIM_ADD, &nid );
}
static void RemoveTrayIcon (HWND hWnd)
{
NOTIFYICONDATA nid;
nid.hWnd = hWnd;
nid.uID = ID_TRAY_ICON;
Shell_NotifyIcon (NIM_DELETE, &nid);
}
static LRESULT CALLBACK WndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
{
AddTrayIcon (hWnd);
break;
}
case WM_CLOSE:
{
RemoveTrayIcon (hWnd);
PostQuitMessage (0);
break;
}
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case ID_ABOUT:
{
MessageBox( hWnd, TEXT("i2pd"), TEXT("About"), MB_ICONINFORMATION | MB_OK );
return 0;
}
case ID_EXIT:
{
PostMessage (hWnd, WM_CLOSE, 0, 0);
return 0;
}
}
break;
}
case WM_TRAYICON:
{
SetForegroundWindow (hWnd);
switch (lParam)
{
case WM_RBUTTONUP:
{
SetForegroundWindow (hWnd);
ShowPopupMenu(hWnd, NULL, -1);
PostMessage (hWnd, WM_APP + 1, 0, 0);
break;
}
}
break;
}
}
return DefWindowProc( hWnd, uMsg, wParam, lParam);
}
bool StartWin32App ()
{
if (FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd")))
{
MessageBox(NULL, TEXT("I2Pd is running already"), TEXT("Warning"), MB_OK);
return false;
}
// register main window
auto hInst = GetModuleHandle(NULL);
WNDCLASSEX wclx;
memset (&wclx, 0, sizeof(wclx));
wclx.cbSize = sizeof(wclx);
wclx.style = 0;
wclx.lpfnWndProc = WndProc;
wclx.cbClsExtra = 0;
wclx.cbWndExtra = 0;
wclx.hInstance = hInst;
wclx.hIcon = LoadIcon (hInst, IDI_APPLICATION);
wclx.hIconSm = LoadIcon (hInst, IDI_APPLICATION);
wclx.hCursor = LoadCursor (NULL, IDC_ARROW);
wclx.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wclx.lpszMenuName = NULL;
wclx.lpszClassName = I2PD_WIN32_CLASSNAME;
RegisterClassEx (&wclx);
// create new window
if (!CreateWindow(I2PD_WIN32_CLASSNAME, TEXT("i2pd"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 250, 150, NULL, NULL, hInst, NULL))
{
MessageBox(NULL, "Failed to create main window", TEXT("Warning!"), MB_ICONERROR | MB_OK | MB_TOPMOST);
return false;
}
return true;
}
int RunWin32App ()
{
MSG msg;
while (GetMessage (&msg, NULL, 0, 0 ))
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
return msg.wParam;
}
void StopWin32App ()
{
UnregisterClass (I2PD_WIN32_CLASSNAME, GetModuleHandle(NULL));
}
}
}

15
Win32/Win32App.h Normal file
View File

@@ -0,0 +1,15 @@
#ifndef WIN32APP_H__
#define WIN32APP_H__
#define I2PD_WIN32_CLASSNAME "i2pd main window"
namespace i2p
{
namespace win32
{
bool StartWin32App ();
void StopWin32App ();
int RunWin32App ();
}
}
#endif // WIN32APP_H__

BIN
Win32/ictoopie_16.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

14
api.cpp
View File

@@ -9,7 +9,7 @@
#include "Identity.h"
#include "Destination.h"
#include "Crypto.h"
#include "util.h"
#include "FS.h"
#include "api.h"
namespace i2p
@@ -18,10 +18,16 @@ namespace api
{
void InitI2P (int argc, char* argv[], const char * appName)
{
i2p::util::filesystem::SetAppName (appName);
i2p::config::Init ();
i2p::config::ParseCmdline (argc, argv);
i2p::config::Finalize ();
std::string datadir; i2p::config::GetOption("datadir", datadir);
i2p::fs::SetAppName (appName);
i2p::fs::DetectDataDir(datadir, false);
i2p::fs::Init();
i2p::crypto::InitCrypto ();
i2p::context.Init ();
}
@@ -31,12 +37,12 @@ namespace api
i2p::crypto::TerminateCrypto ();
}
void StartI2P (std::ostream * logStream)
void StartI2P (std::shared_ptr<std::ostream> logStream)
{
if (logStream)
StartLog (logStream);
else
StartLog (i2p::util::filesystem::GetFullPath (i2p::util::filesystem::GetAppName () + ".log"));
StartLog (i2p::fs::DataDirPath (i2p::fs::GetAppName () + ".log"));
LogPrint(eLogInfo, "API: starting NetDB");
i2p::data::netdb.Start();
LogPrint(eLogInfo, "API: starting Transports");

2
api.h
View File

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

View File

@@ -23,6 +23,7 @@ set (LIBI2PD_SRC
"${CMAKE_SOURCE_DIR}/I2NPProtocol.cpp"
"${CMAKE_SOURCE_DIR}/Identity.cpp"
"${CMAKE_SOURCE_DIR}/LeaseSet.cpp"
"${CMAKE_SOURCE_DIR}/FS.cpp"
"${CMAKE_SOURCE_DIR}/Log.cpp"
"${CMAKE_SOURCE_DIR}/NTCPSession.cpp"
"${CMAKE_SOURCE_DIR}/NetDbRequests.cpp"
@@ -45,6 +46,7 @@ set (LIBI2PD_SRC
"${CMAKE_SOURCE_DIR}/Base.cpp"
"${CMAKE_SOURCE_DIR}/util.cpp"
"${CMAKE_SOURCE_DIR}/Datagram.cpp"
"${CMAKE_SOURCE_DIR}/Family.cpp"
"${CMAKE_SOURCE_DIR}/Signature.cpp"
"${CMAKE_SOURCE_DIR}/api.cpp"
)
@@ -91,11 +93,6 @@ if (WITH_UPNP)
endif ()
endif ()
# Default build is Debug
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug)
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
@@ -210,7 +207,7 @@ else()
endif ()
if (WITH_PCH)
include_directories(${CMAKE_BINARY_DIR})
include_directories(BEFORE ${CMAKE_BINARY_DIR})
add_library(stdafx STATIC "${CMAKE_SOURCE_DIR}/stdafx.cpp")
if(MSVC)
target_compile_options(stdafx PRIVATE /Ycstdafx.h /Zm155)
@@ -247,11 +244,9 @@ if(NOT DEFINED OPENSSL_INCLUDE_DIR)
message(SEND_ERROR "Could not find OpenSSL. Please download and install it first!")
endif()
find_package ( MiniUPnPc )
if (MINIUPNPC_FOUND)
include_directories( ${MINIUPNPC_INCLUDE_DIR} )
else ()
set(WITH_UPNP OFF)
if (WITH_UPNP)
find_package ( MiniUPnPc REQUIRED )
include_directories( SYSTEM ${MINIUPNPC_INCLUDE_DIR} )
endif()
find_package ( ZLIB )
@@ -290,7 +285,7 @@ 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} )
include_directories( SYSTEM ${Boost_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} )
# show summary
message(STATUS "---------------------------------------")

View File

@@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE-----
MIICCjCCAa2gAwIBAgIEfT9YJTAMBggqhkjOPQQDAgUAMHkxCzAJBgNVBAYTAlhY
MQswCQYDVQQIEwJYWDELMAkGA1UEBxMCWFgxHjAcBgNVBAoTFUkyUCBBbm9ueW1v
dXMgTmV0d29yazEPMA0GA1UECxMGZmFtaWx5MR8wHQYDVQQDExZpMnAtZGV2LmZh
bWlseS5pMnAubmV0MB4XDTE1MTIwOTIxNDIzM1oXDTI1MTIwODIxNDIzM1oweTEL
MAkGA1UEBhMCWFgxCzAJBgNVBAgTAlhYMQswCQYDVQQHEwJYWDEeMBwGA1UEChMV
STJQIEFub255bW91cyBOZXR3b3JrMQ8wDQYDVQQLEwZmYW1pbHkxHzAdBgNVBAMT
FmkycC1kZXYuZmFtaWx5LmkycC5uZXQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
AAR7FPSglYrxeSPzv74A1fTwjajZWV0TljqEMBS/56juZQB/7xOwrsHFHA0eEEF9
dTH64wx3lhV/9sh/stwPU2MToyEwHzAdBgNVHQ4EFgQUQh4uRP1aaX8TJX5dljrS
CeFNjcAwDAYIKoZIzj0EAwIFAANJADBGAiEAhXlEKGCjJ4urpi2db3OIMl9pB+9t
M+oVtAqBamWvVBICIQDBaIqfwLzFameO5ULgGRMysKQkL0O5mH6xo910YQV8jQ==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE-----
MIIB6TCCAY+gAwIBAgIJAI7G9MXxh7OjMAoGCCqGSM49BAMCMHoxCzAJBgNVBAYT
AlhYMQswCQYDVQQIDAJYWDELMAkGA1UEBwwCWFgxHjAcBgNVBAoMFUkyUCBBbm9u
eW1vdXMgTmV0d29yazEPMA0GA1UECwwGZmFtaWx5MSAwHgYDVQQDDBdpMnBkLWRl
di5mYW1pbHkuaTJwLm5ldDAeFw0xNjAyMjAxNDE2MzhaFw0yNjAyMTcxNDE2Mzha
MHoxCzAJBgNVBAYTAlhYMQswCQYDVQQIDAJYWDELMAkGA1UEBwwCWFgxHjAcBgNV
BAoMFUkyUCBBbm9ueW1vdXMgTmV0d29yazEPMA0GA1UECwwGZmFtaWx5MSAwHgYD
VQQDDBdpMnBkLWRldi5mYW1pbHkuaTJwLm5ldDBZMBMGByqGSM49AgEGCCqGSM49
AwEHA0IABMlWL3loKVOfsA8Rm91QR53Il69mQiaB7n3rUhfPkJb9MYc1S4198azE
iSnNZSXicKDPIifaCgvONmbACzElHc8wCgYIKoZIzj0EAwIDSAAwRQIgYWmSFuai
TJvVrlB5RlbiiNFCEootjWP8BFM3t/yFeaQCIQDkg4xcQIRGTHhjrCsxmlz9KcRF
G+eIF+ATfI93nPseLw==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,34 @@
-----BEGIN CERTIFICATE-----
MIIF7TCCA9egAwIBAgIQJpzITX40IacsYOr3X98gPzALBgkqhkiG9w0BAQswczEL
MAkGA1UEBhMCWFgxHjAcBgNVBAoTFUkyUCBBbm9ueW1vdXMgTmV0d29yazEMMAoG
A1UECxMDSTJQMQswCQYDVQQHEwJYWDELMAkGA1UECRMCWFgxHDAaBgNVBAMME2pA
dG9yb250b2NyeXB0by5vcmcwHhcNMTUwOTIyMjIxNTMzWhcNMjUwOTIyMjIxNTMz
WjBzMQswCQYDVQQGEwJYWDEeMBwGA1UEChMVSTJQIEFub255bW91cyBOZXR3b3Jr
MQwwCgYDVQQLEwNJMlAxCzAJBgNVBAcTAlhYMQswCQYDVQQJEwJYWDEcMBoGA1UE
AwwTakB0b3JvbnRvY3J5cHRvLm9yZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC
AgoCggIBAKbQH61RibAeLRemYah/071wPid99vpPoVxJMwFc/42kbnpSFHUiXRYP
WMkzqPmdZRkr9BNqt3Fa19IiMQbJ49yKRh9+HPJ09b88r2Z75wo71b4eq4Ohd8/4
pSfn7zPCxtqvBh79N0e6O1jC7I01WkXaQfRN1BpIpRT/80H7muWOHoN/AFbJL2KK
eRx+G1hsHqn3pBcsq5QV+bAQdpzxYYYKHn/EPFYk9LM3p1F2uWOQDN0UU+rINvpw
JIR+cvk/bTpPpMCQrYIXdn4hxgCX7KeKYvsFpTieMmGU0omFGWMRc5nm23REpm1N
cU7Oj8kUIW9YbCMzR4KT/x6h1BwRS4L9Hq/ofQM+vDXff3zvcw7MMmVpgU/jh/9I
XNc6A3IBHfpJaxIzhk7UfOZX6k1kyeXjXA8Gr5FvA9Ap9eH7KVFXeyaYq1gTWrGA
MPvgY6dNAH7OFXtqZUGrIAqyWnbaxEsO1HWyRYitCM91LI5gFURUwQPzo2ewgshq
0uGaO+2J61fM9cb8aKOU8Yaa4N04sZfu85k402Kr7bP/DE7Hv9K0+U5ZtbCJxrOU
z5YgbfCrh/iwFti8VP8wFv29S1d6Kqj9OVroM1ns9aNwqyYsMbj/STe8BBRncxuw
lkf69FXxyaGtyfc9ry8enkL8QYyzbVDRXw01yogwToZ8Mc/PinI7AgMBAAGjgYAw
fjAOBgNVHQ8BAf8EBAMCAIQwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMB
MA8GA1UdEwEB/wQFMAMBAf8wHAYDVR0OBBUEE2pAdG9yb250b2NyeXB0by5vcmcw
HgYDVR0jBBcwFYATakB0b3JvbnRvY3J5cHRvLm9yZzALBgkqhkiG9w0BAQsDggIB
AJGmZv3TKCwuNafmPUCvvJV6PwdBqYdVX270pLI2IjPa5sE+dDiCrrrH5tVsoUfY
1xAy0eclic3SCu2DdQxicYFIsyN91oyZWljnVuOWDRQoyeGvcwN3FN8WQZ/VnoX/
b4Xtx0D3HsQjLXfzk0AzSXp9TP9/orMR5bkWiqhUhXvlb7XhpZ+p9/8N0D7bjcaJ
74Rn6g3sS+/wKJ0c7h5R3+mRNPW1SecbfQFN/GkgDQxZscvmbRsCG03IRQeYpqt2
M8KA5KXu/H6ZU5XlC6+VI7vf6yWWPf3s8CRBDgfYtI7uRFkfwJLsTBZCOFoyQe+F
CIZZj4lg6f46FHMekbPouw+g2B+2QNdW+fZqdVLAXbuN2xMsVakZn5X9iBfanNmN
t5QH4T81SZb9ZIJSD+L0lKiMw1klbaYYPp2mjwbo42DhsezcJX3TKXhMe3qkYZ3I
E0a9Kq4TmoWAkdycT1oH51wmybwWc3ix7rXbUe8h6KgBEXqJV60ybX7iacrq9WgG
xIr5hnSUEGZtMcdhEA4oD319h+8j/UjXKgWwuuNExpSnARbwQTbPJ/PLD6mQVpHv
jL2S9nbb1r/GmRdzCpHVwLGczUJvwfjAZ8bDCONSGHzuzw8lgpdRpdeWCLfQzXyo
mjh0U8QNpeHEMdQhmnaYa8WJ83DTnO7pwaoYqjeDQ9yM
-----END CERTIFICATE-----

View File

@@ -1,32 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFgzCCA2ugAwIBAgIEB52rdjANBgkqhkiG9w0BAQ0FADByMQswCQYDVQQGEwJY
WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt
b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEbMBkGA1UEAwwSbWF0dEBkcm9sbGV0
dGUuY29tMB4XDTE0MDcyMTEzMjYxM1oXDTI0MDcyMDEzMjYxM1owcjELMAkGA1UE
BhMCWFgxCzAJBgNVBAgTAlhYMQswCQYDVQQHEwJYWDEeMBwGA1UEChMVSTJQIEFu
b255bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxGzAZBgNVBAMMEm1hdHRAZHJv
bGxldHRlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL5M9wKT
csNLg4EA3fW7LleTQdrm3stPnoUvFmsNZHGgsKt1Nc1qCNis3kr2QEY+4Z398U7r
7xGEQFa7D/9SPHf6n1uVXc9DIcmwBtEB0FPB1XPFp2h00ZXIv24yiLN3GQT1woAM
yEbBWsUgn8K/iMBeA5dU2vPwAbGO/0ibD62frgGdYqU2EeiJ/U6vBmKxvC+q2noL
gnyfQJEJANXgf+Cw/gBaS6yn5ZsYcenLNenID2TQKQ6Q/NxYrDYRdWdId29iwldt
dmNSmASv8C7g9d/isZkpmtYNkE4J4m0W9wKziOoyvLSMo8ec67QmCKaPaYKTHTjx
aUuja02+mnlV4DSdZo6nPkSdokRY0+5e6q7+dIPefu8ealGEAE5oedEfl5iM5Fnz
phTR+ePodBK3sB+bMi1NMppbWugpFpdqs1hg2KNKSSG8C4/eTqf2nnlDiVvvFANc
imt6tk0pZcKqveRiDSgI8mTzTcrNgVClsCLoInY5Vab7onZjY9bGijPQ2i1P6+qu
5G6LiLFW7xFq2BcX1DnTztcJ8Yu9NYHhR21J6u7Dr8YHntes3mnth1F0BX3FVA1s
9SaE9/pNhdqap9owpEhNoE1Ke3LorVLL8jyQsqgRHx8VdhWdi9Ao0mzzeI9HYX0j
nZ7uXK5DqGG74K6eWoS9jZSDJLj3IBkIr3B/AgMBAAGjITAfMB0GA1UdDgQWBBTK
YjH+9Jv82Zqi86r95/1sXUCOnDANBgkqhkiG9w0BAQ0FAAOCAgEAsDyl3dS/5pR1
iDN0zE70HN1Sjv55c5um6N39rgz8JSObbAMihhpjRXPR6yl0PdfVcswdCuEaaykp
ppPNY5ObqZIdqI92XOaOhSA3AkZwZffbwaoXFYiawq1aQG1HP7oxXzWwbnbPOxgz
6ThNP5DJan53Mk8TAhxoJkEJxVlMwIiC+QEgqDNYrP8oNOR2J1EXgzsHheEKObyP
xTwRYFqZU/7BQlFeB0LG1LIy9zXAHlb/XIor10w6ChPDW7DiDwGq3zDJw1d8eiUn
RoPRmFjTqn+3rGaEkk+vUFHoWo7cLCEIC3+P9wlY4Kel+ldXMmuJ+BZ1glFXeO3L
VO85n7iVIyBbwo7RLtNaBvrRQIEG3ld5UOKklLlWwhrX/FXksEhdFvmuF9sbiYNr
cg81sbwZlX7Gi7VicXkykFFXwRRr3UblDtfeevouxk4nMVzcDsmzGeAZKQBvcxHa
Pzc70YwnVRqTc87c0bEwPoxK1Vb26+DILyDjKb/AkTw/rwj6vcJZP2ad+hpiz5Ka
nlbY2cI3JJb0TQiDiOIk+xFqC5oHUTSEmfqA6sA5o/RqdwDpkfpgI5mCwhYzDSLD
jfS+263ylhanl7oz0sM+GtH63owVbYJAFT2EozT9siTIErvJESL4Z80yUQG63d/7
fss8T6gOo19esb/KEMZGZE4pAApakWM=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,34 @@
-----BEGIN CERTIFICATE-----
MIIF1TCCA72gAwIBAgIRAJBHySZnvNg3lU00//fwny4wDQYJKoZIhvcNAQELBQAw
bDELMAkGA1UEBhMCWFgxHjAcBgNVBAoTFUkyUCBBbm9ueW1vdXMgTmV0d29yazEM
MAoGA1UECxMDSTJQMQswCQYDVQQHEwJYWDELMAkGA1UECRMCWFgxFTATBgNVBAMM
DHpteEBtYWlsLmkycDAeFw0xNjAxMDExNzE5MTlaFw0yNjAxMDExNzE5MTlaMGwx
CzAJBgNVBAYTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAK
BgNVBAsTA0kyUDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMRUwEwYDVQQDDAx6
bXhAbWFpbC5pMnAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnDGVU
iC6pNJ3mfqZRQYACUbQ6SQI05yh3PawHqQrmiW3rD05SXBCF+6b2EpA4U0ThFhtm
cGyUObtBL749x03SUYcWhknZNq+zrvb9AypaKFpIx2DjFT8vQadn0l71cNaiwxX1
Wzk1Au6mh9SFPvH5gDF9SQol7dYYKnn9L61V7hvH9fDiZyoi9Cz3ifE3SAWoM2PJ
lBzbu16tyQE94HvIdZhp8cE/6/kiW1wjSqvT9dfZ4gMuZHOF5E8lkq/bg8tPa/oj
rglY7ozT/9/IWtJ7ERcDyepmKjq7+Xx4sNXTvc+B7D4XfMjhaxFLtV/kLQ9mqx8R
UPvPy+atw7mlfUf822YFSft2jBAxNJwCPdhXuuFkTUTIk9YXcChUCSPyv17gej/P
A++/hdhYI/kIs8AVsaJjytTqwU3A2Pt1QogM8VLsSJ2NY7gSzj868nzIZ4OuoWbz
KzpnS/3bQkYHrqMtDIjRr1bOudxbu2/ben5v8Qg9wE9uV/8YNhhaKAcfJOV6OXfF
MYec9DOEVVvECOfYUX35Vtn/w7E6SSL7Gu6QEWviA4Bf2XBh1YFX0ZpBUMY9awNz
7PDf+z+YGkrQ6ifvLPW9vHW3lmouRWzo5NgJIIvLYBJKmxkf08p94s8YailjiGzA
dJWXg3HDWgwMe7BY7AJQbU/o35Vv+0CroUsR3wIDAQABo3IwcDAOBgNVHQ8BAf8E
BAMCAoQwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMA8GA1UdEwEB/wQF
MAMBAf8wFQYDVR0OBA4EDHpteEBtYWlsLmkycDAXBgNVHSMEEDAOgAx6bXhAbWFp
bC5pMnAwDQYJKoZIhvcNAQELBQADggIBAATXH/PNdF40DjD9DcF4W5Ot7CWGskDY
cR4ywtvU2EcDNEwv4q0FPEpxy5LPaUmTKQ6fsRXUZizjaPLpgCLbv9qYc5xRLrSi
yk9mrAbJ1iEU+DfHHBcS1VQWtc7+9LA0W3ZIA+pygjPjTxwQqQAcjn4BdfaIQpVa
VJ2kl5JtbTuYHL80GAQFYnzCCa5GKM7zgcLsyO1mQwnpDvFeSlKJJ6rx1QjhlJu+
90Ig8IOBCIgokfUv9OdYBl6rmDq9i9pvqJU+H4VepqE1jnDAO+YqQ4laZj7LVVM8
I9uia+8RKntUOBkUkLB3ouGdVJUmp3kGrkExxUdDHYP9VNJG6ZMwyKO8HXGtoTsR
TFWIEIbq/biBL9obM/d8fRV5xpfZNbPi6cRzw8REY9UIKECKr7B2B6PnDVVQIQw0
7SCVjmSYWexOqoJPZ1L7/AZDP/tFvx32cWwCszj5jqUaPo9ZNPb6DxQJDdNaZrFH
3CA+PbiaeEz9IH0yBY/6wQgO0k3qOyFQrlkC+YRoYUQNc+6xS38l5ZnYUtBAy8ms
N43eODQ/OhsLzy6PwwXdzvR/0g18SrQyTLfbn2b/kwvbC8Qe40QFfkOf5lPXjdnP
Ii/lcMuvDMlMhoWGFwWm5bkkXE81TKnFXu2/IMsW6HYb3oiTjkaCap22fCr9l0jj
fNr8P7NIRyZ8
-----END CERTIFICATE-----

View File

@@ -1,21 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDgDCCAmgCCQCAKEkFUJcEezANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UEBhMC
Tk8xDTALBgNVBAgMBE9zbG8xDTALBgNVBAcMBE9zbG8xDDAKBgNVBAoMA0kyUDEM
MAoGA1UECwwDSTJQMRcwFQYDVQQDDA4xOTMuMTUwLjEyMS42NjEfMB0GCSqGSIb3
DQEJARYQbWVlaEBpMnBtYWlsLm9yZzAeFw0xMzA2MjcxODM2MjhaFw0yMDA2MjUx
ODM2MjhaMIGBMQswCQYDVQQGEwJOTzENMAsGA1UECAwET3NsbzENMAsGA1UEBwwE
T3NsbzEMMAoGA1UECgwDSTJQMQwwCgYDVQQLDANJMlAxFzAVBgNVBAMMDjE5My4x
NTAuMTIxLjY2MR8wHQYJKoZIhvcNAQkBFhBtZWVoQGkycG1haWwub3JnMIIBIjAN
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuBuFY4ZFvsbr5l1/s/GeUBLIWQLB
nqrRkonrwCyxgjSnnG1uz/Z5nf6QDUjiVnFKMXenLaDn4KCmEi4LjWQllhK9r6pj
BRkR7C0DTHq7WqfyvWnGSZZsOJDiH2vLlivV8N9oGdjxvv0N9No3AJcsmLYrxSLi
6/JF8xZ2HGuT/oWW6aWvpIOKpIqti865BJw5P5KgYAS24J8vHRFM3FA4dfLNTBA2
IGqPqYLQA+2zfOC4z01aArmcYnT1iJLT7krgKnr/BXdJfGQ2GjxkRSt8IwB6WmXA
byz6QdNYM/0eubi102/zpD/DrySTU2kc8xKjknGUqBJvVdsL+iLK98uJrQIDAQAB
MA0GCSqGSIb3DQEBBQUAA4IBAQCTimMu3X7+ztXxlIFhwGh42GfMjeBYT0NHOLAy
ZtQNRqhNvkl3jZ4ERPLxP99+bcAfCX0wgVpgD32OWEZopwveRyMImP8HfFr4NnZ+
edbM37fRYiVJv57kbi6O0rhEC7J5JF+fnCaZVLCuvYIrIXTdxTjvxuLhyan6Ej7V
7iGDJ8t16tpLVJgcXfRg+dvAa6aDOK6x3w78j0bvh6rhvpOd9sW/Nk3LBKP4Xgkx
PHkqm3hNfDIu8Hubeav9SA1kLVMS/uce52VyYMEDauObfC65ds0GRmCtYhZqMvj+
FFCbssLraVJE9Hi/ZKGu33jNngDCG+wG+nmleksMYE1yTSRt
-----END CERTIFICATE-----

View File

@@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDLDCCArKgAwIBAgIJAMOgj4vE9qpcMAoGCCqGSM49BAMEMIHTMQswCQYDVQQG
EwJERTEeMBwGA1UECAwVZG93bmxvYWQueHhsc3BlZWQuY29tMR4wHAYDVQQHDBVk
b3dubG9hZC54eGxzcGVlZC5jb20xHjAcBgNVBAoMFWRvd25sb2FkLnh4bHNwZWVk
LmNvbTEeMBwGA1UECwwVZG93bmxvYWQueHhsc3BlZWQuY29tMR4wHAYDVQQDDBVk
b3dubG9hZC54eGxzcGVlZC5jb20xJDAiBgkqhkiG9w0BCQEWFWRvd25sb2FkLnh4
bHNwZWVkLmNvbTAeFw0xNTEyMzAxMTI4NDJaFw0yMTA2MjExMTI4NDJaMIHTMQsw
CQYDVQQGEwJERTEeMBwGA1UECAwVZG93bmxvYWQueHhsc3BlZWQuY29tMR4wHAYD
VQQHDBVkb3dubG9hZC54eGxzcGVlZC5jb20xHjAcBgNVBAoMFWRvd25sb2FkLnh4
bHNwZWVkLmNvbTEeMBwGA1UECwwVZG93bmxvYWQueHhsc3BlZWQuY29tMR4wHAYD
VQQDDBVkb3dubG9hZC54eGxzcGVlZC5jb20xJDAiBgkqhkiG9w0BCQEWFWRvd25s
b2FkLnh4bHNwZWVkLmNvbTB2MBAGByqGSM49AgEGBSuBBAAiA2IABFObW+pRshVD
gvMPvGdPGji2DAfdvkl3gvpyiQ0PUqxuTxwtBlwBo6cz2cMnkKdActuvE/VOTRG5
/z7CcvG7b0+qgrHDffg7C2wWlAN0dSjuoV2Av7VoN1vEU96TCtheSqNQME4wHQYD
VR0OBBYEFPbEZH9oidjadUfvsnsh23b1jZnVMB8GA1UdIwQYMBaAFPbEZH9oidja
dUfvsnsh23b1jZnVMAwGA1UdEwQFMAMBAf8wCgYIKoZIzj0EAwQDaAAwZQIwT1py
AV2hLFL/5ZgwmybdaCBBUsj3cGYroXb/Z2BHLDYmH8enK0DhhWyPdN1a7eCsAjEA
oQRU7lhXrisckjA2911Q5mA8y2sFAN/PDPrUeU9PI5vDF/ezTi20zULMOqbU1uRz
-----END CERTIFICATE-----

View File

@@ -1,23 +1,23 @@
-----BEGIN CERTIFICATE-----
MIIDvjCCAyegAwIBAgICZhcwDQYJKoZIhvcNAQEFBQAwdTELMAkGA1UEBhMCVVMx
DTALBgNVBAgMBG5vbmUxDTALBgNVBAcMBG5vbmUxDTALBgNVBAoMBG5vbmUxDTAL
BgNVBAsMBG5vbmUxFTATBgNVBAMMDGkycC5tb29vLmNvbTETMBEGCSqGSIb3DQEJ
ARYEbm9uZTAeFw0xMTEwMjMyMTM2NDFaFw0xOTEwMjMyMTM2NDFaMGYxCzAJBgNV
BAYTAlVTMQ0wCwYDVQQIDARub25lMQ0wCwYDVQQKDARub25lMQ0wCwYDVQQLDARu
b25lMRUwEwYDVQQDDAxpMnAubW9vby5jb20xEzARBgkqhkiG9w0BCQEWBG5vbmUw
ggGPMA0GCSqGSIb3DQEBAQUAA4IBfAAwggF3AoIBbgMG1O7HRVa7UoiKbQTmKy5m
x79Na8vjD3etcOwfc4TSenQFvn+GbAWkJwKpM8uvOcgj1CxNeHWdSaeTFH1OwJsw
vl3leJ7clMdo3hpQDhPeGzBLyOiWwFHVn15YKa9xcM7S9Op5Q6rKBHUyyx1vGSz+
/NBmkktpI6rcGFfP3ISRL0auR+db+adWv4TS6W8YiwQIVZNbSlKP6FNO9Mv1kxQZ
KoHPn8vT/LtAh1fcI6ryBuy3F5oHfbGumIwsS5dpowryFxQzwg5vtMA7AMCMKyXv
hP/W6OuaaEP5MCIxkWjQs35gOYa8eF1dLoy3AD9yVVhoNrA8Bc5FnVFJ32Qv7agy
qRY85cXBA6hT/Qzs/wWwp7WrrnZuifaSv/u/Ayi5vX42/bf86PSM2IRNIESoA98A
NFz4U2KGq9s1K2JbkQmnFy8IU0w7CMq6PvNEm/uNjSk6OE1rcCXML+EuX0zmXy8d
PjRbLzC9csSg2CqMtQIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQf
Fh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUdjuOczdG
hUpYzH0UXqKrOleT8GkwHwYDVR0jBBgwFoAU+SKWC49cM5sCodv89AFin3pkS0Yw
DQYJKoZIhvcNAQEFBQADgYEAKYyWlDIStjjbn/ZzVScKR174I8whTbdqrX/vp9dr
2hMv5m4F+aswX4Jr58WneKg2LvRaL6xEhoL7OAQ6aB/7xVSpDjIrrBLZd513NAam
X6bOPYJ6IH7Vw9ClFY3AlfzsNlgRMXno7rySKKzhg24kusNwKDH2yCphZy4BgjMn
y6A=
MIIDvTCCAqWgAwIBAgIJAOeW0ejPrHimMA0GCSqGSIb3DQEBCwUAMHUxCzAJBgNV
BAYTAlVTMQ0wCwYDVQQIDARub25lMQ0wCwYDVQQHDARub25lMQ0wCwYDVQQKDARu
b25lMQ0wCwYDVQQLDARub25lMRUwEwYDVQQDDAxpMnAubW9vby5jb20xEzARBgkq
hkiG9w0BCQEWBG5vbmUwHhcNMTUwMjA4MTczMzA5WhcNMTkwMzE5MTczMzA5WjB1
MQswCQYDVQQGEwJVUzENMAsGA1UECAwEbm9uZTENMAsGA1UEBwwEbm9uZTENMAsG
A1UECgwEbm9uZTENMAsGA1UECwwEbm9uZTEVMBMGA1UEAwwMaTJwLm1vb28uY29t
MRMwEQYJKoZIhvcNAQkBFgRub25lMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEAqxej7oRl9GOb8benIBCENrJXoow1iWhI9M+2nU0SaonrCDql5M2YMlwd
HzYUWtFbRjz2NinjB0fgFq9cfzHfr1Sc8k/OeGg1jvNfqt8wWo9tryQNjiHtDQUZ
6lQ5T13I+lj0CBasowgbApKQfrYjvaeuTaVYTfP8IVA60hoUQ+sy9JN+Unsx3/0Y
PLLd98+bT27qYuBNRB1g/ifUTd9Wosj2PevGBlCxYDaUjmCG4Q8kcQr87KvM6RTu
3AV61s/Wyy1j2YemlGG/ZhJ44YnlVMSu1vTjt9HInVf3lRRx/+RzbQO3lqeVC8LC
Bq3KbSlfJVx4vHslfHwBFw9A4rmD1QIDAQABo1AwTjAdBgNVHQ4EFgQUsSUvX0ED
yivB67iksVwZ+b8vLtQwHwYDVR0jBBgwFoAUsSUvX0EDyivB67iksVwZ+b8vLtQw
DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAde4wts7Q8TylFEc38ftJ
2f285fFIR7P1SSbBcHPK2eBwLEg0zJyFrCeiHuEpPrn+d5GqL2zOskjfcESGmDBT
aFajj8jPBJj/AmpkdWJG6a1YKro5tu9wrlenGwHOHu2/Cl0IJvafxrOs2x4G+2Nl
5Hcw/FIy8mK7eIch4pACfi0zNMZ6KMCKfX9bxPrQo78WdBfVjbrIBlgyOQJ5NJEF
JlWvS7Butv7eERi4I2huN5VRJSCFzjbuO+tjP3I8IB6WgdBmTeqq8ObtXRgahBuD
ZmkvqVSfIzK5JN4GjO8FOdCBomuwm9A92kgmAptwQwAHM9qCDJpH8L07/7poxlGb
iA==
-----END CERTIFICATE-----

View File

@@ -1,23 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDvTCCAqWgAwIBAgIJAOeW0ejPrHimMA0GCSqGSIb3DQEBCwUAMHUxCzAJBgNV
BAYTAlVTMQ0wCwYDVQQIDARub25lMQ0wCwYDVQQHDARub25lMQ0wCwYDVQQKDARu
b25lMQ0wCwYDVQQLDARub25lMRUwEwYDVQQDDAxpMnAubW9vby5jb20xEzARBgkq
hkiG9w0BCQEWBG5vbmUwHhcNMTUwMjA4MTczMzA5WhcNMTkwMzE5MTczMzA5WjB1
MQswCQYDVQQGEwJVUzENMAsGA1UECAwEbm9uZTENMAsGA1UEBwwEbm9uZTENMAsG
A1UECgwEbm9uZTENMAsGA1UECwwEbm9uZTEVMBMGA1UEAwwMaTJwLm1vb28uY29t
MRMwEQYJKoZIhvcNAQkBFgRub25lMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEAqxej7oRl9GOb8benIBCENrJXoow1iWhI9M+2nU0SaonrCDql5M2YMlwd
HzYUWtFbRjz2NinjB0fgFq9cfzHfr1Sc8k/OeGg1jvNfqt8wWo9tryQNjiHtDQUZ
6lQ5T13I+lj0CBasowgbApKQfrYjvaeuTaVYTfP8IVA60hoUQ+sy9JN+Unsx3/0Y
PLLd98+bT27qYuBNRB1g/ifUTd9Wosj2PevGBlCxYDaUjmCG4Q8kcQr87KvM6RTu
3AV61s/Wyy1j2YemlGG/ZhJ44YnlVMSu1vTjt9HInVf3lRRx/+RzbQO3lqeVC8LC
Bq3KbSlfJVx4vHslfHwBFw9A4rmD1QIDAQABo1AwTjAdBgNVHQ4EFgQUsSUvX0ED
yivB67iksVwZ+b8vLtQwHwYDVR0jBBgwFoAUsSUvX0EDyivB67iksVwZ+b8vLtQw
DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAde4wts7Q8TylFEc38ftJ
2f285fFIR7P1SSbBcHPK2eBwLEg0zJyFrCeiHuEpPrn+d5GqL2zOskjfcESGmDBT
aFajj8jPBJj/AmpkdWJG6a1YKro5tu9wrlenGwHOHu2/Cl0IJvafxrOs2x4G+2Nl
5Hcw/FIy8mK7eIch4pACfi0zNMZ6KMCKfX9bxPrQo78WdBfVjbrIBlgyOQJ5NJEF
JlWvS7Butv7eERi4I2huN5VRJSCFzjbuO+tjP3I8IB6WgdBmTeqq8ObtXRgahBuD
ZmkvqVSfIzK5JN4GjO8FOdCBomuwm9A92kgmAptwQwAHM9qCDJpH8L07/7poxlGb
iA==
-----END CERTIFICATE-----

View File

@@ -1,25 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIESzCCAzOgAwIBAgIJAKII1waVnWddMA0GCSqGSIb3DQEBCwUAMIG7MQswCQYD
VQQGEwJERTEaMBgGA1UECAwRaWViOW9vcG8ubW9vby5jb20xGjAYBgNVBAcMEWll
Yjlvb3BvLm1vb28uY29tMRowGAYDVQQKDBFpZWI5b29wby5tb29vLmNvbTEaMBgG
A1UECwwRaWViOW9vcG8ubW9vby5jb20xGjAYBgNVBAMMEWllYjlvb3BvLm1vb28u
Y29tMSAwHgYJKoZIhvcNAQkBFhFpZWI5b29wby5tb29vLmNvbTAeFw0xNDExMjIx
MzQzNThaFw0yMDA1MTQxMzQzNThaMIG7MQswCQYDVQQGEwJERTEaMBgGA1UECAwR
aWViOW9vcG8ubW9vby5jb20xGjAYBgNVBAcMEWllYjlvb3BvLm1vb28uY29tMRow
GAYDVQQKDBFpZWI5b29wby5tb29vLmNvbTEaMBgGA1UECwwRaWViOW9vcG8ubW9v
by5jb20xGjAYBgNVBAMMEWllYjlvb3BvLm1vb28uY29tMSAwHgYJKoZIhvcNAQkB
FhFpZWI5b29wby5tb29vLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAMhcnkSifOMw5bd66UlvYVsc42H22Nuy64qhtJHtggofrwBooF38kRCBVFL8
9Xjzr0xsSshvO6p7E+CEUtA8v55l5vNbUTAvGP9WmzeZyZuCFg9Heo3orNMbIK7m
ppwKhwh6tFEIEpUTz/+xF5NRt0+CqcS4aNHuH3JPwNugfTBuSa86GeSaqL7K4eEZ
bZXqQ16Onvi0yyMqRJDp/ijRFxr2eKGPWb55kuRSET9PxVhlgRKULZkr39Dh9q1c
wb9lAMLMRZIzPVnyvC9jWkIqSDl5bkAAto0n1Jkw92rRp6EVKgSLA/4vl9wTb6xf
WfT5cs7pykAE0WXBr9TqpS3okncCAwEAAaNQME4wHQYDVR0OBBYEFGeEOHhWiKwZ
TGbc7uuK3DD7YjYZMB8GA1UdIwQYMBaAFGeEOHhWiKwZTGbc7uuK3DD7YjYZMAwG
A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAAzRA/0OpJtCO4kQkTn/hux9
dRi9T6B54Xav5jG53iAPLTeMxsaLkvweh2pZ3kvEUrQhvW0JF8QBrHTsgxzb4Wd6
FNDHSgJbZv3uCjFtWeuUh+GTG1k9uwgNIEnx7J9Vp0JCi4ezi/HMNI7c+LjinM9f
hrAzclkeRPLYg645DkxckLyDUbrc9v1qWFoTpezXSBPO7n3Wk4sCytdoA1FkTdXh
RF4BWCl/3uOxcrn0TqoC9vCh8RcxnllOiOO5j4+PQ1Z6NkQ/5oRCK/jjaWc3Lr6/
FicOZJe29BVnrPGynqe0Ky1o+kTdXFflKowfr7g8dwn8k9YavjtGbl1ZSHeuMF8=
-----END CERTIFICATE-----

View File

@@ -1,24 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIEDzCCAvegAwIBAgIJAMsPNG1k0yV4MA0GCSqGSIb3DQEBCwUAMIGdMQswCQYD
VQQGEwJERTEVMBMGA1UECAwMbGluay5teDI0LmV1MRUwEwYDVQQHDAxsaW5rLm14
MjQuZXUxFTATBgNVBAoMDGxpbmsubXgyNC5ldTEVMBMGA1UECwwMbGluay5teDI0
LmV1MRUwEwYDVQQDDAxsaW5rLm14MjQuZXUxGzAZBgkqhkiG9w0BCQEWDGxpbmsu
bXgyNC5ldTAeFw0xNDExMTkxOTE4NTRaFw0yMDA1MTExOTE4NTRaMIGdMQswCQYD
VQQGEwJERTEVMBMGA1UECAwMbGluay5teDI0LmV1MRUwEwYDVQQHDAxsaW5rLm14
MjQuZXUxFTATBgNVBAoMDGxpbmsubXgyNC5ldTEVMBMGA1UECwwMbGluay5teDI0
LmV1MRUwEwYDVQQDDAxsaW5rLm14MjQuZXUxGzAZBgkqhkiG9w0BCQEWDGxpbmsu
bXgyNC5ldTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL8modDBRkyh
SHSm92pTfguO3F6n5ocsBJ4vaVoosYq3ILCsapjqmynMHZUef6gEB7+Gn5cKXsH2
JaKOeb8DHrOFCaxfj187x1QfZj1UNMQblx2T9q4th12tqp+k4JuLwgemr+2uAUpM
xx/uHRJXD0hf67+fHQFYNVfa+WvT46xlKGsWDQ0LBsA/z4YGnyeaV4PrS5nj3euA
IbdfDj7rJea3bfhSqYA1ZH1cquKlsXOOYO5cIcXsa5dxDWX51QS+i7+ocph+JN1X
dRh6ZirE9OXZVXwXXVRnJSYjgBlP/DQBdE7YkE1R3LyCVZsgxJaaLV/ujijOIK61
SqEhHvFNRe0CAwEAAaNQME4wHQYDVR0OBBYEFB6XRz6VZlrAE+3xL6AyKrkq+y2X
MB8GA1UdIwQYMBaAFB6XRz6VZlrAE+3xL6AyKrkq+y2XMAwGA1UdEwQFMAMBAf8w
DQYJKoZIhvcNAQELBQADggEBADhxBA5GHisDVf5a+1hIi7FBGBjJJLqzlaKh+bFB
gTCYfk3F4wYzndr1HpdCZSSYDtY3mXFNMWQCpwvwvy1DM+9AMRY68wKNXHa/WypW
zQSqTfEH8cdaIXUALB7pdWFVr3rx0f7/8I0Gj/ByUbJ94rzd22vduX5riY0Rag6B
dPtW0M9bJrC1AIjexzDcStupj9v/ceGYZQYC4zb2tZ7Ek/6q+vei8TxWZjku7Dl4
YRPXXufyB24uQ1hJVy2fSyIJ63tIRJoEFLBNaKDOB53i10xLWBcsJpXKY57AOQMn
flqW4HG8uGJ/o1WjhiOB9eI7T9toy08zNzt+kSI/blFIoek=
-----END CERTIFICATE-----

View File

@@ -1,33 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFszCCA52gAwIBAgIRALWZzF745GPT8GVUcZ0RMg0wCwYJKoZIhvcNAQELMG0x
CzAJBgNVBAYTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAK
BgNVBAsTA0kyUDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMRYwFAYDVQQDEw1u
ZXRkYi5yb3dzLmlvMB4XDTE0MTIyMDE2NDIwNVoXDTE2MTIxOTE2NDIwNVowbTEL
MAkGA1UEBhMCWFgxHjAcBgNVBAoTFUkyUCBBbm9ueW1vdXMgTmV0d29yazEMMAoG
A1UECxMDSTJQMQswCQYDVQQHEwJYWDELMAkGA1UECRMCWFgxFjAUBgNVBAMTDW5l
dGRiLnJvd3MuaW8wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCTZyJF
Im9pnc7OO5DfQy4SuotUztO5BJX7xniTqD4fKLQQXzZFeT4XHrkDste8TsTzUfxt
CWDEBH3af5cpnwWMT28rlRw2DlPr+LnAgt7VjFXdhFZr1N5VfNlTI1K3OiZ/DRlB
92CoTypyx4ebNfLtZfh+TPLOdg5UqROpHIrybsUj2IaG3IpGHJK8FuH79b/X5oVI
FlDZJs5QsJEARzq2QMJd6fnNqkCBSSjNpeL7TtDar9EKa6+O7s351kH8MVFNSogB
F0Hqu8LYaRC1L1JCz5lsOYKepp3MMIOdDOhy+FTd8NuNZXYkUTdTNI4dB6w4Z6o+
xlnHEPpezIAAlPXLiupvlEi0om69/TMS+pLDBLAOlCZ2YaXS18UrSbmYYlekg40J
nEeALt8ZdsU/is7Q6SJZ3UltFIPCuMD+ixvaIvakkhNiqEWPxdg0XxAK1ZJYFup+
2aVtPLQIzWePkG/VbdA5cxQKNtRwOgvCoKIE29nUbxuq2PCmMhLAfXHeieSzP5c7
Q8A23qX94hwCIePj1YA9uNtStjECfVS1wjyXV4M1tTFUdSJv4aVtFjtya7PY+6SG
Srz11SqBWSqyJ/C14Su0QY/HquglzMRnkJ49Scwb+79hl7kPslO1iIgPLE5S2fIW
ZwJ/4AgGb6BZT8XPEYYANEA5y7KGanYNo8KdYwIDAQABo1IwUDAOBgNVHQ8BAf8E
BAMCAKQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUwAwEB/zAYBgNV
HREEETAPgg1uZXRkYi5yb3dzLmlvMAsGCSqGSIb3DQEBCwOCAgEAMjQSHPR/p9If
mJA1y489D1NB2CxfwO+CgAIs9HA7OsdneQBZTldMgBHoQGifkpD1uSl8DHoZqnJ8
wo5YWcT1rYkP+V1jGfZj92VvfQL0/R4G4hWdQwYY0CcXN8ixS36UDQVSFKb4zvNG
j9iIN57WToEmxp5noHguKrpViwhXCMCpAXr3ZIv/Fd+QACNEXuvdZgbtwfOTPLKh
ZlkUPgVHiQopeQnZhZCT3aLZ5lndrUtWlQYiGN/OolVyRie+ysuxjRR4L5brt4Rz
hrwFBswbQZlgxJ3Nod9/wEdEJWP4+X69ggzOkBB+PgpOFpuDlJxNTcPA/WFIlsm0
CzCv/o8Vg+MMWFPMwEZrk6UQXXACr1AEF+MUnZq3o5JaLvHoUcikewbZPcTCNvDp
nqT1RN9vq/MGdlRfPJkF028IXPz7T9DXXPXhJvv+FAfnOkREeUYpzBIftyYf92ol
l63z0FooVUTKWYPvFFgl5ShNnINTMVXPCZp8j7myLGSLOAFFwiaL1OtvftgxXfzC
B7Qj42SNhFUrHmO9fH3H2ptm/iW/Xe5eqgeb6MVGQ/eQJpdp0AvpDa50/AYNt1Iq
CcMKmBgzUezrIN24XXW/LZwazlc7I8e5RzgbEgXEDBZu21TApTKlmOqEYle8294W
fWThMdwk1kTrWxLooiVrS5A1hXqADqE=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,33 @@
-----BEGIN CERTIFICATE-----
MIIFyDCCA7KgAwIBAgIRAJD+6g+eAsWKlwas0Ymsq24wCwYJKoZIhvcNAQELMHQx
CzAJBgNVBAYTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAK
BgNVBAsTA0kyUDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMR0wGwYDVQQDExRy
ZXNlZWQuaTJwLnZ6YXdzLmNvbTAeFw0xNTA1MTkyMDIwNTRaFw0xNzA1MTgyMDIw
NTRaMHQxCzAJBgNVBAYTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnltb3VzIE5ldHdv
cmsxDDAKBgNVBAsTA0kyUDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMR0wGwYD
VQQDExRyZXNlZWQuaTJwLnZ6YXdzLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
ADCCAgoCggIBAJCAUT9WD2kLPgh5tK5Pb9xpvjKZU5o4HxzM2Nja34+AESnjDwSw
vIuQgjUQ3mqlHS292sdy30nk8kLJvnQ8rRVFrBn9xWdWzSp53thm5rn8h+7cUsBG
r51w0VY/5Zo8b3oxd8PWDd91otuRgJc6xSqIz5i3G1IvTIhHjXfqPwIFvaAbgGOb
xyf5q/LNz9KPAE9DzI4g63AM7+EIBUd/3+TO/27+s6rOWQlIBpHmd+YvyyG9PwM/
bpj9sVpz8S6THSu8srxoI/L4vxsMp0KkySxPAVdmZi8Z5HyJ8b7LtabeEmXaOeIh
F9ZRWyIZWqPZm+dTfM6GyT/JWunBNXWVFlUDJqPCsFB7gdN1GBGW7uv4c6Lq0h7g
Xqd6R2hcthmH8vRasrYisZdfaODZtdUM16Sk6MIl2ALoA6tyAJNGlRKHJutLnY7l
dsD81VfU9Q8ovZ+kb4EHYJx53enW7CUswvKyN2VPKYH3qNoiWW2fGdrEsjdbX575
2bRn7f2BEDTuQgKSTdFjVMZ/d7ljddwNcPS7TS24X2i6lWFAAQpCarHzSE0uwzhZ
ikqhOEKdYwrmzYKv6QFszq2ALiWk1lrasB4zkMl1RY2nwGuh7OfsrXlaehDYZLOe
M9Ib7MfqXpdBFN5oHGXRKFc+1Bz7ZlOhC/OYiwqhSR9uZPEEg/YSMFsnAgMBAAGj
WTBXMA4GA1UdDwEB/wQEAwIApDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMB
Af8EBTADAQH/MB8GA1UdEQQYMBaCFHJlc2VlZC5pMnAudnphd3MuY29tMAsGCSqG
SIb3DQEBCwOCAgEASxpWtby7DBoSlHfJFwoQhp4n8WQTK9xt8HZ7vrmrq5XDkXef
QftjxEEhchGb/QPSt8RippKZqnFAGsoVeWb+tjQH1ijFHanifiuYz77C/08bCcfR
T+fNPhgCixnnGY9ZN+fKE0bQSrZAtGGl/q4rpRcZMQJ5TfhxJA6dC5ZiGAsFZwRQ
ziNUKRGxrLf7Wj2/J4vuHEezPA0XyNJMbG7MLRDWBS4Q9yHtmeVdduxn81WdgnlZ
ToYEEgh68i2sehDUQ+1ro/oLCISDP+hZF3OIUDmz13x7peFFpMb4lKbyoc1siOlV
7/e+XboYKDsTb6fb/mTVL4GjnRvdmXx4cOAkGM2LHbGSIZKGkIEvQWrXwRol3WUn
AcEMWY8KGaee23Syg4fG/4ejVuRZYz8fbk8es6Z6W1vw6gnra434dnYmCrEO6hQl
/77LntLODSgAkus6polZ5O1c7Aj0USMNDW/EFP98APVokT1RGK1wStZVxSUDqBDF
RRPSpEsOGJ6qA7GJuAWi9I3Msy2lBlKMK6Xgk3l/e7ZPU0he95JfxySldl0JzR2N
EGvUCRPDXAMVnp3eP/41MrODdyGo2wBf/0IutfkpJf+Xmbu4ZbgkdPDEwG1+4VZH
MMsGAo3fOR4sI0Wu9W92rXEbzkxwekfnG6D7QQI64AAr0p4w2yO1ALbqW2A=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICwDCCAkagAwIBAgIJAKXCoCBjd/C0MAoGCCqGSM49BAMEMIGdMQswCQYDVQQG
EwJERTEVMBMGA1UECAwMdXNlci5teDI0LmV1MRUwEwYDVQQHDAx1c2VyLm14MjQu
ZXUxFTATBgNVBAoMDHVzZXIubXgyNC5ldTEVMBMGA1UECwwMdXNlci5teDI0LmV1
MRUwEwYDVQQDDAx1c2VyLm14MjQuZXUxGzAZBgkqhkiG9w0BCQEWDHVzZXIubXgy
NC5ldTAeFw0xNTA5MDMxNjMyNDVaFw0yMTAyMjMxNjMyNDVaMIGdMQswCQYDVQQG
EwJERTEVMBMGA1UECAwMdXNlci5teDI0LmV1MRUwEwYDVQQHDAx1c2VyLm14MjQu
ZXUxFTATBgNVBAoMDHVzZXIubXgyNC5ldTEVMBMGA1UECwwMdXNlci5teDI0LmV1
MRUwEwYDVQQDDAx1c2VyLm14MjQuZXUxGzAZBgkqhkiG9w0BCQEWDHVzZXIubXgy
NC5ldTB2MBAGByqGSM49AgEGBSuBBAAiA2IABPlKs5fYTqVhIOMiR6U9U4TimxS3
P5NBDVzeeIAgbw5KBC8UImScZVt9g4V1wQe5kPs7TxA2BfanAPZ+ekQiRRvMVQxD
bSlRYupEWhq5BrJI6Lq/HDc7VJe9UUWffWKUoKNQME4wHQYDVR0OBBYEFBGJ0Yr+
PZXnrk5RafQEALUpAU6ZMB8GA1UdIwQYMBaAFBGJ0Yr+PZXnrk5RafQEALUpAU6Z
MAwGA1UdEwQFMAMBAf8wCgYIKoZIzj0EAwQDaAAwZQIxAPcovePHMCosrAQNzS5i
VDUiyPNLOxHyRBm79yKXGl13LxysB6OK+2M7t8j8E/udBwIwXVVjxN6aSgXYTJ7d
p+Hg/2CuBMwf41/ENRcYQA+oGS9bU6A+7U9KJ1xTWWoqsUEs
-----END CERTIFICATE-----

6
debian/i2pd.init vendored
View File

@@ -18,6 +18,7 @@ DAEMON_OPTS="" # Arguments to run the daemon with
PIDFILE=/var/run/$NAME.pid
I2PCONF=/etc/$NAME/i2pd.conf
TUNCONF=/etc/$NAME/tunnels.conf
LOGFILE=/var/log/$NAME.log
USER="i2pd"
# Exit if the package is not installed
@@ -43,10 +44,13 @@ do_start()
touch "$PIDFILE"
chown -f $USER:adm "$PIDFILE"
touch "$LOGFILE"
chown -f $USER:adm "$LOGFILE"
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --chuid "$USER" --test > /dev/null \
|| return 1
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --chuid "$USER" -- \
--service --daemon --log --conf=$I2PCONF --tunconf=$TUNCONF \
--service --daemon --log=file --logfile=$LOGFILE --conf=$I2PCONF --tunconf=$TUNCONF \
--port=$I2PD_PORT $DAEMON_OPTS > /dev/null 2>&1 \
|| return 2
return $?

3
debian/i2pd.upstart vendored
View File

@@ -6,5 +6,6 @@ stop on runlevel [016] or unmounting-filesystem
# these can be overridden in /etc/init/i2pd.override
env I2PD_HOST="1.2.3.4"
env I2PD_PORT="4567"
env LOGFILE="/var/log/i2pd.log"
exec /usr/sbin/i2pd --daemon --log --host=$I2PD_HOST --port=$I2PD_PORT
exec /usr/sbin/i2pd --daemon --log=file --logfile=$LOGFILE --service --host=$I2PD_HOST --port=$I2PD_PORT

View File

@@ -23,6 +23,13 @@ After successfull build i2pd could be installed with:
```bash
make install
```
or you can just use 'make' once you have all dependacies (boost and openssl) installed
```bash
git clone https://github.com/PurpleI2P/i2pd.git
cd i2pd
make
```
Debian/Ubuntu
-------------
@@ -89,6 +96,9 @@ miniupnpc-devel
FreeBSD
-------
For 10.X use clang. You would also need boost and openssl ports.
Type gmake, it invokes Makefile.bsd, make necessary changes there is required.
Branch 9.X has gcc v4.2, that knows nothing about required c++11 standart.
Required ports:
@@ -103,10 +113,6 @@ export CC=/usr/local/bin/gcc47
export CXX=/usr/local/bin/g++47
```
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.
CMake Options
-------------

View File

@@ -20,11 +20,15 @@ development location for the sake of convenience. Adjust paths
accordingly if it is not the case. Note that msys uses unix-alike
paths like /c/dev/ for C:\dev\.
msys2
-----
### x86 (32-bit architecture)
Get install file msys2-i686-20150916.exe from https://msys2.github.io.
open MSys2Shell (from Start menu).
open MSYS2 Shell (from Start menu).
Install all prerequisites and download i2pd source:
```bash
@@ -37,14 +41,23 @@ export PATH=/mingw32/bin:/usr/bin # we need compiler on PATH which is usually he
make
```
If your processor has
[AES instruction set](https://en.wikipedia.org/wiki/AES_instruction_set),
you may try adding `-DWITH_AESNI=ON`. No check is done however, it
will compile but will crash with `Illegal instruction` if not supported.
You should be able to run ./i2pd . If you need to start from the new
shell, consider starting *MinGW-w64 Win32 Shell* instead of *MSYS2 Shell* as
it adds`/minw32/bin` to the PATH.
### x64 (64-bit architecture)
Get install file msys2-x86_64-20150916.exe from https://msys2.github.io.
open MSYS2 Shell (from Start menu).
Install all prerequisites and download i2pd source:
```bash
pacman -S mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-gcc git make
mkdir -p /c/dev/i2pd
cd /c/dev/i2pd
git clone https://github.com/PurpleI2P/i2pd.git
cd i2pd
export PATH=/mingw64/bin:/usr/bin # we need compiler on PATH which is usually heavily cluttered on Windows
make
```
### Caveats
@@ -63,6 +76,19 @@ home page, otherwise you might end up with DLLs incompatibility
problems.
### AES-NI
If your processor has
[AES instruction set](https://en.wikipedia.org/wiki/AES_instruction_set),
you use `make USE_AESNI=1`. No check is done however, it
will compile, but it might crash with `Illegal instruction` if not supported.
You should be able to run ./i2pd . If you need to start from the new
shell, consider starting *MinGW-w64 Win32 Shell* instead of *MSYS2 Shell* as
it adds`/minw32/bin` to the PATH.
Using Visual Studio
-------------------
@@ -77,7 +103,7 @@ Requirements for building:
* Strawberry Perl or ActiveState Perl, do NOT try msys2 perl, it won't work
## Building Boost
### Building Boost
Open a Command Prompt (there is no need to start Visual Studio command
prompt to build Boost) and run the following:
@@ -98,8 +124,8 @@ only and static linking, and/or you are out of space/time, you might
consider `--build-type=minimal`. Take a look at
[appveyor.yml](../appveyor.yml) for details on how test builds are done.
Building OpenSSL
-----------------
### Building OpenSSL
Download OpenSSL, e.g. with git
@@ -123,8 +149,8 @@ maintaining multiple versions, e.g. 64 bit and/or
static/shared. Consult `C:\Program Files
(x86)\CMake\share\cmake-3.3\Modules\FindOpenSSL.cmake` for details.
Get miniupnpc
-------------
### Get miniupnpc
If you are behind a UPnP enabled router and don't feel like manually
configuring port forwarding, you should consider using
@@ -139,8 +165,7 @@ Note that you might need to build DLL yourself for 64-bit systems
using msys2 as 64-bit DLLs are not provided by the project.
Creating Visual Studio project
------------------------------
### Creating Visual Studio project
Start CMake GUI, navigate to i2pd directory, choose building directory, e.g. ./out, and configure options.
@@ -155,8 +180,8 @@ cmake ..\build -G "Visual Studio 12 2013" -DWITH_UPNP=ON -DWITH_PCH=ON -DCMAKE_I
WITH_UPNP will stay off, if necessary files are not found.
Building i2pd
-------------
### Building i2pd
You can open generated solution/project with Visual Studio and build
from there, alternatively you can use `cmake --build . --config Release --target install` or

View File

@@ -12,6 +12,7 @@ Command line options
* --log= - Logs destination: stdout, file (stdout if not set, file - otherwise, for compatibility)
* --logfile= - Path to logfile (default - autodetect)
* --loglevel= - Log messages above this level (debug, *info, warn, error)
* --datadir= - Path to storage of i2pd data (RI, keys, peer profiles, ...)
* --host= - The external IP
* --port= - The port to listen on
* --daemon - Router will go to background after start
@@ -20,6 +21,7 @@ Command line options
* --notransit - Router will not accept transit tunnels at startup
* --floodfill - Router will be floodfill
* --bandwidth= - L if bandwidth is limited to 32Kbs/sec, O - to 256Kbs/sec, P - unlimited
* --family= - Name of a family, router belongs to
* --svcctl= - Windows service management (--svcctl="install" or --svcctl="remove")
* --http.address= - The address to listen on (HTTP server)

32
docs/family.md Normal file
View File

@@ -0,0 +1,32 @@
Family configuration
====================
Your might want to specify a family, your router belongs to.
There are two possibilities: create new family or joing to existing.
New family
-----------
You must create family self-signed certificate and key.
The only key type supposted is prime256v1.
Use the following list of commands:
openssl ecparam -name prime256v1 -genkey -out <your family name>.key
openssl req -new -key <your family name>.key -out <your family name>.csr
touch v3.ext
openssl x509 -req -days 3650 -in <your family name>.csr -signkey <your family name>.key -out <your family name>.crt -extfile v3.ext
specify <your family name>.family.i2p.net for CN.
Once you are done with it place <your family name>.key and <your family name>.crt to <ip2d data>/family folder (for exmple ~/.i2pd/family).
You should provide these two files to other members joining your family.
If you want to register you family and let I2P network recorgnize it, create pull request for you .crt file into contrib/certificate/family.
It will appear in i2pd and I2P next releases packages. Don't place .key file, it must be shared betwwen you family members only.
Join existing family
--------------------
Once you and that family agree to do it, they must give you .key and .crt file and you must place to <ip2d data>/family folder.
Publish your family
------------------
Run i2pd with parameter 'family=<your family name>', make sure you have <your family name>.key and <your family name>.crt in your 'family' folder.
If everything is set properly, you router.info will contain two new fields: 'family' and 'family.sig'.

View File

@@ -26,4 +26,5 @@ Contents:
build_notes_unix
build_notes_windows
configuration
family

View File

@@ -4,11 +4,12 @@ LIB_SRC = \
Reseed.cpp RouterContext.cpp RouterInfo.cpp Signature.cpp SSU.cpp \
SSUSession.cpp SSUData.cpp Streaming.cpp Identity.cpp TransitTunnel.cpp \
Transports.cpp Tunnel.cpp TunnelEndpoint.cpp TunnelPool.cpp TunnelGateway.cpp \
Destination.cpp Base.cpp I2PEndian.cpp util.cpp api.cpp
Destination.cpp Base.cpp I2PEndian.cpp FS.cpp Config.cpp Family.cpp \
util.cpp api.cpp
LIB_CLIENT_SRC = \
AddressBook.cpp BOB.cpp ClientContext.cpp I2PTunnel.cpp I2PService.cpp \
SAM.cpp SOCKS.cpp HTTPProxy.cpp Config.cpp
SAM.cpp SOCKS.cpp HTTPProxy.cpp
# also: Daemon{Linux,Win32}.cpp will be added later
DAEMON_SRC = \

View File

@@ -1,4 +1,3 @@
#include <thread>
#include <stdlib.h>
#include "Daemon.h"
@@ -6,12 +5,7 @@ int main( int argc, char* argv[] )
{
Daemon.init(argc, argv);
if (Daemon.start())
{
while (Daemon.running)
{
std::this_thread::sleep_for (std::chrono::seconds(1));
}
}
Daemon.run ();
Daemon.stop();
return EXIT_SUCCESS;
}

132
util.cpp
View File

@@ -6,13 +6,7 @@
#include <fstream>
#include <set>
#include <boost/asio.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/program_options/detail/config_file.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/algorithm/string.hpp>
#include "Config.h"
#include "util.h"
#include "Log.h"
@@ -67,131 +61,6 @@ namespace i2p
{
namespace util
{
namespace filesystem
{
std::string appName ("i2pd");
void SetAppName (const std::string& name)
{
appName = name;
}
std::string GetAppName ()
{
return appName;
}
const boost::filesystem::path &GetDataDir()
{
static boost::filesystem::path path;
// TODO: datadir parameter is useless because GetDataDir is called before OptionParser
// and mapArgs is not initialized yet
/*
std::string datadir; i2p::config::GetOption("datadir", datadir);
if (datadir != "")
path = boost::filesystem::system_complete(datadir);
else */
path = GetDefaultDataDir();
if (!boost::filesystem::exists( path ))
{
// Create data directory
if (!boost::filesystem::create_directory( path ))
{
LogPrint(eLogError, "FS: Failed to create data directory!");
path = "";
return path;
}
}
if (!boost::filesystem::is_directory(path))
path = GetDefaultDataDir();
return path;
}
std::string GetFullPath (const std::string& filename)
{
std::string fullPath = GetDataDir ().string ();
#ifndef _WIN32
fullPath.append ("/");
#else
fullPath.append ("\\");
#endif
fullPath.append (filename);
return fullPath;
}
boost::filesystem::path GetConfigFile()
{
std::string config; i2p::config::GetOption("conf", config);
if (config != "") {
/* config file set with cmdline */
boost::filesystem::path path(config);
return path;
}
/* else - try autodetect */
boost::filesystem::path path("i2p.conf");
path = GetDataDir() / path;
if (!boost::filesystem::exists(path))
path = ""; /* reset */
return path;
}
boost::filesystem::path GetTunnelsConfigFile()
{
std::string tunconf; i2p::config::GetOption("tunconf", tunconf);
if (tunconf != "") {
/* config file set with cmdline */
boost::filesystem::path path(tunconf);
return path;
}
/* else - try autodetect */
boost::filesystem::path path("tunnels.cfg");
path = GetDataDir() / path;
if (!boost::filesystem::exists(path))
path = ""; /* reset */
return path;
}
boost::filesystem::path GetDefaultDataDir()
{
// Windows < Vista: C:\Documents and Settings\Username\Application Data\i2pd
// Windows >= Vista: C:\Users\Username\AppData\Roaming\i2pd
// Mac: ~/Library/Application Support/i2pd
// Unix: ~/.i2pd or /var/lib/i2pd is system=1
#ifdef WIN32
// Windows
char localAppData[MAX_PATH];
SHGetFolderPath(NULL, CSIDL_APPDATA, 0, NULL, localAppData);
return boost::filesystem::path(std::string(localAppData) + "\\" + appName);
#else /* UNIX */
bool service; i2p::config::GetOption("service", service);
if (service) // use system folder
return boost::filesystem::path(std::string ("/var/lib/") + appName);
boost::filesystem::path pathRet;
char* pszHome = getenv("HOME");
if (pszHome == NULL || strlen(pszHome) == 0)
pathRet = boost::filesystem::path("/");
else
pathRet = boost::filesystem::path(pszHome);
#ifdef MAC_OSX
// Mac
pathRet /= "Library/Application Support";
boost::filesystem::create_directory(pathRet);
return pathRet / appName;
#else /* Other Unix */
// Unix
return pathRet / (std::string (".") + appName);
#endif
#endif /* UNIX */
}
boost::filesystem::path GetCertificatesDir()
{
return GetDataDir () / "certificates";
}
}
namespace http
{
std::string GetHttpContent (std::istream& response)
@@ -212,6 +81,7 @@ namespace http
if (colon != std::string::npos)
{
std::string field = header.substr (0, colon);
std::transform(field.begin(), field.end(), field.begin(), ::tolower);
if (field == i2p::util::http::TRANSFER_ENCODING)
isChunked = (header.find ("chunked", colon + 1) != std::string::npos);
}

30
util.h
View File

@@ -5,36 +5,22 @@
#include <string>
#include <iostream>
#include <boost/asio.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#define PAIRTYPE(t1, t2) std::pair<t1, t2>
namespace i2p
{
namespace util
{
namespace filesystem
{
void SetAppName (const std::string& name);
std::string GetAppName ();
const boost::filesystem::path &GetDataDir();
std::string GetFullPath (const std::string& filename);
boost::filesystem::path GetDefaultDataDir();
boost::filesystem::path GetConfigFile();
boost::filesystem::path GetTunnelsConfigFile();
boost::filesystem::path GetCertificatesDir();
}
namespace http
{
const char ETAG[] = "ETag";
// in (lower case)
const char ETAG[] = "etag"; // ETag
const char LAST_MODIFIED[] = "last-modified"; // Last-Modified
const char TRANSFER_ENCODING[] = "transfer-encoding"; // Transfer-Encoding
const char CONTENT_ENCODING[] = "content-encoding"; // Content-Encoding
// out
const char IF_NONE_MATCH[] = "If-None-Match";
const char IF_MODIFIED_SINCE[] = "If-Modified-Since";
const char LAST_MODIFIED[] = "Last-Modified";
const char TRANSFER_ENCODING[] = "Transfer-Encoding";
const char IF_MODIFIED_SINCE[] = "If-Modified-Since";
std::string GetHttpContent (std::istream& response);
void MergeChunkedResponse (std::istream& response, std::ostream& merged);
std::string urlDecode(const std::string& data);

View File

@@ -7,8 +7,8 @@
#define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c)
#define I2PD_VERSION_MAJOR 2
#define I2PD_VERSION_MINOR 4
#define I2PD_VERSION_MICRO 0
#define I2PD_VERSION_MINOR 5
#define I2PD_VERSION_MICRO 1
#define I2PD_VERSION_PATCH 0
#define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO)
#define VERSION I2PD_VERSION