Compare commits

..

196 Commits

Author SHA1 Message Date
R4SAS
31936f6025 [make] change daemon sources list, add unix/win32 depending on system
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-06-08 23:03:52 +03:00
R4SAS
f3dcc5364f [make] update Unix daemon source name
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-06-08 22:57:37 +03:00
R4SAS
fbe2e734c2 [daemon] WIP: rework accessing from webconsole and App
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-06-08 22:51:09 +03:00
R4SAS
78193fc8f8 [daemon] WIP: use callbacks to work with daemon
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-06-08 19:35:23 +03:00
R4SAS
463d43b0bb [cmake] remove HTTPServer.cpp from daemon sources
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-06-08 00:40:50 +03:00
R4SAS
7197fce349 [webconsole] add base templates from current code
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-06-08 00:37:20 +03:00
R4SAS
5ba387ba2b [cmake] add webconsole library
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-06-07 22:50:44 +03:00
R4SAS
a843be75f3 start work on webconsole with templates
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-06-07 22:45:53 +03:00
orignal
47460d86b2 verify signature and send peer test msg 5 2022-06-07 12:55:58 -04:00
orignal
3cd74f0d4f send PeerTest message 2022-06-06 17:28:39 -04:00
R4SAS
690c9f7c6f [FS] add support for windows ProgramData path when running as service
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-06-06 18:25:22 +03:00
R4SAS
e2718e5a12 [config] change descriptions for deprecated options
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-06-06 17:44:36 +03:00
orignal
d9fefe757e SSU2/SSU2Session split 2022-06-05 19:33:36 -04:00
orignal
55e4bf6b65 set correct statuc code for peer test 2022-06-05 14:59:33 -04:00
TomasGl
0176e5cf18 Do not show 'Address registration' line if leaseset is encrypted 2022-06-04 19:28:01 +00:00
orignal
4670b12d49 correct buffer size for token request 2022-06-04 08:18:45 -04:00
orignal
321ec8ae4d correct size for Ack block with ranges 2022-06-03 19:16:52 -04:00
orignal
1ccbb8d10b correct offset for nonce in peer test message 2022-06-03 14:02:31 -04:00
orignal
86c0accdce check nonce for peer test msg 5 2022-06-03 13:18:37 -04:00
orignal
38d6c29ce9 correct timestamp size for peer test message 2022-06-03 08:39:54 -04:00
orignal
0cf9478cd4 create SSU2 session for peer test msgs 5-7 2022-06-02 20:12:25 -04:00
orignal
a04abd304a don't send own hash for peer test msg 1 2022-06-02 18:23:51 -04:00
orignal
84aec9fe31 correct msg for first peer test message 2022-06-02 15:40:51 -04:00
orignal
593b9bb6c5 start SSU2 server before peer test 2022-06-02 15:08:38 -04:00
orignal
d3a9cc8fde check if session is established before sending peer test 2022-06-02 15:04:35 -04:00
orignal
87a434c377 start peer test for SSU2 2022-06-01 21:51:02 -04:00
orignal
56022c9442 handle garlic messages from tunnels without pool 2022-05-31 21:43:31 -04:00
orignal
593d6bf466 create initial peer test 2022-05-31 18:31:05 -04:00
R4SAS
29a4366dcf fix mingw build script
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-06-01 00:12:51 +03:00
R4SAS
0a42f414bf [makefile] update support for WSL, remove gcc version detect
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-05-31 21:59:28 +03:00
R4SAS
9b2ac4349e [cmake] use Threads::Threads (closes #1735)
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-05-31 21:59:28 +03:00
orignal
2d4c7729ad case-insensitive headers 2022-05-29 16:59:15 -04:00
orignal
6ecab66b0e always send Connection: close, strip out Keep-Alive for server HTTP tunnel 2022-05-28 21:54:58 -04:00
orignal
1dded57a1c fix typo in Referer 2022-05-27 13:29:59 -04:00
orignal
1d6104ecf3 addressbook.enabled config param 2022-05-27 13:17:06 -04:00
orignal
14da941ff4 Fixed #1761. Correct section for SSU2 2022-05-25 08:37:36 -04:00
R4SAS
06b87311ea 2.42.1
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-05-24 15:09:26 +03:00
R4SAS
3b31773117 [deb] remove O3 optimization flag
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-05-24 15:07:16 +03:00
R4SAS
9c87fe79ea [openssl] suppress deprecation messages
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-05-24 15:06:01 +03:00
R4SAS
bd00112562 update windows build script
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-05-24 14:39:11 +03:00
orignal
1c9160c37d correct jump link 2022-05-24 07:09:24 -04:00
orignal
e2ef88229f fixed warning 2022-05-22 12:22:24 -04:00
orignal
fd7b889a0f 2.42.0 2022-05-22 08:26:14 -04:00
R4SAS
a7aa056ec1 [gha] fix typo
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-05-20 21:30:14 +03:00
R4SAS
4f74acb2d3 [gha] build docker containers on tags
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-05-20 21:26:20 +03:00
R4SAS
22ef1be82b [gha] build docker containers only when pushing to openssl branch
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-05-20 21:11:19 +03:00
R4SAS
9ddbf255ba fix const std::map usage
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-05-20 21:04:41 +03:00
R4SAS
dfb171d32a [httpproxy] ordered jumps list
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-05-20 20:49:26 +03:00
R4SAS
6b4ffcff5a cleanup code (spaces, tabs)
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-05-20 17:44:29 +00:00
R4SAS
d31cd2e5d6 fix incorrect boolean value parsing
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-05-17 19:02:12 +03:00
R4SAS
396c74e6c6 Revert "Simple refactor of nested if-statements" 2022-05-17 04:55:46 +00:00
R4SAS
609c658a9b [gha] publish releases with latest-release tag
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-05-15 14:12:26 +03:00
R4SAS
ee6bb40736 remove obsolete msvc define
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-05-15 11:47:10 +03:00
R4SAS
f8c5ea2b42 [i18n] add french translation
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-05-15 11:47:10 +03:00
R4SAS
923eb9fdb3 fix udp tunnels reload
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-05-15 11:47:10 +03:00
orignal
2cd3ebbdb3 copy peer test block 2022-05-14 19:18:58 -04:00
orignal
5e25e30330 check if there is only one unacked packet 2022-05-14 16:36:16 -04:00
orignal
5aa2a8f60f handle peer tests 2022-05-13 20:38:18 -04:00
orbea
0a1e302e8a libi2pd: Fix the build with LibreSSL 3.5.2 2022-05-12 19:11:17 +00:00
orignal
bb705a77cf handle PeerTest message 2022-05-11 17:48:25 -04:00
orignal
cb6155b946 fixed warning 2022-05-11 11:44:27 -04:00
orignal
714d1cc993 close stream if delete requested 2022-05-08 11:49:11 -04:00
orignal
bc8e4494c4 random new profiles cleanup interval 2022-05-07 09:56:58 -04:00
R4SAS
c3a064f980 change int type
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-05-07 03:40:59 +03:00
R4SAS
eb3feb7dbd [profiles] add daily cleanup
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-05-07 03:19:32 +03:00
orignal
da3f3ccac9 connect to reachable introducers only 2022-05-06 19:38:48 -04:00
orignal
1a1871e8cd add RouterInfo block before RelayIntro 2022-05-06 15:02:09 -04:00
orignal
c22ab7e1fc use openssl's siphash for 3.0.1 and higher 2022-05-04 18:58:08 -04:00
orignal
436992b069 send and process HolePunch message 2022-05-04 13:58:06 -04:00
orignal
18cb3912e5 fixed imccorect termination 2022-05-02 15:05:44 -04:00
orignal
a818b0ba02 Merge pull request #1748 from voltamperoff/Refactor-I2CP-CreateSessionMessageHandler
Simple refactor of nested if-statements
2022-05-01 17:13:13 -04:00
R4SAS
3716b6f988 move TunnelHopVisitor inside Tunnel class
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-05-01 23:40:00 +03:00
R4SAS
c9e4e78f41 [webconsole] remove version from title, move tunnel chain print from Tunnel class
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-05-01 23:25:08 +03:00
R4SAS
9b4e8bf64b [webconsole] do not show registration block when token is not provided
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-05-01 18:12:43 +03:00
orignal
5aebefe73f connect through introducer 2022-05-01 10:33:25 -04:00
R4SAS
8f2124beab update reseeds
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-04-30 19:33:30 +03:00
R4SAS
8b8b43df28 [rpm] support rhel 9
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-04-30 17:54:52 +03:00
R4SAS
c42b991bc9 [rpm] pre-support rhel 9
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-04-30 17:04:08 +03:00
R4SAS
ec08333bf9 [rpm] fix build on fedora 37
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-04-30 16:45:53 +03:00
R4SAS
9e5b4e14c9 [rpm] fix build on fedora 37
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-04-30 16:39:36 +03:00
orignal
1f5ed89a88 set blinded signature type to RedDSA for EdDSA 2022-04-29 12:48:45 -04:00
R4SAS
2304a2bc2e remove android contrib files (moved to android repo)
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-04-29 12:48:40 +03:00
orignal
dc82105226 check status code and verify RelayResponse signature 2022-04-28 20:41:06 -04:00
orignal
5221f3ddc9 one SSU2 session per remote router 2022-04-28 13:11:51 -04:00
orignal
e970deb92b check presense of introducers in SSU2 address 2022-04-28 11:43:33 -04:00
orignal
9db7ec6bb0 create and send RelayRequest 2022-04-27 18:52:44 -04:00
orignal
2e691b6655 check if next manage time is too long 2022-04-26 21:02:39 -04:00
orignal
f22e10537b fixed typo 2022-04-26 20:45:10 -04:00
orignal
6e532c494c create new published SSU2 addresses 2022-04-26 20:30:39 -04:00
orignal
f9ed0d4aa2 fixed crash 2022-04-26 20:01:32 -04:00
orignal
78b1afcc8c publish introducer cap for SSU2 address 2022-04-26 15:20:57 -04:00
orignal
40340cf9c2 handle RelayResponse 2022-04-26 13:59:59 -04:00
orignal
eb6437050f SSU2 introducers 2022-04-25 19:57:46 -04:00
orignal
45ebfe378b correct Ack range 2022-04-23 11:11:49 -04:00
R4SAS
1326597226 use ipv6 preference only when netinet headers not used (entware with musl workaround)'
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-04-23 13:50:34 +03:00
orignal
751da92c13 send relay response 2022-04-22 20:34:19 -04:00
orignal
e10ca637da handle RelayIntro 2022-04-22 15:03:49 -04:00
orignal
c5d9d71a8a create relay tag and relay request block 2022-04-21 15:47:36 -04:00
orignal
3e0f5d231d send queue after batch of packets 2022-04-18 15:47:35 -04:00
orignal
6990f177ba window size 2022-04-18 13:14:09 -04:00
orignal
98e713166b show port for non-published SSU addresses 2022-04-18 12:27:57 -04:00
orignal
4c91ae0085 check if end of list 2022-04-16 17:01:06 -04:00
orignal
43f74d4d5a resend packet with new packet number 2022-04-16 15:42:11 -04:00
orignal
8c3e716c3f ranges in ack block 2022-04-15 16:26:44 -04:00
orignal
05946125b5 handle single packet 2022-04-13 12:33:59 -04:00
orignal
1e2a0a4549 handle incoming packets in batch 2022-04-12 11:42:51 -04:00
R4SAS
f9f5084dd7 typo
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-04-11 11:26:10 +03:00
R4SAS
b7e7c6db7b UDP Client: ignore incomming traffic and error when stopping (prevent socket restarting)
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-04-10 23:10:41 +03:00
orignal
f9d67b28ec handle fragmented SessionConfirmed 2022-04-09 19:56:57 -04:00
orignal
46b77cc280 increase RouterInfo buffer size 2022-04-09 14:40:38 -04:00
R4SAS
2f10decf56 daemon: make possible to set datadir before init
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-04-09 19:57:32 +03:00
orignal
678a1ae0fb send fragmented messages 2022-04-09 11:42:34 -04:00
orignal
51cbffd097 don't lookup session for every sinle packet 2022-04-07 10:57:57 -04:00
orignal
207b13dcab send correct acnt if gaps 2022-04-05 18:23:52 -04:00
orignal
3052dbd1e8 single receive thread for both ipv4 and ipv6 2022-04-05 16:27:52 -04:00
orignal
5891b1ceb2 separate receive thread 2022-04-05 16:14:13 -04:00
orignal
07e14ddda8 check if SSU2 enabled 2022-04-04 20:37:29 -04:00
orignal
db5e90787c update I2NP header after all fragments received 2022-04-04 13:25:08 -04:00
orignal
67e501f5c7 correct nonce for SessionCorfirmed part 2 2022-04-04 11:52:14 -04:00
orignal
2160001167 correct non for token request and retry encryption 2022-04-04 09:58:17 -04:00
orignal
f5f4150d17 fixed typo 2022-04-03 13:43:33 -04:00
R4SAS
887f292612 update install target to use correct share directory, skip dh_auto_install in debian
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-04-02 23:16:39 +03:00
orignal
f5f282af97 cost for published SSU2 address 2022-04-02 14:32:26 -04:00
orignal
82f9585b7a handle fragments 2022-04-02 13:05:11 -04:00
orignal
eb561bb0c2 handle Ack ranges 2022-04-01 15:09:35 -04:00
orignal
81207999eb check token in SessionRequest 2022-03-31 21:07:51 -04:00
orignal
2fef595b83 resend packets 2022-03-31 15:35:55 -04:00
orignal
2024e790ca send I2NP messages 2022-03-30 18:04:12 -04:00
orignal
f9925c7374 hanlde Ack block 2022-03-30 15:03:45 -04:00
orignal
dd774b8dfd store out of sequence packet numbers 2022-03-30 12:31:24 -04:00
orignal
064b8042a5 ssu2.published and update SSU2 ipv4 2022-03-29 14:56:57 -04:00
orignal
7923ed9567 publish SSU2 address 2022-03-29 13:56:56 -04:00
orignal
30b83414ef find SSU2 address by address type 2022-03-28 18:03:22 -04:00
orignal
990906c57f insert garlic tag in destination's thread 2022-03-28 12:15:40 -04:00
orignal
4c323a666a show SSU2 transports in web console 2022-03-27 19:29:50 -04:00
orignal
a3f165d374 handle and send termination 2022-03-27 16:39:58 -04:00
Volt Amperoff
4977f9e6b4 If-statements are simplified. Checks are rearranged for faster errors detection without unnecessary actions. 2022-03-27 18:05:37 +03:00
orignal
7d5f51e357 don't send instant Ack for out-of-sequence message 2022-03-27 09:26:45 -04:00
orignal
371a339b18 encrypt Data header 2022-03-27 07:47:25 -04:00
orignal
7e7aee27b6 handle I2NP message block 2022-03-26 21:59:21 -04:00
orignal
53148fe58f send Ack packet 2022-03-26 16:35:07 -04:00
orignal
56b6de6962 correct header decryption for Data message 2022-03-25 17:57:59 -04:00
orignal
44735681af KDF and process Data message 2022-03-25 15:34:43 -04:00
orignal
ee1c4f4fdc internal numeric id for families 2022-03-24 15:50:20 -04:00
orignal
fb6ecdde1e handle TokenRequest 2022-03-23 21:48:41 -04:00
orignal
861166d8a9 send TokenRequest message: 2022-03-23 19:13:44 -04:00
R4SAS
70dca81c40 dropped MESHNET build option
Dropping MESHNET build option due to lack of usage. That change won't
affect on usage with currently supported Yggdrasil network.

Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-03-24 01:36:12 +03:00
R4SAS
2774d72888 [makefile] add install target for linux
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-03-24 01:36:12 +03:00
orignal
2440ffbfc9 handle SSU2 SessionConfirmed 2022-03-23 14:06:55 -04:00
orignal
77c5dde320 send SessionConfirmed 2022-03-21 21:06:14 -04:00
orignal
aa49cad279 correct encrypted payload size for MixHash 2022-03-21 13:21:08 -04:00
orignal
f56ae240ab don't delete peding endpoint if Retry received 2022-03-21 12:56:02 -04:00
orignal
e871a30a78 initialize connid in constructor 2022-03-20 16:53:32 -04:00
orignal
30e6984889 handle Retry message 2022-03-20 15:10:18 -04:00
orignal
324932c758 separate i and key fields for shared SSU address 2022-03-20 10:28:08 -04:00
orignal
421800bc8f recognize SSU address supporting SSU2 2022-03-19 17:34:07 -04:00
orignal
86fb47b2b4 Merge pull request #1744 from WaxySteelWorm/openssl
Added StormyCloud Inc family cert
2022-03-19 12:34:24 -04:00
WaxySteelWorm
715f83bf84 Create stormycloud.crt 2022-03-19 10:59:54 -05:00
orignal
87bf5c2418 cleanup pending sessions 2022-03-18 20:21:31 -04:00
orignal
5c9af1c613 MixHash with encrypted payload after decryption 2022-03-18 15:32:32 -04:00
orignal
765e0e5c6b correct 'i' size for SSU2 2022-03-18 13:33:33 -04:00
orignal
cc296e16dc don't make SSU2 address published is 'i' is presented 2022-03-18 13:02:59 -04:00
orignal
ab9901525b separated sockets for ipv4 and ipv6 2022-03-17 18:45:14 -04:00
orignal
3643a46a0c don't update SSU2 port 2022-03-17 14:47:00 -04:00
orignal
d467e6869d don't update address for SSU2 2022-03-17 13:21:51 -04:00
Dimitris Apostolou
db36018849 Fix typo 2022-03-17 10:41:39 +00:00
orignal
3c5c375f71 connect to SSU2 address 2022-03-16 21:11:48 -04:00
orignal
7473d8c9aa create and handle Address block 2022-03-16 13:13:31 -04:00
R4SAS
33645d7f09 [gha] XP: use make option for XP
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-03-16 04:29:02 +03:00
R4SAS
9f1106b14a [gha] XP: noconfirm for pacman
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-03-16 04:09:23 +03:00
R4SAS
3dd952b49b [gha] XP: noconfirm for pacman
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-03-16 04:03:26 +03:00
R4SAS
6b85bd2cb8 [gha] XP: fix MinGW repo url
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-03-16 03:54:32 +03:00
orignal
60b164c853 Merge branch 'openssl' of https://github.com/PurpleI2P/i2pd into openssl 2022-03-15 20:50:24 -04:00
orignal
40c8a1bc1d handle payload blocks 2022-03-15 20:49:41 -04:00
R4SAS
22de695f12 [gha] install git to XP builder
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-03-16 03:45:55 +03:00
R4SAS
e91f588cd7 [gha] build for winxp
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-03-16 03:42:10 +03:00
orignal
7b72d91549 receive incoming SSU2 packets 2022-03-14 19:25:59 -04:00
orignal
b3c2e86436 skip unknown address 2022-03-14 15:54:55 -04:00
orignal
908bdc7624 always publish intro key for SSU2 address 2022-03-13 21:55:03 -04:00
orignal
21c1ec9c8c enable SSU2 server 2022-03-13 21:34:11 -04:00
orignal
6d7d71bb16 don't show address:port for non-published addresses 2022-03-13 11:58:19 -04:00
orignal
6eba061c2a show local SSU2 address 2022-03-13 11:04:37 -04:00
orignal
f184f550b9 SSU2 address in config and RouterInfo 2022-03-12 21:51:17 -05:00
orignal
bb7c0fef20 SSU2 address in config and RouterInfo 2022-03-12 21:40:12 -05:00
orignal
5c15a12116 don't allocate buffer from netdb for LocalRouterInfo 2022-03-11 19:03:00 -05:00
orignal
68d015763e recognize SSU2 addresses 2022-03-11 16:17:44 -05:00
orignal
7faa732f38 send SessionCreated 2022-03-08 21:33:21 -05:00
orignal
11f9eeabf1 inbound.lengthVariance and outbound.lengthVariance 2022-03-07 22:20:11 -05:00
orignal
a152f36894 MixHash for SSU2 long header 2022-03-07 18:20:06 -05:00
orignal
d4ede6ff01 process SessionRequest 2022-03-05 18:39:27 -05:00
orignal
35542d803c KDF for session request 2022-03-04 21:51:40 -05:00
orignal
f6ba776c12 SSU2 keys 2022-03-01 21:23:08 -05:00
orignal
1511dcb309 store endpoint and send packet 2022-02-28 21:46:00 -05:00
R4SAS
35afa98112 [reseed] add new reseed
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-03-01 00:23:52 +03:00
R4SAS
df62b40ca7 [win32] return back service control code (#1733)
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2022-02-28 23:02:19 +03:00
orignal
9f1a125ed9 decrypt connID for incoming packet 2022-02-27 20:15:14 -05:00
173 changed files with 30167 additions and 1284 deletions

View File

@@ -35,3 +35,41 @@ jobs:
with:
name: i2pd-${{ matrix.arch_short }}.exe
path: i2pd.exe
build-xp:
name: Building for Windows XP
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Setup MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: MINGW32
install: base-devel git mingw-w64-i686-gcc mingw-w64-i686-boost mingw-w64-i686-openssl mingw-w64-i686-miniupnpc
update: true
- name: Build WinXP-capable CRT packages
run: |
git clone https://github.com/msys2/MINGW-packages
pushd MINGW-packages
pushd mingw-w64-headers-git
sed -i 's/0x601/0x501/' PKGBUILD
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm
pacman --noconfirm -U mingw-w64-i686-headers-git-*-any.pkg.tar.zst
popd
pushd mingw-w64-crt-git
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm
pacman --noconfirm -U mingw-w64-i686-crt-git-*-any.pkg.tar.zst
popd
pushd mingw-w64-winpthreads-git
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm
pacman --noconfirm -U mingw-w64-i686-libwinpthread-git-*-any.pkg.tar.zst mingw-w64-i686-winpthreads-git-*-any.pkg.tar.zst
popd
popd
- name: Build application
run: |
mkdir -p obj/Win32 obj/libi2pd obj/libi2pd_client obj/daemon
make USE_UPNP=yes DEBUG=no USE_GIT_VERSION=yes USE_WINXP_FLAGS=yes -j3
- name: Upload artifacts
uses: actions/upload-artifact@v2
with:
name: i2pd-xp.exe
path: i2pd.exe

View File

@@ -1,6 +1,11 @@
name: Build containers
on: [push]
on:
push:
branches:
- openssl
tags:
- '*'
jobs:
docker:
@@ -58,6 +63,8 @@ jobs:
push: true
tags: |
purplei2p/i2pd:latest
purplei2p/i2pd:latest-release
purplei2p/i2pd:release-${{ env.RELEASE_VERSION }}
ghcr.io/purplei2p/i2pd:latest
ghcr.io/purplei2p/i2pd:latest-release
ghcr.io/purplei2p/i2pd:release-${{ env.RELEASE_VERSION }}

3
.gitignore vendored
View File

@@ -8,12 +8,15 @@ netDb
/libi2pd.a
/libi2pdclient.a
/libi2pdlang.a
/libi2pdwebconsole.a
/libi2pd.so
/libi2pdclient.so
/libi2pdlang.so
/libi2pdwebconsole.so
/libi2pd.dll
/libi2pdclient.dll
/libi2pdlang.dll
/libi2pdwebconsole.dll
*.exe

View File

@@ -1,6 +1,40 @@
# for this file format description,
# see https://github.com/olivierlacan/keep-a-changelog
## [2.42.1] - 2022-05-24
### Fixed
- Incorrect jump link in HTTP Proxy
## [2.42.0] - 2022-05-22
### Added
- Preliminary SSU2 implementation
- Tunnel length variance
- Localization to French
- Daily cleanup of obsolete peer profiles
- Ordered jump services list in HTTP proxy
- Win32 service
- Show port for local non-published SSU addresses in web console
### Changed
- Maximum RouterInfo length increased to 3K
- Skip unknown addresses in RouterInfo
- Don't pick own router for peer test
- Reseeds list
- Internal numeric id for families
- Use ipv6 preference only when netinet headers not used
- Close stream if delete requested
- Remove version from title in web console
- Drop MESHNET build option
- Set data path before initialization
- Don't show registration block in web console if token is not provided
### Fixed
- Encrypted LeaseSet for EdDSA signature
- Clients tunnels are not built if clock is not synced on start
- Incorrect processing of i2cp.dontPublishLeaseSet param
- UDP tunnels reload
- Build for LibreSSL 3.5.2
- Race condition in short tunnel build message
- Race condition in local RouterInfo buffer allocation
## [2.41.0] - 2022-02-20
### Added
- Clock syncronization through SSU

View File

@@ -4,7 +4,7 @@ SYS := $(shell $(CXX) -dumpmachine)
ifneq (, $(findstring darwin, $(SYS)))
SHARED_SUFFIX = dylib
else ifneq (, $(findstring mingw, $(SYS))$(findstring cygwin, $(SYS)))
else ifneq (, $(findstring mingw, $(SYS))$(findstring windows-gnu, $(SYS))$(findstring cygwin, $(SYS)))
SHARED_SUFFIX = dll
else
SHARED_SUFFIX = so
@@ -12,26 +12,28 @@ endif
SHLIB := libi2pd.$(SHARED_SUFFIX)
ARLIB := libi2pd.a
SHLIB_LANG := libi2pdlang.$(SHARED_SUFFIX)
ARLIB_LANG := libi2pdlang.a
SHLIB_CLIENT := libi2pdclient.$(SHARED_SUFFIX)
ARLIB_CLIENT := libi2pdclient.a
SHLIB_LANG := libi2pdlang.$(SHARED_SUFFIX)
ARLIB_LANG := libi2pdlang.a
SHLIB_WEBCONSOLE := libi2pdwebconsole.$(SHARED_SUFFIX)
ARLIB_WEBCONSOLE := libi2pdwebconsole.a
SHLIB_WRAP := libi2pdwrapper.$(SHARED_SUFFIX)
ARLIB_WRAP := libi2pdwrapper.a
I2PD := i2pd
LIB_SRC_DIR := libi2pd
LIB_CLIENT_SRC_DIR := libi2pd_client
WRAP_SRC_DIR := libi2pd_wrapper
WEBCONSOLE_SRC_DIR := libi2pd_webconsole
LANG_SRC_DIR := i18n
DAEMON_SRC_DIR := daemon
WRAP_SRC_DIR := libi2pd_wrapper
# import source files lists
include filelist.mk
USE_AESNI := $(or $(USE_AESNI),yes)
USE_STATIC := $(or $(USE_STATIC),no)
USE_MESHNET := $(or $(USE_MESHNET),no)
USE_UPNP := $(or $(USE_UPNP),no)
DEBUG := $(or $(DEBUG),yes)
@@ -49,59 +51,58 @@ else
endif
ifneq (, $(findstring darwin, $(SYS)))
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
DAEMON_SRC += $(DAEMON_SRC_DIR)/DaemonUnix.cpp
ifeq ($(HOMEBREW),1)
include Makefile.homebrew
else
include Makefile.osx
endif
else ifneq (, $(findstring linux, $(SYS))$(findstring gnu, $(SYS)))
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
DAEMON_SRC += $(DAEMON_SRC_DIR)/DaemonUnix.cpp
include Makefile.linux
else ifneq (, $(findstring freebsd, $(SYS))$(findstring openbsd, $(SYS)))
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
DAEMON_SRC += $(DAEMON_SRC_DIR)/DaemonUnix.cpp
include Makefile.bsd
else ifneq (, $(findstring mingw, $(SYS))$(findstring cygwin, $(SYS)))
DAEMON_SRC += Win32/DaemonWin32.cpp Win32/Win32App.cpp Win32/Win32NetState.cpp
else ifneq (, $(findstring mingw, $(SYS))$(findstring windows-gnu, $(SYS))$(findstring cygwin, $(SYS)))
DAEMON_SRC += $(DAEMON_SRC_DIR)/DaemonWin32.cpp Win32/Win32App.cpp Win32/Win32Service.cpp Win32/Win32NetState.cpp
include Makefile.mingw
else # not supported
$(error Not supported platform)
endif
ifeq ($(USE_MESHNET),yes)
NEEDED_CXXFLAGS += -DMESHNET
endif
ifeq ($(USE_GIT_VERSION),yes)
GIT_VERSION := $(shell git describe --tags)
NEEDED_CXXFLAGS += -DGITVER=\"$(GIT_VERSION)\"
endif
NEEDED_CXXFLAGS += -MMD -MP -I$(LIB_SRC_DIR) -I$(LIB_CLIENT_SRC_DIR) -I$(LANG_SRC_DIR)
NEEDED_CXXFLAGS += -MMD -MP -I$(LIB_SRC_DIR) -I$(LIB_CLIENT_SRC_DIR) -I$(LANG_SRC_DIR) -I$(WEBCONSOLE_SRC_DIR) -DOPENSSL_SUPPRESS_DEPRECATED
LIB_OBJS += $(patsubst %.cpp,obj/%.o,$(LIB_SRC))
LIB_CLIENT_OBJS += $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC))
LANG_OBJS += $(patsubst %.cpp,obj/%.o,$(LANG_SRC))
WEBCONSOLE_OBJS += $(patsubst %.cpp,obj/%.o,$(WEBCONSOLE_SRC))
DAEMON_OBJS += $(patsubst %.cpp,obj/%.o,$(DAEMON_SRC))
WRAP_LIB_OBJS += $(patsubst %.cpp,obj/%.o,$(WRAP_LIB_SRC))
DEPS += $(LIB_OBJS:.o=.d) $(LIB_CLIENT_OBJS:.o=.d) $(LANG_OBJS:.o=.d) $(DAEMON_OBJS:.o=.d) $(WRAP_LIB_OBJS:.o=.d)
DEPS += $(LIB_OBJS:.o=.d) $(LIB_CLIENT_OBJS:.o=.d) $(LANG_OBJS:.o=.d) $(WEBCONSOLE_OBJS:.o=.d) $(DAEMON_OBJS:.o=.d) $(WRAP_LIB_OBJS:.o=.d)
## Build all code (libi2pd, libi2pdclient, libi2pdlang), link it to .a and build binary
all: $(ARLIB) $(ARLIB_CLIENT) $(ARLIB_LANG) $(I2PD)
all: $(ARLIB) $(ARLIB_CLIENT) $(ARLIB_LANG) $(ARLIB_WEBCONSOLE) $(I2PD)
mk_obj_dir:
@mkdir -p obj/$(LIB_SRC_DIR)
@mkdir -p obj/$(LIB_CLIENT_SRC_DIR)
@mkdir -p obj/$(LANG_SRC_DIR)
@mkdir -p obj/$(WEBCONSOLE_SRC_DIR)
@mkdir -p obj/$(DAEMON_SRC_DIR)
@mkdir -p obj/$(WRAP_SRC_DIR)
@mkdir -p obj/Win32
api: $(SHLIB) $(ARLIB)
client: $(SHLIB_CLIENT) $(ARLIB_CLIENT)
lang: $(SHLIB_LANG) $(ARLIB_LANG)
api_client: api client lang
wrapper: api_client $(SHLIB_WRAP) $(ARLIB_WRAP)
api: $(SHLIB) $(ARLIB)
client: $(SHLIB_CLIENT) $(ARLIB_CLIENT)
lang: $(SHLIB_LANG) $(ARLIB_LANG)
webconsole: $(SHLIB_WEBCONSOLE) $(ARLIB_WEBCONSOLE)
api_client: api client lang webconsole
wrapper: api_client $(SHLIB_WRAP) $(ARLIB_WRAP)
## 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.
@@ -116,7 +117,7 @@ obj/%.o: %.cpp | mk_obj_dir
# '-' is 'ignore if missing' on first run
-include $(DEPS)
$(I2PD): $(DAEMON_OBJS) $(ARLIB) $(ARLIB_CLIENT) $(ARLIB_LANG)
$(I2PD): $(DAEMON_OBJS) $(ARLIB_WEBCONSOLE) $(ARLIB) $(ARLIB_CLIENT) $(ARLIB_LANG)
$(CXX) -o $@ $(LDFLAGS) $^ $(LDLIBS)
$(SHLIB): $(LIB_OBJS) $(SHLIB_LANG)
@@ -129,12 +130,17 @@ ifneq ($(USE_STATIC),yes)
$(CXX) $(LDFLAGS) -shared -o $@ $^ $(LDLIBS) $(SHLIB) $(SHLIB_LANG)
endif
$(SHLIB_WRAP): $(WRAP_LIB_OBJS)
$(SHLIB_LANG): $(LANG_OBJS)
ifneq ($(USE_STATIC),yes)
$(CXX) $(LDFLAGS) -shared -o $@ $^ $(LDLIBS)
endif
$(SHLIB_LANG): $(LANG_OBJS)
$(SHLIB_WEBCONSOLE): $(WEBCONSOLE_OBJS) $(SHLIB) $(SHLIB_CLIENT) $(SHLIB_LANG)
ifneq ($(USE_STATIC),yes)
$(CXX) $(LDFLAGS) -shared -o $@ $^ $(LDLIBS) $(SHLIB) $(SHLIB_CLIENT) $(SHLIB_LANG)
endif
$(SHLIB_WRAP): $(WRAP_LIB_OBJS)
ifneq ($(USE_STATIC),yes)
$(CXX) $(LDFLAGS) -shared -o $@ $^ $(LDLIBS)
endif
@@ -145,18 +151,21 @@ $(ARLIB): $(LIB_OBJS)
$(ARLIB_CLIENT): $(LIB_CLIENT_OBJS)
$(AR) -r $@ $^
$(ARLIB_WRAP): $(WRAP_LIB_OBJS)
$(ARLIB_LANG): $(LANG_OBJS)
$(AR) -r $@ $^
$(ARLIB_LANG): $(LANG_OBJS)
$(ARLIB_WEBCONSOLE): $(WEBCONSOLE_OBJS)
$(AR) -r $@ $^
$(ARLIB_WRAP): $(WRAP_LIB_OBJS)
$(AR) -r $@ $^
clean:
$(RM) -r obj
$(RM) -r docs/generated
$(RM) $(I2PD) $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT) $(SHLIB_LANG) $(ARLIB_LANG) $(SHLIB_WRAP) $(ARLIB_WRAP)
$(RM) $(I2PD) $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT) $(SHLIB_LANG) $(ARLIB_LANG) $(SHLIB_WEBCONSOLE) $(ARLIB_WEBCONSOLE) $(SHLIB_WRAP) $(ARLIB_WRAP)
strip: $(I2PD) $(SHLIB) $(SHLIB_CLIENT) $(SHLIB_LANG)
strip: $(I2PD) $(SHLIB) $(SHLIB_CLIENT) $(SHLIB_LANG) $(SHLIB_WEBCONSOLE)
strip $^
LATEST_TAG=$(shell git describe --tags --abbrev=0 openssl)

View File

@@ -39,13 +39,14 @@ ifeq ($(USE_AESNI),yes)
endif
install: all
install -d ${PREFIX}/bin ${PREFIX}/etc/i2pd ${PREFIX}/share/doc/i2pd ${PREFIX}/share/i2pd ${PREFIX}/share/man/man1 ${PREFIX}/var/lib/i2pd
install -d ${PREFIX}/bin ${PREFIX}/etc/i2pd ${PREFIX}/etc/i2pd/tunnels.conf.d ${PREFIX}/share/doc/i2pd ${PREFIX}/share/i2pd ${PREFIX}/share/man/man1 ${PREFIX}/var/lib/i2pd
install -m 755 ${I2PD} ${PREFIX}/bin/
install -m 644 contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/etc/i2pd
@cp -R contrib/certificates ${PREFIX}/share/i2pd/
install -m 644 ChangeLog LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/share/doc/i2pd
@gzip -kf debian/i2pd.1 && install debian/i2pd.1.gz ${PREFIX}/share/man/man1
@ln -sf ${PREFIX}/share/i2pd/certificates ${PREFIX}/var/lib/i2pd/
@ln -sf ${PREFIX}/etc/i2pd/tunnels.conf.d ${PREFIX}/var/lib/i2pd/tunnels.d
@ln -sf ${PREFIX}/etc/i2pd/i2pd.conf ${PREFIX}/var/lib/i2pd/i2pd.conf
@ln -sf ${PREFIX}/etc/i2pd/subscriptions.txt ${PREFIX}/var/lib/i2pd/subscriptions.txt
@ln -sf ${PREFIX}/etc/i2pd/tunnels.conf ${PREFIX}/var/lib/i2pd/tunnels.conf

View File

@@ -62,3 +62,16 @@ ifneq (, $(findstring i386, $(SYS))$(findstring i686, $(SYS))$(findstring x86_64
NEEDED_CXXFLAGS += -D__AES__ -maes
endif
endif
install: all
install -d ${PREFIX}/bin ${PREFIX}/etc ${PREFIX}/etc/i2pd ${PREFIX}/etc/i2pd/tunnels.conf.d ${PREFIX}/usr ${PREFIX}/usr/share ${PREFIX}/usr/share/doc/i2pd ${PREFIX}/usr/share/i2pd ${PREFIX}/usr/share/man ${PREFIX}/usr/share/man/man1 ${PREFIX}/var/lib ${PREFIX}/var/lib/i2pd
install -m 755 ${I2PD} ${PREFIX}/bin/
install -m 644 contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/etc/i2pd
@cp -R contrib/certificates ${PREFIX}/usr/share/i2pd/
install -m 644 ChangeLog LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/usr/share/doc/i2pd
@gzip -kf debian/i2pd.1 && install debian/i2pd.1.gz ${PREFIX}/usr/share/man/man1
@ln -sf ${PREFIX}/usr/share/i2pd/certificates ${PREFIX}/var/lib/i2pd/
@ln -sf ${PREFIX}/etc/i2pd/tunnels.conf.d ${PREFIX}/var/lib/i2pd/tunnels.d
@ln -sf ${PREFIX}/etc/i2pd/i2pd.conf ${PREFIX}/var/lib/i2pd/i2pd.conf
@ln -sf ${PREFIX}/etc/i2pd/subscriptions.txt ${PREFIX}/var/lib/i2pd/subscriptions.txt
@ln -sf ${PREFIX}/etc/i2pd/tunnels.conf ${PREFIX}/var/lib/i2pd/tunnels.conf

View File

@@ -3,19 +3,11 @@ USE_WIN32_APP := yes
WINDRES = windres
CXXFLAGS := $(CXX_DEBUG) -DWIN32_LEAN_AND_MEAN -fPIC -msse
INCFLAGS = -I$(DAEMON_SRC_DIR) -IWin32
CXXFLAGS := $(CXX_DEBUG) -fPIC -msse
INCFLAGS = -IWin32
LDFLAGS := ${LD_DEBUG} -static
# detect proper flag for c++11 support by compilers
CXXVER := $(shell $(CXX) -dumpversion)
ifeq ($(shell expr match ${CXXVER} "[4]\.[7-9]\|4\.1[0-9]\|[5-6]"),4) # gcc 4.7 - 6
NEEDED_CXXFLAGS += -std=c++11
else ifeq ($(shell expr match ${CXXVER} "[1,7-9]"),1) # gcc >= 7
NEEDED_CXXFLAGS += -std=c++17
else # not supported
$(error Compiler too old)
endif
NEEDED_CXXFLAGS += -std=c++17 -DWIN32_LEAN_AND_MEAN
# Boost libraries suffix
BOOST_SUFFIX = -mt

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
* Copyright (c) 2013-2022, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -18,7 +18,7 @@
#include "Tunnel.h"
#include "version.h"
#include "resource.h"
#include "Daemon.h"
#include "Win32App.h"
#include "Win32NetState.h"
@@ -55,13 +55,15 @@ namespace win32
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_ABOUT, "&About...");
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
if(!i2p::context.AcceptsTunnels())
InsertMenu (hPopup, -1,
i2p::util::DaemonWin32::Instance ().isGraceful ? MF_BYPOSITION | MF_STRING | MF_GRAYED : MF_BYPOSITION | MF_STRING,
ID_ACCEPT_TRANSIT, "Accept &transit");
if(m_getIsGraceful)
if(m_getIsGraceful())
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING | MF_GRAYED, ID_ACCEPT_TRANSIT, "Accept &transit");
else
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_ACCEPT_TRANSIT, "Accept &transit");
else
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_DECLINE_TRANSIT, "Decline &transit");
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_RELOAD, "&Reload tunnels config");
if (!i2p::util::DaemonWin32::Instance ().isGraceful)
if (!m_getIsGraceful)
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_GRACEFUL_SHUTDOWN, "&Graceful shutdown");
else
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_STOP_GRACEFUL_SHUTDOWN, "Stop &graceful shutdown");
@@ -270,7 +272,7 @@ namespace win32
SetTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER, 10*60*1000, nullptr); // 10 minutes
SetTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER, 1000, nullptr); // check tunnels every second
g_GracefulShutdownEndtime = GetTickCount() + 10*60*1000;
i2p::util::DaemonWin32::Instance ().isGraceful = true;
if (m_setIsGraceful) m_setIsGraceful(true);
return 0;
}
case ID_STOP_GRACEFUL_SHUTDOWN:
@@ -279,7 +281,7 @@ namespace win32
KillTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER);
KillTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER);
g_GracefulShutdownEndtime = 0;
i2p::util::DaemonWin32::Instance ().isGraceful = false;
if (m_setIsGraceful) m_setIsGraceful(false);
return 0;
}
case ID_RELOAD:

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
* Copyright (c) 2013-2022, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -22,6 +22,15 @@ namespace win32
int RunWin32App ();
bool GracefulShutdown ();
bool StopGracefulShutdown ();
inline typedef std::function<void (bool)> DaemonSetIsGraceful;
inline DaemonSetIsGraceful m_setIsGraceful;
inline void SetIsGraceful (const DaemonSetIsGraceful& f) { m_setIsGraceful = f; };
inline typedef std::function<bool ()> DaemonGetIsGraceful;
inline DaemonGetIsGraceful m_getIsGraceful;
inline void GetIsGraceful (const DaemonGetIsGraceful& f) { m_getIsGraceful = f; };
}
}
#endif // WIN32APP_H__

292
Win32/Win32Service.cpp Normal file
View File

@@ -0,0 +1,292 @@
/*
* Copyright (c) 2013-2022, 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 "Win32Service.h"
#include <assert.h>
#include <windows.h>
#include "Log.h"
I2PService *I2PService::s_service = NULL;
BOOL I2PService::isService()
{
BOOL bIsService = FALSE;
HWINSTA hWinStation = GetProcessWindowStation();
if (hWinStation != NULL)
{
USEROBJECTFLAGS uof = { 0 };
if (GetUserObjectInformation(hWinStation, UOI_FLAGS, &uof, sizeof(USEROBJECTFLAGS), NULL) && ((uof.dwFlags & WSF_VISIBLE) == 0))
{
bIsService = TRUE;
}
}
return bIsService;
}
BOOL I2PService::Run(I2PService &service)
{
s_service = &service;
SERVICE_TABLE_ENTRY serviceTable[] =
{
{ service.m_name, ServiceMain },
{ NULL, NULL }
};
return StartServiceCtrlDispatcher(serviceTable);
}
void WINAPI I2PService::ServiceMain(DWORD dwArgc, PSTR *pszArgv)
{
assert(s_service != NULL);
s_service->m_statusHandle = RegisterServiceCtrlHandler(
s_service->m_name, ServiceCtrlHandler);
if (s_service->m_statusHandle == NULL)
{
throw GetLastError();
}
s_service->Start(dwArgc, pszArgv);
}
void WINAPI I2PService::ServiceCtrlHandler(DWORD dwCtrl)
{
switch (dwCtrl)
{
case SERVICE_CONTROL_STOP: s_service->Stop(); break;
case SERVICE_CONTROL_PAUSE: s_service->Pause(); break;
case SERVICE_CONTROL_CONTINUE: s_service->Continue(); break;
case SERVICE_CONTROL_SHUTDOWN: s_service->Shutdown(); break;
case SERVICE_CONTROL_INTERROGATE: break;
default: break;
}
}
I2PService::I2PService(PSTR pszServiceName,
BOOL fCanStop,
BOOL fCanShutdown,
BOOL fCanPauseContinue)
{
m_name = (pszServiceName == NULL) ? (PSTR)"" : pszServiceName;
m_statusHandle = NULL;
m_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
m_status.dwCurrentState = SERVICE_START_PENDING;
DWORD dwControlsAccepted = 0;
if (fCanStop)
dwControlsAccepted |= SERVICE_ACCEPT_STOP;
if (fCanShutdown)
dwControlsAccepted |= SERVICE_ACCEPT_SHUTDOWN;
if (fCanPauseContinue)
dwControlsAccepted |= SERVICE_ACCEPT_PAUSE_CONTINUE;
m_status.dwControlsAccepted = dwControlsAccepted;
m_status.dwWin32ExitCode = NO_ERROR;
m_status.dwServiceSpecificExitCode = 0;
m_status.dwCheckPoint = 0;
m_status.dwWaitHint = 0;
m_fStopping = FALSE;
// Create a manual-reset event that is not signaled at first to indicate
// the stopped signal of the service.
m_hStoppedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (m_hStoppedEvent == NULL)
{
throw GetLastError();
}
}
I2PService::~I2PService(void)
{
if (m_hStoppedEvent)
{
CloseHandle(m_hStoppedEvent);
m_hStoppedEvent = NULL;
}
}
void I2PService::Start(DWORD dwArgc, PSTR *pszArgv)
{
try
{
SetServiceStatus(SERVICE_START_PENDING);
OnStart(dwArgc, pszArgv);
SetServiceStatus(SERVICE_RUNNING);
}
catch (DWORD dwError)
{
LogPrint(eLogError, "Win32Service: Start error: ", dwError);
SetServiceStatus(SERVICE_STOPPED, dwError);
}
catch (...)
{
LogPrint(eLogError, "Win32Service: failed to start: ", EVENTLOG_ERROR_TYPE);
SetServiceStatus(SERVICE_STOPPED);
}
}
void I2PService::OnStart(DWORD dwArgc, PSTR *pszArgv)
{
LogPrint(eLogInfo, "Win32Service: in OnStart (", EVENTLOG_INFORMATION_TYPE, ")");
if(m_daemonStart)
m_daemonStart();
else
{
LogPrint(eLogError, "Win32Service: failed to start: Unable to call callback");
SetServiceStatus(SERVICE_STOPPED);
}
_worker = new std::thread(std::bind(&I2PService::WorkerThread, this));
}
void I2PService::WorkerThread()
{
while (!m_fStopping)
{
::Sleep(1000); // Simulate some lengthy operations.
}
// Signal the stopped event.
SetEvent(m_hStoppedEvent);
}
void I2PService::Stop()
{
DWORD dwOriginalState = m_status.dwCurrentState;
try
{
SetServiceStatus(SERVICE_STOP_PENDING);
OnStop();
SetServiceStatus(SERVICE_STOPPED);
}
catch (DWORD dwError)
{
LogPrint(eLogInfo, "Win32Service: Stop error: ", dwError);
SetServiceStatus(dwOriginalState);
}
catch (...)
{
LogPrint(eLogError, "Win32Service: Failed to stop: ", EVENTLOG_ERROR_TYPE);
SetServiceStatus(dwOriginalState);
}
}
void I2PService::OnStop()
{
// Log a service stop message to the Application log.
LogPrint(eLogInfo, "Win32Service: in OnStop (", EVENTLOG_INFORMATION_TYPE, ")");
if(m_daemonStop)
m_daemonStop();
else
LogPrint(eLogError, "Win32Service: failed to stop: Unable to call callback");
m_fStopping = TRUE;
if (WaitForSingleObject(m_hStoppedEvent, INFINITE) != WAIT_OBJECT_0)
{
throw GetLastError();
}
_worker->join();
delete _worker;
}
void I2PService::Pause()
{
try
{
SetServiceStatus(SERVICE_PAUSE_PENDING);
OnPause();
SetServiceStatus(SERVICE_PAUSED);
}
catch (DWORD dwError)
{
LogPrint(eLogError, "Win32Service: Pause error: ", dwError);
SetServiceStatus(SERVICE_RUNNING);
}
catch (...)
{
LogPrint(eLogError, "Win32Service: Failed to pause: ", EVENTLOG_ERROR_TYPE);
SetServiceStatus(SERVICE_RUNNING);
}
}
void I2PService::OnPause()
{
}
void I2PService::Continue()
{
try
{
SetServiceStatus(SERVICE_CONTINUE_PENDING);
OnContinue();
SetServiceStatus(SERVICE_RUNNING);
}
catch (DWORD dwError)
{
LogPrint(eLogError, "Win32Service: Continue error: ", dwError);
SetServiceStatus(SERVICE_PAUSED);
}
catch (...)
{
LogPrint(eLogError, "Win32Service: Failed to resume: ", EVENTLOG_ERROR_TYPE);
SetServiceStatus(SERVICE_PAUSED);
}
}
void I2PService::OnContinue()
{
}
void I2PService::Shutdown()
{
try
{
OnShutdown();
SetServiceStatus(SERVICE_STOPPED);
}
catch (DWORD dwError)
{
LogPrint(eLogError, "Win32Service: Shutdown error: ", dwError);
}
catch (...)
{
LogPrint(eLogError, "Win32Service: Failed to shut down: ", EVENTLOG_ERROR_TYPE);
}
}
void I2PService::OnShutdown()
{
}
void I2PService::SetServiceStatus(DWORD dwCurrentState,
DWORD dwWin32ExitCode,
DWORD dwWaitHint)
{
static DWORD dwCheckPoint = 1;
m_status.dwCurrentState = dwCurrentState;
m_status.dwWin32ExitCode = dwWin32ExitCode;
m_status.dwWaitHint = dwWaitHint;
m_status.dwCheckPoint =
((dwCurrentState == SERVICE_RUNNING) ||
(dwCurrentState == SERVICE_STOPPED)) ?
0 : dwCheckPoint++;
::SetServiceStatus(m_statusHandle, &m_status);
}
//*****************************************************************************
void FreeHandles(SC_HANDLE schSCManager, SC_HANDLE schService)
{
if (schSCManager)
{
CloseServiceHandle(schSCManager);
schSCManager = NULL;
}
if (schService)
{
CloseServiceHandle(schService);
schService = NULL;
}
}

76
Win32/Win32Service.h Normal file
View File

@@ -0,0 +1,76 @@
/*
* Copyright (c) 2013-2022, 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 WIN32SERVICE_H__
#define WIN32SERVICE_H__
#include <functional>
#include <thread>
#include <windows.h>
#define SERVICE_NAME "i2pdService"
class I2PService
{
public:
I2PService(PSTR pszServiceName,
BOOL fCanStop = TRUE,
BOOL fCanShutdown = TRUE,
BOOL fCanPauseContinue = FALSE);
virtual ~I2PService(void);
static BOOL isService();
static BOOL Run(I2PService &service);
void Stop();
typedef std::function<bool ()> DaemonStart;
void SetDaemonStart (const DaemonStart& f) { m_daemonStart = f; };
typedef std::function<bool ()> DaemonStop;
void SetDaemonStop (const DaemonStop& f) { m_daemonStop = f; };
protected:
virtual void OnStart(DWORD dwArgc, PSTR *pszArgv);
virtual void OnStop();
virtual void OnPause();
virtual void OnContinue();
virtual void OnShutdown();
void SetServiceStatus(DWORD dwCurrentState,
DWORD dwWin32ExitCode = NO_ERROR,
DWORD dwWaitHint = 0);
private:
static void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArgv);
static void WINAPI ServiceCtrlHandler(DWORD dwCtrl);
void WorkerThread();
void Start(DWORD dwArgc, PSTR *pszArgv);
void Pause();
void Continue();
void Shutdown();
static I2PService* s_service;
PSTR m_name;
SERVICE_STATUS m_status;
SERVICE_STATUS_HANDLE m_statusHandle;
BOOL m_fStopping;
HANDLE m_hStoppedEvent;
std::thread* _worker;
private:
DaemonStart m_daemonStart;
DaemonStop m_daemonStop;
};
#endif // WIN32SERVICE_H__

View File

@@ -17,7 +17,6 @@ option(WITH_LIBRARY "Build library" ON)
option(WITH_BINARY "Build binary" ON)
option(WITH_STATIC "Static build" OFF)
option(WITH_UPNP "Include support for UPnP client" OFF)
option(WITH_MESHNET "Build for cjdns test network" OFF)
option(WITH_ADDRSANITIZER "Build with address sanitizer unix only" OFF)
option(WITH_THREADSANITIZER "Build with thread sanitizer unix only" OFF)
@@ -34,11 +33,13 @@ target_architecture(ARCHITECTURE)
set(LIBI2PD_SRC_DIR ../libi2pd)
set(LIBI2PD_CLIENT_SRC_DIR ../libi2pd_client)
set(WEBCONSOLE_SRC_DIR ../libi2pd_webconsole)
set(LANG_SRC_DIR ../i18n)
set(DAEMON_SRC_DIR ../daemon)
include_directories(${LIBI2PD_SRC_DIR})
include_directories(${LIBI2PD_CLIENT_SRC_DIR})
include_directories(${WEBCONSOLE_SRC_DIR})
include_directories(${LANG_SRC_DIR})
include_directories(${DAEMON_SRC_DIR})
@@ -69,6 +70,18 @@ if(WITH_LIBRARY)
COMPONENT Libraries)
endif()
FILE(GLOB WEBCONSOLE_SRC ${WEBCONSOLE_SRC_DIR}/*.cpp)
add_library(libi2pdwebconsole ${WEBCONSOLE_SRC})
set_target_properties(libi2pdwebconsole PROPERTIES PREFIX "")
if(WITH_LIBRARY)
install(TARGETS libi2pdwebconsole
EXPORT libi2pdwebconsole
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT Libraries)
endif()
FILE(GLOB LANG_SRC ${LANG_SRC_DIR}/*.cpp)
add_library(libi2pdlang ${LANG_SRC})
set_target_properties(libi2pdlang PROPERTIES PREFIX "")
@@ -83,16 +96,11 @@ endif()
set(DAEMON_SRC
"${DAEMON_SRC_DIR}/Daemon.cpp"
"${DAEMON_SRC_DIR}/HTTPServer.cpp"
"${DAEMON_SRC_DIR}/I2PControl.cpp"
"${DAEMON_SRC_DIR}/i2pd.cpp"
"${DAEMON_SRC_DIR}/UPnP.cpp"
)
if(WITH_MESHNET)
add_definitions(-DMESHNET)
endif()
if(WITH_UPNP)
add_definitions(-DUSE_UPNP)
endif()
@@ -140,7 +148,7 @@ endif()
# compiler flags customization(by system)
if(UNIX)
list(APPEND DAEMON_SRC "${DAEMON_SRC_DIR}/UnixDaemon.cpp")
list(APPEND DAEMON_SRC "${DAEMON_SRC_DIR}/DaemonUnix.cpp")
if(NOT(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD" OR APPLE))
# "'sleep_for' is not a member of 'std::this_thread'" in gcc 4.7/4.8
add_definitions("-D_GLIBCXX_USE_NANOSLEEP=1")
@@ -170,20 +178,8 @@ endif()
# libraries
# TODO: once CMake 3.1+ becomes mainstream, see e.g. http://stackoverflow.com/a/29871891/673826
# use imported Threads::Threads instead
set(THREADS_PREFER_PTHREAD_FLAG ON)
if(IOS)
set(CMAKE_THREAD_LIBS_INIT "-lpthread")
set(CMAKE_HAVE_THREADS_LIBRARY 1)
set(CMAKE_USE_WIN32_THREADS_INIT 0)
set(CMAKE_USE_PTHREADS_INIT 1)
else()
find_package(Threads REQUIRED)
endif()
if(THREADS_HAVE_PTHREAD_ARG) # compile time flag
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
endif()
find_package(Threads REQUIRED)
if(WITH_STATIC)
set(Boost_USE_STATIC_LIBS ON)
@@ -202,7 +198,7 @@ else()
add_definitions(-DBOOST_SYSTEM_DYN_LINK -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_PROGRAM_OPTIONS_DYN_LINK -DBOOST_DATE_TIME_DYN_LINK -DBOOST_REGEX_DYN_LINK)
endif()
target_link_libraries(libi2pdclient libi2pd libi2pdlang)
target_link_libraries(libi2pdwebconsole libi2pdclient libi2pd libi2pdlang)
find_package(Boost COMPONENTS system filesystem program_options date_time REQUIRED)
if(NOT DEFINED Boost_INCLUDE_DIRS)
@@ -215,7 +211,7 @@ if(NOT DEFINED OPENSSL_INCLUDE_DIR)
endif()
if(OPENSSL_VERSION VERSION_GREATER_EQUAL "3.0.0")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations")
add_definitions(-DOPENSSL_SUPPRESS_DEPRECATED)
endif()
if(WITH_UPNP)
@@ -235,12 +231,6 @@ endif()
# load includes
include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR})
# warn if for meshnet
if(WITH_MESHNET)
message(STATUS "Building for testnet")
message(WARNING "This build will NOT work on mainline i2p")
endif()
include(CheckAtomic)
# show summary
@@ -258,15 +248,10 @@ message(STATUS " LIBRARY : ${WITH_LIBRARY}")
message(STATUS " BINARY : ${WITH_BINARY}")
message(STATUS " STATIC BUILD : ${WITH_STATIC}")
message(STATUS " UPnP : ${WITH_UPNP}")
message(STATUS " MESHNET : ${WITH_MESHNET}")
message(STATUS " ADDRSANITIZER : ${WITH_ADDRSANITIZER}")
message(STATUS " THREADSANITIZER : ${WITH_THREADSANITIZER}")
message(STATUS "---------------------------------------")
if(WITH_MESHNET)
message(STATUS "WARNING: Using the MESHNET option will make it impossible to use the application with the main network!!!")
endif()
if(WITH_BINARY)
add_executable("${PROJECT_NAME}" ${DAEMON_SRC})
@@ -294,7 +279,7 @@ if(WITH_BINARY)
endif()
target_link_libraries(libi2pd ${Boost_LIBRARIES} ${ZLIB_LIBRARY})
target_link_libraries("${PROJECT_NAME}" libi2pd libi2pdclient libi2pdlang ${DL_LIB} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${UPNP_LIB} ${ZLIB_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${DL_LIB} ${CMAKE_REQUIRED_LIBRARIES})
target_link_libraries("${PROJECT_NAME}" libi2pdwebconsole libi2pd libi2pdclient libi2pdlang ${DL_LIB} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${UPNP_LIB} ${ZLIB_LIBRARY} Threads::Threads ${DL_LIB} ${CMAKE_REQUIRED_LIBRARIES})
install(TARGETS "${PROJECT_NAME}" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime)
set(APPS "\${CMAKE_INSTALL_PREFIX}/bin/${PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX}")

View File

@@ -52,22 +52,28 @@ REM converting configuration files to DOS format (make usable in Windows Notepad
%xSH% "unix2dos contrib/i2pd.conf contrib/tunnels.conf contrib/tunnels.d/* contrib/webconsole/style.css" >> build\build.log 2>&1
REM Prepare binary signing command if signing key and password provided
if defined SIGNKEY (
if defined SIGNPASS (
echo Signing options found
if defined SIGN (
echo Signing enabled
for %%X in (signtool.exe) do (set xSIGNTOOL=%%~$PATH:X)
if not defined xSIGNTOOL (
if not defined SIGNTOOL (
echo Error: Can't find signtool. Please provide path to binary using SIGNTOOL variable.
exit /b 1
) else (
set "xSIGNTOOL=%SIGNTOOL%"
)
for %%X in (signtool.exe) do (set xSIGNTOOL=%%~$PATH:X)
if not defined xSIGNTOOL (
if not defined SIGNTOOL (
echo Error: Can't find signtool. Please provide path to binary using SIGNTOOL variable.
exit /b 1
) else (
set "xSIGNTOOL=%SIGNTOOL%"
)
set "xSIGNOPTS=sign /tr http://timestamp.digicert.com /td sha256 /fd sha256 /f ^"%SIGNKEY%^" /p ^"%SIGNPASS%^""
)
if defined SIGNKEY (
set "xSIGNKEYOPTS=/f ^"%SIGNKEY%^""
)
if defined SIGNPASS (
set "xSIGNPASSOPTS=/p ^"%SIGNPASS%^""
)
set "xSIGNOPTS=sign /tr http://timestamp.digicert.com /td sha256 /fd sha256 %xSIGNKEYOPTS% %xSIGNPASSOPTS%"
)
REM starting building

View File

@@ -1,18 +0,0 @@
gen
tests
bin
libs
log*
obj
.gradle
.idea
.externalNativeBuild
ant.properties
local.properties
build.sh
android.iml
build
gradle
gradlew
gradlew.bat

View File

@@ -1,74 +0,0 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := i2pd
LOCAL_CPP_FEATURES := rtti exceptions
LOCAL_C_INCLUDES += $(IFADDRS_PATH) $(LIB_SRC_PATH) $(LIB_CLIENT_SRC_PATH) $(DAEMON_SRC_PATH)
LOCAL_STATIC_LIBRARIES := \
boost_system \
boost_date_time \
boost_filesystem \
boost_program_options \
crypto ssl \
miniupnpc
LOCAL_LDLIBS := -lz
LOCAL_SRC_FILES := $(IFADDRS_PATH)/ifaddrs.c \
$(wildcard $(LIB_SRC_PATH)/*.cpp)\
$(wildcard $(LIB_CLIENT_SRC_PATH)/*.cpp)\
$(DAEMON_SRC_PATH)/UnixDaemon.cpp \
$(DAEMON_SRC_PATH)/Daemon.cpp \
$(DAEMON_SRC_PATH)/UPnP.cpp \
$(DAEMON_SRC_PATH)/HTTPServer.cpp \
$(DAEMON_SRC_PATH)/I2PControl.cpp \
$(DAEMON_SRC_PATH)/i2pd.cpp
include $(BUILD_EXECUTABLE)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := boost_system
LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_system.a
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include
include $(PREBUILT_STATIC_LIBRARY)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := boost_date_time
LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_date_time.a
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include
include $(PREBUILT_STATIC_LIBRARY)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := boost_filesystem
LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_filesystem.a
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include
include $(PREBUILT_STATIC_LIBRARY)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := boost_program_options
LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_program_options.a
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include
include $(PREBUILT_STATIC_LIBRARY)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := crypto
LOCAL_SRC_FILES := $(OPENSSL_PATH)/openssl-1.1.1a-clang/$(TARGET_ARCH_ABI)/lib/libcrypto.a
LOCAL_EXPORT_C_INCLUDES := $(OPENSSL_PATH)/openssl-1.1.1a-clang/include
include $(PREBUILT_STATIC_LIBRARY)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ssl
LOCAL_SRC_FILES := $(OPENSSL_PATH)/openssl-1.1.1a-clang/$(TARGET_ARCH_ABI)/lib/libssl.a
LOCAL_EXPORT_C_INCLUDES := $(OPENSSL_PATH)/openssl-1.1.1a-clang/include
LOCAL_STATIC_LIBRARIES := crypto
include $(PREBUILT_STATIC_LIBRARY)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := miniupnpc
LOCAL_SRC_FILES := $(MINIUPNP_PATH)/miniupnpc-2.1/$(TARGET_ARCH_ABI)/lib/libminiupnpc.a
LOCAL_EXPORT_C_INCLUDES := $(MINIUPNP_PATH)/miniupnpc-2.1/include
include $(PREBUILT_STATIC_LIBRARY)

View File

@@ -1,40 +0,0 @@
APP_ABI := all
#APP_ABI += x86
#APP_ABI += x86_64
#APP_ABI += armeabi-v7a
#APP_ABI += arm64-v8a
#can be android-3 but will fail for x86 since arch-x86 is not present at ndkroot/platforms/android-3/ . libz is taken from there.
APP_PLATFORM := android-14
NDK_TOOLCHAIN_VERSION := clang
APP_STL := c++_static
# Enable c++17 extensions in source code
APP_CPPFLAGS += -std=c++17 -fvisibility=default -fPIE
APP_CPPFLAGS += -DANDROID_BINARY -DANDROID -D__ANDROID__ -DUSE_UPNP
APP_LDFLAGS += -rdynamic -fPIE -pie
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
APP_CPPFLAGS += -DANDROID_ARM7A
endif
# Forcing debug optimization. Use `ndk-build NDK_DEBUG=1` instead.
#APP_OPTIM := debug
# git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git -b boost-1_72_0
# git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git
# git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git
# git clone https://github.com/PurpleI2P/android-ifaddrs.git
# change to your own
I2PD_LIBS_PATH = /path/to/libraries
BOOST_PATH = $(I2PD_LIBS_PATH)/Boost-for-Android-Prebuilt
OPENSSL_PATH = $(I2PD_LIBS_PATH)/OpenSSL-for-Android-Prebuilt
MINIUPNP_PATH = $(I2PD_LIBS_PATH)/MiniUPnP-for-Android-Prebuilt
IFADDRS_PATH = $(I2PD_LIBS_PATH)/android-ifaddrs
# don't change me
I2PD_SRC_PATH = $(PWD)/../..
LIB_SRC_PATH = $(I2PD_SRC_PATH)/libi2pd
LIB_CLIENT_SRC_PATH = $(I2PD_SRC_PATH)/libi2pd_client
DAEMON_SRC_PATH = $(I2PD_SRC_PATH)/daemon

View File

@@ -1,2 +0,0 @@
archive
i2pd_*_android_binary.zip

View File

@@ -1,48 +0,0 @@
#!/bin/bash
# Copyright (c) 2013-2020, The PurpleI2P Project
#
# This file is part of Purple i2pd project and licensed under BSD3
#
# See full license text in LICENSE file at top of project tree
GITDESC=$(git describe --tags)
declare -A ABILIST=(
["armeabi-v7a"]="armv7l"
["arm64-v8a"]="aarch64"
["x86"]="x86"
["x86_64"]="x86_64"
)
# Remove old files and archives
if [ -d archive ]; then
rm -r archive
fi
if [ -f ../i2pd_*_android_binary.zip ]; then
rm i2pd_*_android_binary.zip
fi
# Prepare files for package
mkdir archive
for ABI in "${!ABILIST[@]}"; do
if [ -f ../android_binary_only/libs/${ABI}/i2pd ]; then
cp ../android_binary_only/libs/${ABI}/i2pd archive/i2pd-${ABILIST[$ABI]}
fi
done
cp i2pd archive/i2pd
cp -rH ../android/assets/certificates archive/
cp -rH ../android/assets/tunnels.conf.d archive/
cp -H ../android/assets/i2pd.conf archive/
cp -H ../android/assets/tunnels.conf archive/
# Compress files
cd archive
zip -r6 ../i2pd_${GITDESC}_android_binary.zip .
# Remove temporary folder
cd ..
rm -r archive

View File

@@ -1,33 +0,0 @@
#!/bin/sh
# Copyright (c) 2013-2020, The PurpleI2P Project
#
# This file is part of Purple i2pd project and licensed under BSD3
#
# See full license text in LICENSE file at top of project tree
#
# That script written for use with Termux.
# https://stackoverflow.com/a/246128
SOURCE="${0}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
SOURCE="$(readlink "$SOURCE")"
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
arch=$(uname -m)
screenfind=$(which screen)
if [ -z $screenfind ]; then
echo "Can't find 'screen' installed. That script needs it!";
exit 1;
fi
if [ -z i2pd-$arch ]; then
echo "Can't find i2pd binary for your archtecture.";
exit 1;
fi
screen -AmdS i2pd ./i2pd-$arch --datadir=$DIR

View File

@@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICKDCCAc6gAwIBAgIUcPHZXtYSqGNRCD6z8gp79WUFtI0wCgYIKoZIzj0EAwIw
gZMxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEPMA0GA1UEBwwGQXVzdGlu
MRgwFgYDVQQKDA9TdG9ybXlDbG91ZCBJbmMxIzAhBgNVBAMMGnN0b3JteWNsb3Vk
LmZhbWlseS5pMnAubmV0MSQwIgYJKoZIhvcNAQkBFhVhZG1pbkBzdG9ybXljbG91
ZC5vcmcwHhcNMjIwMzE5MTU1MjU2WhcNMzIwMzE2MTU1MjU2WjCBkzELMAkGA1UE
BhMCVVMxDjAMBgNVBAgMBVRleGFzMQ8wDQYDVQQHDAZBdXN0aW4xGDAWBgNVBAoM
D1N0b3JteUNsb3VkIEluYzEjMCEGA1UEAwwac3Rvcm15Y2xvdWQuZmFtaWx5Lmky
cC5uZXQxJDAiBgkqhkiG9w0BCQEWFWFkbWluQHN0b3JteWNsb3VkLm9yZzBZMBMG
ByqGSM49AgEGCCqGSM49AwEHA0IABFUli0hvJEmowNjJVjbKEIWBJhqe973S4VdL
cJuA5yY3dC4Y998abWEox7/Y1BhnBbpJuiodA341bXKkLMXQy/kwCgYIKoZIzj0E
AwIDSAAwRQIgD12F/TfY3iV1/WDF7BSKgbD5g2MfELUIy1dtUlJQuJUCIQD69mZw
V1Z9j2x0ZsuirS3i6AMfVyTDj0RFS3U1jeHzIQ==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,34 @@
-----BEGIN CERTIFICATE-----
MIIFzTCCA7WgAwIBAgIQeUqFi0fHNQopg6BZlBLhVzANBgkqhkiG9w0BAQsFADBy
MQswCQYDVQQGEwJYWDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMR4wHAYDVQQK
ExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEbMBkGA1UEAwwS
aTJwLXJlc2VlZEBtazE2LmRlMB4XDTIyMDIwNTE3MzkzM1oXDTMyMDIwNTE3Mzkz
M1owcjELMAkGA1UEBhMCWFgxCzAJBgNVBAcTAlhYMQswCQYDVQQJEwJYWDEeMBwG
A1UEChMVSTJQIEFub255bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxGzAZBgNV
BAMMEmkycC1yZXNlZWRAbWsxNi5kZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC
AgoCggIBAMYxs2D2xpN/8blGawvAlU9DemHIxApOEwaLNfh8aAvqEdB41NTqcx4U
H8VchSormCfkCvezuMHO+K2HX7ihEZ1v6tbr6aX6hY9UZUyDDYsKmJoB1oKEhddv
5UYfcWPE2eSykdFsWgTQD6Z+cRQWHEoCzb7qc+Jrw6KcnHMD0VrmBrEQPzTBxMHW
4HC97PVkSLJTDArnS6ZiX4IbWRPw/mbpJT6EoVZo8J/it0pdn/X4KodEXDcnEMSe
VRulfZH/nSmOOvKhoHPckmgz/u66BlnuSYXEIB0KfDIcAlSYiPDxGnAemTozJYXA
UVMeFMs+YE5wiPgzzu+vpC31xtZLq0gyaCfgEi1P9j2ES/8pH3Gw6W2OH4kBx+jO
TBsfI+ph6qFZ3WWT23MRVyl3ATuI/GHdczTxD9JaOn74lLI+Hnu8wXnyztVWkTMB
4sAnzjdeHkvNDyQ10vSaN0HnGfg6zuAuUSqFQujFF8Vg8ZCcsh8GouWfzYDvi9mj
9pfxx8v6UCC719I4J9CgFjWnn2Hqez3fO8fFulY61VPyCCZp4gKWbI2SIQP/n5gz
ecYJRrJoem+rYfEQ/fwxROsvm3fCO4D6dt7ILRuX286GDIw2qSvP1zZVAioMwSj3
9CAjKLwD/BhTRiMOlpaVv6IWqjtevbiaIKvbHTnoxvkGsDqe3gJhAgMBAAGjXzBd
MA4GA1UdDwEB/wQEAwIChDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEw
DwYDVR0TAQH/BAUwAwEB/zAbBgNVHQ4EFAQSaTJwLXJlc2VlZEBtazE2LmRlMA0G
CSqGSIb3DQEBCwUAA4ICAQAb+x6XpJdjpVYw2bvWIUbatQJwq0YaEW5W61xGLgIG
a37oll3YZbSY9Vk+N1cE0f61L3ya4Ioz6zlH/MO2zUG/dEk8vqdgIPUYJvyF7wwF
w3/G4VMaDKOJx4bAZNmaiRFGYNhCOhCnZx6uZGrLNIJ2Dc+mflrGmGwYphtXVV3e
Iv+ki3gSRgfXuMfKi4B5bLPnz7XDe4TSmwZZSRac4ly4KqmZUyntqbilRxaGTej3
VYJ1tac8yppyk5N3VopMQNmBarNZG16wSOTD7CtKgn382jgRW8cR7BMeqhORivp0
ZnPJFhzh4uthdlPdXXo6lxfvZjfiwlDPytvEu2QBz3urTgopGqRLcTBnLucWg9li
OSy9z7hNEnIN3iIJJAwI1wBdDa7K0h3PFBbIUa7X2ybn81VeNSfO25Lo8YTZEKsc
wcThJrNV6qOQv8rM/7aXugi6+VzPlCR+18iKRbebCnlqGR2dT1zFtj3negtOkrjo
LH4H6VUr3q2Ie56IubS2hUKiUkDm0ckP3Vum35GGntyEAzl6uyog0hJFOJb3aq30
YQLzyVEOz8NnA+32oMRzJJdDxQ7pqG5fgq7EF4d++YSgEfdVXxvfgXQ6m3jAyC7Z
p/gX4rlxNsjeGU3Ds51wkmhH4IB1aSQr52PE6RaBhhh3SmADEv6S/3eGvE4F4MN5
2Q==
-----END CERTIFICATE-----

View File

@@ -110,8 +110,8 @@ port = 7070
# user = i2pd
# pass = changeme
## Select webconsole language
## Currently supported english (default), afrikaans, armenian, german, russian,
## turkmen, ukrainian and uzbek languages
## Currently supported english (default), afrikaans, armenian, french, german,
## russian, turkmen, ukrainian and uzbek languages
# lang = english
[httpproxy]

View File

@@ -1,7 +1,7 @@
%define git_hash %(git rev-parse HEAD | cut -c -7)
Name: i2pd-git
Version: 2.41.0
Version: 2.42.1
Release: git%{git_hash}%{?dist}
Summary: I2P router written in C++
Conflicts: i2pd
@@ -57,8 +57,14 @@ cd build
%endif
%if 0%{?fedora} >= 35
%if 0%{?rhel} == 9
pushd redhat-linux-build
%endif
%if 0%{?fedora} >= 35
%if 0%{?fedora} < 37
pushd redhat-linux-build
%endif
%else
%if 0%{?fedora} >= 33
pushd %{_target_platform}
@@ -71,10 +77,16 @@ pushd build
make %{?_smp_mflags}
%if 0%{?fedora} >= 33
%if 0%{?rhel} == 9
popd
%endif
%if 0%{?fedora} >= 33
%if 0%{?fedora} < 37
popd
%endif
%endif
%if 0%{?mageia} > 7
popd
%endif
@@ -82,8 +94,14 @@ popd
%install
pushd build
%if 0%{?fedora} >= 35
%if 0%{?rhel} == 9
pushd redhat-linux-build
%endif
%if 0%{?fedora} >= 35
%if 0%{?fedora} < 37
pushd redhat-linux-build
%endif
%else
%if 0%{?fedora} >= 33
pushd %{_target_platform}
@@ -146,6 +164,12 @@ getent passwd i2pd >/dev/null || \
%changelog
* Tue May 24 2022 r4sas <r4sas@i2pmail.org> - 2.42.1
- update to 2.42.1
* Sun May 22 2022 orignal <orignal@i2pmail.org> - 2.42.0
- update to 2.42.0
* Sun Feb 20 2022 r4sas <r4sas@i2pmail.org> - 2.41.0
- update to 2.41.0
- fixed build on Fedora Copr over openssl trunk code

View File

@@ -1,5 +1,5 @@
Name: i2pd
Version: 2.41.0
Version: 2.42.1
Release: 1%{?dist}
Summary: I2P router written in C++
Conflicts: i2pd-git
@@ -54,8 +54,14 @@ cd build
%endif
%endif
%if 0%{?fedora} >= 35
%if 0%{?rhel} == 9
pushd redhat-linux-build
%endif
%if 0%{?fedora} >= 35
%if 0%{?fedora} < 37
pushd redhat-linux-build
%endif
%else
%if 0%{?fedora} >= 33
pushd %{_target_platform}
@@ -68,10 +74,16 @@ pushd build
make %{?_smp_mflags}
%if 0%{?fedora} >= 33
%if 0%{?rhel} == 9
popd
%endif
%if 0%{?fedora} >= 33
%if 0%{?fedora} < 37
popd
%endif
%endif
%if 0%{?mageia} > 7
popd
%endif
@@ -79,8 +91,14 @@ popd
%install
pushd build
%if 0%{?fedora} >= 35
%if 0%{?rhel} == 9
pushd redhat-linux-build
%endif
%if 0%{?fedora} >= 35
%if 0%{?fedora} < 37
pushd redhat-linux-build
%endif
%else
%if 0%{?fedora} >= 33
pushd %{_target_platform}
@@ -143,6 +161,12 @@ getent passwd i2pd >/dev/null || \
%changelog
* Tue May 24 2022 r4sas <r4sas@i2pmail.org> - 2.42.1
- update to 2.42.1
* Sun May 22 2022 orignal <orignal@i2pmail.org> - 2.42.0
- update to 2.42.0
* Sun Feb 20 2022 r4sas <r4sas@i2pmail.org> - 2.41.0
- update to 2.41.0

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
* Copyright (c) 2013-2022, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -58,12 +58,16 @@ namespace util
bool Daemon_Singleton::IsService () const
{
bool service = false;
#ifndef _WIN32
i2p::config::GetOption("service", service);
#endif
return service;
}
void Daemon_Singleton::setDataDir(std::string path)
{
if (path != "")
DaemonDataDir = path;
}
bool Daemon_Singleton::init(int argc, char* argv[]) {
return init(argc, argv, nullptr);
}
@@ -73,8 +77,14 @@ namespace util
i2p::config::Init();
i2p::config::ParseCmdline(argc, argv);
std::string config; i2p::config::GetOption("conf", config);
std::string datadir; i2p::config::GetOption("datadir", datadir);
std::string config; i2p::config::GetOption("conf", config);
std::string datadir;
if(DaemonDataDir != "") {
datadir = DaemonDataDir;
} else {
i2p::config::GetOption("datadir", datadir);
}
i2p::fs::DetectDataDir(datadir, IsService());
i2p::fs::Init();
@@ -99,9 +109,9 @@ namespace util
certsdir = i2p::fs::GetCertsDir();
std::string logs = ""; i2p::config::GetOption("log", logs);
std::string logfile = ""; i2p::config::GetOption("logfile", logfile);
std::string loglevel = ""; i2p::config::GetOption("loglevel", loglevel);
std::string logs = ""; i2p::config::GetOption("log", logs);
std::string logfile = ""; i2p::config::GetOption("logfile", logfile);
std::string loglevel = ""; i2p::config::GetOption("loglevel", loglevel);
bool logclftime; i2p::config::GetOption("logclftime", logclftime);
/* setup logging */
@@ -151,11 +161,7 @@ namespace util
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
#ifdef MESHNET
// manual override for meshnet
ipv4 = false;
ipv6 = true;
#endif
// ifname -> address
std::string ifname; i2p::config::GetOption("ifname", ifname);
if (ipv4 && i2p::config::IsDefault ("address4"))
@@ -244,6 +250,18 @@ namespace util
if (!ipv4 && !ipv6)
i2p::context.SetStatus (eRouterStatusMesh);
}
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
if (ssu2)
{
bool published; i2p::config::GetOption("ssu2.published", published);
if (published)
{
uint16_t ssu2port; i2p::config::GetOption("ssu2.port", ssu2port);
i2p::context.PublishSSU2Address (ssu2port, true, ipv4, ipv6); // publish
}
else
i2p::context.PublishSSU2Address (0, false, ipv4, ipv6); // unpublish
}
bool transit; i2p::config::GetOption("notransit", transit);
i2p::context.SetAcceptsTunnels (!transit);
@@ -377,6 +395,7 @@ namespace util
}
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
bool ssu; i2p::config::GetOption("ssu", ssu);
bool checkInReserved; i2p::config::GetOption("reservedrange", checkInReserved);
LogPrint(eLogInfo, "Daemon: Starting Transports");
@@ -384,7 +403,7 @@ namespace util
if(!ntcp2) LogPrint(eLogInfo, "Daemon: NTCP2 disabled");
i2p::transport::transports.SetCheckReserved(checkInReserved);
i2p::transport::transports.Start(ntcp2, ssu);
i2p::transport::transports.Start(ntcp2, ssu, ssu2);
if (i2p::transport::transports.IsBoundSSU() || i2p::transport::transports.IsBoundNTCP2())
LogPrint(eLogInfo, "Daemon: Transports started");
else
@@ -404,6 +423,10 @@ namespace util
try
{
d.httpServer = std::unique_ptr<i2p::http::HTTPServer>(new i2p::http::HTTPServer(httpAddr, httpPort));
d.httpServer->SetDaemonStop (std::bind (Daemon_Singleton::stop, this));
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
d.httpServer->SetDaemonGracefulTimer (std::bind (gracefulShutdownInterval, this));
#endif
d.httpServer->Start();
}
catch (std::exception& ex)

View File

@@ -20,27 +20,33 @@ namespace util
class Daemon_Singleton_Private;
class Daemon_Singleton
{
public:
public:
virtual bool init(int argc, char* argv[], std::shared_ptr<std::ostream> logstream);
virtual bool init(int argc, char* argv[]);
virtual bool start();
virtual bool stop();
virtual void run () {};
virtual bool init (int argc, char* argv[], std::shared_ptr<std::ostream> logstream);
virtual bool init (int argc, char* argv[]);
virtual bool start ();
virtual bool stop ();
virtual void run () {};
bool isDaemon;
bool running;
virtual void setDataDir (std::string path);
protected:
bool isDaemon;
bool running;
Daemon_Singleton();
virtual ~Daemon_Singleton();
protected:
bool IsService () const;
Daemon_Singleton ();
virtual ~Daemon_Singleton ();
// d-pointer for httpServer, httpProxy, etc.
class Daemon_Singleton_Private;
Daemon_Singleton_Private &d;
bool IsService () const;
// d-pointer for httpServer, httpProxy, etc.
class Daemon_Singleton_Private;
Daemon_Singleton_Private &d;
private:
std::string DaemonDataDir;
};
#if defined(QT_GUI_LIB) // check if QT
@@ -69,14 +75,17 @@ namespace util
return instance;
}
bool init(int argc, char* argv[]);
bool start();
bool stop();
bool init (int argc, char* argv[]);
bool start ();
bool stop ();
void run ();
bool isGraceful;
void SetIsGraceful (bool state) { m_isGraceful = state; };
const bool GetIsGraceful () { return m_isGraceful; };
DaemonWin32 ():isGraceful(false) {}
private:
bool m_isGraceful;
};
#elif (defined(ANDROID) && !defined(ANDROID_BINARY))
#define Daemon i2p::util::DaemonAndroid::Instance()
@@ -103,8 +112,8 @@ namespace util
return instance;
}
bool start();
bool stop();
bool start ();
bool stop ();
void run ();
private:

View File

@@ -1,11 +1,13 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
* Copyright (c) 2013-2022, 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
*/
#ifdef _WIN32
#include <thread>
#include <clocale>
#include "Config.h"
@@ -13,7 +15,7 @@
#include "util.h"
#include "Log.h"
#ifdef _WIN32
#include "Win32Service.h"
#ifdef WIN32_APP
#include <windows.h>
#include "Win32App.h"
@@ -37,8 +39,26 @@ namespace util
}
);
i2p::win32::SetIsGraceful (std::bind (&DaemonWin32::SetIsGraceful, this, std::placeholders::_1));
i2p::win32::GetIsGraceful (std::bind (&DaemonWin32::GetIsGraceful, this));
if (!Daemon_Singleton::init(argc, argv))
return false;
if (isDaemon)
{
LogPrint(eLogDebug, "Daemon: running as service");
I2PService service((PSTR)SERVICE_NAME);
service.SetDaemonStart (std::bind (&DaemonWin32::start, this));
service.SetDaemonStop (std::bind (&DaemonWin32::stop, this));
if (!I2PService::Run(service))
{
LogPrint(eLogError, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError());
return false;
}
return false;
}
return true;
}

View File

@@ -66,29 +66,28 @@ namespace client
m_SSLContext.use_private_key_file (i2pcp_key, boost::asio::ssl::context::pem);
// handlers
m_MethodHandlers["Authenticate"] = &I2PControlService::AuthenticateHandler;
m_MethodHandlers["Echo"] = &I2PControlService::EchoHandler;
m_MethodHandlers["I2PControl"] = &I2PControlService::I2PControlHandler;
m_MethodHandlers["RouterInfo"] = &I2PControlService::RouterInfoHandler;
m_MethodHandlers["RouterManager"] = &I2PControlService::RouterManagerHandler;
m_MethodHandlers["NetworkSetting"] = &I2PControlService::NetworkSettingHandler;
m_MethodHandlers["ClientServicesInfo"] = &I2PControlService::ClientServicesInfoHandler;
m_MethodHandlers["Authenticate"] = &I2PControlService::AuthenticateHandler;
m_MethodHandlers["Echo"] = &I2PControlService::EchoHandler;
m_MethodHandlers["I2PControl"] = &I2PControlService::I2PControlHandler;
m_MethodHandlers["RouterInfo"] = &I2PControlService::RouterInfoHandler;
m_MethodHandlers["RouterManager"] = &I2PControlService::RouterManagerHandler;
m_MethodHandlers["NetworkSetting"] = &I2PControlService::NetworkSettingHandler;
m_MethodHandlers["ClientServicesInfo"] = &I2PControlService::ClientServicesInfoHandler;
// I2PControl
m_I2PControlHandlers["i2pcontrol.password"] = &I2PControlService::PasswordHandler;
// RouterInfo
m_RouterInfoHandlers["i2p.router.uptime"] = &I2PControlService::UptimeHandler;
m_RouterInfoHandlers["i2p.router.version"] = &I2PControlService::VersionHandler;
m_RouterInfoHandlers["i2p.router.status"] = &I2PControlService::StatusHandler;
m_RouterInfoHandlers["i2p.router.netdb.knownpeers"] = &I2PControlService::NetDbKnownPeersHandler;
m_RouterInfoHandlers["i2p.router.netdb.activepeers"] = &I2PControlService::NetDbActivePeersHandler;
m_RouterInfoHandlers["i2p.router.net.bw.inbound.1s"] = &I2PControlService::InboundBandwidth1S;
m_RouterInfoHandlers["i2p.router.net.bw.outbound.1s"] = &I2PControlService::OutboundBandwidth1S;
m_RouterInfoHandlers["i2p.router.net.status"] = &I2PControlService::NetStatusHandler;
m_RouterInfoHandlers["i2p.router.uptime"] = &I2PControlService::UptimeHandler;
m_RouterInfoHandlers["i2p.router.version"] = &I2PControlService::VersionHandler;
m_RouterInfoHandlers["i2p.router.status"] = &I2PControlService::StatusHandler;
m_RouterInfoHandlers["i2p.router.netdb.knownpeers"] = &I2PControlService::NetDbKnownPeersHandler;
m_RouterInfoHandlers["i2p.router.netdb.activepeers"] = &I2PControlService::NetDbActivePeersHandler;
m_RouterInfoHandlers["i2p.router.net.bw.inbound.1s"] = &I2PControlService::InboundBandwidth1S;
m_RouterInfoHandlers["i2p.router.net.bw.outbound.1s"] = &I2PControlService::OutboundBandwidth1S;
m_RouterInfoHandlers["i2p.router.net.status"] = &I2PControlService::NetStatusHandler;
m_RouterInfoHandlers["i2p.router.net.tunnels.participating"] = &I2PControlService::TunnelsParticipatingHandler;
m_RouterInfoHandlers["i2p.router.net.tunnels.successrate"] =
&I2PControlService::TunnelsSuccessRateHandler;
m_RouterInfoHandlers["i2p.router.net.tunnels.successrate"] = &I2PControlService::TunnelsSuccessRateHandler;
m_RouterInfoHandlers["i2p.router.net.total.received.bytes"] = &I2PControlService::NetTotalReceivedBytes;
m_RouterInfoHandlers["i2p.router.net.total.sent.bytes"] = &I2PControlService::NetTotalSentBytes;
@@ -104,10 +103,10 @@ namespace client
// ClientServicesInfo
m_ClientServicesInfoHandlers["I2PTunnel"] = &I2PControlService::I2PTunnelInfoHandler;
m_ClientServicesInfoHandlers["HTTPProxy"] = &I2PControlService::HTTPProxyInfoHandler;
m_ClientServicesInfoHandlers["SOCKS"] = &I2PControlService::SOCKSInfoHandler;
m_ClientServicesInfoHandlers["SAM"] = &I2PControlService::SAMInfoHandler;
m_ClientServicesInfoHandlers["BOB"] = &I2PControlService::BOBInfoHandler;
m_ClientServicesInfoHandlers["I2CP"] = &I2PControlService::I2CPInfoHandler;
m_ClientServicesInfoHandlers["SOCKS"] = &I2PControlService::SOCKSInfoHandler;
m_ClientServicesInfoHandlers["SAM"] = &I2PControlService::SAMInfoHandler;
m_ClientServicesInfoHandlers["BOB"] = &I2PControlService::BOBInfoHandler;
m_ClientServicesInfoHandlers["I2CP"] = &I2PControlService::I2CPInfoHandler;
}
I2PControlService::~I2PControlService ()
@@ -168,7 +167,7 @@ namespace client
Accept ();
if (ecode) {
LogPrint (eLogError, "I2PControl: Accept error: ", ecode.message ());
LogPrint (eLogError, "I2PControl: Accept error: ", ecode.message ());
return;
}
LogPrint (eLogDebug, "I2PControl: New request from ", socket->lowest_layer ().remote_endpoint ());
@@ -290,12 +289,12 @@ namespace client
{
ss << "\"" << name << "\":";
if (value.length () > 0)
{
{
if (quotes)
ss << "\"" << value << "\"";
else
ss << value;
}
}
else
ss << "null";
}
@@ -479,7 +478,7 @@ namespace client
void I2PControlService::NetTotalSentBytes (std::ostringstream& results)
{
InsertParam (results, "i2p.router.net.total.sent.bytes", (double)i2p::transport::transports.GetTotalSentBytes ());
InsertParam (results, "i2p.router.net.total.sent.bytes", (double)i2p::transport::transports.GetTotalSentBytes ());
}
@@ -507,7 +506,7 @@ namespace client
m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(1)); // 1 second to make sure response has been sent
m_ShutdownTimer.async_wait (
[](const boost::system::error_code& ecode)
{
{
Daemon.running = 0;
});
}
@@ -521,7 +520,7 @@ namespace client
m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(timeout + 1)); // + 1 second
m_ShutdownTimer.async_wait (
[](const boost::system::error_code& ecode)
{
{
Daemon.running = 0;
});
}

View File

@@ -93,7 +93,7 @@ namespace transport
#endif
isError = err != UPNPDISCOVER_SUCCESS;
#else // MINIUPNPC_API_VERSION >= 8
#else // MINIUPNPC_API_VERSION >= 8
err = 0;
m_Devlist = upnpDiscover (UPNP_RESPONSE_TIMEOUT, NULL, NULL, 0);
isError = m_Devlist == NULL;

View File

@@ -51,7 +51,7 @@ namespace transport
private:
void Discover ();
int CheckMapping (const char* port, const char* type);
int CheckMapping (const char* port, const char* type);
void PortMapping ();
void TryPortMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address);
void CloseMapping ();
@@ -80,7 +80,7 @@ namespace transport
}
}
#else // USE_UPNP
#else // USE_UPNP
namespace i2p {
namespace transport {
/* class stub */

13
debian/changelog vendored
View File

@@ -1,3 +1,16 @@
i2pd (2.42.1-1) unstable; urgency=medium
* updated to version 2.42.1/0.9.54
* remove -O3 optimization flag
-- r4sas <r4sas@i2pmail.org> Tue, 24 May 2022 12:00:00 +0000
i2pd (2.42.0-1) unstable; urgency=medium
* updated to version 2.42.0/0.9.54
-- orignal <orignal@i2pmail.org> Sun, 22 May 2022 16:00:00 +0000
i2pd (2.41.0-1) unstable; urgency=medium
* updated to version 2.41.0/0.9.53

View File

@@ -2,14 +2,14 @@ Description: Enable UPnP usage in package
Author: r4sas <r4sas@i2pmail.org>
Reviewed-By: r4sas <r4sas@i2pmail.org>
Last-Update: 2021-10-22
Last-Update: 2022-03-23
--- i2pd.orig/Makefile
+++ i2pd/Makefile
@@ -32,7 +32,7 @@ include filelist.mk
@@ -31,7 +31,7 @@ include filelist.mk
USE_AESNI := $(or $(USE_AESNI),yes)
USE_STATIC := $(or $(USE_STATIC),no)
USE_MESHNET := $(or $(USE_MESHNET),no)
-USE_UPNP := $(or $(USE_UPNP),no)
+USE_UPNP := $(or $(USE_UPNP),yes)
DEBUG := $(or $(DEBUG),yes)

9
debian/rules vendored
View File

@@ -1,16 +1,13 @@
#!/usr/bin/make -f
#export DH_VERBOSE=1
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
include /usr/share/dpkg/architecture.mk
export DEB_CXXFLAGS_MAINT_APPEND = -Wall -pedantic -O3
export DEB_CXXFLAGS_MAINT_APPEND = -Wall -pedantic
export DEB_LDFLAGS_MAINT_APPEND =
%:
dh $@ --parallel
override_dh_auto_install:

View File

@@ -1,26 +1,7 @@
#LIB_SRC = \
# BloomFilter.cpp Gzip.cpp Crypto.cpp Datagram.cpp Garlic.cpp I2NPProtocol.cpp LeaseSet.cpp \
# Log.cpp NTCPSession.cpp NetDb.cpp NetDbRequests.cpp Profiling.cpp \
# 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 FS.cpp Config.cpp Family.cpp \
# Config.cpp HTTP.cpp Timestamp.cpp util.cpp api.cpp Gost.cpp
LIB_SRC = $(wildcard $(LIB_SRC_DIR)/*.cpp)
#LIB_CLIENT_SRC = \
# AddressBook.cpp BOB.cpp ClientContext.cpp I2PTunnel.cpp I2PService.cpp MatchedDestination.cpp \
# SAM.cpp SOCKS.cpp HTTPProxy.cpp I2CP.cpp
LIB_CLIENT_SRC = $(wildcard $(LIB_CLIENT_SRC_DIR)/*.cpp)
# also: Daemon{Linux,Win32}.cpp will be added later
#DAEMON_SRC = \
# HTTPServer.cpp I2PControl.cpp UPnP.cpp Daemon.cpp i2pd.cpp
LANG_SRC = $(wildcard $(LANG_SRC_DIR)/*.cpp)
WEBCONSOLE_SRC = $(wildcard $(WEBCONSOLE_SRC_DIR)/*.cpp)
WRAP_LIB_SRC = $(wildcard $(WRAP_SRC_DIR)/*.cpp)
DAEMON_SRC = $(wildcard $(DAEMON_SRC_DIR)/*.cpp)
DAEMON_SRC = $(DAEMON_SRC_DIR)/Daemon.cpp $(DAEMON_SRC_DIR)/I2PControl.cpp $(DAEMON_SRC_DIR)/i2pd.cpp $(DAEMON_SRC_DIR)/UPnP.cpp

102
i18n/French.cpp Normal file
View File

@@ -0,0 +1,102 @@
/*
* Copyright (c) 2022, 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 <map>
#include <vector>
#include <string>
#include <memory>
#include "I18N.h"
// French localization file
namespace i2p
{
namespace i18n
{
namespace french // language namespace
{
// language name in lowercase
static std::string language = "french";
// See for language plural forms here:
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
static int plural (int n) {
return n != 1 ? 1 : 0;
}
static std::map<std::string, std::string> strings
{
{"KiB", "Kio"},
{"MiB", "Mio"},
{"GiB", "Gio"},
{"building", "En construction"},
{"failed", "echoué"},
{"expiring", "expiré"},
{"established", "établi"},
{"unknown", "inconnu"},
{"exploratory", "exploratoire"},
{"<b>i2pd</b> webconsole", "Console web <b>i2pd</b>"},
{"Main page", "Page principale"},
{"Router commands", "Commandes du routeur"},
{"Local Destinations", "Destinations locales"},
{"Tunnels", "Tunnels"},
{"Transit Tunnels", "Tunnels transitoires"},
{"I2P tunnels", "Tunnels I2P"},
{"SAM sessions", "Sessions SAM"},
{"ERROR", "ERREUR"},
{"OK", "OK"},
{"Firewalled", "Derrière un pare-feu"},
{"Error", "Erreur"},
{"Offline", "Hors ligne"},
{"Uptime", "Temps de fonctionnement"},
{"Network status", "État du réseau"},
{"Network status v6", "État du réseau v6"},
{"Stopping in", "Arrêt dans"},
{"Family", "Famille"},
{"Tunnel creation success rate", "Taux de succès de création de tunnels"},
{"Received", "Reçu"},
{"KiB/s", "kio/s"},
{"Sent", "Envoyé"},
{"Transit", "Transit"},
{"Hidden content. Press on text to see.", "Contenu caché. Cliquez sur le texte pour regarder."},
{"Router Ident", "Identifiant du routeur"},
{"Router Family", "Famille du routeur"},
{"Version", "Version"},
{"Our external address", "Notre adresse externe"},
{"Client Tunnels", "Tunnels clients"},
{"Services", "Services"},
{"Enabled", "Activé"},
{"Disabled", "Désactivé"},
{"Encrypted B33 address", "Adresse B33 chiffrée"},
{"Domain", "Domaine"},
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Note:</b> La chaîne résultante peut seulement être utilisée pour enregistrer les domaines 2LD (exemple.i2p). Pour enregistrer des sous-domaines, veuillez utiliser i2pd-tools."},
{"Address", "Adresse"},
{"ms", "ms"},
{"Outbound tunnels", "Tunnels sortants"},
{"Destination", "Destination"},
{"Local Destination", "Destination locale"},
{"", ""},
};
static std::map<std::string, std::vector<std::string>> plurals
{
{"days", {"jour", "jours"}},
{"hours", {"heure", "heures"}},
{"minutes", {"minute", "minutes"}},
{"seconds", {"seconde", "secondes"}},
{"", {"", ""}},
};
std::shared_ptr<const i2p::i18n::Locale> GetLocale()
{
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
}
} // language
} // i18n
} // i2p

View File

@@ -74,6 +74,7 @@ namespace i18n
namespace afrikaans { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace armenian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace english { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace french { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace german { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace russian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace turkmen { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
@@ -88,6 +89,7 @@ namespace i18n
{ "afrikaans", {"Afrikaans", "af", i2p::i18n::afrikaans::GetLocale} },
{ "armenian", {"հայերէն", "hy", i2p::i18n::armenian::GetLocale} },
{ "english", {"English", "en", i2p::i18n::english::GetLocale} },
{ "french", {"Français", "fr", i2p::i18n::french::GetLocale} },
{ "german", {"Deutsch", "de", i2p::i18n::german::GetLocale} },
{ "russian", {"русский язык", "ru", i2p::i18n::russian::GetLocale} },
{ "turkmen", {"türkmen dili", "tk", i2p::i18n::turkmen::GetLocale} },

View File

@@ -24,8 +24,8 @@ namespace data {
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
*/
* 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);
std::string ToBase64Standard (const std::string& in); // using standard table, for Proxy-Authorization

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2021, The PurpleI2P Project
* Copyright (c) 2013-2022, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -99,7 +99,7 @@ namespace data
static size_t BlindECDSA (i2p::data::SigningKeyType sigType, const uint8_t * key, const uint8_t * seed, Fn blind, Args&&...args)
// blind is BlindEncodedPublicKeyECDSA or BlindEncodedPrivateKeyECDSA
{
size_t publicKeyLength = 0;
size_t publicKeyLength = 0;
EC_GROUP * group = nullptr;
switch (sigType)
{
@@ -146,7 +146,10 @@ namespace data
m_PublicKey.resize (len);
memcpy (m_PublicKey.data (), identity->GetSigningPublicKeyBuffer (), len);
m_SigType = identity->GetSigningKeyType ();
m_BlindedSigType = m_SigType;
if (m_SigType == i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519)
m_BlindedSigType = i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519; // 7 -> 11
else
m_BlindedSigType = m_SigType;
}
BlindedPublicKey::BlindedPublicKey (const std::string& b33):

View File

@@ -28,8 +28,8 @@ namespace data
const uint8_t * GetPublicKey () const { return m_PublicKey.data (); };
size_t GetPublicKeyLen () const { return m_PublicKey.size (); };
SigningKeyType GetSigType () const { return m_SigType; };
SigningKeyType GetBlindedSigType () const { return m_BlindedSigType; };
SigningKeyType GetSigType () const { return m_SigType; };
SigningKeyType GetBlindedSigType () const { return m_BlindedSigType; };
bool IsValid () const { return GetSigType (); }; // signature type 0 means invalid
void GetSubcredential (const uint8_t * blinded, size_t len, uint8_t * subcredential) const; // 32 bytes

View File

@@ -78,9 +78,9 @@ namespace config {
("limits.coresize", value<uint32_t>()->default_value(0), "Maximum size of corefile in Kb (0 - use system limit)")
("limits.openfiles", value<uint16_t>()->default_value(0), "Maximum number of open files (0 - use system default)")
("limits.transittunnels", value<uint16_t>()->default_value(2500), "Maximum active transit sessions (default:2500)")
("limits.ntcpsoft", value<uint16_t>()->default_value(0), "Threshold to start probabilistic backoff with ntcp sessions (default: use system limit)")
("limits.ntcphard", value<uint16_t>()->default_value(0), "Maximum number of ntcp sessions (default: use system limit)")
("limits.ntcpthreads", value<uint16_t>()->default_value(1), "Maximum number of threads used by NTCP DH worker (default: 1)")
("limits.ntcpsoft", value<uint16_t>()->default_value(0), "Ignored")
("limits.ntcphard", value<uint16_t>()->default_value(0), "Ignored")
("limits.ntcpthreads", value<uint16_t>()->default_value(1), "Ignored")
;
options_description httpserver("HTTP Server options");
@@ -109,6 +109,8 @@ namespace config {
("httpproxy.outbound.length", value<std::string>()->default_value("3"), "HTTP proxy outbound tunnel length")
("httpproxy.inbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy inbound tunnels quantity")
("httpproxy.outbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy outbound tunnels quantity")
("httpproxy.inbound.lengthVariance", value<std::string>()->default_value("0"), "HTTP proxy inbound tunnels length variance")
("httpproxy.outbound.lengthVariance", value<std::string>()->default_value("0"), "HTTP proxy outbound tunnels length variance")
("httpproxy.latency.min", value<std::string>()->default_value("0"), "HTTP proxy min latency for tunnels")
("httpproxy.latency.max", value<std::string>()->default_value("0"), "HTTP proxy max latency for tunnels")
("httpproxy.outproxy", value<std::string>()->default_value(""), "HTTP proxy upstream out proxy url")
@@ -130,6 +132,8 @@ namespace config {
("socksproxy.outbound.length", value<std::string>()->default_value("3"), "SOCKS proxy outbound tunnel length")
("socksproxy.inbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy inbound tunnels quantity")
("socksproxy.outbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy outbound tunnels quantity")
("socksproxy.inbound.lengthVariance", value<std::string>()->default_value("0"), "SOCKS proxy inbound tunnels length variance")
("socksproxy.outbound.lengthVariance", value<std::string>()->default_value("0"), "SOCKS proxy outbound tunnels length variance")
("socksproxy.latency.min", value<std::string>()->default_value("0"), "SOCKS proxy min latency for tunnels")
("socksproxy.latency.max", value<std::string>()->default_value("0"), "SOCKS proxy max latency for tunnels")
("socksproxy.outproxy.enabled", value<bool>()->default_value(false), "Enable or disable SOCKS outproxy")
@@ -211,18 +215,22 @@ namespace config {
"https://i2pseed.creativecowpat.net:8443/,"
"https://reseed.i2pgit.org/,"
"https://i2p.novg.net/,"
"https://banana.incognet.io/"
"https://banana.incognet.io/,"
"https://reseed-pl.i2pd.xyz/,"
"https://www2.mk16.de/"
), "Reseed URLs, separated by comma")
("reseed.yggurls", value<std::string>()->default_value(
"http://[324:71e:281a:9ed3::ace]:7070/,"
"http://[301:65b9:c7cd:9a36::1]:18801/,"
"http://[320:8936:ec1a:31f1::216]/,"
"http://[306:3834:97b9:a00a::1]/"
"http://[306:3834:97b9:a00a::1]/,"
"http://[316:f9e0:f22e:a74f::216]/"
), "Reseed URLs through the Yggdrasil, separated by comma")
;
options_description addressbook("AddressBook options");
addressbook.add_options()
("addressbook.enabled", value<bool>()->default_value(true), "Enable address book lookups and subscritions (default: enabled)")
("addressbook.defaulturl", value<std::string>()->default_value(
"http://shx5vqsw7usdaunyzr2qmes2fq37oumybpudrd4jjj4e4vk4uusa.b32.i2p/hosts.txt"
), "AddressBook subscription URL for initial setup")
@@ -264,6 +272,13 @@ namespace config {
("ntcp2.proxy", value<std::string>()->default_value(""), "Proxy URL for NTCP2 transport")
;
options_description ssu2("SSU2 Options");
ssu2.add_options()
("ssu2.enabled", value<bool>()->default_value(false), "Enable SSU2 (default: disabled)")
("ssu2.published", value<bool>()->default_value(false), "Publish SSU2 (default: disabled)")
("ssu2.port", value<uint16_t>()->default_value(0), "Port to listen for incoming SSU2 packets (default: auto)")
;
options_description nettime("Time sync options");
nettime.add_options()
("nettime.enabled", value<bool>()->default_value(false), "Disable time sync (default: disabled)")
@@ -314,6 +329,7 @@ namespace config {
.add(websocket) // deprecated
.add(exploratory)
.add(ntcp2)
.add(ssu2)
.add(nettime)
.add(persist)
.add(cpuext)

View File

@@ -29,16 +29,16 @@ namespace config {
extern boost::program_options::variables_map m_Options;
/**
* @brief Initialize list of acceptable parameters
* @brief Initialize list of acceptable parameters
*
* Should be called before any Parse* functions.
*/
void Init();
/**
* @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()
* @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()
*
* If --help is given in parameters, shows its list with description
* and terminates the program with exitcode 0.
@@ -52,8 +52,8 @@ namespace config {
void ParseCmdline(int argc, char* argv[], bool ignoreUnknown = false);
/**
* @brief Load and parse given config file
* @param path Path to config file
* @brief Load and parse given config file
* @param path Path to config file
*
* If error occurred when opening file path is points to,
* we show the error message and terminate program.
@@ -67,14 +67,14 @@ namespace config {
void ParseConfig(const std::string& path);
/**
* @brief Used to combine options from cmdline, config and default values
* @brief Used to combine options from cmdline, config and default values
*/
void Finalize();
/**
* @brief Accessor to parameters by name
* @param name Name of the requested parameter
* @param value Variable where to store option
* @brief Accessor to parameters by name
* @param name Name of the requested parameter
* @param value Variable where to store option
* @return this function returns false if parameter not found
*
* Example: uint16_t port; GetOption("sam.port", port);
@@ -98,9 +98,9 @@ namespace config {
bool GetOptionAsAny(const std::string& name, boost::any& value);
/**
* @brief Set value of given parameter
* @param name Name of settable parameter
* @param value New parameter value
* @brief Set value of given parameter
* @param name Name of settable parameter
* @param value New parameter value
* @return true if value set up successful, false otherwise
*
* Example: uint16_t port = 2827; SetOption("bob.port", port);
@@ -116,8 +116,8 @@ namespace config {
}
/**
* @brief Check is value explicitly given or default
* @param name Name of checked parameter
* @brief Check is value explicitly given or default
* @param name Name of checked parameter
* @return true if value set to default, false otherwise
*/
bool IsDefault(const char *name);

View File

@@ -1305,6 +1305,16 @@ namespace crypto
SHA256_Final (m_H, &ctx);
}
void NoiseSymmetricState::MixHash (const std::vector<std::pair<uint8_t *, size_t> >& bufs)
{
SHA256_CTX ctx;
SHA256_Init (&ctx);
SHA256_Update (&ctx, m_H, 32);
for (const auto& it: bufs)
SHA256_Update (&ctx, it.first, it.second);
SHA256_Final (m_H, &ctx);
}
void NoiseSymmetricState::MixKey (const uint8_t * sharedSecret)
{
HKDF (m_CK, sharedSecret, 32, "", m_CK);
@@ -1320,7 +1330,7 @@ namespace crypto
SHA256_Init (&ctx);
SHA256_Update (&ctx, hh, 32);
SHA256_Update (&ctx, pub, 32);
SHA256_Final (state.m_H, &ctx); // h = MixHash(pub) = SHA256(hh || pub)
SHA256_Final (state.m_H, &ctx); // h = MixHash(pub) = SHA256(hh || pub)
}
void InitNoiseNState (NoiseSymmetricState& state, const uint8_t * pub)
@@ -1358,12 +1368,12 @@ namespace crypto
}; // SHA256 ("Noise_XKchaobfse+hs1+hs2+hs3_25519_ChaChaPoly_SHA256")
static const uint8_t hh[32] =
{
0xdc, 0x85, 0xe6, 0xaf, 0x7b, 0x02, 0x65, 0x0c, 0xf1, 0xf9, 0x0d, 0x71, 0xfb, 0xc6, 0xd4, 0x53,
0xdc, 0x85, 0xe6, 0xaf, 0x7b, 0x02, 0x65, 0x0c, 0xf1, 0xf9, 0x0d, 0x71, 0xfb, 0xc6, 0xd4, 0x53,
0xa7, 0xcf, 0x6d, 0xbf, 0xbd, 0x52, 0x5e, 0xa5, 0xb5, 0x79, 0x1c, 0x47, 0xb3, 0x5e, 0xbc, 0x33
}; // SHA256 (protocolNameHash)
InitNoiseState (state, protocolNameHash, hh, pub);
}
void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub)
{
static const uint8_t protocolNameHash[32] =

View File

@@ -29,23 +29,25 @@
#include "CPU.h"
// recognize openssl version and features
#if ((OPENSSL_VERSION_NUMBER < 0x010100000) || defined(LIBRESSL_VERSION_NUMBER)) // 1.0.2 and below or LibreSSL
# define LEGACY_OPENSSL 1
# define X509_getm_notBefore X509_get_notBefore
# define X509_getm_notAfter X509_get_notAfter
#if (defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER >= 0x3050200fL)) // LibreSSL 3.5.2 and above
# define LEGACY_OPENSSL 0
#elif ((OPENSSL_VERSION_NUMBER < 0x010100000) || defined(LIBRESSL_VERSION_NUMBER)) // 1.0.2 and below or LibreSSL
# define LEGACY_OPENSSL 1
# define X509_getm_notBefore X509_get_notBefore
# define X509_getm_notAfter X509_get_notAfter
#else
# define LEGACY_OPENSSL 0
# if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1
# define OPENSSL_HKDF 1
# define OPENSSL_EDDSA 1
# define OPENSSL_X25519 1
# if (OPENSSL_VERSION_NUMBER < 0x030000000) // 3.0.0, regression in SipHash
# define OPENSSL_SIPHASH 1
# define LEGACY_OPENSSL 0
# if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1
# define OPENSSL_HKDF 1
# define OPENSSL_EDDSA 1
# define OPENSSL_X25519 1
# if (OPENSSL_VERSION_NUMBER != 0x030000000) // 3.0.0, regression in SipHash
# define OPENSSL_SIPHASH 1
# endif
# endif
# if !defined OPENSSL_NO_CHACHA && !defined OPENSSL_NO_POLY1305 // some builds might not include them
# define OPENSSL_AEAD_CHACHA20_POLY1305 1
# endif
# endif
# if !defined OPENSSL_NO_CHACHA && !defined OPENSSL_NO_POLY1305 // some builds might not include them
# define OPENSSL_AEAD_CHACHA20_POLY1305 1
# endif
#endif
namespace i2p
@@ -317,6 +319,7 @@ namespace crypto
uint8_t m_H[32] /*h*/, m_CK[64] /*[ck, k]*/;
void MixHash (const uint8_t * buf, size_t len);
void MixHash (const std::vector<std::pair<uint8_t *, size_t> >& bufs);
void MixKey (const uint8_t * sharedSecret);
};
@@ -382,7 +385,7 @@ inline int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
if (dh->p) BN_free (dh->p);
if (dh->q) BN_free (dh->q);
if (dh->g) BN_free (dh->g);
dh->p = p; dh->q = q; dh->g = g; return 1;
dh->p = p; dh->q = q; dh->g = g; return 1;
}
inline int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
{

View File

@@ -324,7 +324,7 @@ namespace datagram
auto path = m_RoutingSession->GetSharedRoutingPath();
if (path && m_RoutingSession->IsRatchets () &&
m_LastUse > m_RoutingSession->GetLastActivityTimestamp ()*1000 + DATAGRAM_SESSION_PATH_TIMEOUT)
m_LastUse > m_RoutingSession->GetLastActivityTimestamp ()*1000 + DATAGRAM_SESSION_PATH_TIMEOUT)
{
m_RoutingSession->SetSharedRoutingPath (nullptr);
path = nullptr;

View File

@@ -13,7 +13,6 @@
#include <vector>
#include <boost/algorithm/string.hpp>
#include "Crypto.h"
#include "Config.h"
#include "Log.h"
#include "FS.h"
#include "Timestamp.h"
@@ -35,6 +34,8 @@ namespace client
int inQty = DEFAULT_INBOUND_TUNNELS_QUANTITY;
int outLen = DEFAULT_OUTBOUND_TUNNEL_LENGTH;
int outQty = DEFAULT_OUTBOUND_TUNNELS_QUANTITY;
int inVar = DEFAULT_INBOUND_TUNNELS_LENGTH_VARIANCE;
int outVar = DEFAULT_OUTBOUND_TUNNELS_LENGTH_VARIANCE;
int numTags = DEFAULT_TAGS_TO_SEND;
std::shared_ptr<std::vector<i2p::data::IdentHash> > explicitPeers;
try
@@ -53,6 +54,12 @@ namespace client
it = params->find (I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY);
if (it != params->end ())
outQty = std::stoi(it->second);
it = params->find (I2CP_PARAM_INBOUND_TUNNELS_LENGTH_VARIANCE);
if (it != params->end ())
inVar = std::stoi(it->second);
it = params->find (I2CP_PARAM_OUTBOUND_TUNNELS_LENGTH_VARIANCE);
if (it != params->end ())
outVar = std::stoi(it->second);
it = params->find (I2CP_PARAM_TAGS_TO_SEND);
if (it != params->end ())
numTags = std::stoi(it->second);
@@ -86,9 +93,7 @@ namespace client
if (it != params->end ())
{
// oveeride isPublic
bool dontpublish = false;
i2p::config::GetOption (it->second, dontpublish);
m_IsPublic = !dontpublish;
m_IsPublic = (it->second != "true");
}
it = params->find (I2CP_PARAM_LEASESET_TYPE);
if (it != params->end ())
@@ -123,7 +128,7 @@ namespace client
LogPrint(eLogError, "Destination: Unable to parse parameters for destination: ", ex.what());
}
SetNumTags (numTags);
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (inLen, outLen, inQty, outQty);
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (inLen, outLen, inQty, outQty, inVar, outVar);
if (explicitPeers)
m_Pool->SetExplicitPeers (explicitPeers);
if(params)
@@ -331,6 +336,22 @@ namespace client
return true;
}
void LeaseSetDestination::SubmitECIESx25519Key (const uint8_t * key, uint64_t tag)
{
struct
{
uint8_t k[32];
uint64_t t;
} data;
memcpy (data.k, key, 32);
data.t = tag;
auto s = shared_from_this ();
m_Service.post ([s,data](void)
{
s->AddECIESx25519Key (data.k, data.t);
});
}
void LeaseSetDestination::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
{
m_Service.post (std::bind (&LeaseSetDestination::HandleGarlicMessage, shared_from_this (), msg));
@@ -396,7 +417,7 @@ namespace client
std::lock_guard<std::mutex> lock(m_RemoteLeaseSetsMutex);
auto it = m_RemoteLeaseSets.find (key);
if (it != m_RemoteLeaseSets.end () &&
it->second->GetStoreType () == buf[DATABASE_STORE_TYPE_OFFSET]) // update only if same type
it->second->GetStoreType () == buf[DATABASE_STORE_TYPE_OFFSET]) // update only if same type
{
leaseSet = it->second;
if (leaseSet->IsNewer (buf + offset, len - offset))
@@ -566,7 +587,7 @@ namespace client
LogPrint (eLogError, "Destination: Can't publish LeaseSet, no more floodfills found");
m_ExcludedFloodfills.clear ();
return;
}
}
auto outbound = m_Pool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false));
auto inbound = m_Pool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true));
if (!outbound || !inbound)
@@ -578,22 +599,22 @@ namespace client
{
outbound = m_Pool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false));
if (outbound)
{
{
inbound = m_Pool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true));
if (!inbound)
LogPrint (eLogError, "Destination: Can't publish LeaseSet. No inbound tunnels");
}
}
else
LogPrint (eLogError, "Destination: Can't publish LeaseSet. No outbound tunnels");
}
}
else
LogPrint (eLogError, "Destination: Can't publish LeaseSet, no more floodfills found");
if (!floodfill || !outbound || !inbound)
{
m_ExcludedFloodfills.clear ();
return;
}
}
}
}
m_ExcludedFloodfills.insert (floodfill->GetIdentHash ());
LogPrint (eLogDebug, "Destination: Publish LeaseSet of ", GetIdentHash ().ToBase32 ());
RAND_bytes ((uint8_t *)&m_PublishReplyToken, 4);
@@ -930,7 +951,7 @@ namespace client
for (auto& it: encryptionKeyTypes)
{
auto encryptionKey = new EncryptionKey (it);
if (isPublic)
if (IsPublic ())
PersistTemporaryKeys (encryptionKey, isSingleKey);
else
encryptionKey->GenerateKeys ();
@@ -945,7 +966,7 @@ namespace client
m_StandardEncryptionKey.reset (encryptionKey);
}
if (isPublic)
if (IsPublic ())
LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created");
try
@@ -958,7 +979,7 @@ namespace client
m_StreamingAckDelay = std::stoi(it->second);
it = params->find (I2CP_PARAM_STREAMING_ANSWER_PINGS);
if (it != params->end ())
i2p::config::GetOption (it->second, m_IsStreamingAnswerPings);
m_IsStreamingAnswerPings = (it->second == "true");
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
{

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2021, The PurpleI2P Project
* Copyright (c) 2013-2022, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -53,6 +53,10 @@ namespace client
const int DEFAULT_INBOUND_TUNNELS_QUANTITY = 5;
const char I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY[] = "outbound.quantity";
const int DEFAULT_OUTBOUND_TUNNELS_QUANTITY = 5;
const char I2CP_PARAM_INBOUND_TUNNELS_LENGTH_VARIANCE[] = "inbound.lengthVariance";
const int DEFAULT_INBOUND_TUNNELS_LENGTH_VARIANCE = 0;
const char I2CP_PARAM_OUTBOUND_TUNNELS_LENGTH_VARIANCE[] = "outbound.lengthVariance";
const int DEFAULT_OUTBOUND_TUNNELS_LENGTH_VARIANCE = 0;
const char I2CP_PARAM_EXPLICIT_PEERS[] = "explicitPeers";
const int STREAM_REQUEST_TIMEOUT = 60; //in seconds
const char I2CP_PARAM_TAGS_TO_SEND[] = "crypto.tagsToSend";
@@ -134,6 +138,7 @@ namespace client
// override GarlicDestination
bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag);
void SubmitECIESx25519Key (const uint8_t * key, uint64_t tag);
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
void SetLeaseSetUpdated ();

View File

@@ -212,7 +212,7 @@ namespace garlic
uint8_t m_NSREncodedKey[32], m_NSRH[32], m_NSRKey[32]; // new session reply, for incoming only
std::shared_ptr<i2p::crypto::X25519Keys> m_EphemeralKeys;
SessionState m_State = eSessionStateNew;
uint64_t m_SessionCreatedTimestamp = 0, m_LastActivityTimestamp = 0, // incoming (in seconds)
uint64_t m_SessionCreatedTimestamp = 0, m_LastActivityTimestamp = 0, // incoming (in seconds)
m_LastSentTimestamp = 0; // in milliseconds
std::shared_ptr<RatchetTagSet> m_SendTagset, m_NSRSendTagset;
std::unique_ptr<i2p::data::IdentHash> m_Destination;// TODO: might not need it
@@ -229,7 +229,7 @@ namespace garlic
{
return m_Destination ? *m_Destination : i2p::data::IdentHash ();
}
};
};
// single session for all incoming messages
class RouterIncomingRatchetSession: public ECIESX25519AEADRatchetSession

View File

@@ -33,7 +33,7 @@ namespace crypto
BN_add (l, l, tmp);
BN_sub_word (two_252_2, 2); // 2^252 - 2
// -121665*inv(121666)
// -121665*inv(121666)
d = BN_new ();
BN_set_word (tmp, 121666);
BN_mod_inverse (tmp, tmp, q, ctx);
@@ -61,7 +61,7 @@ namespace crypto
BN_mod (By, By, q, ctx); // % q
// precalculate Bi256 table
Bi256Carry = { Bx, By }; // B
Bi256Carry = { Bx, By }; // B
for (int i = 0; i < 32; i++)
{
Bi256[i][0] = Bi256Carry; // first point
@@ -215,7 +215,7 @@ namespace crypto
if (!t1) { t1 = BN_CTX_get (ctx); BN_mul (t1, p1.x, p1.y, ctx); }
if (!t2) { t2 = BN_CTX_get (ctx); BN_mul (t2, p2.x, p2.y, ctx); }
BN_mul (t3, t1, t2, ctx);
BN_mul (t3, t3, d, ctx); // C = d*t1*t2
BN_mul (t3, t3, d, ctx); // C = d*t1*t2
if (p1.z)
{
@@ -264,9 +264,9 @@ namespace crypto
else
{
BN_mul (t2, p.x, p.y, ctx); // t = x*y
BN_sqr (t2, t2, ctx); // t2 = t^2
BN_sqr (t2, t2, ctx); // t2 = t^2
}
BN_mul (t2, t2, d, ctx); // t2 = C = d*t^2
BN_mul (t2, t2, d, ctx); // t2 = C = d*t^2
if (p.z)
BN_sqr (z2, p.z, ctx); // z2 = D = z^2
else
@@ -349,7 +349,7 @@ namespace crypto
BN_mod_inverse (y, p.z, q, ctx);
BN_mod_mul (x, p.x, y, q, ctx); // x = x/z
BN_mod_mul (y, p.y, y, q, ctx); // y = y/z
return EDDSAPoint{x, y};
return EDDSAPoint{x, y};
}
else
return EDDSAPoint{BN_dup (p.x), BN_dup (p.y)};
@@ -506,13 +506,13 @@ namespace crypto
std::swap (z2, z3);
}
BN_mod_inverse (z2, z2, q, ctx);
BIGNUM * res = BN_new (); // not from ctx
BIGNUM * res = BN_new (); // not from ctx
BN_mod_mul(res, x2, z2, q, ctx);
BN_CTX_end (ctx);
return res;
}
void Ed25519::ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const
void Ed25519::ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const
{
BIGNUM * p1 = DecodeBN<32> (p);
uint8_t k[32];
@@ -524,7 +524,7 @@ namespace crypto
BN_free (p1); BN_free (n); BN_free (q1);
}
void Ed25519::ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const
void Ed25519::ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const
{
BIGNUM *p1 = BN_new (); BN_set_word (p1, 9);
uint8_t k[32];

View File

@@ -85,8 +85,8 @@ namespace crypto
EDDSAPoint DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const;
void EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const;
#if !OPENSSL_X25519
void ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; // p is point, e is number for x25519
void ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const;
void ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; // p is point, e is number for x25519
void ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const;
#endif
void BlindPublicKey (const uint8_t * pub, const uint8_t * seed, uint8_t * blinded); // for encrypted LeaseSet2, pub - 32, seed - 64, blinded - 32
void BlindPrivateKey (const uint8_t * priv, const uint8_t * seed, uint8_t * blindedPriv, uint8_t * blindedPub); // for encrypted LeaseSet2, pub - 32, seed - 64, blinded - 32

View File

@@ -189,7 +189,7 @@ namespace crypto
// assume a < p, so don't check for a % p = 0, but a = 0 only
if (BN_is_zero(a)) return 0;
BIGNUM * r = BN_CTX_get (ctx);
BN_mod_exp (r, a, p12, p, ctx); // r = a^((p-1)/2) mod p
BN_mod_exp (r, a, p12, p, ctx); // r = a^((p-1)/2) mod p
if (BN_is_word(r, 1))
return 1;
else if (BN_is_zero(r))

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
* Copyright (c) 2013-2022, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -60,10 +60,38 @@ namespace fs {
}
void DetectDataDir(const std::string & cmdline_param, bool isService) {
// with 'datadir' option
if (cmdline_param != "") {
dataDir = cmdline_param;
return;
}
#if !defined(MAC_OSX) && !defined(ANDROID)
// with 'service' option
if (isService) {
#ifdef _WIN32
wchar_t commonAppData[MAX_PATH];
if(SHGetFolderPathW(NULL, CSIDL_COMMON_APPDATA, NULL, 0, commonAppData) != S_OK)
{
#ifdef WIN32_APP
MessageBox(NULL, TEXT("Unable to get common AppData path!"), TEXT("I2Pd: error"), MB_ICONERROR | MB_OK);
#else
fprintf(stderr, "Error: Unable to get common AppData path!");
#endif
exit(1);
}
else
{
dataDir = boost::filesystem::wpath(commonAppData).string() + "\\" + appName;
}
#else
dataDir = "/var/lib/" + appName;
#endif
return;
}
#endif
// detect directory as usual
#ifdef _WIN32
wchar_t localAppData[MAX_PATH];
@@ -117,12 +145,10 @@ namespace fs {
dataDir = std::string (ext) + "/" + appName;
return;
}
#endif
// otherwise use /data/files
#endif // ANDROID
// use /home/user/.i2pd or /tmp/i2pd
char *home = getenv("HOME");
if (isService) {
dataDir = "/var/lib/" + appName;
} else if (home != NULL && strlen(home) > 0) {
if (home != NULL && strlen(home) > 0) {
dataDir = std::string(home) + "/." + appName;
} else {
dataDir = "/tmp/" + appName;

View File

@@ -83,8 +83,8 @@ namespace fs {
/**
* @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
* @param cmdline_param Value of cmdline parameter --datadir=<something>
* @param isService Value of cmdline parameter --service
*
* Examples of autodetected paths:
*
@@ -93,11 +93,11 @@ namespace fs {
* 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);
void DetectDataDir(const std::string & cmdline_datadir, bool isService = false);
/**
* @brief Set certsdir either from cmdline option or using autodetection
* @param cmdline_param Value of cmdline parameter --certsdir=<something>
* @param cmdline_param Value of cmdline parameter --certsdir=<something>
*
* Examples of autodetected paths:
*
@@ -106,7 +106,7 @@ namespace fs {
* Mac: /Library/Application Support/i2pd/ or ~/Library/Application Support/i2pd/certificates
* Unix: /var/lib/i2pd/certificates (system=1) >> ~/.i2pd/ or /tmp/i2pd/certificates
*/
void SetCertsDir(const std::string & cmdline_certsdir);
void SetCertsDir(const std::string & cmdline_certsdir);
/**
* @brief Create subdirectories inside datadir
@@ -115,7 +115,7 @@ namespace fs {
/**
* @brief Get list of files in directory
* @param path Path to directory
* @param path Path to directory
* @param files Vector to store found files
* @return true on success and false if directory not exists
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
* Copyright (c) 2013-2022, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -88,7 +88,7 @@ namespace data
}
EVP_PKEY_free (pkey);
if (verifier && cn)
m_SigningKeys[cn] = verifier;
m_SigningKeys.emplace (cn, std::make_pair(verifier, m_SigningKeys.size () + 1));
}
SSL_free (ssl);
}
@@ -121,7 +121,7 @@ namespace data
}
bool Families::VerifyFamily (const std::string& family, const IdentHash& ident,
const char * signature, const char * key)
const char * signature, const char * key) const
{
uint8_t buf[100], signatureBuf[64];
size_t len = family.length (), signatureLen = strlen (signature);
@@ -137,11 +137,19 @@ namespace data
Base64ToByteStream (signature, signatureLen, signatureBuf, 64);
auto it = m_SigningKeys.find (family);
if (it != m_SigningKeys.end ())
return it->second->Verify (buf, len, signatureBuf);
return it->second.first->Verify (buf, len, signatureBuf);
// TODO: process key
return true;
}
FamilyID Families::GetFamilyID (const std::string& family) const
{
auto it = m_SigningKeys.find (family);
if (it != m_SigningKeys.end ())
return it->second.second;
return 0;
}
std::string CreateFamilySignature (const std::string& family, const IdentHash& ident)
{
auto filename = i2p::fs::DataDirPath("family", (family + ".key"));

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
* Copyright (c) 2013-2022, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -19,6 +19,7 @@ namespace i2p
{
namespace data
{
typedef int FamilyID;
class Families
{
public:
@@ -27,7 +28,8 @@ namespace data
~Families ();
void LoadCertificates ();
bool VerifyFamily (const std::string& family, const IdentHash& ident,
const char * signature, const char * key = nullptr);
const char * signature, const char * key = nullptr) const;
FamilyID GetFamilyID (const std::string& family) const;
private:
@@ -35,7 +37,7 @@ namespace data
private:
std::map<std::string, std::shared_ptr<i2p::crypto::Verifier> > m_SigningKeys;
std::map<std::string, std::pair<std::shared_ptr<i2p::crypto::Verifier>, FamilyID> > m_SigningKeys; // family -> (verifier, id)
};
std::string CreateFamilySignature (const std::string& family, const IdentHash& ident);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2021, The PurpleI2P Project
* Copyright (c) 2013-2022, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -293,14 +293,14 @@ namespace garlic
size_t size = 0;
if (isDestination)
{
buf[size] = eGarlicDeliveryTypeDestination << 5;// delivery instructions flag destination
buf[size] = eGarlicDeliveryTypeDestination << 5;// delivery instructions flag destination
size++;
memcpy (buf + size, m_Destination->GetIdentHash (), 32);
size += 32;
}
else
{
buf[size] = 0;// delivery instructions flag local
buf[size] = 0;// delivery instructions flag local
size++;
}
@@ -484,6 +484,11 @@ namespace garlic
return true;
}
void GarlicDestination::SubmitECIESx25519Key (const uint8_t * key, uint64_t tag)
{
AddECIESx25519Key (key, tag);
}
void GarlicDestination::HandleGarlicMessage (std::shared_ptr<I2NPMessage> msg)
{
uint8_t * buf = msg->GetPayload ();
@@ -739,7 +744,7 @@ namespace garlic
LogPrint (eLogError, "Garlic: Message is too short");
break;
}
buf += GetI2NPMessageLength (buf, len - offset); // I2NP
buf += GetI2NPMessageLength (buf, len - offset); // I2NP
buf += 4; // CloveID
buf += 8; // Date
buf += 3; // Certificate
@@ -1019,7 +1024,7 @@ namespace garlic
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
for (auto it: files)
if (ts >= i2p::fs::GetLastUpdateTime (it) + INCOMING_TAGS_EXPIRATION_TIMEOUT)
i2p::fs::Remove (it);
i2p::fs::Remove (it);
}
void GarlicDestination::HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len)

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2021, The PurpleI2P Project
* Copyright (c) 2013-2022, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -245,6 +245,7 @@ namespace garlic
void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag
void AddECIESx25519Key (const uint8_t * key, uint64_t tag); // one tag
virtual bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); // from different thread
virtual void SubmitECIESx25519Key (const uint8_t * key, uint64_t tag); // from different thread
void DeliveryStatusSent (GarlicRoutingSessionPtr session, uint32_t msgID);
uint64_t AddECIESx25519SessionNextTag (ReceiveRatchetTagSetPtr tagset);
void AddECIESx25519Session (const uint8_t * staticKey, ECIESX25519AEADRatchetSessionPtr session);

View File

@@ -96,7 +96,7 @@ namespace crypto
EC_POINT * C = EC_POINT_new (m_Group);
EC_POINT_mul (m_Group, C, z1, pub, z2, ctx); // z1*P + z2*pub
BIGNUM * x = BN_CTX_get (ctx);
GetXY (C, x, nullptr); // Cx
GetXY (C, x, nullptr); // Cx
BN_mod (x, x, q, ctx); // Cx % q
bool ret = !BN_cmp (x, r); // Cx = r ?
EC_POINT_free (C);
@@ -111,8 +111,8 @@ namespace crypto
BN_CTX * ctx = BN_CTX_new ();
BN_CTX_start (ctx);
EC_POINT * C = EC_POINT_new (m_Group); // C = k*P = (rx, ry)
EC_POINT * Q = nullptr;
if (EC_POINT_set_compressed_coordinates_GFp (m_Group, C, r, isNegativeY ? 1 : 0, ctx))
EC_POINT * Q = nullptr;
if (EC_POINT_set_compressed_coordinates_GFp (m_Group, C, r, isNegativeY ? 1 : 0, ctx))
{
EC_POINT * S = EC_POINT_new (m_Group); // S = s*P
EC_POINT_mul (m_Group, S, s, nullptr, nullptr, ctx);

View File

@@ -279,7 +279,7 @@ namespace http
method = tokens[0];
uri = tokens[1];
version = tokens[2];
expect = HEADER_LINE;
expect = HEADER_LINE;
}
else
{
@@ -363,7 +363,7 @@ namespace http
return false; /* no header */
if (it->second.find("gzip") != std::string::npos)
return true; /* gotcha! */
if (includingI2PGzip && it->second.find("x-i2p-gzip") != std::string::npos)
if (includingI2PGzip && it->second.find("x-i2p-gzip") != std::string::npos)
return true;
return false;
}
@@ -409,7 +409,7 @@ namespace http
/* all ok */
version = tokens[0];
status = tokens[2];
expect = HEADER_LINE;
expect = HEADER_LINE;
} else {
std::string line = str.substr(pos, eol - pos);
auto p = parse_header_line(line);
@@ -460,7 +460,7 @@ namespace http
case 304: ptr = "Not Modified"; break;
case 307: ptr = "Temporary Redirect"; break;
/* client error */
case 400: ptr = "Bad Request"; break;
case 400: ptr = "Bad Request"; break;
case 401: ptr = "Unauthorized"; break;
case 403: ptr = "Forbidden"; break;
case 404: ptr = "Not Found"; break;
@@ -471,7 +471,7 @@ namespace http
case 502: ptr = "Bad Gateway"; break;
case 503: ptr = "Not Implemented"; break;
case 504: ptr = "Gateway Timeout"; break;
default: ptr = "Unknown Status"; break;
default: ptr = "Unknown Status"; break;
}
return ptr;
}

View File

@@ -161,7 +161,7 @@ namespace http
/**
* @brief Merge HTTP response content with Transfer-Encoding: chunked
* @param in Input stream
* @param in Input stream
* @param out Output stream
* @return true on success, false otherwise
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2021, The PurpleI2P Project
* Copyright (c) 2013-2022, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -171,7 +171,7 @@ namespace i2p
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
const std::set<i2p::data::IdentHash>& excludedFloodfills,
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, const uint8_t * replyKey,
const uint8_t * replyTag, bool replyECIES)
const uint8_t * replyTag, bool replyECIES)
{
int cnt = excludedFloodfills.size ();
auto m = cnt > 7 ? NewI2NPMessage () : NewI2NPShortMessage ();
@@ -244,7 +244,7 @@ namespace i2p
}
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router,
uint32_t replyToken, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel)
uint32_t replyToken, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel)
{
if (!router) // we send own RouterInfo
router = context.GetSharedRouterInfo ();
@@ -629,7 +629,7 @@ namespace i2p
// we send it to reply tunnel
transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET,
CreateTunnelGatewayMsg (bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
i2p::garlic::WrapECIESX25519Message (replyMsg, noiseState.m_CK + 32, tag)));
i2p::garlic::WrapECIESX25519Message (replyMsg, noiseState.m_CK + 32, tag)));
}
else
{
@@ -802,13 +802,8 @@ namespace i2p
break;
case eI2NPGarlic:
{
if (msg->from)
{
if (msg->from->GetTunnelPool ())
msg->from->GetTunnelPool ()->ProcessGarlicMessage (msg);
else
LogPrint (eLogInfo, "I2NP: Local destination for garlic doesn't exist anymore");
}
if (msg->from && msg->from->GetTunnelPool ())
msg->from->GetTunnelPool ()->ProcessGarlicMessage (msg);
else
i2p::context.ProcessGarlicMessage (msg);
break;

View File

@@ -150,7 +150,7 @@ namespace tunnel
std::shared_ptr<i2p::tunnel::InboundTunnel> from;
I2NPMessage (): buf (nullptr),len (I2NP_HEADER_SIZE + 2),
offset(2), maxLen (0), from (nullptr) {}; // reserve 2 bytes for NTCP header
offset(2), maxLen (0), from (nullptr) {}; // reserve 2 bytes for NTCP header
// header accessors
uint8_t * GetHeader () { return GetBuffer (); };
@@ -274,8 +274,8 @@ 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,
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel,
const uint8_t * replyKey, const uint8_t * replyTag, bool replyECIES = false);
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel,
const uint8_t * replyKey, const uint8_t * replyTag, bool replyECIES = false);
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, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel = nullptr);

View File

@@ -64,7 +64,7 @@ namespace data
{
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
{
size_t padding = 128 - i2p::crypto::ECDSAP256_KEY_LENGTH; // 64 = 128 - 64
size_t padding = 128 - i2p::crypto::ECDSAP256_KEY_LENGTH; // 64 = 128 - 64
RAND_bytes (m_StandardIdentity.signingKey, padding);
memcpy (m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::ECDSAP256_KEY_LENGTH);
break;
@@ -788,7 +788,7 @@ namespace data
keys.m_OfflineSignature.resize (pubKeyLen + m_Public->GetSignatureLen () + 6);
htobe32buf (keys.m_OfflineSignature.data (), expires); // expires
htobe16buf (keys.m_OfflineSignature.data () + 4, type); // type
GenerateSigningKeyPair (type, keys.m_SigningPrivateKey, keys.m_OfflineSignature.data () + 6); // public key
GenerateSigningKeyPair (type, keys.m_SigningPrivateKey, keys.m_OfflineSignature.data () + 6); // public key
Sign (keys.m_OfflineSignature.data (), pubKeyLen + 6, keys.m_OfflineSignature.data () + 6 + pubKeyLen); // signature
// recreate signer
keys.m_Signer = nullptr;

View File

@@ -120,7 +120,7 @@ namespace data
CryptoKeyType GetCryptoKeyType () const;
void DropVerifier () const; // to save memory
bool operator == (const IdentityEx & other) const { return GetIdentHash() == other.GetIdentHash(); }
bool operator == (const IdentityEx & other) const { return GetIdentHash() == other.GetIdentHash(); }
void RecalculateIdentHash(uint8_t * buff=nullptr);
static i2p::crypto::Verifier * CreateVerifier (SigningKeyType keyType);
@@ -222,7 +222,7 @@ namespace data
RoutingDestination () {};
virtual ~RoutingDestination () {};
virtual std::shared_ptr<const IdentityEx> GetIdentity () const = 0;
virtual std::shared_ptr<const IdentityEx> GetIdentity () const = 0;
virtual void Encrypt (const uint8_t * data, uint8_t * encrypted) const = 0; // encrypt data for
virtual bool IsDestination () const = 0; // for garlic

View File

@@ -582,7 +582,7 @@ namespace data
// helper for ExtractClientAuthData
static inline bool GetAuthCookie (const uint8_t * authClients, int numClients, const uint8_t * okm, uint8_t * authCookie)
{
// try to find clientCookie_i for clientID_i = okm[44:51]
// try to find clientCookie_i for clientID_i = okm[44:51]
for (int i = 0; i < numClients; i++)
{
if (!memcmp (okm + 44, authClients + i*40, 8)) // clientID_i
@@ -606,7 +606,7 @@ namespace data
{
const uint8_t * ephemeralPublicKey = buf + offset; offset += 32; // ephemeralPublicKey
uint16_t numClients = bufbe16toh (buf + offset); offset += 2; // clients
const uint8_t * authClients = buf + offset; offset += numClients*40; // authClients
const uint8_t * authClients = buf + offset; offset += numClients*40; // authClients
if (offset > len)
{
LogPrint (eLogError, "LeaseSet2: Too many clients ", numClients, " in DH auth data");
@@ -632,7 +632,7 @@ namespace data
{
const uint8_t * authSalt = buf + offset; offset += 32; // authSalt
uint16_t numClients = bufbe16toh (buf + offset); offset += 2; // clients
const uint8_t * authClients = buf + offset; offset += numClients*40; // authClients
const uint8_t * authClients = buf + offset; offset += numClients*40; // authClients
if (offset > len)
{
LogPrint (eLogError, "LeaseSet2: Too many clients ", numClients, " in PSK auth data");
@@ -737,7 +737,7 @@ namespace data
htobe64buf (m_Buffer + offset, ts);
offset += 8; // end date
}
// we don't sign it yet. must be signed later on
// we don't sign it yet. must be signed later on
}
LocalLeaseSet::LocalLeaseSet (std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len):
@@ -995,7 +995,7 @@ namespace data
ek.GenerateKeys (); // esk and epk
memcpy (authData, ek.GetPublicKey (), 32); authData += 32; // epk
htobe16buf (authData, authKeys->size ()); authData += 2; // num clients
uint8_t authInput[100]; // sharedSecret || cpk_i || subcredential || publishedTimestamp
uint8_t authInput[100]; // sharedSecret || cpk_i || subcredential || publishedTimestamp
memcpy (authInput + 64, subcredential, 36);
for (auto& it: *authKeys)
{

View File

@@ -128,8 +128,8 @@ namespace data
};
/**
validate lease set buffer signature and extract expiration timestamp
@returns true if the leaseset is well formed and signature is valid
* validate lease set buffer signature and extract expiration timestamp
* @returns true if the leaseset is well formed and signature is valid
*/
bool LeaseSetBufferValidate(const uint8_t * ptr, size_t sz, uint64_t & expires);

View File

@@ -46,7 +46,7 @@ namespace log {
#ifndef _WIN32
/**
* @brief Maps our log levels to syslog one
* @brief Maps our log levels to syslog one
* @return syslog priority LOG_*, as defined in syslog.h
*/
static inline int GetSyslogPrio (enum LogLevel l) {
@@ -113,11 +113,11 @@ namespace log {
std::string str_tolower(std::string s) {
std::transform(s.begin(), s.end(), s.begin(),
// static_cast<int(*)(int)>(std::tolower) // wrong
// [](int c){ return std::tolower(c); } // wrong
// [](char c){ return std::tolower(c); } // wrong
[](unsigned char c){ return std::tolower(c); } // correct
);
// static_cast<int(*)(int)>(std::tolower) // wrong
// [](int c){ return std::tolower(c); } // wrong
// [](char c){ return std::tolower(c); } // wrong
[](unsigned char c){ return std::tolower(c); } // correct
);
return s;
}
@@ -170,7 +170,7 @@ namespace log {
break;
case eLogStdout:
default:
std::cout << TimeAsString(msg->timestamp)
std::cout << TimeAsString(msg->timestamp)
<< "@" << short_tid
<< "/" << LogMsgColors[msg->level] << g_LogLevelStr[msg->level] << LogMsgColors[eNumLogLevels]
<< " - " << msg->text << std::endl;

View File

@@ -52,7 +52,7 @@ namespace log {
{
private:
enum LogType m_Destination;
enum LogType m_Destination;
enum LogLevel m_MinLevel;
std::shared_ptr<std::ostream> m_LogStream;
std::string m_Logfile;
@@ -75,7 +75,7 @@ namespace log {
/**
* @brief Makes formatted string from unix timestamp
* @param ts Second since epoch
* @param ts Second since epoch
*
* This function internally caches the result for last provided value
*/
@@ -86,52 +86,52 @@ namespace log {
Log ();
~Log ();
LogType GetLogType () { return m_Destination; };
LogType GetLogType () { return m_Destination; };
LogLevel GetLogLevel () { return m_MinLevel; };
void Start ();
void Stop ();
/**
* @brief Sets minimal allowed level for log messages
* @param level String with wanted minimal msg level
* @brief Sets minimal allowed level for log messages
* @param level String with wanted minimal msg level
*/
void SetLogLevel (const std::string& level);
void SetLogLevel (const std::string& level);
/**
* @brief Sets log destination to logfile
* @param path Path to logfile
* @param path Path to logfile
*/
void SendTo (const std::string &path);
/**
* @brief Sets log destination to given output stream
* @param os Output stream
* @param os Output stream
*/
void SendTo (std::shared_ptr<std::ostream> os);
/**
* @brief Sets format for timestamps in log
* @param format String with timestamp format
* @brief Sets format for timestamps in log
* @param format String with timestamp format
*/
void SetTimeFormat (std::string format) { m_TimeFormat = format; };
#ifndef _WIN32
/**
* @brief Sets log destination to syslog
* @param name Wanted program name
* @param name Wanted program name
* @param facility Wanted log category
*/
void SendTo (const char *name, int facility);
#endif
/**
* @brief Format log message and write to output stream/syslog
* @param msg Pointer to processed message
* @brief Format log message and write to output stream/syslog
* @param msg Pointer to processed message
*/
void Append(std::shared_ptr<i2p::log::LogMsg> &);
/** @brief Reopen log file */
/** @brief Reopen log file */
void Reopen();
};
@@ -144,8 +144,8 @@ namespace log {
*/
struct LogMsg {
std::time_t timestamp;
std::string text; /**< message text as single string */
LogLevel level; /**< message level */
std::string text; /**< message text as single string */
LogLevel level; /**< message level */
std::thread::id tid; /**< id of thread that generated message */
LogMsg (LogLevel lvl, std::time_t ts, std::string&& txt): timestamp(ts), text(std::move(txt)), level(lvl) {}
@@ -153,7 +153,7 @@ namespace log {
Log & Logger();
typedef std::function<void (const std::string&)> ThrowFunction;
typedef std::function<void (const std::string&)> ThrowFunction;
ThrowFunction GetThrowFunction ();
void SetThrowFunction (ThrowFunction f);
} // log

View File

@@ -23,7 +23,7 @@
#include "HTTP.h"
#include "util.h"
#ifdef __linux__
#if defined(__linux__) && !defined(_NETINET_IN_H)
#include <linux/in6.h>
#endif
@@ -59,14 +59,14 @@ namespace transport
void NTCP2Establisher::KDF1Bob ()
{
KeyDerivationFunction1 (GetRemotePub (), i2p::context.GetStaticKeys (), i2p::context.GetNTCP2StaticPublicKey (), GetRemotePub ());
KeyDerivationFunction1 (GetRemotePub (), i2p::context.GetNTCP2StaticKeys (), i2p::context.GetNTCP2StaticPublicKey (), GetRemotePub ());
}
void NTCP2Establisher::KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub)
{
MixHash (sessionRequest + 32, 32); // encrypted payload
int paddingLength = sessionRequestLen - 64;
int paddingLength = sessionRequestLen - 64;
if (paddingLength > 0)
MixHash (sessionRequest + 64, paddingLength);
MixHash (epub, 32);
@@ -91,7 +91,7 @@ namespace transport
void NTCP2Establisher::KDF3Alice ()
{
uint8_t inputKeyMaterial[32];
i2p::context.GetStaticKeys ().Agree (GetRemotePub (), inputKeyMaterial);
i2p::context.GetNTCP2StaticKeys ().Agree (GetRemotePub (), inputKeyMaterial);
MixKey (inputKeyMaterial);
}
@@ -130,7 +130,7 @@ namespace transport
// m3p2Len
auto bufLen = i2p::context.GetRouterInfo ().GetBufferLen ();
m3p2Len = bufLen + 4 + 16; // (RI header + RI + MAC for now) TODO: implement options
htobe16buf (options + 4, m3p2Len);
htobe16buf (options + 4, m3p2Len);
// fill m3p2 payload (RouterInfo block)
m_SessionConfirmedBuffer = new uint8_t[m3p2Len + 48]; // m3p1 is 48 bytes
uint8_t * m3p2 = m_SessionConfirmedBuffer + 48;
@@ -231,11 +231,11 @@ namespace transport
auto ts = i2p::util::GetSecondsSinceEpoch ();
uint32_t tsA = bufbe32toh (options + 8);
if (tsA < ts - NTCP2_CLOCK_SKEW || tsA > ts + NTCP2_CLOCK_SKEW)
{
{
LogPrint (eLogWarning, "NTCP2: SessionRequest time difference ", (int)(ts - tsA), " exceeds clock skew");
clockSkew = true;
// we send SessionCreate to let Alice know our time and then close session
}
}
}
else
{
@@ -320,7 +320,7 @@ namespace transport
}
NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter,
std::shared_ptr<const i2p::data::RouterInfo::Address> addr):
std::shared_ptr<const i2p::data::RouterInfo::Address> addr):
TransportSession (in_RemoteRouter, NTCP2_ESTABLISH_TIMEOUT),
m_Server (server), m_Socket (m_Server.GetService ()),
m_IsEstablished (false), m_IsTerminated (false),
@@ -418,7 +418,7 @@ namespace transport
void NTCP2Session::DeleteNextReceiveBuffer (uint64_t ts)
{
if (m_NextReceivedBuffer && !m_IsReceiving &&
ts > m_LastActivityTimestamp + NTCP2_RECEIVE_BUFFER_DELETION_TIMEOUT)
ts > m_LastActivityTimestamp + NTCP2_RECEIVE_BUFFER_DELETION_TIMEOUT)
{
delete[] m_NextReceivedBuffer;
m_NextReceivedBuffer = nullptr;
@@ -484,9 +484,9 @@ namespace transport
if (clockSkew)
{
// we don't care about padding, send SessionCreated and close session
SendSessionCreated ();
SendSessionCreated ();
m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ()));
}
}
else if (paddingLen > 0)
{
if (paddingLen <= NTCP2_SESSION_REQUEST_MAX_SIZE - 64) // session request is 287 bytes max
@@ -496,7 +496,7 @@ namespace transport
}
else
{
LogPrint (eLogWarning, "NTCP2: SessionRequest padding length ", (int)paddingLen, " is too long");
LogPrint (eLogWarning, "NTCP2: SessionRequest padding length ", (int)paddingLen, " is too long");
Terminate ();
}
}
@@ -549,7 +549,7 @@ namespace transport
}
else
{
LogPrint (eLogWarning, "NTCP2: SessionCreated padding length ", (int)paddingLen, " is too long");
LogPrint (eLogWarning, "NTCP2: SessionCreated padding length ", (int)paddingLen, " is too long");
Terminate ();
}
}
@@ -757,7 +757,7 @@ namespace transport
if (IsTerminated ()) return;
#ifdef __linux__
const int one = 1;
setsockopt(m_Socket.native_handle(), IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one));
setsockopt(m_Socket.native_handle(), IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one));
#endif
boost::asio::async_read (m_Socket, boost::asio::buffer(&m_NextReceivedLen, 2), boost::asio::transfer_all (),
std::bind(&NTCP2Session::HandleReceivedLength, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
@@ -1126,11 +1126,11 @@ namespace transport
{
if (!m_SendKey ||
#if OPENSSL_SIPHASH
!m_SendMDCtx
!m_SendMDCtx
#else
!m_SendSipKey
!m_SendSipKey
#endif
) return;
) return;
m_NextSendBuffer = new uint8_t[49]; // 49 = 12 bytes message + 16 bytes MAC + 2 bytes size + up to 19 padding block
// termination block
m_NextSendBuffer[2] = eNTCP2BlkTermination;
@@ -1164,7 +1164,7 @@ namespace transport
else if (m_SendQueue.size () > NTCP2_MAX_OUTGOING_QUEUE_SIZE)
{
LogPrint (eLogWarning, "NTCP2: Outgoing messages queue size to ",
GetIdentHashBase64(), " exceeds ", NTCP2_MAX_OUTGOING_QUEUE_SIZE);
GetIdentHashBase64(), " exceeds ", NTCP2_MAX_OUTGOING_QUEUE_SIZE);
Terminate ();
}
}
@@ -1177,7 +1177,7 @@ namespace transport
NTCP2Server::NTCP2Server ():
RunnableServiceWithWork ("NTCP2"), m_TerminationTimer (GetService ()),
m_ProxyType(eNoProxy), m_Resolver(GetService ())
m_ProxyType(eNoProxy), m_Resolver(GetService ())
{
}
@@ -1243,7 +1243,7 @@ namespace transport
m_NTCP2V6Acceptor->open (boost::asio::ip::tcp::v6());
m_NTCP2V6Acceptor->set_option (boost::asio::ip::v6_only (true));
m_NTCP2V6Acceptor->set_option (boost::asio::socket_base::reuse_address (true));
#ifdef __linux__
#if defined(__linux__) && !defined(_NETINET_IN_H)
if (!m_Address6 && !m_YggdrasilAddress) // only if not binded to address
{
// Set preference to use public IPv6 address -- tested on linux, not works on windows, and not tested on others

View File

@@ -107,7 +107,10 @@ namespace data
{
i2p::util::SetThreadName("NetDB");
uint32_t lastSave = 0, lastPublish = 0, lastExploratory = 0, lastManageRequest = 0, lastDestinationCleanup = 0;
uint64_t lastSave = 0, lastPublish = 0, lastExploratory = 0, lastManageRequest = 0, lastDestinationCleanup = 0;
uint64_t lastProfilesCleanup = i2p::util::GetSecondsSinceEpoch ();
int16_t profilesCleanupVariance = 0;
while (m_IsRunning)
{
try
@@ -155,6 +158,7 @@ namespace data
m_Requests.ManageRequests ();
lastManageRequest = ts;
}
if (ts - lastSave >= 60) // save routers, manage leasesets and validate subscriptions every minute
{
if (lastSave)
@@ -164,12 +168,20 @@ namespace data
}
lastSave = ts;
}
if (ts - lastDestinationCleanup >= i2p::garlic::INCOMING_TAGS_EXPIRATION_TIMEOUT)
{
i2p::context.CleanupDestination ();
lastDestinationCleanup = ts;
}
if (ts - lastProfilesCleanup >= (uint64_t)(i2p::data::PEER_PROFILE_AUTOCLEAN_TIMEOUT + profilesCleanupVariance))
{
DeleteObsoleteProfiles ();
lastProfilesCleanup = ts;
profilesCleanupVariance = (rand () % (2 * i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE) - i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE);
}
// publish
if (!m_HiddenMode && i2p::transport::transports.IsOnline ())
{
@@ -195,6 +207,7 @@ namespace data
lastPublish = ts;
}
}
if (ts - lastExploratory >= 30) // exploratory every 30 seconds
{
auto numRouters = m_RouterInfos.size ();
@@ -476,7 +489,7 @@ namespace data
{
auto r = std::make_shared<RouterInfo>(path);
if (r->GetRouterIdentity () && !r->IsUnreachable () && r->HasValidAddresses () &&
ts < r->GetTimestamp () + 24*60*60*NETDB_MAX_OFFLINE_EXPIRATION_TIMEOUT*1000LL)
ts < r->GetTimestamp () + 24*60*60*NETDB_MAX_OFFLINE_EXPIRATION_TIMEOUT*1000LL)
{
r->DeleteBuffer ();
if (m_RouterInfos.emplace (r->GetIdentHash (), r).second)
@@ -607,7 +620,7 @@ namespace data
}
// make router reachable back if too few routers or floodfills
if (it.second->IsUnreachable () && (total - deletedCount < NETDB_MIN_ROUTERS ||
(it.second->IsFloodfill () && totalFloodfills - deletedFloodfillsCount < NETDB_MIN_FLOODFILLS)))
(it.second->IsFloodfill () && totalFloodfills - deletedFloodfillsCount < NETDB_MIN_FLOODFILLS)))
it.second->SetUnreachable (false);
// find & mark expired routers
if (!it.second->IsReachable () && it.second->IsSSU (false))
@@ -630,7 +643,7 @@ namespace data
} // m_RouterInfos iteration
m_RouterInfoBuffersPool.CleanUpMt ();
if (updatedCount > 0)
LogPrint (eLogInfo, "NetDb: Saved ", updatedCount, " new/updated routers");
if (deletedCount > 0)
@@ -659,7 +672,7 @@ namespace data
else
++it;
}
}
}
}
void NetDb::RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete, bool direct)
@@ -675,7 +688,7 @@ namespace data
if (floodfill)
{
if (direct && !floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) &&
!i2p::transport::transports.IsConnected (floodfill->GetIdentHash ()))
!i2p::transport::transports.IsConnected (floodfill->GetIdentHash ()))
direct = false; // floodfill can't be reached directly
if (direct)
transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
@@ -958,7 +971,7 @@ namespace data
else
{
if (lookupType == DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP ||
lookupType == DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP)
lookupType == DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP)
{
auto router = FindRouter (ident);
if (router)
@@ -1123,7 +1136,7 @@ namespace data
m_PublishExcluded.insert (floodfill->GetIdentHash ());
m_PublishReplyToken = replyToken;
if (floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) || // are we able to connect?
i2p::transport::transports.IsConnected (floodfill->GetIdentHash ())) // already connected ?
i2p::transport::transports.IsConnected (floodfill->GetIdentHash ())) // already connected ?
// send directly
transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken));
else
@@ -1190,6 +1203,16 @@ namespace data
});
}
std::shared_ptr<const RouterInfo> NetDb::GetRandomSSU2PeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const
{
return GetRandomRouter (
[v4, &excluded](std::shared_ptr<const RouterInfo> router)->bool
{
return !router->IsHidden () && router->IsECIES () &&
router->IsSSU2PeerTesting (v4) && !excluded.count (router->GetIdentHash ());
});
}
std::shared_ptr<const RouterInfo> NetDb::GetRandomSSUV6Router () const
{
return GetRandomRouter (
@@ -1364,7 +1387,8 @@ namespace data
return res;
}
std::shared_ptr<const RouterInfo> NetDb::GetRandomRouterInFamily(const std::string & fam) const {
std::shared_ptr<const RouterInfo> NetDb::GetRandomRouterInFamily (FamilyID fam) const
{
return GetRandomRouter(
[fam](std::shared_ptr<const RouterInfo> router)->bool
{

View File

@@ -90,13 +90,14 @@ namespace data
std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const;
std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const;
std::shared_ptr<const RouterInfo> GetRandomPeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const;
std::shared_ptr<const RouterInfo> GetRandomSSU2PeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const;
std::shared_ptr<const RouterInfo> GetRandomSSUV6Router () const; // TODO: change to v6 peer test later
std::shared_ptr<const RouterInfo> GetRandomIntroducer (bool v4, 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, bool closeThanUsOnly = false) const;
std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
std::shared_ptr<const RouterInfo> GetRandomRouterInFamily(const std::string & fam) const;
std::shared_ptr<const RouterInfo> GetRandomRouterInFamily (FamilyID fam) const;
void SetUnreachable (const IdentHash& ident, bool unreachable);
void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg);
@@ -123,7 +124,7 @@ namespace data
void ClearRouterInfos () { m_RouterInfos.clear (); };
std::shared_ptr<RouterInfo::Buffer> NewRouterInfoBuffer () { return m_RouterInfoBuffersPool.AcquireSharedMt (); };
uint32_t GetPublishReplyToken () const { return m_PublishReplyToken; };
private:

View File

@@ -60,7 +60,7 @@ namespace data
void Start ();
void Stop ();
std::shared_ptr<RequestedDestination> CreateRequest (const IdentHash& destination, bool isExploratory, RequestedDestination::RequestComplete requestComplete = nullptr);
std::shared_ptr<RequestedDestination> CreateRequest (const IdentHash& destination, bool isExploratory, RequestedDestination::RequestComplete requestComplete = nullptr);
void RequestComplete (const IdentHash& ident, std::shared_ptr<RouterInfo> r);
std::shared_ptr<RequestedDestination> FindRequest (const IdentHash& ident) const;
void ManageRequests ();

View File

@@ -1,12 +1,13 @@
#include "Poly1305.h"
/**
This code is licensed under the MCGSI Public License
Copyright 2018 Jeff Becker
Kovri go write your own code
* This code is licensed under the MCGSI Public License
* Copyright 2018 Jeff Becker
*
*Kovri go write your own code
*
*/
#include "Poly1305.h"
#if !OPENSSL_AEAD_CHACHA20_POLY1305
namespace i2p
{

View File

@@ -5,6 +5,7 @@
* Kovri go write your own code
*
*/
#ifndef LIBI2PD_POLY1305_H
#define LIBI2PD_POLY1305_H
#include <cstdint>

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
* Copyright (c) 2013-2022, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -29,6 +29,8 @@ namespace data
const char PEER_PROFILE_USAGE_REJECTED[] = "rejected";
const int PEER_PROFILE_EXPIRATION_TIMEOUT = 72; // in hours (3 days)
const int PEER_PROFILE_AUTOCLEAN_TIMEOUT = 24 * 3600; // in seconds (1 day)
const int PEER_PROFILE_AUTOCLEAN_VARIANCE = 3 * 3600; // in seconds (3 hours)
class RouterProfile
{

View File

@@ -28,7 +28,7 @@ namespace util
void Put (Element e)
{
std::unique_lock<std::mutex> l(m_QueueMutex);
std::unique_lock<std::mutex> l(m_QueueMutex);
m_Queue.push (std::move(e));
m_NonEmpty.notify_one ();
}
@@ -38,7 +38,7 @@ namespace util
{
if (!vec.empty ())
{
std::unique_lock<std::mutex> l(m_QueueMutex);
std::unique_lock<std::mutex> l(m_QueueMutex);
for (const auto& it: vec)
m_Queue.push (std::move(it));
m_NonEmpty.notify_one ();

View File

@@ -187,31 +187,31 @@ namespace data
}
s.seekg (1, std::ios::cur); // su3 file format version
SigningKeyType signatureType;
s.read ((char *)&signatureType, 2); // signature type
s.read ((char *)&signatureType, 2); // signature type
signatureType = be16toh (signatureType);
uint16_t signatureLength;
s.read ((char *)&signatureLength, 2); // signature length
s.read ((char *)&signatureLength, 2); // signature length
signatureLength = be16toh (signatureLength);
s.seekg (1, std::ios::cur); // unused
uint8_t versionLength;
s.read ((char *)&versionLength, 1); // version length
s.read ((char *)&versionLength, 1); // version length
s.seekg (1, std::ios::cur); // unused
uint8_t signerIDLength;
s.read ((char *)&signerIDLength, 1); // signer ID length
s.read ((char *)&signerIDLength, 1); // signer ID length
uint64_t contentLength;
s.read ((char *)&contentLength, 8); // content length
s.read ((char *)&contentLength, 8); // content length
contentLength = be64toh (contentLength);
s.seekg (1, std::ios::cur); // unused
uint8_t fileType;
s.read ((char *)&fileType, 1); // file type
if (fileType != 0x00) // zip file
s.read ((char *)&fileType, 1); // file type
if (fileType != 0x00) // zip file
{
LogPrint (eLogError, "Reseed: Can't handle file type ", (int)fileType);
return 0;
}
s.seekg (1, std::ios::cur); // unused
uint8_t contentType;
s.read ((char *)&contentType, 1); // content type
s.read ((char *)&contentType, 1); // content type
if (contentType != 0x03) // reseed data
{
LogPrint (eLogError, "Reseed: Unexpected content type ", (int)contentType);
@@ -688,7 +688,7 @@ namespace data
{
boost::asio::ip::tcp::endpoint ep = *it;
if ((ep.address ().is_v4 () && i2p::context.SupportsV4 ()) ||
(ep.address ().is_v6 () && i2p::context.SupportsV6 ()))
(ep.address ().is_v6 () && i2p::context.SupportsV6 ()))
{
s.lowest_layer().connect (ep, ecode);
if (!ecode)

View File

@@ -65,15 +65,18 @@ namespace i2p
port = rand () % (30777 - 9111) + 9111; // I2P network ports range
if (port == 9150) port = 9151; // Tor browser
}
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
bool ssu; i2p::config::GetOption("ssu", ssu);
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg);
bool nat; i2p::config::GetOption("nat", nat);
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
bool ssu; i2p::config::GetOption("ssu", ssu);
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg);
bool nat; i2p::config::GetOption("nat", nat);
if ((ntcp2 || ygg) && !m_NTCP2Keys)
NewNTCP2Keys ();
if (ssu2 && !m_SSU2Keys)
NewSSU2Keys ();
bool ntcp2Published = false;
if (ntcp2)
{
@@ -84,6 +87,9 @@ namespace i2p
if (!ntcp2proxy.empty ()) ntcp2Published = false;
}
}
bool ssu2Published = false;
if (ssu2)
i2p::config::GetOption("ssu2.published", ssu2Published);
uint8_t caps = 0, addressCaps = 0;
if (ipv4)
{
@@ -112,6 +118,16 @@ namespace i2p
routerInfo.AddSSUAddress (host.c_str(), port, nullptr);
caps |= i2p::data::RouterInfo::eReachable; // R
}
if (ssu2)
{
if (ssu2Published)
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address_v4::from_string (host), port);
else
{
addressCaps |= i2p::data::RouterInfo::AddressCaps::eV4;
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro);
}
}
}
if (ipv6)
{
@@ -147,6 +163,17 @@ namespace i2p
routerInfo.AddSSUAddress (host.c_str(), port, nullptr);
caps |= i2p::data::RouterInfo::eReachable; // R
}
if (ssu2)
{
if (ssu2Published)
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address_v6::from_string (host), port);
else
{
if (!ipv4) // no other ssu2 addresses yet
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro);
addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6;
}
}
}
if (ygg)
{
@@ -174,17 +201,30 @@ namespace i2p
void RouterContext::NewNTCP2Keys ()
{
m_StaticKeys.reset (new i2p::crypto::X25519Keys ());
m_StaticKeys->GenerateKeys ();
m_NTCP2StaticKeys.reset (new i2p::crypto::X25519Keys ());
m_NTCP2StaticKeys->GenerateKeys ();
m_NTCP2Keys.reset (new NTCP2PrivateKeys ());
m_StaticKeys->GetPrivateKey (m_NTCP2Keys->staticPrivateKey);
memcpy (m_NTCP2Keys->staticPublicKey, m_StaticKeys->GetPublicKey (), 32);
m_NTCP2StaticKeys->GetPrivateKey (m_NTCP2Keys->staticPrivateKey);
memcpy (m_NTCP2Keys->staticPublicKey, m_NTCP2StaticKeys->GetPublicKey (), 32);
RAND_bytes (m_NTCP2Keys->iv, 16);
// save
std::ofstream fk (i2p::fs::DataDirPath (NTCP2_KEYS), std::ofstream::binary | std::ofstream::out);
fk.write ((char *)m_NTCP2Keys.get (), sizeof (NTCP2PrivateKeys));
}
void RouterContext::NewSSU2Keys ()
{
m_SSU2StaticKeys.reset (new i2p::crypto::X25519Keys ());
m_SSU2StaticKeys->GenerateKeys ();
m_SSU2Keys.reset (new SSU2PrivateKeys ());
m_SSU2StaticKeys->GetPrivateKey (m_SSU2Keys->staticPrivateKey);
memcpy (m_SSU2Keys->staticPublicKey, m_SSU2StaticKeys->GetPublicKey (), 32);
RAND_bytes (m_SSU2Keys->intro, 32);
// save
std::ofstream fk (i2p::fs::DataDirPath (SSU2_KEYS), std::ofstream::binary | std::ofstream::out);
fk.write ((char *)m_SSU2Keys.get (), sizeof (SSU2PrivateKeys));
}
void RouterContext::SetStatus (RouterStatus status)
{
if (status != m_Status)
@@ -229,7 +269,7 @@ namespace i2p
bool updated = false;
for (auto& address : m_RouterInfo.GetAddresses ())
{
if (!address->IsNTCP2 () && address->port != port)
if (!address->IsNTCP2 () && !address->IsSSU2 () && address->port != port)
{
address->port = port;
updated = true;
@@ -300,13 +340,66 @@ namespace i2p
UpdateRouterInfo ();
}
void RouterContext::PublishSSU2Address (int port, bool publish, bool v4, bool v6)
{
if (!m_SSU2Keys || (publish && !port)) return;
bool updated = false;
for (auto& address : m_RouterInfo.GetAddresses ())
{
if (address->IsSSU2 () && (address->port != port || address->published != publish) &&
((v4 && address->IsV4 ()) || (v6 && address->IsV6 ())))
{
address->port = port;
address->published = publish;
if (publish)
address->caps |= i2p::data::RouterInfo::eSSUIntroducer;
else
address->caps &= ~i2p::data::RouterInfo::eSSUIntroducer;
updated = true;
}
}
if (updated)
UpdateRouterInfo ();
}
void RouterContext::UpdateSSU2Address (bool enable)
{
auto& addresses = m_RouterInfo.GetAddresses ();
bool found = false, updated = false;
for (auto it = addresses.begin (); it != addresses.end (); ++it)
{
if ((*it)->IsSSU2 ())
{
found = true;
if (!enable)
{
addresses.erase (it);
updated= true;
}
break;
}
}
if (enable && !found)
{
uint8_t addressCaps = 0;
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
if (ipv4) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV4;
if (ipv6) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6;
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addressCaps);
updated = true;
}
if (updated)
UpdateRouterInfo ();
}
void RouterContext::UpdateAddress (const boost::asio::ip::address& host)
{
bool updated = false;
for (auto& address : m_RouterInfo.GetAddresses ())
{
if (address->host != host && address->IsCompatible (host) &&
!i2p::util::net::IsYggdrasilAddress (address->host))
!i2p::util::net::IsYggdrasilAddress (address->host))
{
address->host = host;
if (host.is_v6 () && address->transportStyle == i2p::data::RouterInfo::eTransportSSU)
@@ -475,7 +568,7 @@ namespace i2p
// delete previous introducers
auto& addresses = m_RouterInfo.GetAddresses ();
for (auto& addr : addresses)
if (addr->ssu && ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ())))
if (addr->ssu && !addr->IsSSU2 () && ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ())))
{
addr->published = false;
addr->caps &= ~i2p::data::RouterInfo::eSSUIntroducer; // can't be introducer
@@ -507,7 +600,7 @@ namespace i2p
// delete previous introducers
auto& addresses = m_RouterInfo.GetAddresses ();
for (auto& addr : addresses)
if (addr->ssu && ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ())))
if (addr->ssu && !addr->IsSSU2 () && ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ())))
{
addr->published = true;
addr->caps |= i2p::data::RouterInfo::eSSUIntroducer;
@@ -536,17 +629,26 @@ namespace i2p
if (supportsV6)
{
// insert v6 addresses if necessary
bool foundSSU = false, foundNTCP2 = false;
bool foundSSU = false, foundNTCP2 = false, foundSSU2 = false;
uint16_t port = 0;
auto& addresses = m_RouterInfo.GetAddresses ();
for (auto& addr: addresses)
{
if (addr->IsV6 () && !i2p::util::net::IsYggdrasilAddress (addr->host))
{
if (addr->transportStyle == i2p::data::RouterInfo::eTransportSSU)
foundSSU = true;
else if (addr->transportStyle == i2p::data::RouterInfo::eTransportNTCP)
foundNTCP2 = true;
switch (addr->transportStyle)
{
case i2p::data::RouterInfo::eTransportSSU:
foundSSU = true;
break;
case i2p::data::RouterInfo::eTransportNTCP:
foundNTCP2 = true;
break;
case i2p::data::RouterInfo::eTransportSSU2:
foundSSU2 = true;
break;
default: ;
}
}
port = addr->port;
}
@@ -583,6 +685,22 @@ namespace i2p
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address(), 0, i2p::data::RouterInfo::eV6);
}
}
// SSU2
if (!foundSSU2)
{
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
if (ssu2)
{
bool ssu2Published; i2p::config::GetOption("ssu2.published", ssu2Published);
if (ssu2Published)
{
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address::from_string ("::1"), ssu2Port);
}
else
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::eV6);
}
}
m_RouterInfo.EnableV6 ();
}
else
@@ -598,7 +716,7 @@ namespace i2p
// update
if (supportsV4)
{
bool foundSSU = false, foundNTCP2 = false;
bool foundSSU = false, foundNTCP2 = false, foundSSU2 = false;
std::string host = "127.0.0.1";
uint16_t port = 0;
auto& addresses = m_RouterInfo.GetAddresses ();
@@ -606,10 +724,19 @@ namespace i2p
{
if (addr->IsV4 ())
{
if (addr->transportStyle == i2p::data::RouterInfo::eTransportSSU)
foundSSU = true;
else if (addr->transportStyle == i2p::data::RouterInfo::eTransportNTCP)
foundNTCP2 = true;
switch (addr->transportStyle)
{
case i2p::data::RouterInfo::eTransportSSU:
foundSSU = true;
break;
case i2p::data::RouterInfo::eTransportNTCP:
foundNTCP2 = true;
break;
case i2p::data::RouterInfo::eTransportSSU2:
foundSSU2 = true;
break;
default: ;
}
}
if (addr->port) port = addr->port;
}
@@ -638,6 +765,22 @@ namespace i2p
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address(), 0, i2p::data::RouterInfo::eV4);
}
}
// SSU2
if (!foundSSU2)
{
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
if (ssu2)
{
bool ssu2Published; i2p::config::GetOption("ssu2.published", ssu2Published);
if (ssu2Published)
{
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address::from_string ("127.0.0.1"), ssu2Port);
}
else
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::eV6);
}
}
m_RouterInfo.EnableV4 ();
}
else
@@ -740,7 +883,7 @@ namespace i2p
}
std::shared_ptr<const i2p::data::IdentityEx> oldIdentity;
if (m_Keys.GetPublic ()->GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1 ||
m_Keys.GetPublic ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ELGAMAL)
m_Keys.GetPublic ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ELGAMAL)
{
// update keys
LogPrint (eLogInfo, "Router: router keys are obsolete. Creating new");
@@ -792,7 +935,31 @@ namespace i2p
UpdateNTCP2Address (true); // enable NTCP2
}
else
UpdateNTCP2Address (false); // disable NTCP2
UpdateNTCP2Address (false); // disable NTCP2
// read SSU2
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
if (ssu2)
{
// read SSU2 keys if available
std::ifstream s2k (i2p::fs::DataDirPath (SSU2_KEYS), std::ifstream::in | std::ifstream::binary);
if (s2k)
{
s2k.seekg (0, std::ios::end);
size_t len = s2k.tellg();
s2k.seekg (0, std::ios::beg);
if (len == sizeof (SSU2PrivateKeys))
{
m_SSU2Keys.reset (new SSU2PrivateKeys ());
s2k.read ((char *)m_SSU2Keys.get (), sizeof (SSU2PrivateKeys));
}
s2k.close ();
}
if (!m_SSU2Keys) NewSSU2Keys ();
UpdateSSU2Address (true); // enable SSU2
}
else
UpdateSSU2Address (false); // disable SSU2
return true;
}
@@ -910,17 +1077,31 @@ namespace i2p
return DecryptECIESTunnelBuildRecord (encrypted, data, SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE);
}
i2p::crypto::X25519Keys& RouterContext::GetStaticKeys ()
i2p::crypto::X25519Keys& RouterContext::GetNTCP2StaticKeys ()
{
if (!m_StaticKeys)
if (!m_NTCP2StaticKeys)
{
if (!m_NTCP2Keys) NewNTCP2Keys ();
auto x = new i2p::crypto::X25519Keys (m_NTCP2Keys->staticPrivateKey, m_NTCP2Keys->staticPublicKey);
if (!m_StaticKeys)
m_StaticKeys.reset (x);
if (!m_NTCP2StaticKeys)
m_NTCP2StaticKeys.reset (x);
else
delete x;
}
return *m_StaticKeys;
return *m_NTCP2StaticKeys;
}
i2p::crypto::X25519Keys& RouterContext::GetSSU2StaticKeys ()
{
if (!m_SSU2StaticKeys)
{
if (!m_SSU2Keys) NewSSU2Keys ();
auto x = new i2p::crypto::X25519Keys (m_SSU2Keys->staticPrivateKey, m_SSU2Keys->staticPublicKey);
if (!m_SSU2StaticKeys)
m_SSU2StaticKeys.reset (x);
else
delete x;
}
return *m_SSU2StaticKeys;
}
}

View File

@@ -29,6 +29,7 @@ namespace garlic
const char ROUTER_INFO[] = "router.info";
const char ROUTER_KEYS[] = "router.keys";
const char NTCP2_KEYS[] = "ntcp2.keys";
const char SSU2_KEYS[] = "ssu2.keys";
const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes
enum RouterStatus
@@ -61,6 +62,13 @@ namespace garlic
uint8_t iv[16];
};
struct SSU2PrivateKeys
{
uint8_t staticPublicKey[32];
uint8_t staticPrivateKey[32];
uint8_t intro[32];
};
public:
RouterContext ();
@@ -78,10 +86,16 @@ namespace garlic
return std::shared_ptr<i2p::garlic::GarlicDestination> (this,
[](i2p::garlic::GarlicDestination *) {});
}
const uint8_t * GetNTCP2StaticPublicKey () const { return m_NTCP2Keys ? m_NTCP2Keys->staticPublicKey : nullptr; };
const uint8_t * GetNTCP2StaticPrivateKey () const { return m_NTCP2Keys ? m_NTCP2Keys->staticPrivateKey : nullptr; };
const uint8_t * GetNTCP2IV () const { return m_NTCP2Keys ? m_NTCP2Keys->iv : nullptr; };
i2p::crypto::X25519Keys& GetStaticKeys ();
i2p::crypto::X25519Keys& GetNTCP2StaticKeys ();
const uint8_t * GetSSU2StaticPublicKey () const { return m_SSU2Keys ? m_SSU2Keys->staticPublicKey : nullptr; };
const uint8_t * GetSSU2StaticPrivateKey () const { return m_SSU2Keys ? m_SSU2Keys->staticPrivateKey : nullptr; };
const uint8_t * GetSSU2IntroKey () const { return m_SSU2Keys ? m_SSU2Keys->intro : nullptr; };
i2p::crypto::X25519Keys& GetSSU2StaticKeys ();
uint32_t GetUptime () const; // in seconds
uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; };
@@ -102,6 +116,8 @@ namespace garlic
void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon
void PublishNTCP2Address (int port, bool publish, bool v4, bool v6, bool ygg);
void UpdateNTCP2Address (bool enable);
void PublishSSU2Address (int port, bool publish, bool v4, bool v6);
void UpdateSSU2Address (bool enable);
void RemoveNTCPAddress (bool v4only = true); // delete NTCP address for older routers. TODO: remove later
bool AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer);
void RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
@@ -156,6 +172,7 @@ namespace garlic
void NewRouterInfo ();
void UpdateRouterInfo ();
void NewNTCP2Keys ();
void NewSSU2Keys ();
bool Load ();
void SaveKeys ();
@@ -177,7 +194,8 @@ namespace garlic
int m_NetID;
std::mutex m_GarlicMutex;
std::unique_ptr<NTCP2PrivateKeys> m_NTCP2Keys;
std::unique_ptr<i2p::crypto::X25519Keys> m_StaticKeys;
std::unique_ptr<SSU2PrivateKeys> m_SSU2Keys;
std::unique_ptr<i2p::crypto::X25519Keys> m_NTCP2StaticKeys, m_SSU2StaticKeys;
// for ECIESx25519
i2p::crypto::NoiseSymmetricState m_InitialNoiseState, m_CurrentNoiseState;
};

View File

@@ -33,26 +33,27 @@ namespace data
{
if (len > size ()) len = size ();
memcpy (data (), buf, len);
}
}
RouterInfo::RouterInfo (): m_Buffer (nullptr)
{
m_Addresses = boost::make_shared<Addresses>(); // create empty list
}
RouterInfo::RouterInfo (const std::string& fullPath):
m_IsUpdated (false), m_IsUnreachable (false),
m_SupportedTransports (0),m_ReachableTransports (0),
m_FamilyID (0), m_IsUpdated (false), m_IsUnreachable (false),
m_SupportedTransports (0),m_ReachableTransports (0),
m_Caps (0), m_Version (0)
{
m_Addresses = boost::make_shared<Addresses>(); // create empty list
m_Buffer = netdb.NewRouterInfoBuffer ();
m_Buffer = NewBuffer (); // always RouterInfo's
ReadFromFile (fullPath);
}
RouterInfo::RouterInfo (std::shared_ptr<Buffer>&& buf, size_t len):
m_IsUpdated (true), m_IsUnreachable (false), m_SupportedTransports (0),
m_ReachableTransports (0), m_Caps (0), m_Version (0)
m_FamilyID (0), m_IsUpdated (true), m_IsUnreachable (false),
m_SupportedTransports (0), m_ReachableTransports (0),
m_Caps (0), m_Version (0)
{
if (len <= MAX_RI_BUFFER_SIZE)
{
@@ -67,12 +68,12 @@ namespace data
m_Buffer = nullptr;
m_IsUnreachable = true;
}
}
}
RouterInfo::RouterInfo (const uint8_t * buf, size_t len):
RouterInfo (std::make_shared<Buffer> (buf, len), len)
{
}
}
RouterInfo::~RouterInfo ()
{
@@ -134,7 +135,7 @@ namespace data
}
s.seekg(0, std::ios::beg);
if (!m_Buffer)
m_Buffer = netdb.NewRouterInfoBuffer ();
m_Buffer = NewBuffer ();
s.read((char *)m_Buffer->data (), m_BufferLen);
}
else
@@ -159,7 +160,7 @@ namespace data
{
m_IsUnreachable = true;
return;
}
}
m_RouterIdentity = std::make_shared<IdentityEx>(m_Buffer->data (), m_BufferLen);
size_t identityLen = m_RouterIdentity->GetFullLen ();
if (identityLen >= m_BufferLen)
@@ -216,14 +217,15 @@ namespace data
uint8_t cost; // ignore
s.read ((char *)&cost, sizeof (cost));
s.read ((char *)&address->date, sizeof (address->date));
bool isHost = false, isIntroKey = false, isStaticKey = false;
bool isHost = false, isIntroKey = false, isStaticKey = false, isV2 = false;
Tag<32> iV2; // for 'i' field in SSU, TODO: remove later
char transportStyle[6];
ReadString (transportStyle, 6, s);
if (!strncmp (transportStyle, "NTCP", 4)) // NTCP or NTCP2
address->transportStyle = eTransportNTCP;
else if (!strcmp (transportStyle, "SSU"))
else if (!strncmp (transportStyle, "SSU", 3)) // SSU or SSU2
{
address->transportStyle = eTransportSSU;
address->transportStyle = (transportStyle[3] == '2') ? eTransportSSU2 : eTransportSSU;
address->ssu.reset (new SSUExt ());
address->ssu->mtu = 0;
}
@@ -234,6 +236,12 @@ namespace data
uint16_t size, r = 0;
s.read ((char *)&size, sizeof (size)); if (!s) return;
size = be16toh (size);
if (address->transportStyle == eTransportUnknown)
{
// skip unknown address
s.seekg (size, std::ios_base::cur);
if (s) continue; else return;
}
while (r < size)
{
char key[255], value[255];
@@ -266,15 +274,29 @@ namespace data
}
else if (!strcmp (key, "caps"))
address->caps = ExtractAddressCaps (value);
else if (!strcmp (key, "s")) // ntcp2 static key
else if (!strcmp (key, "s")) // ntcp2 or ssu2 static key
{
Base64ToByteStream (value, strlen (value), address->s, 32);
isStaticKey = true;
}
else if (!strcmp (key, "i")) // ntcp2 iv
else if (!strcmp (key, "i")) // ntcp2 iv or ssu2 intro
{
Base64ToByteStream (value, strlen (value), address->i, 16);
address->published = true; // presence if "i" means "published"
if (address->IsNTCP2 ())
{
Base64ToByteStream (value, strlen (value), address->i, 16);
address->published = true; // presence of "i" means "published" NTCP2
}
else if (address->IsSSU2 ())
Base64ToByteStream (value, strlen (value), address->i, 32);
else
Base64ToByteStream (value, strlen (value), iV2, 32);
}
else if (!strcmp (key, "v"))
{
if (!strcmp (value, "2"))
isV2 = true;
else
LogPrint (eLogWarning, "RouterInfo: Unexpected value ", value, " for v");
}
else if (key[0] == 'i')
{
@@ -308,7 +330,7 @@ namespace data
introducer.iPort = boost::lexical_cast<int>(value);
else if (!strcmp (key, "itag"))
introducer.iTag = boost::lexical_cast<uint32_t>(value);
else if (!strcmp (key, "ikey"))
else if (!strcmp (key, "ikey") || !strcmp (key, "ih"))
Base64ToByteStream (value, strlen (value), introducer.iKey, 32);
else if (!strcmp (key, "iexp"))
introducer.iExp = boost::lexical_cast<uint32_t>(value);
@@ -322,7 +344,7 @@ namespace data
if (isHost)
{
if (address->host.is_v6 ())
supportedTransports |= (i2p::util::net::IsYggdrasilAddress (address->host) ? eNTCP2V6Mesh : eNTCP2V6);
supportedTransports |= (i2p::util::net::IsYggdrasilAddress (address->host) ? eNTCP2V6Mesh : eNTCP2V6);
else
supportedTransports |= eNTCP2V4;
m_ReachableTransports |= supportedTransports;
@@ -344,7 +366,7 @@ namespace data
if (isIntroKey)
{
if (isHost)
supportedTransports |= address->host.is_v4 () ? eSSUV4 : eSSUV6;
supportedTransports |= address->host.is_v4 () ? eSSUV4 : eSSUV6;
else if (address->caps & AddressCaps::eV6)
{
supportedTransports |= eSSUV6;
@@ -361,7 +383,7 @@ namespace data
{
if (!it.iExp) it.iExp = m_Timestamp/1000 + NETDB_INTRODUCEE_EXPIRATION_TIMEOUT;
if (ts <= it.iExp && it.iPort > 0 &&
((it.iHost.is_v4 () && address->IsV4 ()) || (it.iHost.is_v6 () && address->IsV6 ())))
((it.iHost.is_v4 () && address->IsV4 ()) || (it.iHost.is_v6 () && address->IsV6 ())))
numValid++;
else
it.iPort = 0;
@@ -378,10 +400,37 @@ namespace data
}
}
}
if (supportedTransports)
if (address->transportStyle == eTransportSSU2 || (isV2 && address->transportStyle == eTransportSSU))
{
if (address->IsV4 ()) supportedTransports |= eSSU2V4;
if (address->IsV6 ()) supportedTransports |= eSSU2V6;
if (address->port)
{
if (address->host.is_v4 ()) m_ReachableTransports |= eSSU2V4;
if (address->host.is_v6 ()) m_ReachableTransports |= eSSU2V6;
}
}
if (supportedTransports)
{
if (!(m_SupportedTransports & supportedTransports)) // avoid duplicates
{
addresses->push_back(address);
if (address->transportStyle == eTransportSSU && isV2)
{
// create additional SSU2 address. TODO: remove later
auto ssu2addr = std::make_shared<Address> ();
ssu2addr->transportStyle = eTransportSSU2;
ssu2addr->host = address->host; ssu2addr->port = address->port;
ssu2addr->s = address->s; ssu2addr->i = iV2;
ssu2addr->date = address->date; ssu2addr->caps = address->caps;
ssu2addr->published = address->published;
ssu2addr->ssu.reset (new SSUExt ()); ssu2addr->ssu->mtu = address->ssu->mtu;
for (const auto& introducer: address->ssu->introducers)
if (!introducer.iPort) // SSU2
ssu2addr->ssu->introducers.push_back (introducer);
addresses->push_back(ssu2addr);
}
}
m_SupportedTransports |= supportedTransports;
}
}
@@ -397,6 +446,7 @@ namespace data
// read properties
m_Version = 0;
bool isNetId = false;
std::string family;
uint16_t size, r = 0;
s.read ((char *)&size, sizeof (size)); if (!s) return;
size = be16toh (size);
@@ -433,24 +483,23 @@ namespace data
{
isNetId = true;
if (atoi (value) != i2p::context.GetNetID ())
{
{
LogPrint (eLogError, "RouterInfo: 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);
family = value;
boost::to_lower (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 (netdb.GetFamilies ().VerifyFamily (family, GetIdentHash (), value))
m_FamilyID = netdb.GetFamilies ().GetFamilyID (family);
else
LogPrint (eLogWarning, "RouterInfo: Family ", family, " signature verification failed");
}
if (!s) return;
@@ -460,9 +509,9 @@ namespace data
SetUnreachable (true);
}
bool RouterInfo::IsFamily(const std::string & fam) const
bool RouterInfo::IsFamily (FamilyID famid) const
{
return m_Family == fam;
return m_FamilyID == famid;
}
void RouterInfo::ExtractCaps (const char * value)
@@ -627,12 +676,54 @@ namespace data
m_Addresses->push_back(std::move(addr));
}
void RouterInfo::AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey, uint8_t caps)
{
auto addr = std::make_shared<Address>();
addr->transportStyle = eTransportSSU2;
addr->caps = caps;
addr->date = 0;
addr->ssu.reset (new SSUExt ());
addr->ssu->mtu = 0;
memcpy (addr->s, staticKey, 32);
memcpy (addr->i, introKey, 32);
if (addr->IsV4 ()) m_SupportedTransports |= eSSU2V4;
if (addr->IsV6 ()) m_SupportedTransports |= eSSU2V6;
m_Addresses->push_back(std::move(addr));
}
void RouterInfo::AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey,
const boost::asio::ip::address& host, int port)
{
auto addr = std::make_shared<Address>();
addr->transportStyle = eTransportSSU2;
addr->host = host;
addr->port = port;
addr->published = true;
addr->caps = 0;
addr->date = 0;
addr->ssu.reset (new SSUExt ());
addr->ssu->mtu = 0;
memcpy (addr->s, staticKey, 32);
memcpy (addr->i, introKey, 32);
if (addr->IsV4 ())
{
m_SupportedTransports |= eSSU2V4;
m_ReachableTransports |= eSSU2V4;
}
if (addr->IsV6 ())
{
m_SupportedTransports |= eSSU2V6;
m_ReachableTransports |= eSSU2V6;
}
m_Addresses->push_back(std::move(addr));
}
bool RouterInfo::AddIntroducer (const Introducer& introducer)
{
for (auto& addr : *m_Addresses)
{
if (addr->transportStyle == eTransportSSU &&
((addr->IsV4 () && introducer.iHost.is_v4 ()) || (addr->IsV6 () && introducer.iHost.is_v6 ())))
((addr->IsV4 () && introducer.iHost.is_v4 ()) || (addr->IsV6 () && introducer.iHost.is_v6 ())))
{
for (auto& intro: addr->ssu->introducers)
if (intro.iTag == introducer.iTag) return false; // already presented
@@ -649,7 +740,7 @@ namespace data
for (auto& addr: *m_Addresses)
{
if (addr->transportStyle == eTransportSSU &&
((addr->IsV4 () && e.address ().is_v4 ()) || (addr->IsV6 () && e.address ().is_v6 ())))
((addr->IsV4 () && e.address ().is_v4 ()) || (addr->IsV6 () && e.address ().is_v6 ())))
{
for (auto it = addr->ssu->introducers.begin (); it != addr->ssu->introducers.end (); ++it)
if (boost::asio::ip::udp::endpoint (it->iHost, it->iPort) == e)
@@ -672,11 +763,6 @@ namespace data
return m_SupportedTransports & (eSSUV4 | eSSUV6);
}
bool RouterInfo::IsSSUV6 () const
{
return m_SupportedTransports & eSSUV6;
}
bool RouterInfo::IsNTCP2 (bool v4only) const
{
if (v4only)
@@ -685,25 +771,6 @@ namespace data
return m_SupportedTransports & (eNTCP2V4 | eNTCP2V6);
}
bool RouterInfo::IsNTCP2V6 () const
{
return m_SupportedTransports & eNTCP2V6;
}
bool RouterInfo::IsV6 () const
{
return m_SupportedTransports & (eSSUV6 | eNTCP2V6);
}
bool RouterInfo::IsV4 () const
{
return m_SupportedTransports & (eSSUV4 | eNTCP2V4);
}
bool RouterInfo::IsMesh () const
{
return m_SupportedTransports & eNTCP2V6Mesh;
}
void RouterInfo::EnableV6 ()
{
@@ -820,6 +887,24 @@ namespace data
});
}
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSU2V4Address () const
{
return GetAddress (
[](std::shared_ptr<const RouterInfo::Address> address)->bool
{
return (address->transportStyle == eTransportSSU2) && address->IsV4();
});
}
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSU2V6Address () const
{
return GetAddress (
[](std::shared_ptr<const RouterInfo::Address> address)->bool
{
return (address->transportStyle == eTransportSSU2) && address->IsV6();
});
}
template<typename Filter>
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetAddress (Filter filter) const
{
@@ -845,6 +930,16 @@ namespace data
});
}
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSU2AddressWithStaticKey (const uint8_t * key, bool isV6) const
{
if (!key) return nullptr;
return GetAddress (
[key, isV6](std::shared_ptr<const RouterInfo::Address> address)->bool
{
return address->IsSSU2 () && !memcmp (address->s, key, 32) && address->IsV6 () == isV6;
});
}
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetPublishedNTCP2V4Address () const
{
return GetAddress (
@@ -905,6 +1000,17 @@ namespace data
});
}
bool RouterInfo::IsSSU2PeerTesting (bool v4) const
{
if (!(m_SupportedTransports & (v4 ? eSSU2V4 : eSSU2V6))) return false;
return (bool)GetAddress (
[v4](std::shared_ptr<const RouterInfo::Address> address)->bool
{
return (address->IsSSU2 ()) && address->IsPeerTesting () &&
((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())) && address->IsReachableSSU ();
});
}
bool RouterInfo::IsIntroducer (bool v4) const
{
if (!(m_SupportedTransports & (v4 ? eSSUV4 : eSSUV6))) return false;
@@ -921,7 +1027,7 @@ namespace data
for (auto& addr: *m_Addresses)
{
// TODO: implement SSU
if (addr->transportStyle == eTransportNTCP && !addr->IsPublishedNTCP2 ())
if (!addr->published && (addr->transportStyle == eTransportNTCP || addr->transportStyle == eTransportSSU2))
{
addr->caps &= ~(eV4 | eV6);
addr->caps |= transports;
@@ -958,16 +1064,21 @@ namespace data
void RouterInfo::UpdateBuffer (const uint8_t * buf, size_t len)
{
if (!m_Buffer)
m_Buffer = netdb.NewRouterInfoBuffer ();
m_Buffer = NewBuffer ();
if (len > m_Buffer->size ()) len = m_Buffer->size ();
memcpy (m_Buffer->data (), buf, len);
m_BufferLen = len;
}
}
std::shared_ptr<RouterInfo::Buffer> RouterInfo::NewBuffer () const
{
return netdb.NewRouterInfoBuffer ();
}
void RouterInfo::RefreshTimestamp ()
{
m_Timestamp = i2p::util::GetMillisecondsSinceEpoch ();
}
m_Timestamp = i2p::util::GetMillisecondsSinceEpoch ();
}
void LocalRouterInfo::CreateBuffer (const PrivateKeys& privateKeys)
{
@@ -988,13 +1099,13 @@ namespace data
}
else
LogPrint (eLogError, "RouterInfo: Our RouterInfo is too long ", len + signatureLen);
}
}
void LocalRouterInfo::UpdateCaps (uint8_t caps)
{
SetCaps (caps);
UpdateCapsProperty ();
}
}
void LocalRouterInfo::UpdateCapsProperty ()
{
@@ -1041,6 +1152,8 @@ namespace data
cost = address.published ? COST_NTCP2_PUBLISHED : COST_NTCP2_NON_PUBLISHED;
else if (address.transportStyle == eTransportSSU)
cost = address.published ? COST_SSU_DIRECT : COST_SSU_THROUGH_INTRODUCERS;
else if (address.transportStyle == eTransportSSU2)
cost = address.published ? COST_SSU2_DIRECT : COST_SSU2_NON_PUBLISHED;
s.write ((const char *)&cost, sizeof (cost));
s.write ((const char *)&address.date, sizeof (address.date));
std::stringstream properties;
@@ -1051,7 +1164,7 @@ namespace data
{
WriteString ("NTCP2", s);
if (address.IsPublishedNTCP2 () && !address.host.is_unspecified () && address.port)
isPublished = true;
isPublished = true;
else
{
WriteString ("caps", properties);
@@ -1104,6 +1217,30 @@ namespace data
WriteString (caps, properties);
properties << ';';
}
else if (address.transportStyle == eTransportSSU2)
{
WriteString ("SSU2", s);
// caps
std::string caps;
if (address.published)
{
isPublished = true;
if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER;
}
else
{
if (address.IsV4 ()) caps += CAPS_FLAG_V4;
if (address.IsV6 ()) caps += CAPS_FLAG_V6;
if (caps.empty ()) caps += CAPS_FLAG_V4;
}
if (!caps.empty ())
{
WriteString ("caps", properties);
properties << '=';
WriteString (caps, properties);
properties << ';';
}
}
else
WriteString ("", s);
@@ -1114,10 +1251,17 @@ namespace data
WriteString (address.host.to_string (), properties);
properties << ';';
}
if (address.transportStyle == eTransportSSU)
if ((address.IsNTCP2 () && isPublished) || address.IsSSU2 ())
{
// publish i for NTCP2 or SSU2
WriteString ("i", properties); properties << '=';
size_t len = address.IsSSU2 () ? 32 : 16;
WriteString (address.i.ToBase64 (len), properties); properties << ';';
}
if (address.transportStyle == eTransportSSU || address.IsSSU2 ())
{
// write introducers if any
if (!address.ssu->introducers.empty())
if (address.ssu && !address.ssu->introducers.empty())
{
int i = 0;
for (const auto& introducer: address.ssu->introducers)
@@ -1131,19 +1275,25 @@ namespace data
}
i++;
}
i = 0;
for (const auto& introducer: address.ssu->introducers)
if (address.transportStyle == eTransportSSU)
{
WriteString ("ihost" + boost::lexical_cast<std::string>(i), properties);
properties << '=';
WriteString (introducer.iHost.to_string (), properties);
properties << ';';
i++;
i = 0;
for (const auto& introducer: address.ssu->introducers)
{
WriteString ("ihost" + boost::lexical_cast<std::string>(i), properties);
properties << '=';
WriteString (introducer.iHost.to_string (), properties);
properties << ';';
i++;
}
}
i = 0;
for (const auto& introducer: address.ssu->introducers)
{
WriteString ("ikey" + boost::lexical_cast<std::string>(i), properties);
if (address.IsSSU2 ())
WriteString ("ih" + boost::lexical_cast<std::string>(i), properties);
else
WriteString ("ikey" + boost::lexical_cast<std::string>(i), properties);
properties << '=';
char value[64];
size_t l = ByteStreamToBase64 (introducer.iKey, 32, value, 64);
@@ -1152,14 +1302,17 @@ namespace data
properties << ';';
i++;
}
i = 0;
for (const auto& introducer: address.ssu->introducers)
if (address.transportStyle == eTransportSSU)
{
WriteString ("iport" + boost::lexical_cast<std::string>(i), properties);
properties << '=';
WriteString (boost::lexical_cast<std::string>(introducer.iPort), properties);
properties << ';';
i++;
i = 0;
for (const auto& introducer: address.ssu->introducers)
{
WriteString ("iport" + boost::lexical_cast<std::string>(i), properties);
properties << '=';
WriteString (boost::lexical_cast<std::string>(introducer.iPort), properties);
properties << ';';
i++;
}
}
i = 0;
for (const auto& introducer: address.ssu->introducers)
@@ -1171,6 +1324,9 @@ namespace data
i++;
}
}
}
if (address.transportStyle == eTransportSSU)
{
// write intro key
WriteString ("key", properties);
properties << '=';
@@ -1179,8 +1335,11 @@ namespace data
value[l] = 0;
WriteString (value, properties);
properties << ';';
}
if (address.transportStyle == eTransportSSU || address.IsSSU2 ())
{
// write mtu
if (address.ssu->mtu)
if (address.ssu && address.ssu->mtu)
{
WriteString ("mtu", properties);
properties << '=';
@@ -1188,24 +1347,16 @@ namespace data
properties << ';';
}
}
if (address.IsNTCP2 () && isPublished)
{
// publish i for NTCP2
WriteString ("i", properties); properties << '=';
WriteString (address.i.ToBase64 (16), properties); properties << ';';
}
if (isPublished || address.ssu)
if (isPublished || (address.ssu && !address.IsSSU2 ()))
{
WriteString ("port", properties);
properties << '=';
WriteString (boost::lexical_cast<std::string>(address.port), properties);
properties << ';';
}
if (address.IsNTCP2 ())
if (address.IsNTCP2 () || address.IsSSU2 ())
{
// publish s and v for NTCP2
// publish s and v for NTCP2 or SSU2
WriteString ("s", properties); properties << '=';
WriteString (address.s.ToBase64 (), properties); properties << ';';
WriteString ("v", properties); properties << '=';
@@ -1233,7 +1384,7 @@ namespace data
uint16_t size = htobe16 (properties.str ().size ());
s.write ((char *)&size, sizeof (size));
s.write (properties.str ().c_str (), properties.str ().size ());
}
}
void LocalRouterInfo::SetProperty (const std::string& key, const std::string& value)
{
@@ -1251,13 +1402,18 @@ namespace data
if (it != m_Properties.end ())
return it->second;
return "";
}
}
void LocalRouterInfo::WriteString (const std::string& str, std::ostream& s) const
{
uint8_t len = str.size ();
s.write ((char *)&len, 1);
s.write (str.c_str (), len);
}
}
std::shared_ptr<RouterInfo::Buffer> LocalRouterInfo::NewBuffer () const
{
return std::make_shared<Buffer> ();
}
}
}

View File

@@ -19,6 +19,7 @@
#include <boost/shared_ptr.hpp>
#include "Identity.h"
#include "Profiling.h"
#include "Family.h"
namespace i2p
{
@@ -51,10 +52,12 @@ namespace data
const uint8_t COST_NTCP2_PUBLISHED = 3;
const uint8_t COST_NTCP2_NON_PUBLISHED = 14;
const uint8_t COST_SSU2_DIRECT = 8;
const uint8_t COST_SSU_DIRECT = 9;
const uint8_t COST_SSU_THROUGH_INTRODUCERS = 11;
const uint8_t COST_SSU2_NON_PUBLISHED = 15;
const size_t MAX_RI_BUFFER_SIZE = 2048; // if RouterInfo exceeds 2048 we consider it as malformed, might be changed later
const size_t MAX_RI_BUFFER_SIZE = 3072; // if RouterInfo exceeds 3K we consider it as malformed, might extend later
class RouterInfo: public RoutingDestination
{
public:
@@ -66,6 +69,8 @@ namespace data
eSSUV4 = 0x04,
eSSUV6 = 0x08,
eNTCP2V6Mesh = 0x10,
eSSU2V4 = 0x20,
eSSU2V6 = 0x40,
eAllTransports = 0xFF
};
typedef uint8_t CompatibleTransports;
@@ -92,7 +97,8 @@ namespace data
{
eTransportUnknown = 0,
eTransportNTCP,
eTransportSSU
eTransportSSU,
eTransportSSU2
};
typedef Tag<32> IntroKey; // should be castable to MacKey and AESKey
@@ -101,7 +107,7 @@ namespace data
Introducer (): iPort (0), iExp (0) {};
boost::asio::ip::address iHost;
int iPort;
IntroKey iKey;
IntroKey iKey; // or ih for SSU2
uint32_t iTag;
uint32_t iExp;
};
@@ -131,7 +137,7 @@ namespace data
bool operator==(const Address& other) const
{
return transportStyle == other.transportStyle && IsNTCP2 () == other.IsNTCP2 () &&
return transportStyle == other.transportStyle &&
host == other.host && port == other.port;
}
@@ -140,10 +146,11 @@ namespace data
return !(*this == other);
}
bool IsNTCP2 () const { return transportStyle == eTransportNTCP; };
bool IsNTCP2 () const { return transportStyle == eTransportNTCP; };
bool IsSSU2 () const { return transportStyle == eTransportSSU2; };
bool IsPublishedNTCP2 () const { return IsNTCP2 () && published; };
bool IsReachableSSU () const { return (bool)ssu && (published || !ssu->introducers.empty ()); };
bool UsesIntroducer () const { return (bool)ssu && !ssu->introducers.empty (); };
bool IsReachableSSU () const { return (bool)ssu && (published || UsesIntroducer ()); };
bool UsesIntroducer () const { return (bool)ssu && !ssu->introducers.empty (); };
bool IsIntroducer () const { return caps & eSSUIntroducer; };
bool IsPeerTesting () const { return caps & eSSUTesting; };
@@ -159,7 +166,7 @@ namespace data
Buffer () = default;
Buffer (const uint8_t * buf, size_t len);
};
typedef std::vector<std::shared_ptr<Address> > Addresses;
RouterInfo (const std::string& fullPath);
@@ -174,19 +181,25 @@ namespace data
std::string GetIdentHashBase64 () const { return GetIdentHash ().ToBase64 (); };
uint64_t GetTimestamp () const { return m_Timestamp; };
int GetVersion () const { return m_Version; };
virtual void SetProperty (const std::string& key, const std::string& value) {};
virtual void SetProperty (const std::string& key, const std::string& value) {};
virtual void ClearProperties () {};
Addresses& GetAddresses () { return *m_Addresses; }; // should be called for local RI only, otherwise must return shared_ptr
std::shared_ptr<const Address> GetNTCP2AddressWithStaticKey (const uint8_t * key) const;
std::shared_ptr<const Address> GetSSU2AddressWithStaticKey (const uint8_t * key, bool isV6) const;
std::shared_ptr<const Address> GetPublishedNTCP2V4Address () const;
std::shared_ptr<const Address> GetPublishedNTCP2V6Address () const;
std::shared_ptr<const Address> GetSSUAddress (bool v4only = true) const;
std::shared_ptr<const Address> GetSSUV6Address () const;
std::shared_ptr<const Address> GetYggdrasilAddress () const;
std::shared_ptr<const Address> GetSSU2V4Address () const;
std::shared_ptr<const Address> GetSSU2V6Address () const;
void AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu = 0);
void AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,
const boost::asio::ip::address& host = boost::asio::ip::address(), int port = 0, uint8_t caps = 0);
void AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey, uint8_t caps = 0); // non published
void AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey,
const boost::asio::ip::address& host, int port); // published
bool AddIntroducer (const Introducer& introducer);
bool RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
void SetUnreachableAddressesTransportCaps (uint8_t transports); // bitmask of AddressCaps
@@ -195,12 +208,14 @@ namespace data
bool IsReachable () const { return m_Caps & Caps::eReachable; };
bool IsECIES () const { return m_RouterIdentity->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; };
bool IsSSU (bool v4only = true) const;
bool IsSSUV6 () const;
bool IsSSUV6 () const { return m_SupportedTransports & eSSUV6; };
bool IsNTCP2 (bool v4only = true) const;
bool IsNTCP2V6 () const;
bool IsV6 () const;
bool IsV4 () const;
bool IsMesh () const;
bool IsNTCP2V6 () const { return m_SupportedTransports & eNTCP2V6; };
bool IsSSU2V4 () const { return m_SupportedTransports & eSSU2V4; };
bool IsSSU2V6 () const { return m_SupportedTransports & eSSU2V6; };
bool IsV6 () const { return m_SupportedTransports & (eSSUV6 | eNTCP2V6 | eSSU2V6); };
bool IsV4 () const { return m_SupportedTransports & (eSSUV4 | eNTCP2V4 | eSSU2V4); };
bool IsMesh () const { return m_SupportedTransports & eNTCP2V6Mesh; };
void EnableV6 ();
void DisableV6 ();
void EnableV4 ();
@@ -217,6 +232,7 @@ namespace data
bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; };
bool IsEligibleFloodfill () const;
bool IsPeerTesting (bool v4) const;
bool IsSSU2PeerTesting (bool v4) const;
bool IsIntroducer (bool v4) const;
uint8_t GetCaps () const { return m_Caps; };
@@ -241,7 +257,7 @@ namespace data
bool IsNewer (const uint8_t * buf, size_t len) const;
/** return true if we are in a router family and the signature is valid */
bool IsFamily(const std::string & fam) const;
bool IsFamily (FamilyID famid) const;
// implements RoutingDestination
std::shared_ptr<const IdentityEx> GetIdentity () const { return m_RouterIdentity; };
@@ -257,7 +273,7 @@ namespace data
void SetBufferLen (size_t len) { m_BufferLen = len; };
void RefreshTimestamp ();
const Addresses& GetAddresses () const { return *m_Addresses; };
private:
bool LoadFile (const std::string& fullPath);
@@ -269,10 +285,11 @@ namespace data
uint8_t ExtractAddressCaps (const char * value) const;
template<typename Filter>
std::shared_ptr<const Address> GetAddress (Filter filter) const;
virtual std::shared_ptr<Buffer> NewBuffer () const;
private:
std::string m_Family;
FamilyID m_FamilyID;
std::shared_ptr<const IdentityEx> m_RouterIdentity;
std::shared_ptr<Buffer> m_Buffer;
size_t m_BufferLen;
@@ -293,21 +310,22 @@ namespace data
void CreateBuffer (const PrivateKeys& privateKeys);
void UpdateCaps (uint8_t caps);
void SetProperty (const std::string& key, const std::string& value) override;
void DeleteProperty (const std::string& key);
std::string GetProperty (const std::string& key) const;
void SetProperty (const std::string& key, const std::string& value) override;
void DeleteProperty (const std::string& key);
std::string GetProperty (const std::string& key) const;
void ClearProperties () override { m_Properties.clear (); };
private:
void WriteToStream (std::ostream& s) const;
void UpdateCapsProperty ();
void WriteString (const std::string& str, std::ostream& s) const;
std::shared_ptr<Buffer> NewBuffer () const override;
private:
std::map<std::string, std::string> m_Properties;
};
std::map<std::string, std::string> m_Properties;
};
}
}

View File

@@ -15,7 +15,7 @@
#include "util.h"
#include "SSU.h"
#ifdef __linux__
#if defined(__linux__) && !defined(_NETINET_IN_H)
#include <linux/in6.h>
#endif
@@ -68,7 +68,7 @@ namespace transport
m_SocketV6.set_option (boost::asio::ip::v6_only (true));
m_SocketV6.set_option (boost::asio::socket_base::receive_buffer_size (SSU_SOCKET_RECEIVE_BUFFER_SIZE));
m_SocketV6.set_option (boost::asio::socket_base::send_buffer_size (SSU_SOCKET_SEND_BUFFER_SIZE));
#ifdef __linux__
#if defined(__linux__) && !defined(_NETINET_IN_H)
if (m_EndpointV6.address() == boost::asio::ip::address().from_string("::")) // only if not binded to address
{
// Set preference to use public IPv6 address -- tested on linux, not works on windows, and not tested on others
@@ -273,14 +273,14 @@ namespace transport
void SSUServer::HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet)
{
if (!ecode
|| ecode == boost::asio::error::connection_refused
|| ecode == boost::asio::error::connection_reset
|| ecode == boost::asio::error::network_unreachable
|| ecode == boost::asio::error::host_unreachable
|| ecode == boost::asio::error::connection_refused
|| ecode == boost::asio::error::connection_reset
|| ecode == boost::asio::error::network_unreachable
|| ecode == boost::asio::error::host_unreachable
#ifdef _WIN32 // windows can throw WinAPI error, which is not handled by ASIO
|| ecode.value() == boost::winapi::ERROR_CONNECTION_REFUSED_
|| ecode.value() == boost::winapi::ERROR_NETWORK_UNREACHABLE_
|| ecode.value() == boost::winapi::ERROR_HOST_UNREACHABLE_
|| ecode.value() == boost::winapi::ERROR_CONNECTION_REFUSED_
|| ecode.value() == boost::winapi::ERROR_NETWORK_UNREACHABLE_
|| ecode.value() == boost::winapi::ERROR_HOST_UNREACHABLE_
#endif
)
// just try continue reading when received ICMP response otherwise socket can crash,
@@ -332,14 +332,14 @@ namespace transport
void SSUServer::HandleReceivedFromV6 (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet)
{
if (!ecode
|| ecode == boost::asio::error::connection_refused
|| ecode == boost::asio::error::connection_reset
|| ecode == boost::asio::error::network_unreachable
|| ecode == boost::asio::error::host_unreachable
|| ecode == boost::asio::error::connection_refused
|| ecode == boost::asio::error::connection_reset
|| ecode == boost::asio::error::network_unreachable
|| ecode == boost::asio::error::host_unreachable
#ifdef _WIN32 // windows can throw WinAPI error, which is not handled by ASIO
|| ecode.value() == boost::winapi::ERROR_CONNECTION_REFUSED_
|| ecode.value() == boost::winapi::ERROR_NETWORK_UNREACHABLE_
|| ecode.value() == boost::winapi::ERROR_HOST_UNREACHABLE_
|| ecode.value() == boost::winapi::ERROR_CONNECTION_REFUSED_
|| ecode.value() == boost::winapi::ERROR_NETWORK_UNREACHABLE_
|| ecode.value() == boost::winapi::ERROR_HOST_UNREACHABLE_
#endif
)
// just try continue reading when received ICMP response otherwise socket can crash,
@@ -582,7 +582,7 @@ namespace transport
"] through introducer ", introducer->iHost, ":", introducer->iPort);
session->WaitForIntroduction ();
if ((address->host.is_v4 () && i2p::context.GetStatus () == eRouterStatusFirewalled) ||
(address->host.is_v6 () && i2p::context.GetStatusV6 () == eRouterStatusFirewalled))
(address->host.is_v6 () && i2p::context.GetStatusV6 () == eRouterStatusFirewalled))
{
uint8_t buf[1];
Send (buf, 0, remoteEndpoint); // send HolePunch
@@ -676,7 +676,7 @@ namespace transport
for (const auto& s : sessions)
{
if (s.second->GetRelayTag () && s.second->GetState () == eSessionStateEstablished &&
ts < s.second->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_EXPIRATION)
ts < s.second->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_EXPIRATION)
ret.push_back (s.second);
else if (s.second->GetRemoteIdentity ())
excluded.insert (s.second->GetRemoteIdentity ()->GetIdentHash ());

View File

@@ -6,75 +6,562 @@
* See full license text in LICENSE file at top of project tree
*/
#include <string.h>
#include <openssl/rand.h>
#include "Log.h"
#include "RouterContext.h"
#include "Transports.h"
#include "NetDb.hpp"
#include "Config.h"
#include "SSU2.h"
namespace i2p
{
namespace transport
{
SSU2Session::SSU2Session (std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter,
std::shared_ptr<const i2p::data::RouterInfo::Address> addr, bool peerTest):
TransportSession (in_RemoteRouter, SSU2_TERMINATION_TIMEOUT),
m_Address (addr)
{
SSU2Server::SSU2Server ():
RunnableServiceWithWork ("SSU2"), m_ReceiveService ("SSU2r"),
m_SocketV4 (m_ReceiveService.GetService ()), m_SocketV6 (m_ReceiveService.GetService ()),
m_TerminationTimer (GetService ()), m_ResendTimer (GetService ())
{
m_NoiseState.reset (new i2p::crypto::NoiseSymmetricState);
if (in_RemoteRouter && addr)
}
void SSU2Server::Start ()
{
if (!IsRunning ())
{
// outgoing
InitNoiseXKState1 (*m_NoiseState, addr->s);
}
}
SSU2Session::~SSU2Session ()
{
StartIOService ();
bool found = false;
auto& addresses = i2p::context.GetRouterInfo ().GetAddresses ();
for (const auto& address: addresses)
{
if (!address) continue;
if (address->transportStyle == i2p::data::RouterInfo::eTransportSSU2)
{
auto port = address->port;
if (!port)
{
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
if (ssu2Port) port = ssu2Port;
else
{
uint16_t p; i2p::config::GetOption ("port", p);
if (p) port = p;
}
}
if (port)
{
if (address->IsV4 ())
{
found = true;
OpenSocket (boost::asio::ip::udp::endpoint (boost::asio::ip::udp::v4(), port));
m_ReceiveService.GetService ().post(
[this]()
{
Receive (m_SocketV4);
});
}
if (address->IsV6 ())
{
found = true;
OpenSocket (boost::asio::ip::udp::endpoint (boost::asio::ip::udp::v6(), port));
m_ReceiveService.GetService ().post(
[this]()
{
Receive (m_SocketV6);
});
}
}
else
LogPrint (eLogError, "SSU2: Can't start server because port not specified");
}
}
if (found)
m_ReceiveService.Start ();
ScheduleTermination ();
}
}
void SSU2Session::SendSessionRequest ()
void SSU2Server::Stop ()
{
m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair ();
m_NoiseState->MixHash (m_EphemeralKeys->GetPublicKey (), 32);
uint8_t sharedSecret[32];
m_EphemeralKeys->Agree (m_Address->s, sharedSecret);
m_NoiseState->MixKey (sharedSecret);
if (context.SupportsV4 () || context.SupportsV6 ())
m_ReceiveService.Stop ();
Header header;
uint8_t headerX[48], payload[1200]; // TODO: correct payload size
size_t payloadSize = 8;
// fill packet
RAND_bytes (header.h.connID, 8);
memset (header.h.packetNum, 0, 4);
header.h.type = eSSU2SessionRequest;
header.h.flags[0] = 2; // ver
header.h.flags[1] = 2; // netID TODO:
header.h.flags[2] = 0; // flag
RAND_bytes (headerX, 8); // source id
memset (headerX + 8, 0, 8); // token
memcpy (headerX + 16, m_EphemeralKeys->GetPublicKey (), 32); // X
// encrypt
const uint8_t nonce[12] = {0};
i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, payload, payloadSize + 16, true);
payloadSize += 16;
CreateHeaderMask (m_Address->i, payload + (payloadSize - 24), m_Address->i, payload + (payloadSize - 12));
EncryptHeader (header);
i2p::crypto::ChaCha20 (headerX, 48, m_Address->i, nonce, headerX);
if (IsRunning ())
m_TerminationTimer.cancel ();
StopIOService ();
}
boost::asio::ip::udp::socket& SSU2Server::OpenSocket (const boost::asio::ip::udp::endpoint& localEndpoint)
{
boost::asio::ip::udp::socket& socket = localEndpoint.address ().is_v6 () ? m_SocketV6 : m_SocketV4;
try
{
socket.open (localEndpoint.protocol ());
if (localEndpoint.address ().is_v6 ())
socket.set_option (boost::asio::ip::v6_only (true));
socket.set_option (boost::asio::socket_base::receive_buffer_size (SSU2_SOCKET_RECEIVE_BUFFER_SIZE));
socket.set_option (boost::asio::socket_base::send_buffer_size (SSU2_SOCKET_SEND_BUFFER_SIZE));
socket.bind (localEndpoint);
LogPrint (eLogInfo, "SSU2: Start listening on ", localEndpoint);
}
catch (std::exception& ex )
{
LogPrint (eLogError, "SSU2: Failed to bind to ", localEndpoint, ": ", ex.what());
ThrowFatal ("Unable to start SSU2 transport on ", localEndpoint, ": ", ex.what ());
}
return socket;
}
void SSU2Server::Receive (boost::asio::ip::udp::socket& socket)
{
Packet * packet = m_PacketsPool.AcquireMt ();
socket.async_receive_from (boost::asio::buffer (packet->buf, SSU2_MTU), packet->from,
std::bind (&SSU2Server::HandleReceivedFrom, this, std::placeholders::_1, std::placeholders::_2, packet, std::ref (socket)));
}
void SSU2Server::HandleReceivedFrom (const boost::system::error_code& ecode, size_t bytes_transferred,
Packet * packet, boost::asio::ip::udp::socket& socket)
{
if (!ecode)
{
i2p::transport::transports.UpdateReceivedBytes (bytes_transferred);
packet->len = bytes_transferred;
boost::system::error_code ec;
size_t moreBytes = socket.available (ec);
if (!ec && moreBytes)
{
std::vector<Packet *> packets;
packets.push_back (packet);
while (moreBytes && packets.size () < 32)
{
packet = m_PacketsPool.AcquireMt ();
packet->len = socket.receive_from (boost::asio::buffer (packet->buf, SSU2_MTU), packet->from, 0, ec);
if (!ec)
{
i2p::transport::transports.UpdateReceivedBytes (packet->len);
packets.push_back (packet);
moreBytes = socket.available(ec);
if (ec) break;
}
else
{
LogPrint (eLogError, "SSU2: receive_from error: code ", ec.value(), ": ", ec.message ());
m_PacketsPool.ReleaseMt (packet);
break;
}
}
GetService ().post (std::bind (&SSU2Server::HandleReceivedPackets, this, packets));
}
else
GetService ().post (std::bind (&SSU2Server::HandleReceivedPacket, this, packet));
Receive (socket);
}
else
{
m_PacketsPool.ReleaseMt (packet);
if (ecode != boost::asio::error::operation_aborted)
{
LogPrint (eLogError, "SSU2: Receive error: code ", ecode.value(), ": ", ecode.message ());
auto ep = socket.local_endpoint ();
socket.close ();
OpenSocket (ep);
Receive (socket);
}
}
}
void SSU2Server::HandleReceivedPacket (Packet * packet)
{
if (packet)
{
ProcessNextPacket (packet->buf, packet->len, packet->from);
m_PacketsPool.ReleaseMt (packet);
if (m_LastSession) m_LastSession->FlushData ();
}
}
void SSU2Server::HandleReceivedPackets (std::vector<Packet *> packets)
{
for (auto& packet: packets)
ProcessNextPacket (packet->buf, packet->len, packet->from);
m_PacketsPool.ReleaseMt (packets);
if (m_LastSession) m_LastSession->FlushData ();
}
void SSU2Server::AddSession (std::shared_ptr<SSU2Session> session)
{
if (session)
{
m_Sessions.emplace (session->GetConnID (), session);
AddSessionByRouterHash (session);
}
}
void SSU2Server::RemoveSession (uint64_t connID)
{
auto it = m_Sessions.find (connID);
if (it != m_Sessions.end ())
{
auto ident = it->second->GetRemoteIdentity ();
if (ident)
m_SessionsByRouterHash.erase (ident->GetIdentHash ());
m_Sessions.erase (it);
}
}
void SSU2Server::AddSessionByRouterHash (std::shared_ptr<SSU2Session> session)
{
if (session)
{
auto ident = session->GetRemoteIdentity ();
if (ident)
{
auto ret = m_SessionsByRouterHash.emplace (ident->GetIdentHash (), session);
if (!ret.second)
{
// session already exists
LogPrint (eLogWarning, "SSU2: Session to ", ident->GetIdentHash ().ToBase64 (), " aready exists");
// terminate existing
GetService ().post (std::bind (&SSU2Session::Terminate, ret.first->second));
// update session
ret.first->second = session;
}
}
}
}
void SSU2Server::AddPendingOutgoingSession (std::shared_ptr<SSU2Session> session)
{
if (session)
m_PendingOutgoingSessions.emplace (session->GetRemoteEndpoint (), session);
}
std::shared_ptr<SSU2Session> SSU2Server::FindSession (const i2p::data::IdentHash& ident) const
{
auto it = m_SessionsByRouterHash.find (ident);
if (it != m_SessionsByRouterHash.end ())
return it->second;
return nullptr;
}
}
void SSU2Session::EncryptHeader (Header& h)
void SSU2Server::AddRelay (uint32_t tag, std::shared_ptr<SSU2Session> relay)
{
h.ll[0] ^= m_HeaderMask.ll[0];
h.ll[1] ^= m_HeaderMask.ll[1];
}
m_Relays.emplace (tag, relay);
}
void SSU2Session::CreateHeaderMask (const uint8_t * kh1, const uint8_t * nonce1, const uint8_t * kh2, const uint8_t * nonce2)
void SSU2Server::RemoveRelay (uint32_t tag)
{
// Header Encryption KDF
uint8_t data[8] = {0};
i2p::crypto::ChaCha20 (data, 8, kh1, nonce1, m_HeaderMask.buf);
i2p::crypto::ChaCha20 (data, 8, kh2, nonce2, m_HeaderMask.buf + 8);
m_Relays.erase (tag);
}
std::shared_ptr<SSU2Session> SSU2Server::FindRelaySession (uint32_t tag)
{
auto it = m_Relays.find (tag);
if (it != m_Relays.end ())
{
if (it->second->IsEstablished ())
return it->second;
else
m_Relays.erase (it);
}
return nullptr;
}
void SSU2Server::ProcessNextPacket (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
{
if (len < 24) return;
uint64_t connID;
memcpy (&connID, buf, 8);
connID ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), buf + (len - 24));
if (!m_LastSession || m_LastSession->GetConnID () != connID)
{
if (m_LastSession) m_LastSession->FlushData ();
auto it = m_Sessions.find (connID);
if (it != m_Sessions.end ())
m_LastSession = it->second;
else
m_LastSession = nullptr;
}
if (m_LastSession)
{
switch (m_LastSession->GetState ())
{
case eSSU2SessionStateEstablished:
m_LastSession->ProcessData (buf, len);
break;
case eSSU2SessionStateUnknown:
m_LastSession->ProcessSessionConfirmed (buf, len);
break;
case eSSU2SessionStateIntroduced:
m_LastSession->SetRemoteEndpoint (senderEndpoint);
m_LastSession->ProcessHolePunch (buf, len);
break;
case eSSU2SessionStatePeerTest:
m_LastSession->SetRemoteEndpoint (senderEndpoint);
m_LastSession->ProcessPeerTest (buf, len);
break;
default:
LogPrint (eLogWarning, "SSU2: Invalid session state ", (int)m_LastSession->GetState ());
}
}
else
{
// check pending sessions if it's SessionCreated or Retry
auto it1 = m_PendingOutgoingSessions.find (senderEndpoint);
if (it1 != m_PendingOutgoingSessions.end ())
{
if (it1->second->ProcessSessionCreated (buf, len))
m_PendingOutgoingSessions.erase (it1); // we are done with that endpoint
else
it1->second->ProcessRetry (buf, len);
}
else
{
// assume new incoming session
auto session = std::make_shared<SSU2Session> (*this);
session->SetRemoteEndpoint (senderEndpoint);
session->ProcessFirstIncomingMessage (connID, buf, len);
}
}
}
void SSU2Server::Send (const uint8_t * header, size_t headerLen, const uint8_t * payload, size_t payloadLen,
const boost::asio::ip::udp::endpoint& to)
{
std::vector<boost::asio::const_buffer> bufs
{
boost::asio::buffer (header, headerLen),
boost::asio::buffer (payload, payloadLen)
};
boost::system::error_code ec;
if (to.address ().is_v6 ())
m_SocketV6.send_to (bufs, to, 0, ec);
else
m_SocketV4.send_to (bufs, to, 0, ec);
if (!ec)
i2p::transport::transports.UpdateSentBytes (headerLen + payloadLen);
else
LogPrint (eLogError, "SSU2: Send exception: ", ec.message (), " to ", to);
}
void SSU2Server::Send (const uint8_t * header, size_t headerLen, const uint8_t * headerX, size_t headerXLen,
const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to)
{
std::vector<boost::asio::const_buffer> bufs
{
boost::asio::buffer (header, headerLen),
boost::asio::buffer (headerX, headerXLen),
boost::asio::buffer (payload, payloadLen)
};
boost::system::error_code ec;
if (to.address ().is_v6 ())
m_SocketV6.send_to (bufs, to, 0, ec);
else
m_SocketV4.send_to (bufs, to, 0, ec);
if (!ec)
i2p::transport::transports.UpdateSentBytes (headerLen + headerXLen + payloadLen);
else
LogPrint (eLogError, "SSU2: Send exception: ", ec.message (), " to ", to);
}
bool SSU2Server::CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
std::shared_ptr<const i2p::data::RouterInfo::Address> address)
{
if (router && address)
{
if (address->UsesIntroducer ())
GetService ().post (std::bind (&SSU2Server::ConnectThroughIntroducer, this, router, address));
else
GetService ().post (
[this, router, address]()
{
auto session = std::make_shared<SSU2Session> (*this, router, address);
session->Connect ();
});
}
else
return false;
return true;
}
void SSU2Server::ConnectThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router,
std::shared_ptr<const i2p::data::RouterInfo::Address> address)
{
auto session = std::make_shared<SSU2Session> (*this, router, address);
session->SetState (eSSU2SessionStateIntroduced);
// try to find existing session first
for (auto& it: address->ssu->introducers)
{
auto it1 = m_SessionsByRouterHash.find (it.iKey);
if (it1 != m_SessionsByRouterHash.end ())
{
it1->second->Introduce (session, it.iTag);
return;
}
}
// we have to start a new session to an introducer
std::shared_ptr<i2p::data::RouterInfo> r;
uint32_t relayTag = 0;
for (auto& it: address->ssu->introducers)
{
r = i2p::data::netdb.FindRouter (it.iKey);
if (r && r->IsReachableFrom (i2p::context.GetRouterInfo ()))
{
relayTag = it.iTag;
if (relayTag) break;
}
}
if (r)
{
if (relayTag)
{
// introducer and tag found connect to it through SSU2
auto addr = address->IsV6 () ? r->GetSSU2V6Address () : r->GetSSU2V4Address ();
if (addr)
{
auto s = std::make_shared<SSU2Session> (*this, r, addr);
s->SetOnEstablished (
[session, s, relayTag]()
{
s->Introduce (session, relayTag);
});
s->Connect ();
}
}
}
else
{
// introducers not found, try to request them
for (auto& it: address->ssu->introducers)
i2p::data::netdb.RequestDestination (it.iKey);
}
}
bool SSU2Server::StartPeerTest (std::shared_ptr<const i2p::data::RouterInfo> router, bool v4)
{
if (!router) return false;
auto addr = v4 ? router->GetSSU2V4Address () : router->GetSSU2V6Address ();
if (!addr) return false;
auto it = m_SessionsByRouterHash.find (router->GetIdentHash ());
if (it != m_SessionsByRouterHash.end ())
{
if (it->second->IsEstablished ())
it->second->SendPeerTest ();
else
{
auto s = it->second;
s->SetOnEstablished ([s]() { s->SendPeerTest (); });
}
return true;
}
auto s = std::make_shared<SSU2Session> (*this, router, addr);
s->SetOnEstablished ([s]() {s->SendPeerTest (); });
s->Connect ();
return true;
}
void SSU2Server::ScheduleTermination ()
{
m_TerminationTimer.expires_from_now (boost::posix_time::seconds(SSU2_TERMINATION_CHECK_TIMEOUT));
m_TerminationTimer.async_wait (std::bind (&SSU2Server::HandleTerminationTimer,
this, std::placeholders::_1));
}
void SSU2Server::HandleTerminationTimer (const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
{
auto ts = i2p::util::GetSecondsSinceEpoch ();
for (auto it = m_PendingOutgoingSessions.begin (); it != m_PendingOutgoingSessions.end ();)
{
if (it->second->IsTerminationTimeoutExpired (ts))
{
//it->second->Terminate ();
it = m_PendingOutgoingSessions.erase (it);
}
else
it++;
}
for (auto it = m_Sessions.begin (); it != m_Sessions.end ();)
{
if (it->second->IsTerminationTimeoutExpired (ts))
{
if (it->second->IsEstablished ())
it->second->TerminateByTimeout ();
if (it->second == m_LastSession)
m_LastSession = nullptr;
it = m_Sessions.erase (it);
}
else
{
it->second->CleanUp (ts);
it++;
}
}
for (auto it = m_IncomingTokens.begin (); it != m_IncomingTokens.end (); )
{
if (ts > it->second.second)
it = m_IncomingTokens.erase (it);
else
it++;
}
for (auto it = m_OutgoingTokens.begin (); it != m_OutgoingTokens.end (); )
{
if (ts > it->second.second)
it = m_OutgoingTokens.erase (it);
else
it++;
}
ScheduleTermination ();
}
}
void SSU2Server::ScheduleResend ()
{
m_ResendTimer.expires_from_now (boost::posix_time::seconds(SSU2_RESEND_INTERVAL));
m_ResendTimer.async_wait (std::bind (&SSU2Server::HandleResendTimer,
this, std::placeholders::_1));
}
void SSU2Server::HandleResendTimer (const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
{
auto ts = i2p::util::GetSecondsSinceEpoch ();
for (auto it: m_Sessions)
it.second->Resend (ts);
ScheduleResend ();
}
}
void SSU2Server::UpdateOutgoingToken (const boost::asio::ip::udp::endpoint& ep, uint64_t token, uint32_t exp)
{
m_OutgoingTokens[ep] = {token, exp};
}
uint64_t SSU2Server::FindOutgoingToken (const boost::asio::ip::udp::endpoint& ep) const
{
auto it = m_OutgoingTokens.find (ep);
if (it != m_OutgoingTokens.end ())
return it->second.first;
return 0;
}
uint64_t SSU2Server::GetIncomingToken (const boost::asio::ip::udp::endpoint& ep)
{
auto it = m_IncomingTokens.find (ep);
if (it != m_IncomingTokens.end ())
return it->second.first;
uint64_t token;
RAND_bytes ((uint8_t *)&token, 8);
m_IncomingTokens.emplace (ep, std::make_pair (token, i2p::util::GetSecondsSinceEpoch () + SSU2_TOKEN_EXPIRATION_TIMEOUT));
return token;
}
}
}

View File

@@ -9,60 +9,105 @@
#ifndef SSU2_H__
#define SSU2_H__
#include <memory>
#include "Crypto.h"
#include "RouterInfo.h"
#include "TransportSession.h"
#include <unordered_map>
#include "util.h"
#include "SSU2Session.h"
namespace i2p
{
namespace transport
{
const int SSU2_TERMINATION_TIMEOUT = 330; // 5.5 minutes
enum SSU2MessageType
const int SSU2_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds
const size_t SSU2_SOCKET_RECEIVE_BUFFER_SIZE = 0x1FFFF; // 128K
const size_t SSU2_SOCKET_SEND_BUFFER_SIZE = 0x1FFFF; // 128K
class SSU2Server: private i2p::util::RunnableServiceWithWork
{
eSSU2SessionRequest = 0
};
class SSU2Session: public TransportSession, public std::enable_shared_from_this<SSU2Session>
{
union Header
struct Packet
{
uint64_t ll[2];
uint8_t buf[16];
struct
{
uint8_t connID[8];
uint8_t packetNum[4];
uint8_t type;
uint8_t flags[3];
} h;
uint8_t buf[SSU2_MTU];
size_t len;
boost::asio::ip::udp::endpoint from;
};
class ReceiveService: public i2p::util::RunnableService
{
public:
ReceiveService (const std::string& name): RunnableService (name) {};
boost::asio::io_service& GetService () { return GetIOService (); };
void Start () { StartIOService (); };
void Stop () { StopIOService (); };
};
public:
SSU2Session (std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter = nullptr,
std::shared_ptr<const i2p::data::RouterInfo::Address> addr = nullptr, bool peerTest = false);
~SSU2Session ();
SSU2Server ();
~SSU2Server () {};
private:
void Start ();
void Stop ();
boost::asio::io_service& GetService () { return GetIOService (); };
void SendSessionRequest ();
void EncryptHeader (Header& h);
void CreateHeaderMask (const uint8_t * kh1, const uint8_t * nonce1, const uint8_t * kh2, const uint8_t * nonce2);
void AddSession (std::shared_ptr<SSU2Session> session);
void RemoveSession (uint64_t connID);
void AddSessionByRouterHash (std::shared_ptr<SSU2Session> session);
void AddPendingOutgoingSession (std::shared_ptr<SSU2Session> session);
std::shared_ptr<SSU2Session> FindSession (const i2p::data::IdentHash& ident) const;
void AddRelay (uint32_t tag, std::shared_ptr<SSU2Session> relay);
void RemoveRelay (uint32_t tag);
std::shared_ptr<SSU2Session> FindRelaySession (uint32_t tag);
void Send (const uint8_t * header, size_t headerLen, const uint8_t * payload, size_t payloadLen,
const boost::asio::ip::udp::endpoint& to);
void Send (const uint8_t * header, size_t headerLen, const uint8_t * headerX, size_t headerXLen,
const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to);
bool CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
std::shared_ptr<const i2p::data::RouterInfo::Address> address);
bool StartPeerTest (std::shared_ptr<const i2p::data::RouterInfo> router, bool v4);
void UpdateOutgoingToken (const boost::asio::ip::udp::endpoint& ep, uint64_t token, uint32_t exp);
uint64_t FindOutgoingToken (const boost::asio::ip::udp::endpoint& ep) const;
uint64_t GetIncomingToken (const boost::asio::ip::udp::endpoint& ep);
private:
std::shared_ptr<i2p::crypto::X25519Keys> m_EphemeralKeys;
std::unique_ptr<i2p::crypto::NoiseSymmetricState> m_NoiseState;
std::shared_ptr<const i2p::data::RouterInfo::Address> m_Address;
boost::asio::ip::udp::socket& OpenSocket (const boost::asio::ip::udp::endpoint& localEndpoint);
void Receive (boost::asio::ip::udp::socket& socket);
void HandleReceivedFrom (const boost::system::error_code& ecode, size_t bytes_transferred,
Packet * packet, boost::asio::ip::udp::socket& socket);
void HandleReceivedPacket (Packet * packet);
void HandleReceivedPackets (std::vector<Packet *> packets);
void ProcessNextPacket (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
union
{
uint64_t ll[2];
uint8_t buf[16];
} m_HeaderMask;
void ScheduleTermination ();
void HandleTerminationTimer (const boost::system::error_code& ecode);
void ScheduleResend ();
void HandleResendTimer (const boost::system::error_code& ecode);
void ConnectThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router,
std::shared_ptr<const i2p::data::RouterInfo::Address> address);
private:
ReceiveService m_ReceiveService;
boost::asio::ip::udp::socket m_SocketV4, m_SocketV6;
std::unordered_map<uint64_t, std::shared_ptr<SSU2Session> > m_Sessions;
std::map<i2p::data::IdentHash, std::shared_ptr<SSU2Session> > m_SessionsByRouterHash;
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSU2Session> > m_PendingOutgoingSessions;
std::map<boost::asio::ip::udp::endpoint, std::pair<uint64_t, uint32_t> > m_IncomingTokens, m_OutgoingTokens; // remote endpoint -> (token, expires in seconds)
std::map<uint32_t, std::shared_ptr<SSU2Session> > m_Relays; // we are introducer, relay tag -> session
i2p::util::MemoryPoolMt<Packet> m_PacketsPool;
boost::asio::deadline_timer m_TerminationTimer, m_ResendTimer;
std::shared_ptr<SSU2Session> m_LastSession;
public:
// for HTTP/I2PControl
const decltype(m_Sessions)& GetSSU2Sessions () const { return m_Sessions; };
};
}
}

1843
libi2pd/SSU2Session.cpp Normal file

File diff suppressed because it is too large Load Diff

273
libi2pd/SSU2Session.h Normal file
View File

@@ -0,0 +1,273 @@
/*
* Copyright (c) 2022, 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 SSU2_SESSION_H__
#define SSU2_SESSION_H__
#include <memory>
#include <functional>
#include <map>
#include <set>
#include <list>
#include <boost/asio.hpp>
#include "Crypto.h"
#include "RouterInfo.h"
#include "TransportSession.h"
namespace i2p
{
namespace transport
{
const int SSU2_CONNECT_TIMEOUT = 5; // 5 seconds
const int SSU2_TERMINATION_TIMEOUT = 330; // 5.5 minutes
const int SSU2_TOKEN_EXPIRATION_TIMEOUT = 9; // in seconds
const int SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT = 10; // in seconds
const int SSU2_PEER_TEST_EXPIRATION_TIMEOUT = 60; // 60 seconds
const size_t SSU2_MTU = 1488;
const size_t SSU2_MAX_PAYLOAD_SIZE = SSU2_MTU - 32;
const int SSU2_RESEND_INTERVAL = 3; // in seconds
const int SSU2_MAX_NUM_RESENDS = 5;
const int SSU2_INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds
const size_t SSU2_MAX_WINDOW_SIZE = 128; // in packets
enum SSU2MessageType
{
eSSU2SessionRequest = 0,
eSSU2SessionCreated = 1,
eSSU2SessionConfirmed = 2,
eSSU2Data = 6,
eSSU2PeerTest = 7,
eSSU2Retry = 9,
eSSU2TokenRequest = 10,
eSSU2HolePunch = 11
};
enum SSU2BlockType
{
eSSU2BlkDateTime = 0,
eSSU2BlkOptions, // 1
eSSU2BlkRouterInfo, // 2
eSSU2BlkI2NPMessage, // 3
eSSU2BlkFirstFragment, // 4
eSSU2BlkFollowOnFragment, // 5
eSSU2BlkTermination, // 6
eSSU2BlkRelayRequest, // 7
eSSU2BlkRelayResponse, // 8
eSSU2BlkRelayIntro, // 9
eSSU2BlkPeerTest, // 10
eSSU2BlkNextNonce, // 11
eSSU2BlkAck, // 12
eSSU2BlkAddress, // 13
eSSU2BlkIntroKey, // 14
eSSU2BlkRelayTagRequest, // 15
eSSU2BlkRelayTag, // 16
eSSU2BlkNewToken, // 17
eSSU2BlkPathChallenge, // 18
eSSU2BlkPathResponse, // 19
eSSU2BlkFirstPacketNumber, // 20
eSSU2BlkPadding = 254
};
enum SSU2SessionState
{
eSSU2SessionStateUnknown,
eSSU2SessionStateIntroduced,
eSSU2SessionStatePeerTest,
eSSU2SessionStateEstablished,
eSSU2SessionStateTerminated,
eSSU2SessionStateFailed
};
enum SSU2PeerTestCode
{
eSSU2PeerTestCodeAccept = 0,
eSSU2PeerTestCodeBobReasonUnspecified = 1,
eSSU2PeerTestCodeBobNoCharlieAvailable = 2,
eSSU2PeerTestCodeBobLimitExceeded = 3,
eSSU2PeerTestCodeBobSignatureFailure = 4,
eSSU2PeerTestCodeCharlieReasonUnspecified = 64,
eSSU2PeerTestCodeCharlieUnsupportedAddress = 65,
eSSU2PeerTestCodeCharlieLimitExceeded = 66,
eSSU2PeerTestCodeCharlieSignatureFailure = 67,
eSSU2PeerTestCodeCharlieAliceIsAlreadyConnected = 68,
eSSU2PeerTestCodeCharlieAliceIsBanned = 69,
eSSU2PeerTestCodeCharlieAliceIsUnknown = 70,
eSSU2PeerTestCodeUnspecified = 128
};
struct SSU2IncompleteMessage
{
struct Fragment
{
uint8_t buf[SSU2_MTU];
size_t len;
bool isLast;
};
std::shared_ptr<I2NPMessage> msg;
int nextFragmentNum;
uint32_t lastFragmentInsertTime; // in seconds
std::map<int, std::shared_ptr<Fragment> > outOfSequenceFragments;
};
// RouterInfo flags
const uint8_t SSU2_ROUTER_INFO_FLAG_REQUEST_FLOOD = 0x01;
const uint8_t SSU2_ROUTER_INFO_FLAG_GZIP = 0x02;
class SSU2Server;
class SSU2Session: public TransportSession, public std::enable_shared_from_this<SSU2Session>
{
union Header
{
uint64_t ll[2];
uint8_t buf[16];
struct
{
uint64_t connID;
uint32_t packetNum;
uint8_t type;
uint8_t flags[3];
} h;
};
struct SentPacket
{
uint8_t payload[SSU2_MAX_PAYLOAD_SIZE];
size_t payloadSize = 0;
uint32_t nextResendTime; // in seconds
int numResends = 0;
};
struct SessionConfirmedFragment
{
Header header;
uint8_t payload[SSU2_MAX_PAYLOAD_SIZE];
size_t payloadSize;
};
typedef std::function<void ()> OnEstablished;
public:
SSU2Session (SSU2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter = nullptr,
std::shared_ptr<const i2p::data::RouterInfo::Address> addr = nullptr);
~SSU2Session ();
void SetRemoteEndpoint (const boost::asio::ip::udp::endpoint& ep) { m_RemoteEndpoint = ep; };
const boost::asio::ip::udp::endpoint& GetRemoteEndpoint () const { return m_RemoteEndpoint; };
void SetOnEstablished (OnEstablished e) { m_OnEstablished = e; };
void Connect ();
bool Introduce (std::shared_ptr<SSU2Session> session, uint32_t relayTag);
void SendPeerTest (); // Alice, Data message
void Terminate ();
void TerminateByTimeout ();
void CleanUp (uint64_t ts);
void FlushData ();
void Done () override;
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) override;
void Resend (uint64_t ts);
bool IsEstablished () const { return m_State == eSSU2SessionStateEstablished; };
uint64_t GetConnID () const { return m_SourceConnID; };
SSU2SessionState GetState () const { return m_State; };
void SetState (SSU2SessionState state) { m_State = state; };
bool ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len);
bool ProcessSessionCreated (uint8_t * buf, size_t len);
bool ProcessSessionConfirmed (uint8_t * buf, size_t len);
bool ProcessRetry (uint8_t * buf, size_t len);
bool ProcessHolePunch (uint8_t * buf, size_t len);
bool ProcessPeerTest (uint8_t * buf, size_t len);
void ProcessData (uint8_t * buf, size_t len);
private:
void Established ();
void PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs);
bool SendQueue ();
void SendFragmentedMessage (std::shared_ptr<I2NPMessage> msg);
void ProcessSessionRequest (Header& header, uint8_t * buf, size_t len);
void ProcessTokenRequest (Header& header, uint8_t * buf, size_t len);
void SendSessionRequest (uint64_t token = 0);
void SendSessionCreated (const uint8_t * X);
void SendSessionConfirmed (const uint8_t * Y);
void KDFDataPhase (uint8_t * keydata_ab, uint8_t * keydata_ba);
void SendTokenRequest ();
void SendRetry ();
uint32_t SendData (const uint8_t * buf, size_t len); // returns packet num
void SendQuickAck ();
void SendTermination ();
void SendHolePunch (uint32_t nonce, const boost::asio::ip::udp::endpoint& ep, const uint8_t * introKey);
void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, const uint8_t * introKey); // PeerTest message
void HandlePayload (const uint8_t * buf, size_t len);
void HandleAck (const uint8_t * buf, size_t len);
void HandleAckRange (uint32_t firstPacketNum, uint32_t lastPacketNum);
bool ExtractEndpoint (const uint8_t * buf, size_t size, boost::asio::ip::udp::endpoint& ep);
size_t CreateEndpoint (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep);
std::shared_ptr<const i2p::data::RouterInfo::Address> FindLocalAddress () const;
std::shared_ptr<const i2p::data::RouterInfo> ExtractRouterInfo (const uint8_t * buf, size_t size);
void CreateNonce (uint64_t seqn, uint8_t * nonce);
bool UpdateReceivePacketNum (uint32_t packetNum); // for Ack, returns false if duplicate
void HandleFirstFragment (const uint8_t * buf, size_t len);
void HandleFollowOnFragment (const uint8_t * buf, size_t len);
bool ConcatOutOfSequenceFragments (std::shared_ptr<SSU2IncompleteMessage> m); // true if message complete
void HandleRelayRequest (const uint8_t * buf, size_t len);
void HandleRelayIntro (const uint8_t * buf, size_t len);
void HandleRelayResponse (const uint8_t * buf, size_t len);
void HandlePeerTest (const uint8_t * buf, size_t len);
size_t CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep);
size_t CreateRouterInfoBlock (uint8_t * buf, size_t len, std::shared_ptr<const i2p::data::RouterInfo> r);
size_t CreateAckBlock (uint8_t * buf, size_t len);
size_t CreatePaddingBlock (uint8_t * buf, size_t len, size_t minSize = 0);
size_t CreateI2NPBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage>&& msg);
size_t CreateFirstFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage> msg);
size_t CreateFollowOnFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage> msg, uint8_t& fragmentNum, uint32_t msgID);
size_t CreateRelayIntroBlock (uint8_t * buf, size_t len, const uint8_t * introData, size_t introDataLen);
size_t CreateRelayResponseBlock (uint8_t * buf, size_t len, uint32_t nonce); // Charlie
size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint8_t msg, SSU2PeerTestCode code, const uint8_t * routerHash, const uint8_t * signedData, size_t signedDataLen);
size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint32_t nonce); // Alice
private:
SSU2Server& m_Server;
std::shared_ptr<i2p::crypto::X25519Keys> m_EphemeralKeys;
std::unique_ptr<i2p::crypto::NoiseSymmetricState> m_NoiseState;
std::unique_ptr<SessionConfirmedFragment> m_SessionConfirmedFragment1; // for Bob if applicable
std::shared_ptr<const i2p::data::RouterInfo::Address> m_Address;
boost::asio::ip::udp::endpoint m_RemoteEndpoint;
uint64_t m_DestConnID, m_SourceConnID;
SSU2SessionState m_State;
uint8_t m_KeyDataSend[64], m_KeyDataReceive[64];
uint32_t m_SendPacketNum, m_ReceivePacketNum;
std::set<uint32_t> m_OutOfSequencePackets; // packet nums > receive packet num
std::map<uint32_t, std::shared_ptr<SentPacket> > m_SentPackets; // packetNum -> packet
std::map<uint32_t, std::shared_ptr<SSU2IncompleteMessage> > m_IncompleteMessages; // I2NP
std::map<uint32_t, std::pair <std::shared_ptr<SSU2Session>, uint64_t > > m_RelaySessions; // nonce->(Alice, timestamp) for Bob or nonce->(Charlie, timestamp) for Alice
std::map<uint32_t, std::pair <std::shared_ptr<SSU2Session>, uint64_t > > m_PeerTests; // same as for relay sessions
std::list<std::shared_ptr<I2NPMessage> > m_SendQueue;
i2p::I2NPMessagesHandler m_Handler;
bool m_IsDataReceived;
size_t m_WindowSize;
uint32_t m_RelayTag; // between Bob and Charlie
OnEstablished m_OnEstablished; // callback from Established
};
inline uint64_t CreateHeaderMask (const uint8_t * kh, const uint8_t * nonce)
{
uint64_t data = 0;
i2p::crypto::ChaCha20 ((uint8_t *)&data, 8, kh, nonce, (uint8_t *)&data);
return data;
}
}
}
#endif

View File

@@ -171,7 +171,7 @@ namespace transport
return;
}
// find message with msgID
// find message with msgID
auto it = m_IncompleteMessages.find (msgID);
if (it == m_IncompleteMessages.end ())
{
@@ -318,7 +318,7 @@ namespace transport
sentMessage->numResends = 0;
}
auto& fragments = sentMessage->fragments;
size_t payloadSize = m_PacketSize - sizeof (SSUHeader) - 9; // 9 = flag + #frg(1) + messageID(4) + frag info (3)
size_t payloadSize = m_PacketSize - sizeof (SSUHeader) - 9; // 9 = flag + #frg(1) + messageID(4) + frag info (3)
size_t len = msg->GetLength ();
uint8_t * msgBuf = msg->GetSSUHeader ();

View File

@@ -26,11 +26,7 @@ namespace transport
{
const size_t SSU_MTU_V4 = 1484;
#ifdef MESHNET
const size_t SSU_MTU_V6 = 1286;
#else
const size_t SSU_MTU_V6 = 1488;
#endif
const size_t IPV4_HEADER_SIZE = 20;
const size_t IPV6_HEADER_SIZE = 40;
const size_t UDP_HEADER_SIZE = 8;

View File

@@ -296,8 +296,8 @@ namespace transport
{
LogPrint (eLogWarning, "SSU: Clock adjusted by ", -offset, " seconds");
i2p::util::AdjustTimeOffset (-offset);
}
}
}
}
else if (std::abs (offset) > SSU_CLOCK_SKEW)
{
LogPrint (eLogError, "SSU: Clock skew detected ", offset, ". Check your clock");
@@ -388,11 +388,11 @@ namespace transport
// fill extended options, 3 bytes extended options don't change message size
bool isV4 = m_RemoteEndpoint.address ().is_v4 ();
if ((isV4 && i2p::context.GetStatus () == eRouterStatusOK) ||
(!isV4 && i2p::context.GetStatusV6 () == eRouterStatusOK)) // we don't need relays
(!isV4 && i2p::context.GetStatusV6 () == 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
*payload = 2; payload++; // 1 byte length
uint16_t flags = 0; // clear EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG
htobe16buf (payload, flags);
payload += 2;
@@ -1020,7 +1020,7 @@ namespace transport
for (auto it = m_RelayRequests.begin (); it != m_RelayRequests.end ();)
{
if (ts > it->second.second + SSU_CONNECT_TIMEOUT)
it = m_RelayRequests.erase (it);
it = m_RelayRequests.erase (it);
else
++it;
}

View File

@@ -130,7 +130,7 @@ namespace crypto
else
{
size_t l = 64;
uint8_t sig[64]; // temporary buffer for signature. openssl issue #7232
uint8_t sig[64]; // temporary buffer for signature. openssl issue #7232
EVP_DigestSign (m_MDCtx, sig, &l, buf, len);
memcpy (signature, sig, 64);
}

View File

@@ -1249,7 +1249,7 @@ namespace stream
return s;
}
void StreamingDestination::SendPing (std::shared_ptr<const i2p::data::LeaseSet> remote)
void StreamingDestination::SendPing (std::shared_ptr<const i2p::data::LeaseSet> remote)
{
auto s = std::make_shared<Stream> (m_Owner->GetService (), *this, remote, 0);
s->SendPing ();
@@ -1277,7 +1277,7 @@ namespace stream
{
m_PacketsPool.CleanUp ();
m_I2NPMsgsPool.CleanUp ();
}
}
}
bool StreamingDestination::DeleteStream (uint32_t recvStreamID)
@@ -1285,7 +1285,13 @@ namespace stream
auto it = m_Streams.find (recvStreamID);
if (it == m_Streams.end ())
return false;
DeleteStream (it->second);
auto s = it->second;
m_Owner->GetService ().post ([this, s] ()
{
s->Close (); // try to send FIN
s->Terminate (false);
DeleteStream (s);
});
return true;
}

View File

@@ -254,6 +254,6 @@ namespace util
void AdjustTimeOffset (int64_t offset)
{
g_TimeOffset += offset;
}
}
}
}

View File

@@ -27,7 +27,7 @@ namespace util
void GetCurrentDate (char * date); // returns date as YYYYMMDD string, 9 bytes
void GetDateString (uint64_t timestamp, char * date); // timestap is seconds since epoch, returns date as YYYYMMDD string, 9 bytes
void AdjustTimeOffset (int64_t offset); // in seconds from current
class NTPTimeSync
{
public:

View File

@@ -136,7 +136,7 @@ namespace transport
Transports::Transports ():
m_IsOnline (true), m_IsRunning (false), m_IsNAT (true), m_CheckReserved(true), m_Thread (nullptr),
m_Service (nullptr), m_Work (nullptr), m_PeerCleanupTimer (nullptr), m_PeerTestTimer (nullptr),
m_SSUServer (nullptr), m_NTCP2Server (nullptr),
m_SSUServer (nullptr), m_SSU2Server (nullptr), m_NTCP2Server (nullptr),
m_X25519KeysPairSupplier (15), // 15 pre-generated keys
m_TotalSentBytes(0), m_TotalReceivedBytes(0), m_TotalTransitTransmittedBytes (0),
m_InBandwidth (0), m_OutBandwidth (0), m_TransitBandwidth(0),
@@ -157,7 +157,7 @@ namespace transport
}
}
void Transports::Start (bool enableNTCP2, bool enableSSU)
void Transports::Start (bool enableNTCP2, bool enableSSU, bool enableSSU2)
{
if (!m_Service)
{
@@ -217,6 +217,8 @@ namespace transport
}
}
}
// create SSU2 server
if (enableSSU2) m_SSU2Server = new SSU2Server ();
// bind to interfaces
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
@@ -266,6 +268,7 @@ namespace transport
// start servers
if (m_NTCP2Server) m_NTCP2Server->Start ();
if (m_SSU2Server) m_SSU2Server->Start ();
if (m_SSUServer)
{
LogPrint (eLogInfo, "Transports: Start listening UDP port ", ssuPort);
@@ -305,6 +308,13 @@ namespace transport
m_SSUServer = nullptr;
}
if (m_SSU2Server)
{
m_SSU2Server->Stop ();
delete m_SSU2Server;
m_SSU2Server = nullptr;
}
if (m_NTCP2Server)
{
m_NTCP2Server->Stop ();
@@ -526,6 +536,40 @@ namespace transport
}
}
}
if (peer.numAttempts == 5 || peer.numAttempts == 6) // SSU2
{
if (m_SSU2Server)
{
std::shared_ptr<const RouterInfo::Address> address;
if (peer.numAttempts == 5) // SSU2 ipv6
{
if (context.GetRouterInfo ().IsSSU2V6 () && peer.router->IsReachableBy (RouterInfo::eSSU2V6))
{
address = peer.router->GetSSU2V6Address ();
if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host))
address = nullptr;
}
peer.numAttempts++;
}
if (!address && peer.numAttempts == 6) // SSU2 ipv4
{
if (context.GetRouterInfo ().IsSSU2V4 () && peer.router->IsReachableBy (RouterInfo::eSSU2V4))
{
address = peer.router->GetSSU2V4Address ();
if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host))
address = nullptr;
}
peer.numAttempts++;
}
if (address && address->IsReachableSSU ())
{
if (m_SSU2Server->CreateSession (peer.router, address))
return true;
}
}
else
peer.numAttempts += 2;
}
LogPrint (eLogInfo, "Transports: No compatble NTCP2 or SSU addresses available");
i2p::data::netdb.SetUnreachable (ident, true); // we are here because all connection attempts failed
peer.Done ();
@@ -610,6 +654,16 @@ namespace transport
}
if (!statusChanged)
LogPrint (eLogWarning, "Transports: Can't find routers for peer test IPv4");
// SSU2
if (m_SSU2Server)
{
excluded.clear ();
excluded.insert (i2p::context.GetIdentHash ());
auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (true, excluded); // v4
if (router)
m_SSU2Server->StartPeerTest (router, true);
}
}
if (ipv6 && i2p::context.SupportsV6 ())
{
@@ -637,6 +691,16 @@ namespace transport
}
if (!statusChanged)
LogPrint (eLogWarning, "Transports: Can't find routers for peer test IPv6");
// SSU2
if (m_SSU2Server)
{
excluded.clear ();
excluded.insert (i2p::context.GetIdentHash ());
auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (false, excluded); // v6
if (router)
m_SSU2Server->StartPeerTest (router, false);
}
}
}
@@ -785,12 +849,18 @@ namespace transport
}
return i2p::data::netdb.FindRouter (ident);
}
void Transports::RestrictRoutesToFamilies(std::set<std::string> families)
void Transports::RestrictRoutesToFamilies(const std::set<std::string>& families)
{
std::lock_guard<std::mutex> lock(m_FamilyMutex);
m_TrustedFamilies.clear();
for ( const auto& fam : families )
m_TrustedFamilies.push_back(fam);
for (auto fam : families)
{
boost::to_lower (fam);
auto id = i2p::data::netdb.GetFamilies ().GetFamilyID (fam);
if (id)
m_TrustedFamilies.push_back (id);
}
}
void Transports::RestrictRoutesToRouters(std::set<i2p::data::IdentHash> routers)
@@ -812,20 +882,19 @@ namespace transport
{
{
std::lock_guard<std::mutex> l(m_FamilyMutex);
std::string fam;
i2p::data::FamilyID fam = 0;
auto sz = m_TrustedFamilies.size();
if(sz > 1)
{
auto it = m_TrustedFamilies.begin ();
std::advance(it, rand() % sz);
fam = *it;
boost::to_lower(fam);
}
else if (sz == 1)
{
fam = m_TrustedFamilies[0];
}
if (fam.size())
if (fam)
return i2p::data::netdb.GetRandomRouterInFamily(fam);
}
{

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
* Copyright (c) 2013-2022, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -22,6 +22,7 @@
#include <boost/asio.hpp>
#include "TransportSession.h"
#include "SSU.h"
#include "SSU2.h"
#include "NTCP2.h"
#include "RouterInfo.h"
#include "I2NPProtocol.h"
@@ -86,7 +87,7 @@ namespace transport
Transports ();
~Transports ();
void Start (bool enableNTCP2=true, bool enableSSU=true);
void Start (bool enableNTCP2=true, bool enableSSU=true, bool enableSSU2=false);
void Stop ();
bool IsBoundSSU() const { return m_SSUServer != nullptr; }
@@ -125,7 +126,7 @@ namespace transport
/** do we want to use restricted routes? */
bool RoutesRestricted() const;
/** restrict routes to use only these router families for first hops */
void RestrictRoutesToFamilies(std::set<std::string> families);
void RestrictRoutesToFamilies(const std::set<std::string>& families);
/** restrict routes to use only these routers for first hops */
void RestrictRoutesToRouters(std::set<i2p::data::IdentHash> routers);
@@ -159,6 +160,7 @@ namespace transport
boost::asio::deadline_timer * m_PeerCleanupTimer, * m_PeerTestTimer;
SSUServer * m_SSUServer;
SSU2Server * m_SSU2Server;
NTCP2Server * m_NTCP2Server;
mutable std::mutex m_PeersMutex;
std::unordered_map<i2p::data::IdentHash, Peer> m_Peers;
@@ -171,7 +173,7 @@ namespace transport
uint64_t m_LastBandwidthUpdateTime;
/** which router families to trust for first hops */
std::vector<std::string> m_TrustedFamilies;
std::vector<i2p::data::FamilyID> m_TrustedFamilies;
mutable std::mutex m_FamilyMutex;
/** which routers for first hop to trust */
@@ -185,6 +187,7 @@ namespace transport
// for HTTP only
const SSUServer * GetSSUServer () const { return m_SSUServer; };
const NTCP2Server * GetNTCP2Server () const { return m_NTCP2Server; };
const SSU2Server * GetSSU2Server () const { return m_SSU2Server; };
const decltype(m_Peers)& GetPeers () const { return m_Peers; };
};

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2021, The PurpleI2P Project
* Copyright (c) 2013-2022, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -108,13 +108,13 @@ namespace tunnel
else
{
if (m_Config->IsShort () && m_Config->GetLastHop () &&
m_Config->GetLastHop ()->ident->GetIdentHash () != m_Config->GetLastHop ()->nextIdent)
m_Config->GetLastHop ()->ident->GetIdentHash () != m_Config->GetLastHop ()->nextIdent)
{
// add garlic key/tag for reply
uint8_t key[32];
uint64_t tag = m_Config->GetLastHop ()->GetGarlicKey (key);
if (m_Pool && m_Pool->GetLocalDestination ())
m_Pool->GetLocalDestination ()->AddECIESx25519Key (key, tag);
m_Pool->GetLocalDestination ()->SubmitECIESx25519Key (key, tag);
else
i2p::context.AddECIESx25519Key (key, tag);
}
@@ -235,15 +235,11 @@ namespace tunnel
m_State = state;
}
void Tunnel::PrintHops (std::stringstream& s) const
void Tunnel::VisitTunnelHops(TunnelHopVisitor v)
{
// hops are in inverted order, we must print in direct order
// hops are in inverted order, we must return in direct order
for (auto it = m_Hops.rbegin (); it != m_Hops.rend (); it++)
{
s << " &#8658; ";
s << i2p::data::GetIdentHashAbbreviation ((*it).ident->GetIdentHash ());
}
v((*it).ident);
}
void InboundTunnel::HandleTunnelDataMsg (std::shared_ptr<I2NPMessage>&& msg)
@@ -254,12 +250,6 @@ namespace tunnel
m_Endpoint.HandleDecryptedTunnelDataMsg (msg);
}
void InboundTunnel::Print (std::stringstream& s) const
{
PrintHops (s);
s << " &#8658; " << GetTunnelID () << ":me";
}
ZeroHopsInboundTunnel::ZeroHopsInboundTunnel ():
InboundTunnel (std::make_shared<ZeroHopsTunnelConfig> ()),
m_NumReceivedBytes (0)
@@ -276,11 +266,6 @@ namespace tunnel
}
}
void ZeroHopsInboundTunnel::Print (std::stringstream& s) const
{
s << " &#8658; " << GetTunnelID () << ":me";
}
void OutboundTunnel::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg)
{
TunnelMessageBlock block;
@@ -315,13 +300,6 @@ namespace tunnel
LogPrint (eLogError, "Tunnel: Incoming message for outbound tunnel ", GetTunnelID ());
}
void OutboundTunnel::Print (std::stringstream& s) const
{
s << GetTunnelID () << ":me";
PrintHops (s);
s << " &#8658; ";
}
ZeroHopsOutboundTunnel::ZeroHopsOutboundTunnel ():
OutboundTunnel (std::make_shared<ZeroHopsTunnelConfig> ()),
m_NumSentBytes (0)
@@ -351,11 +329,6 @@ namespace tunnel
}
}
void ZeroHopsOutboundTunnel::Print (std::stringstream& s) const
{
s << GetTunnelID () << ":me &#8658; ";
}
Tunnels tunnels;
Tunnels::Tunnels (): m_IsRunning (false), m_Thread (nullptr),
@@ -430,10 +403,10 @@ namespace tunnel
return tunnel;
}
std::shared_ptr<TunnelPool> Tunnels::CreateTunnelPool (int numInboundHops,
int numOutboundHops, int numInboundTunnels, int numOutboundTunnels)
std::shared_ptr<TunnelPool> Tunnels::CreateTunnelPool (int numInboundHops, int numOutboundHops,
int numInboundTunnels, int numOutboundTunnels, int inboundVariance, int outboundVariance)
{
auto pool = std::make_shared<TunnelPool> (numInboundHops, numOutboundHops, numInboundTunnels, numOutboundTunnels);
auto pool = std::make_shared<TunnelPool> (numInboundHops, numOutboundHops, numInboundTunnels, numOutboundTunnels, inboundVariance, outboundVariance);
std::unique_lock<std::mutex> l(m_PoolsMutex);
m_Pools.push_back (pool);
return pool;
@@ -783,7 +756,7 @@ namespace tunnel
int obLen; i2p::config::GetOption("exploratory.outbound.length", obLen);
int ibNum; i2p::config::GetOption("exploratory.inbound.quantity", ibNum);
int obNum; i2p::config::GetOption("exploratory.outbound.quantity", obNum);
m_ExploratoryPool = CreateTunnelPool (ibLen, obLen, ibNum, obNum);
m_ExploratoryPool = CreateTunnelPool (ibLen, obLen, ibNum, obNum, 0, 0);
m_ExploratoryPool->SetLocalDestination (i2p::context.GetSharedDestination ());
}
return;
@@ -849,7 +822,7 @@ namespace tunnel
template<class TTunnel>
std::shared_ptr<TTunnel> Tunnels::CreateTunnel (std::shared_ptr<TunnelConfig> config,
std::shared_ptr<TunnelPool> pool, std::shared_ptr<OutboundTunnel> outboundTunnel)
std::shared_ptr<TunnelPool> pool, std::shared_ptr<OutboundTunnel> outboundTunnel)
{
auto newTunnel = std::make_shared<TTunnel> (config);
newTunnel->SetTunnelPool (pool);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2021, The PurpleI2P Project
* Copyright (c) 2013-2022, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -67,6 +67,9 @@ namespace tunnel
public:
/** function for visiting a hops stored in a tunnel */
typedef std::function<void(std::shared_ptr<const i2p::data::IdentityEx>)> TunnelHopVisitor;
Tunnel (std::shared_ptr<const TunnelConfig> config);
~Tunnel ();
@@ -91,8 +94,6 @@ namespace tunnel
bool HandleTunnelBuildResponse (uint8_t * msg, size_t len);
virtual void Print (std::stringstream&) const {};
// implements TunnelBase
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out);
@@ -107,9 +108,8 @@ namespace tunnel
bool LatencyIsKnown() const { return m_Latency > 0; }
bool IsSlow () const { return LatencyIsKnown() && (int)m_Latency > HIGH_LATENCY_PER_HOP*GetNumHops (); }
protected:
void PrintHops (std::stringstream& s) const;
/** visit all hops we currently store */
void VisitTunnelHops(TunnelHopVisitor v);
private:
@@ -134,7 +134,6 @@ namespace tunnel
virtual void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs); // multiple messages
const i2p::data::IdentHash& GetEndpointIdentHash () const { return m_EndpointIdentHash; };
virtual size_t GetNumSentBytes () const { return m_Gateway.GetNumSentBytes (); };
void Print (std::stringstream& s) const;
// implements TunnelBase
void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg);
@@ -155,7 +154,6 @@ namespace tunnel
InboundTunnel (std::shared_ptr<const TunnelConfig> config): Tunnel (config), m_Endpoint (true) {};
void HandleTunnelDataMsg (std::shared_ptr<I2NPMessage>&& msg);
virtual size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); };
void Print (std::stringstream& s) const;
bool IsInbound() const { return true; }
// override TunnelBase
@@ -172,7 +170,6 @@ namespace tunnel
ZeroHopsInboundTunnel ();
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
void Print (std::stringstream& s) const;
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
private:
@@ -186,7 +183,6 @@ namespace tunnel
ZeroHopsOutboundTunnel ();
void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs);
void Print (std::stringstream& s) const;
size_t GetNumSentBytes () const { return m_NumSentBytes; };
private:
@@ -219,8 +215,8 @@ namespace tunnel
void PostTunnelData (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<InboundTunnel> tunnel);
void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> tunnel);
std::shared_ptr<TunnelPool> CreateTunnelPool (int numInboundHops,
int numOuboundHops, int numInboundTunnels, int numOutboundTunnels);
std::shared_ptr<TunnelPool> CreateTunnelPool (int numInboundHops, int numOuboundHops,
int numInboundTunnels, int numOutboundTunnels, int inboundVariance, int outboundVariance);
void DeleteTunnelPool (std::shared_ptr<TunnelPool> pool);
void StopTunnelPool (std::shared_ptr<TunnelPool> pool);
@@ -230,7 +226,7 @@ namespace tunnel
template<class TTunnel>
std::shared_ptr<TTunnel> CreateTunnel (std::shared_ptr<TunnelConfig> config,
std::shared_ptr<TunnelPool> pool, std::shared_ptr<OutboundTunnel> outboundTunnel = nullptr);
std::shared_ptr<TunnelPool> pool, std::shared_ptr<OutboundTunnel> outboundTunnel = nullptr);
template<class TTunnel>
std::shared_ptr<TTunnel> GetPendingTunnel (uint32_t replyMsgID, const std::map<uint32_t, std::shared_ptr<TTunnel> >& pendingTunnels);

View File

@@ -167,7 +167,7 @@ namespace tunnel
memset (clearText + SHORT_REQUEST_RECORD_MORE_FLAGS_OFFSET, 0, 2);
clearText[SHORT_REQUEST_RECORD_LAYER_ENCRYPTION_TYPE] = 0; // AES
htobe32buf (clearText + SHORT_REQUEST_RECORD_REQUEST_TIME_OFFSET, i2p::util::GetMinutesSinceEpoch ());
htobe32buf (clearText + SHORT_REQUEST_RECORD_REQUEST_EXPIRATION_OFFSET , 600); // +10 minutes
htobe32buf (clearText + SHORT_REQUEST_RECORD_REQUEST_EXPIRATION_OFFSET , 600); // +10 minutes
htobe32buf (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET, replyMsgID);
memset (clearText + SHORT_REQUEST_RECORD_PADDING_OFFSET, 0, SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE - SHORT_REQUEST_RECORD_PADDING_OFFSET);
// encrypt

View File

@@ -91,7 +91,7 @@ namespace tunnel
TunnelConfig (const std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& peers,
uint32_t replyTunnelID, const i2p::data::IdentHash& replyIdent, bool isShort,
i2p::data::RouterInfo::CompatibleTransports farEndTransports = i2p::data::RouterInfo::eAllTransports): // outbound
i2p::data::RouterInfo::CompatibleTransports farEndTransports = i2p::data::RouterInfo::eAllTransports): // outbound
m_IsShort (isShort), m_FarEndTransports (farEndTransports)
{
CreatePeers (peers);

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