mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-03-07 06:09:42 +00:00
Compare commits
679 Commits
2.50.1
...
13604ccbb6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
13604ccbb6 | ||
|
|
e996db03c0 | ||
|
|
f79a2e81ff | ||
|
|
4b1ac7420c | ||
|
|
e518b92a89 | ||
|
|
1a32ed9088 | ||
|
|
b17bbd754a | ||
|
|
7b0ff2850c | ||
|
|
31ff0ff1cb | ||
|
|
fcc70025fd | ||
|
|
56145d0f3c | ||
|
|
8b9f427aa4 | ||
|
|
cc768de8ea | ||
|
|
ffd18baf30 | ||
|
|
3474538697 | ||
|
|
5f1b31213f | ||
|
|
6fb3c7c3ba | ||
|
|
a248a2a732 | ||
|
|
09ae278306 | ||
|
|
d241e5d5cb | ||
|
|
b80278421d | ||
|
|
f2596e0187 | ||
|
|
5265dc71e9 | ||
|
|
a05bb93792 | ||
|
|
5d5970bed4 | ||
|
|
86080b26ae | ||
|
|
5b2d0c579b | ||
|
|
3c4926f377 | ||
|
|
391e3b7814 | ||
|
|
72a39609ed | ||
|
|
0c5f39ad81 | ||
|
|
3c608ec07c | ||
|
|
ce0461bf86 | ||
|
|
ce96f93c80 | ||
|
|
d88ba768d7 | ||
|
|
574d12298b | ||
|
|
7285caa4f1 | ||
|
|
2778b092e3 | ||
|
|
dbef3fe9d2 | ||
|
|
09b7d44dad | ||
|
|
a411fff1d9 | ||
|
|
e574354896 | ||
|
|
0a08383471 | ||
|
|
c5e464a8b5 | ||
|
|
002d8c7773 | ||
|
|
32921ead80 | ||
|
|
be24a3e336 | ||
|
|
d99a7d9b20 | ||
|
|
2f6bdd1c84 | ||
|
|
5a4ce66d42 | ||
|
|
76190ea365 | ||
|
|
f90386803f | ||
|
|
29d77113cc | ||
|
|
0d09a8be00 | ||
|
|
b8d61e04f0 | ||
|
|
4432c5a2c4 | ||
|
|
2419f52af4 | ||
|
|
b2a10ac82b | ||
|
|
0086f8e27a | ||
|
|
8a8277edda | ||
|
|
3f10f6651d | ||
|
|
9bc595a9a2 | ||
|
|
f04048717d | ||
|
|
361f364966 | ||
|
|
4c90a88b85 | ||
|
|
23e66671c2 | ||
|
|
ec67f48d85 | ||
|
|
3a229ea65c | ||
|
|
0e8d624d86 | ||
|
|
8f9874570a | ||
|
|
43939cedf4 | ||
|
|
4c66608caf | ||
|
|
ec4fe9a1e6 | ||
|
|
79e8ccbb5b | ||
|
|
608056dcd2 | ||
|
|
7461b640e3 | ||
|
|
743126b2ad | ||
|
|
f611136ea7 | ||
|
|
87ae9c4b74 | ||
|
|
d3630fb2b2 | ||
|
|
500afe745f | ||
|
|
26901e2945 | ||
|
|
64bde69967 | ||
|
|
ddf30784ec | ||
|
|
ea14b00d63 | ||
|
|
a24e0eb2dc | ||
|
|
0cb677a2c0 | ||
|
|
e6cbc842bf | ||
|
|
f087654f25 | ||
|
|
10335b90c5 | ||
|
|
8a234f70e6 | ||
|
|
f98a310235 | ||
|
|
1419745a5d | ||
|
|
890fe77b10 | ||
|
|
bc9d25ec3b | ||
|
|
fe71776b6f | ||
|
|
0213f058d1 | ||
|
|
0ccf0a6339 | ||
|
|
e26682f4cb | ||
|
|
8981e406f5 | ||
|
|
50d9252ba9 | ||
|
|
4f73f60e51 | ||
|
|
d69e957213 | ||
|
|
97fdedfbe3 | ||
|
|
ec1f41b13c | ||
|
|
7104d334fd | ||
|
|
4e581af3ba | ||
|
|
48f7131a7d | ||
|
|
fbd07a5276 | ||
|
|
8210911bc5 | ||
|
|
4a5406b803 | ||
|
|
ab02f722af | ||
|
|
c86e0ec371 | ||
|
|
ac4c58bbe9 | ||
|
|
23bac4a403 | ||
|
|
2321a897f5 | ||
|
|
88a5f8b125 | ||
|
|
78847306e9 | ||
|
|
1a6109109a | ||
|
|
905c6debf2 | ||
|
|
d7c4d0ff3e | ||
|
|
da3e83138a | ||
|
|
c6eba73653 | ||
|
|
0d224dfc54 | ||
|
|
dc48fb0180 | ||
|
|
cc05f9c5d9 | ||
|
|
e4c8cc300d | ||
|
|
0710f62948 | ||
|
|
58245bf121 | ||
|
|
4436c49ccc | ||
|
|
bce9630ff8 | ||
|
|
7f3a04a72f | ||
|
|
34f1ba5bd9 | ||
|
|
dc4cd34893 | ||
|
|
1fb45c4b0d | ||
|
|
514be6d048 | ||
|
|
8c292727da | ||
|
|
d5c40bb6be | ||
|
|
eed48c43fd | ||
|
|
600f36539f | ||
|
|
e1e530b4a9 | ||
|
|
98e93468a6 | ||
|
|
0f5e8d8424 | ||
|
|
d521350588 | ||
|
|
237d9474d8 | ||
|
|
5466983b36 | ||
|
|
ba41f7107d | ||
|
|
c2234599cd | ||
|
|
6ebb019e15 | ||
|
|
15cd4feade | ||
|
|
abbe1fea64 | ||
|
|
62b811c2c1 | ||
|
|
64e4b3871a | ||
|
|
c3a1631319 | ||
|
|
a06cce0aaf | ||
|
|
75b1c144b4 | ||
|
|
32ad4b4858 | ||
|
|
98669eff4f | ||
|
|
67763248cc | ||
|
|
262a803d10 | ||
|
|
0912de5b77 | ||
|
|
edb2ba7107 | ||
|
|
74f0330730 | ||
|
|
5cd0248494 | ||
|
|
816771dd00 | ||
|
|
189d7179c0 | ||
|
|
2dfc9003a7 | ||
|
|
9968afc038 | ||
|
|
5073c9637e | ||
|
|
2c594dc67a | ||
|
|
11bca5c3cd | ||
|
|
9d1e526812 | ||
|
|
018fa0ec00 | ||
|
|
f733f0a636 | ||
|
|
fd2b15fe81 | ||
|
|
c8958d71a2 | ||
|
|
e4962b855f | ||
|
|
9f30499984 | ||
|
|
5324197e43 | ||
|
|
715e063550 | ||
|
|
7ef1fdf634 | ||
|
|
db19c32381 | ||
|
|
ac1c28cb39 | ||
|
|
2fa4237acd | ||
|
|
ae26758170 | ||
|
|
a723405fb0 | ||
|
|
f20391d460 | ||
|
|
ca4db7aab2 | ||
|
|
13b2fc3266 | ||
|
|
d4c1a1c0bb | ||
|
|
d5aca85a35 | ||
|
|
17d0e59d02 | ||
|
|
d20475e3d0 | ||
|
|
ebec4d8a5e | ||
|
|
cb0801fc16 | ||
|
|
a5e9d9c6a3 | ||
|
|
3d0a1afd64 | ||
|
|
78ec5b2c6e | ||
|
|
272bf7dbc1 | ||
|
|
261acbbd66 | ||
|
|
a65dd218da | ||
|
|
50d297fa29 | ||
|
|
699e17b594 | ||
|
|
a91caa6559 | ||
|
|
07d108bb6f | ||
|
|
bcace3fb29 | ||
|
|
cd648b9b3f | ||
|
|
ba451eeca5 | ||
|
|
8d1c186665 | ||
|
|
d539c9677e | ||
|
|
855fd4d471 | ||
|
|
e0af7b077f | ||
|
|
fde301deaf | ||
|
|
9a77c0a4b1 | ||
|
|
306ea2df37 | ||
|
|
cab671e177 | ||
|
|
2ee5af0c06 | ||
|
|
911620bcd3 | ||
|
|
d1620d70bb | ||
|
|
53db54dafb | ||
|
|
ead1b72886 | ||
|
|
ae65af07c2 | ||
|
|
0046a8b3ec | ||
|
|
06e3a1b57a | ||
|
|
cc59003560 | ||
|
|
a3e0b3710c | ||
|
|
56b8534e0c | ||
|
|
c21cf0565b | ||
|
|
9668ea9338 | ||
|
|
a837e5c502 | ||
|
|
bbadbdbfdb | ||
|
|
509c039e2f | ||
|
|
8cf9cc1a01 | ||
|
|
a1f40d3048 | ||
|
|
83c0764ed4 | ||
|
|
2f5f39aaf2 | ||
|
|
5cc15fac31 | ||
|
|
ea3f356856 | ||
|
|
8189ff0f48 | ||
|
|
2679e8cfd8 | ||
|
|
3679c6aea0 | ||
|
|
604bdf314f | ||
|
|
937809bc0f | ||
|
|
d71f3d40fa | ||
|
|
e87ace0c3d | ||
|
|
bc48e6881d | ||
|
|
e957d7bbfb | ||
|
|
b3aa5ad998 | ||
|
|
ac876a0cd5 | ||
|
|
d85cb6e30a | ||
|
|
4a4b76141a | ||
|
|
a93043f064 | ||
|
|
ae309ca632 | ||
|
|
9037e8b2b1 | ||
|
|
3ff79038b5 | ||
|
|
da0e527777 | ||
|
|
66223792f3 | ||
|
|
a69eade1f4 | ||
|
|
0992a5124f | ||
|
|
e7423b1ffc | ||
|
|
65ceb08290 | ||
|
|
879d54fad4 | ||
|
|
ff5c76f8f2 | ||
|
|
0191e58b05 | ||
|
|
c43926083e | ||
|
|
bd98f2c3ee | ||
|
|
02c52f59cb | ||
|
|
fa218d3cf5 | ||
|
|
d169b422da | ||
|
|
7be64dad89 | ||
|
|
3720a5fce3 | ||
|
|
0df895b6a7 | ||
|
|
32ab95478e | ||
|
|
28adb54c0a | ||
|
|
b4fcf76480 | ||
|
|
fb8e0e1b5b | ||
|
|
41dd8b527d | ||
|
|
7376f7c399 | ||
|
|
d47ae3012a | ||
|
|
09dbe9fc03 | ||
|
|
11328a429d | ||
|
|
0c924836cf | ||
|
|
52a313bb65 | ||
|
|
d75f15104e | ||
|
|
b306bf2db9 | ||
|
|
349c4e30b6 | ||
|
|
3c69e0b2af | ||
|
|
8e1fb8ca9f | ||
|
|
42782944fb | ||
|
|
efd754eb93 | ||
|
|
81cc3e3de8 | ||
|
|
db4208e2e2 | ||
|
|
fe740249a5 | ||
|
|
4ad6cef5a5 | ||
|
|
86f86fc711 | ||
|
|
e5dac605f6 | ||
|
|
ab1abf584f | ||
|
|
8a3d6ddb3e | ||
|
|
1410fa5c21 | ||
|
|
ea19d2296c | ||
|
|
3a4833aa67 | ||
|
|
4a66624b04 | ||
|
|
0153748134 | ||
|
|
d3062d2994 | ||
|
|
d7ff459f12 | ||
|
|
e0ac8a7298 | ||
|
|
96ea630274 | ||
|
|
f232c8f2df | ||
|
|
2f54d95187 | ||
|
|
830e49f2c5 | ||
|
|
23e323438a | ||
|
|
48f1514053 | ||
|
|
a1aa6c62d7 | ||
|
|
9e1ea289c2 | ||
|
|
f6ddcd432e | ||
|
|
9a6654943d | ||
|
|
bed5a18294 | ||
|
|
45221da1dc | ||
|
|
8440633614 | ||
|
|
50f455e0a2 | ||
|
|
5fbcfadd6d | ||
|
|
5af13849a9 | ||
|
|
a9c486d7a1 | ||
|
|
8c0a1197d7 | ||
|
|
4e5f5c218a | ||
|
|
64cc59d1e9 | ||
|
|
0c943f4405 | ||
|
|
37d3d9e604 | ||
|
|
d23451fdf6 | ||
|
|
d843502832 | ||
|
|
0428b5ece1 | ||
|
|
df787060c3 | ||
|
|
ea9c69cd53 | ||
|
|
199d149bed | ||
|
|
ff8941af71 | ||
|
|
f125936b2e | ||
|
|
697d831441 | ||
|
|
457b64f92d | ||
|
|
6caec6b551 | ||
|
|
362edc68ad | ||
|
|
29872fc003 | ||
|
|
81d383c99e | ||
|
|
12653f2fe4 | ||
|
|
43f5ba286c | ||
|
|
f990a2f69f | ||
|
|
0b97b4294c | ||
|
|
4178ac8eac | ||
|
|
6a590bf970 | ||
|
|
2f847d62bb | ||
|
|
df6d48dbae | ||
|
|
bacce7dc60 | ||
|
|
b3314380cc | ||
|
|
d4eea61b82 | ||
|
|
a1995c13cd | ||
|
|
bc8adf1433 | ||
|
|
a1322d4667 | ||
|
|
4100249313 | ||
|
|
acbd3f897b | ||
|
|
7dc5a04b8d | ||
|
|
03635f4444 | ||
|
|
0fae04f96a | ||
|
|
bb531a878d | ||
|
|
0f7db8e418 | ||
|
|
9a724b2af9 | ||
|
|
f4ea6138e8 | ||
|
|
e74272781f | ||
|
|
b75e418879 | ||
|
|
927123188c | ||
|
|
c00eb8cf44 | ||
|
|
265bb8b779 | ||
|
|
e3be409945 | ||
|
|
d8707ceb57 | ||
|
|
39e16824b9 | ||
|
|
285e693a4e | ||
|
|
940628bf36 | ||
|
|
b5994e058a | ||
|
|
22dabfd79e | ||
|
|
0e41c3fa36 | ||
|
|
124698854f | ||
|
|
f223e668ce | ||
|
|
f5b823a712 | ||
|
|
4163542125 | ||
|
|
6921c8391e | ||
|
|
47a2020472 | ||
|
|
9d38facf3b | ||
|
|
a1be1aa9ec | ||
|
|
c4bbe2bb4a | ||
|
|
601695dede | ||
|
|
cdc81e19a0 | ||
|
|
b98b3a87b0 | ||
|
|
425ef2cfe5 | ||
|
|
c454685605 | ||
|
|
c98926abf2 | ||
|
|
7aacc97351 | ||
|
|
c49e17ad40 | ||
|
|
296b721929 | ||
|
|
d0cf385f4b | ||
|
|
b91f5a7430 | ||
|
|
4d8431907d | ||
|
|
b0cf5130a2 | ||
|
|
396aa6944d | ||
|
|
8a20d3219b | ||
|
|
13a746162a | ||
|
|
7e5370fbe5 | ||
|
|
ec59308fad | ||
|
|
5ed76b997c | ||
|
|
535fbdb4c9 | ||
|
|
034332a0ef | ||
|
|
a1eac6f28e | ||
|
|
ba22a940f1 | ||
|
|
8439f6dc57 | ||
|
|
a21bec0ed8 | ||
|
|
5adbc2c3fe | ||
|
|
c515f49903 | ||
|
|
845b14f581 | ||
|
|
cdfdfc9e24 | ||
|
|
62d279e1b0 | ||
|
|
a1fcd8af39 | ||
|
|
8c6c954ea2 | ||
|
|
77bb7432bc | ||
|
|
720ffa8a31 | ||
|
|
c1c69258c3 | ||
|
|
733a4a2869 | ||
|
|
ca3ac8c11d | ||
|
|
d4e3991257 | ||
|
|
648a884a18 | ||
|
|
8fe989050e | ||
|
|
bb6212ccc1 | ||
|
|
5f39f65540 | ||
|
|
146b3f52c0 | ||
|
|
cc75ccd070 | ||
|
|
0ddc514221 | ||
|
|
d3b699d7cd | ||
|
|
6592fab41c | ||
|
|
02895d4cf5 | ||
|
|
8b7941c4ce | ||
|
|
de673464d1 | ||
|
|
6ce2c30522 | ||
|
|
c5a1e8cac8 | ||
|
|
f67c38d8d2 | ||
|
|
1f1a3270f7 | ||
|
|
ffee29272f | ||
|
|
2d2469c23d | ||
|
|
8e80a8b06f | ||
|
|
26fac94d05 | ||
|
|
9a30068ae5 | ||
|
|
46c72a7137 | ||
|
|
04bccedd9b | ||
|
|
b2e21a4f12 | ||
|
|
57e46ba0cf | ||
|
|
df3dc1f574 | ||
|
|
1b5f67e185 | ||
|
|
89064b6fb4 | ||
|
|
c49dd712de | ||
|
|
4f1cb74f75 | ||
|
|
75df8d3c7b | ||
|
|
85be76b01a | ||
|
|
835c480269 | ||
|
|
ac9d92c681 | ||
|
|
a30d1972e5 | ||
|
|
0c2330bf14 | ||
|
|
a703d31893 | ||
|
|
4f8f3a386f | ||
|
|
83f0b9c041 | ||
|
|
cf77be0eeb | ||
|
|
b2aa34baa6 | ||
|
|
4def0b6ea5 | ||
|
|
25592a00b6 | ||
|
|
edaf162f9c | ||
|
|
e7ff15c573 | ||
|
|
161ff3579b | ||
|
|
f2085ecc8d | ||
|
|
0c5dee69ba | ||
|
|
d74033dd2b | ||
|
|
5412e29ff5 | ||
|
|
0236769134 | ||
|
|
530a078535 | ||
|
|
fbca27fe73 | ||
|
|
08cc256c54 | ||
|
|
6432963294 | ||
|
|
59beb5e4e4 | ||
|
|
217aa0c882 | ||
|
|
e889dc1508 | ||
|
|
0141489d34 | ||
|
|
2d06c0cbe6 | ||
|
|
51446f0324 | ||
|
|
66d0b7aec4 | ||
|
|
92b49fb969 | ||
|
|
17dd5c1285 | ||
|
|
ce97ec1534 | ||
|
|
3ceb64db2e | ||
|
|
bb702700f7 | ||
|
|
ff3fec9a00 | ||
|
|
3873e60cbb | ||
|
|
2dbf094433 | ||
|
|
e85e96bc35 | ||
|
|
98543af92b | ||
|
|
af0d853ccd | ||
|
|
20a5e19ea1 | ||
|
|
f1058410fb | ||
|
|
6ba42a0912 | ||
|
|
1292ec67c0 | ||
|
|
2f2f14e3a7 | ||
|
|
edd9dd2c39 | ||
|
|
f8722f17c6 | ||
|
|
38cc01e13d | ||
|
|
6ca266ff3b | ||
|
|
b9773c88e4 | ||
|
|
3311fe62bb | ||
|
|
a284c85153 | ||
|
|
e5f75eb61c | ||
|
|
89f9bec49a | ||
|
|
dbc3952654 | ||
|
|
f3c052ed0c | ||
|
|
692f495adc | ||
|
|
aa1de7fe94 | ||
|
|
ca45fe73e9 | ||
|
|
a8af683643 | ||
|
|
b86c83a068 | ||
|
|
6656ef3c8d | ||
|
|
6898d04a1d | ||
|
|
3215125950 | ||
|
|
612f51ba7f | ||
|
|
3d03732555 | ||
|
|
d6d440ba8a | ||
|
|
821a76a7c5 | ||
|
|
34154596f2 | ||
|
|
a1dce017f4 | ||
|
|
78af34237e | ||
|
|
8874ea8033 | ||
|
|
6bd1ee36f7 | ||
|
|
f07c4bd1dd | ||
|
|
8524a67895 | ||
|
|
43d880752e | ||
|
|
d4246edb82 | ||
|
|
fd4513ebb2 | ||
|
|
ee8449fa05 | ||
|
|
5415598f60 | ||
|
|
7d73c304b5 | ||
|
|
d25206abce | ||
|
|
5d7c6fb0b3 | ||
|
|
36a060d50f | ||
|
|
577ed56af0 | ||
|
|
695dc96a83 | ||
|
|
e5251bf3c3 | ||
|
|
2692aef53d | ||
|
|
d524105727 | ||
|
|
26463c50fc | ||
|
|
b092e712ec | ||
|
|
cb8fbb0135 | ||
|
|
19e23b34da | ||
|
|
a4a3f8e96b | ||
|
|
f2b720617c | ||
|
|
d677d67676 | ||
|
|
7e3157b162 | ||
|
|
2b6a95cbee | ||
|
|
900153765a | ||
|
|
441e847de8 | ||
|
|
6439e227f6 | ||
|
|
def404b61a | ||
|
|
d8be5b8ce1 | ||
|
|
dddbca6ffb | ||
|
|
56619caa71 | ||
|
|
0e502c49b5 | ||
|
|
710b27688b | ||
|
|
a9ad6fc31e | ||
|
|
967627e58a | ||
|
|
7691a5b4a9 | ||
|
|
d9b6262a6e | ||
|
|
075f80aea2 | ||
|
|
b07530a8a1 | ||
|
|
0ae7931a6f | ||
|
|
158160f5c0 | ||
|
|
4cb2ad48be | ||
|
|
adba3987f8 | ||
|
|
36dbc15bca | ||
|
|
d96803a290 | ||
|
|
592d6ae4f4 | ||
|
|
7dd9a7a0af | ||
|
|
1b23aa2d7b | ||
|
|
f980277552 | ||
|
|
586695673b | ||
|
|
c158bbe90a | ||
|
|
c01fd3299f | ||
|
|
f64b136f5a | ||
|
|
37e67cbcaa | ||
|
|
be815804e6 | ||
|
|
ce35637866 | ||
|
|
de2b0f6e09 | ||
|
|
7b776666a3 | ||
|
|
47578b69c6 | ||
|
|
8f28cee32f | ||
|
|
96cf6ca531 | ||
|
|
83cb3a1820 | ||
|
|
ffdd5935e9 | ||
|
|
2e9f2d4a3b | ||
|
|
0ca782ed71 | ||
|
|
e40b656ecf | ||
|
|
85f5f5b91e | ||
|
|
f008478505 | ||
|
|
d926a31064 | ||
|
|
822cb35efe | ||
|
|
faaa8115d9 | ||
|
|
81015a5228 | ||
|
|
a3246cd9dc | ||
|
|
530c353b00 | ||
|
|
75c2cb751f | ||
|
|
67c4d4bcaa | ||
|
|
25e82105b2 | ||
|
|
4b167fdbaf | ||
|
|
5b93558bd0 | ||
|
|
70639f1139 | ||
|
|
c5a1806528 | ||
|
|
a2249f0a82 | ||
|
|
9f217f8a11 | ||
|
|
5e19e361e7 | ||
|
|
0b47f65b06 | ||
|
|
140146e433 | ||
|
|
b4484c8e8f | ||
|
|
1e5604ed43 | ||
|
|
39e378a03d | ||
|
|
7cfcb12c7b | ||
|
|
49f4dc53ad | ||
|
|
4afdca090d | ||
|
|
d8f6c4a93d | ||
|
|
d724948d03 | ||
|
|
34d75b08dd | ||
|
|
ca9782dd0d | ||
|
|
2ad26dd4c9 | ||
|
|
828facab57 | ||
|
|
cd087568b5 | ||
|
|
dfe8b25e5e | ||
|
|
1e9bcd6b8b | ||
|
|
8bc58daa5a | ||
|
|
3b97feb89f | ||
|
|
a8135b8d18 | ||
|
|
5cf1961fa4 | ||
|
|
577c71b930 | ||
|
|
c5cab05a6b | ||
|
|
b855c71891 | ||
|
|
21f41a2b2a | ||
|
|
8319dd6b25 | ||
|
|
d4c47d90cb | ||
|
|
302af823a3 | ||
|
|
69ee6112b3 | ||
|
|
245e6b6efd | ||
|
|
6930106d26 | ||
|
|
9a2f744630 | ||
|
|
4540d22de8 | ||
|
|
6e3aef0b9b | ||
|
|
74b2ba7ae2 | ||
|
|
d5e1d56fde | ||
|
|
9685754511 | ||
|
|
88145eaf94 | ||
|
|
1b3c3fae89 | ||
|
|
fde79eecc6 | ||
|
|
a518320e3b | ||
|
|
f6a09f59a3 | ||
|
|
a2c28d0837 | ||
|
|
2ff6f9d346 | ||
|
|
975d5f44b6 | ||
|
|
260564345a | ||
|
|
305a654a37 | ||
|
|
d510f7e473 | ||
|
|
b992fbab52 | ||
|
|
ddf3774aec | ||
|
|
814f854c5a | ||
|
|
d3bbdb1011 | ||
|
|
d6d9f05443 | ||
|
|
13e09e231d | ||
|
|
7866f644d3 | ||
|
|
84de3f081f | ||
|
|
f0725c9b40 | ||
|
|
f176f1909b | ||
|
|
d231f944c0 | ||
|
|
cc48436794 | ||
|
|
ea51fc8410 | ||
|
|
c212a30d33 | ||
|
|
670bf16cd0 |
32
.github/workflows/build-deb.yml
vendored
32
.github/workflows/build-deb.yml
vendored
@@ -1,6 +1,24 @@
|
||||
name: Build Debian packages
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- .github/workflows/build-deb.yml
|
||||
- contrib/**
|
||||
- daemon/**
|
||||
- debian/**
|
||||
- i18n/**
|
||||
- libi2pd/**
|
||||
- libi2pd_client/**
|
||||
- Makefile
|
||||
- Makefile.linux
|
||||
tags:
|
||||
- '*'
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -14,26 +32,30 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Commit Hash
|
||||
id: commit
|
||||
uses: prompt/actions-commit-hash@v3.0.0
|
||||
|
||||
- name: Build package
|
||||
uses: jtdor/build-deb-action@v1
|
||||
with:
|
||||
docker-image: debian:${{ matrix.dist }}-slim
|
||||
buildpackage-opts: --build=binary --no-sign
|
||||
before-build-hook: debchange --controlmaint --local "+${{ github.sha }}~${{ matrix.dist }}" -b --distribution ${{ matrix.dist }} "CI build"
|
||||
before-build-hook: debchange --controlmaint --local "+${{ steps.commit.outputs.short }}~${{ matrix.dist }}" -b --distribution ${{ matrix.dist }} "CI build"
|
||||
extra-build-deps: devscripts git
|
||||
|
||||
- name: Upload package
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: i2pd_${{ matrix.dist }}
|
||||
path: debian/artifacts/i2pd_*.deb
|
||||
|
||||
- name: Upload debugging symbols
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: i2pd-dbgsym_${{ matrix.dist }}
|
||||
path: debian/artifacts/i2pd-dbgsym_*.deb
|
||||
|
||||
24
.github/workflows/build-freebsd.yml
vendored
24
.github/workflows/build-freebsd.yml
vendored
@@ -1,6 +1,24 @@
|
||||
name: Build on FreeBSD
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- .github/workflows/build-freebsd.yml
|
||||
- build/CMakeLists.txt
|
||||
- build/cmake_modules/**
|
||||
- daemon/**
|
||||
- i18n/**
|
||||
- libi2pd/**
|
||||
- libi2pd_client/**
|
||||
- Makefile
|
||||
- Makefile.bsd
|
||||
tags:
|
||||
- '*'
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -9,7 +27,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Test in FreeBSD
|
||||
id: test
|
||||
@@ -26,7 +44,7 @@ jobs:
|
||||
gmake -j2
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: i2pd-freebsd
|
||||
path: build/i2pd
|
||||
|
||||
27
.github/workflows/build-osx.yml
vendored
27
.github/workflows/build-osx.yml
vendored
@@ -1,6 +1,22 @@
|
||||
name: Build on OSX
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- .github/workflows/build-osx.yml
|
||||
- daemon/**
|
||||
- i18n/**
|
||||
- libi2pd/**
|
||||
- libi2pd_client/**
|
||||
- Makefile
|
||||
- Makefile.homebrew
|
||||
tags:
|
||||
- '*'
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -14,13 +30,16 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: install packages
|
||||
- name: Install required formulae
|
||||
run: |
|
||||
find /usr/local/bin -lname '*/Library/Frameworks/Python.framework/*' -delete
|
||||
brew update
|
||||
brew install boost miniupnpc openssl@1.1
|
||||
|
||||
- name: build application
|
||||
- name: List installed formulae
|
||||
run: brew list
|
||||
|
||||
- name: Build application
|
||||
run: make HOMEBREW=1 USE_UPNP=${{ matrix.with_upnp }} PREFIX=$GITHUB_WORKSPACE/output -j3
|
||||
|
||||
52
.github/workflows/build-windows-msvc.yml
vendored
52
.github/workflows/build-windows-msvc.yml
vendored
@@ -1,52 +0,0 @@
|
||||
name: Build on Windows with MSVC
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: windows-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Build and install zlib
|
||||
run: |
|
||||
powershell -Command "(Invoke-WebRequest -Uri https://raw.githubusercontent.com/r4sas/zlib.install/master/install.bat -OutFile install_zlib.bat)"
|
||||
powershell -Command "(Get-Content install_zlib.bat) | Set-Content install_zlib.bat" # fixing line endings
|
||||
set BUILD_TYPE=Debug
|
||||
./install_zlib.bat
|
||||
set BUILD_TYPE=Release
|
||||
./install_zlib.bat
|
||||
del install_zlib.bat
|
||||
|
||||
- name: Install Boost
|
||||
uses: crazy-max/ghaction-chocolatey@v2
|
||||
with:
|
||||
args: install boost-msvc-14.3 --version=1.81.0
|
||||
|
||||
- name: Install OpenSSL
|
||||
uses: crazy-max/ghaction-chocolatey@v2
|
||||
with:
|
||||
args: install openssl
|
||||
|
||||
- name: Configure
|
||||
working-directory: build
|
||||
run: cmake -DWITH_STATIC=ON .
|
||||
|
||||
- name: Build
|
||||
working-directory: build
|
||||
run: cmake --build . --config Debug -- -m
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: i2pd-msvc
|
||||
path: build/Debug/i2pd.*
|
||||
|
||||
80
.github/workflows/build-windows-msvc.yml-disabled
vendored
Normal file
80
.github/workflows/build-windows-msvc.yml-disabled
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
name: Build on Windows with MSVC
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- .github/workflows/build-windows-msvc.yml
|
||||
- build/CMakeLists.txt
|
||||
- build/cmake_modules/**
|
||||
- daemon/**
|
||||
- i18n/**
|
||||
- libi2pd/**
|
||||
- libi2pd_client/**
|
||||
- Win32/**
|
||||
tags:
|
||||
- '*'
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: windows-latest
|
||||
env:
|
||||
boost_path: ${{ github.workspace }}\boost_1_83_0
|
||||
openssl_path: ${{ github.workspace }}\openssl_3_2_1
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Build and install zlib
|
||||
run: |
|
||||
powershell -Command "(Invoke-WebRequest -Uri https://raw.githubusercontent.com/r4sas/zlib.install/master/install.bat -OutFile install_zlib.bat)"
|
||||
powershell -Command "(Get-Content install_zlib.bat) | Set-Content install_zlib.bat" # fixing line endings
|
||||
set BUILD_TYPE=Debug
|
||||
./install_zlib.bat
|
||||
set BUILD_TYPE=Release
|
||||
./install_zlib.bat
|
||||
del install_zlib.bat
|
||||
|
||||
- name: Install Boost
|
||||
run: |
|
||||
powershell -Command "(Start-BitsTransfer -Source https://sourceforge.net/projects/boost/files/boost-binaries/1.83.0/boost_1_83_0-msvc-14.3-64.exe/download -Destination boost_1_83_0-msvc-14.3-64.exe)"
|
||||
./boost_1_83_0-msvc-14.3-64.exe /DIR="${{env.boost_path}}" /VERYSILENT /SUPPRESSMSGBOXES /SP-
|
||||
|
||||
- name: Install OpenSSL
|
||||
run: |
|
||||
powershell -Command "(Start-BitsTransfer -Source https://slproweb.com/download/Win64OpenSSL-3_2_1.exe -Destination Win64OpenSSL-3_2_1.exe)"
|
||||
./Win64OpenSSL-3_2_1.exe /DIR="${{env.openssl_path}}" /TASKS="copytobin" /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-
|
||||
|
||||
- name: Make copy of the OpenSSL libraries for CMake
|
||||
run: |
|
||||
dir ${{ github.workspace }}
|
||||
dir ${{env.openssl_path}}\lib\VC
|
||||
dir ${{env.openssl_path}}\lib\VC\x64\
|
||||
dir ${{env.openssl_path}}\lib\VC\x64\MTd\
|
||||
xcopy /s /y "${{env.openssl_path}}\lib\VC\x64\MTd" "${{env.openssl_path}}\lib"
|
||||
|
||||
- name: Configure
|
||||
working-directory: build
|
||||
run: cmake -DBoost_ROOT="${{env.boost_path}}" -DOPENSSL_ROOT_DIR="${{env.openssl_path}}" -DWITH_STATIC=ON .
|
||||
|
||||
- name: Build
|
||||
working-directory: build
|
||||
run: cmake --build . --config Debug -- -m
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: i2pd-msvc
|
||||
path: build/Debug/i2pd.*
|
||||
|
||||
153
.github/workflows/build-windows.yml
vendored
153
.github/workflows/build-windows.yml
vendored
@@ -1,6 +1,25 @@
|
||||
name: Build on Windows
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- .github/workflows/build-windows.yml
|
||||
- build/CMakeLists.txt
|
||||
- build/cmake_modules/**
|
||||
- daemon/**
|
||||
- i18n/**
|
||||
- libi2pd/**
|
||||
- libi2pd_client/**
|
||||
- Win32/**
|
||||
- Makefile
|
||||
- Makefile.mingw
|
||||
tags:
|
||||
- '*'
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
|
||||
defaults:
|
||||
run:
|
||||
@@ -23,7 +42,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -44,7 +63,7 @@ jobs:
|
||||
make USE_UPNP=yes DEBUG=no USE_GIT_VERSION=yes -j3
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: i2pd-${{ matrix.arch_short }}.exe
|
||||
path: i2pd.exe
|
||||
@@ -65,7 +84,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -83,7 +102,7 @@ jobs:
|
||||
cmake --build . -- -j3
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: i2pd-cmake-${{ matrix.arch_short }}.exe
|
||||
path: build/i2pd.exe
|
||||
@@ -97,7 +116,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -106,34 +125,122 @@ jobs:
|
||||
with:
|
||||
msystem: MINGW32
|
||||
install: base-devel git mingw-w64-i686-gcc mingw-w64-i686-boost mingw-w64-i686-openssl mingw-w64-i686-miniupnpc
|
||||
cache: true
|
||||
update: true
|
||||
|
||||
- name: Build WinXP-capable CRT packages
|
||||
- name: Clone MinGW packages repository and revert boost to 1.85.0
|
||||
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
|
||||
cd MINGW-packages
|
||||
git checkout 4cbb366edf2f268ac3146174b40ce38604646fc5 mingw-w64-boost
|
||||
|
||||
# headers
|
||||
- name: Get headers package version
|
||||
id: version-headers
|
||||
run: |
|
||||
echo "version=$(pacman -Si mingw-w64-i686-headers-git | grep -Po '^Version\s*: \K.+')" >> $GITHUB_OUTPUT
|
||||
- name: Cache headers package
|
||||
uses: actions/cache@v4
|
||||
id: cache-headers
|
||||
with:
|
||||
path: MINGW-packages/mingw-w64-headers-git/*.zst
|
||||
key: winxp-headers-${{ steps.version-headers.outputs.version }}
|
||||
- name: Build WinXP-capable headers package
|
||||
if: steps.cache-headers.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cd MINGW-packages/mingw-w64-headers-git
|
||||
sed -i 's/0x601/0x501/' PKGBUILD
|
||||
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm --nocheck
|
||||
- name: Install headers package
|
||||
run: pacman --noconfirm -U MINGW-packages/mingw-w64-headers-git/mingw-w64-i686-*-any.pkg.tar.zst
|
||||
|
||||
# CRT
|
||||
- name: Get crt package version
|
||||
id: version-crt
|
||||
run: |
|
||||
echo "version=$(pacman -Si mingw-w64-i686-crt-git | grep -Po '^Version\s*: \K.+')" >> $GITHUB_OUTPUT
|
||||
- name: Cache crt package
|
||||
uses: actions/cache@v4
|
||||
id: cache-crt
|
||||
with:
|
||||
path: MINGW-packages/mingw-w64-crt-git/*.zst
|
||||
key: winxp-crt-${{ steps.version-crt.outputs.version }}
|
||||
- name: Build WinXP-capable crt package
|
||||
if: steps.cache-crt.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cd MINGW-packages/mingw-w64-crt-git
|
||||
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm --nocheck
|
||||
- name: Install crt package
|
||||
run: pacman --noconfirm -U MINGW-packages/mingw-w64-crt-git/mingw-w64-i686-*-any.pkg.tar.zst
|
||||
|
||||
# winpthreads
|
||||
- name: Get winpthreads package version
|
||||
id: version-winpthreads
|
||||
run: |
|
||||
echo "version=$(pacman -Si mingw-w64-i686-winpthreads-git | grep -Po '^Version\s*: \K.+')" >> $GITHUB_OUTPUT
|
||||
- name: Cache winpthreads package
|
||||
uses: actions/cache@v4
|
||||
id: cache-winpthreads
|
||||
with:
|
||||
path: MINGW-packages/mingw-w64-winpthreads-git/*.zst
|
||||
key: winxp-winpthreads-${{ steps.version-winpthreads.outputs.version }}
|
||||
- name: Build WinXP-capable winpthreads package
|
||||
if: steps.cache-winpthreads.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cd MINGW-packages/mingw-w64-winpthreads-git
|
||||
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm --nocheck
|
||||
- name: Install winpthreads package
|
||||
run: pacman --noconfirm -U MINGW-packages/mingw-w64-winpthreads-git/mingw-w64-i686-*-any.pkg.tar.zst
|
||||
|
||||
# OpenSSL
|
||||
- name: Get openssl package version
|
||||
id: version-openssl
|
||||
run: |
|
||||
echo "version=$(pacman -Si mingw-w64-i686-openssl | grep -Po '^Version\s*: \K.+')" >> $GITHUB_OUTPUT
|
||||
- name: Cache openssl package
|
||||
uses: actions/cache@v4
|
||||
id: cache-openssl
|
||||
with:
|
||||
path: MINGW-packages/mingw-w64-openssl/*.zst
|
||||
key: winxp-openssl-${{ steps.version-openssl.outputs.version }}
|
||||
- name: Build WinXP-capable openssl package
|
||||
if: steps.cache-openssl.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cd MINGW-packages/mingw-w64-openssl
|
||||
gpg --recv-keys D894E2CE8B3D79F5
|
||||
gpg --recv-keys 216094DFD0CB81EF
|
||||
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm --nocheck
|
||||
- name: Install openssl package
|
||||
run: pacman --noconfirm -U MINGW-packages/mingw-w64-openssl/mingw-w64-i686-*-any.pkg.tar.zst
|
||||
|
||||
# Boost
|
||||
#- name: Get boost package version
|
||||
# id: version-boost
|
||||
# run: |
|
||||
# echo "version=$(pacman -Si mingw-w64-i686-boost | grep -Po '^Version\s*: \K.+')" >> $GITHUB_OUTPUT
|
||||
- name: Cache boost package
|
||||
uses: actions/cache@v4
|
||||
id: cache-boost
|
||||
with:
|
||||
path: MINGW-packages/mingw-w64-boost/*.zst
|
||||
key: winxp-boost-1.85.0+crt-${{ steps.version-headers.outputs.version }}+ossl-${{ steps.version-openssl.outputs.version }}
|
||||
# Rebuild package if packages above has changed
|
||||
- name: Build WinXP-capable boost package
|
||||
if: steps.cache-boost.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cd MINGW-packages/mingw-w64-boost
|
||||
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm --nocheck
|
||||
- name: Install boost package
|
||||
run: pacman --noconfirm -U --overwrite MINGW-packages/mingw-w64-boost/mingw-w64-i686-*-any.pkg.tar.zst
|
||||
|
||||
# Building i2pd
|
||||
- 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@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: i2pd-xp.exe
|
||||
path: i2pd.exe
|
||||
|
||||
24
.github/workflows/build.yml
vendored
24
.github/workflows/build.yml
vendored
@@ -1,6 +1,24 @@
|
||||
name: Build on Ubuntu
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- .github/workflows/build.yml
|
||||
- build/CMakeLists.txt
|
||||
- build/cmake_modules/**
|
||||
- daemon/**
|
||||
- i18n/**
|
||||
- libi2pd/**
|
||||
- libi2pd_client/**
|
||||
- Makefile
|
||||
- Makefile.linux
|
||||
tags:
|
||||
- '*'
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build-make:
|
||||
@@ -14,7 +32,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: install packages
|
||||
run: |
|
||||
@@ -35,7 +53,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: install packages
|
||||
run: |
|
||||
|
||||
22
.github/workflows/docker.yml
vendored
22
.github/workflows/docker.yml
vendored
@@ -37,29 +37,29 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Login to GitHub Container registry
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build container for ${{ matrix.archname }}
|
||||
uses: docker/build-push-action@v3
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: ./contrib/docker
|
||||
file: ./contrib/docker/Dockerfile
|
||||
@@ -82,22 +82,22 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Login to GitHub Container registry
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
|
||||
165
ChangeLog
165
ChangeLog
@@ -1,7 +1,170 @@
|
||||
# for this file format description,
|
||||
# see https://github.com/olivierlacan/keep-a-changelog
|
||||
|
||||
## [2.50.0] - 2023-12-23
|
||||
## [2.54.0] - 2024-10-06
|
||||
### Added
|
||||
- Maintain recently connected routers list to avoid false-positive peer test
|
||||
- Limited connectivity mode(through proxy)
|
||||
- "i2p.streaming.profile" tunnel's param to let tunnel select also low-bandwidth routers
|
||||
- Limit stream's inbound speed
|
||||
- Periodic ack requests in ratchets session
|
||||
- Set congestion cap G immediately if through proxy
|
||||
- Show tunnel's routers bandwidth caps in web console
|
||||
- Handle immediate ack requested flag in SSU2 data packets
|
||||
- Resend and ack peer test and relay messages
|
||||
- "senduseragent" HTTP proxy's param to pass through user's User-Agent
|
||||
### Changed
|
||||
- Exclude 'N' routers from high-bandwidth routers for client tunnels
|
||||
- C++11 support has been dropped, the minimal requirement is C++17 now, C++20 for some compilers
|
||||
- Removed dependency from boost::date_time and boost::filesystem
|
||||
- Set default i2cp.leaseSetEncType to 0,4 and to 4 for server tunnels
|
||||
- Handle i2cp.inboundlimit and i2cp.outboundlimit params in I2CP
|
||||
- Publish LeaseSet with new timestamp update if tunnel was replaced in the same second
|
||||
- Increase max number of generated tags to 800 per tagset
|
||||
- Routing path expiration by time instead num attempts
|
||||
- Save timestamp from epoch instead local time to profiles
|
||||
- Update introducer's iTag if session to introducer was replaced to new one
|
||||
- RTT, window size and number of NACKs calculation for streaming
|
||||
- Don't select same peer for tunnel too often
|
||||
- Use WinApi for data path UTF-8 conversion for Windows
|
||||
### Fixed
|
||||
- Jump link crash if address book is disabled
|
||||
- Race condition if connect through an introducer
|
||||
- "Date" header in I2PControl response
|
||||
- Incomplete response from web console
|
||||
- AEAD verification with LibreSSL
|
||||
- Number of generated tags and new keys for follow-on tagsets
|
||||
- Expired leases in LeaseSet
|
||||
- Attempts to send HolePunch to 0.0.0.0
|
||||
- Incorrect options size in quick ack streaming packet
|
||||
- Low bandwidth router appeared as first peer in high-bandwidth client tunnel
|
||||
|
||||
## [2.53.1] - 2024-07-29
|
||||
### Changed
|
||||
- I2CP performance improvement
|
||||
### Fixed
|
||||
- 100% CPU usage after I2CP/SAM/BOB session termination
|
||||
- Incorrect client limits returned through I2CP
|
||||
- Build with LibreSSL
|
||||
|
||||
## [2.53.0] - 2024-07-19
|
||||
### Added
|
||||
- New congestion control algorithm for streaming
|
||||
- Support miniupnp-2.2.8
|
||||
- Limit stream's outbound speed
|
||||
- Flood to next day closest floodfills before UTC midnight
|
||||
- Recognize duplicated routers and bypass them
|
||||
- Random SSU2 resend interval
|
||||
### Changed
|
||||
- Set minimal version to 0.9.69 for floodfills and 0.9.58 for client tunnels
|
||||
- Removed openssl 1.0.2 support
|
||||
- Move unsent I2NP messages to the new session if replaced
|
||||
- Use mt19937 RNG instead rand()
|
||||
- Update router's congestion caps before initial publishing
|
||||
- Don't try introducer with invalid address
|
||||
- Select newest introducers to publish
|
||||
- Don't request relay tag for every session if we have enough introducers
|
||||
- Update timestamp for non-reachable or hidden router
|
||||
- Reset streaming routing path if duplicated SYN received
|
||||
- Update LeaseSet if inbound tunnel failed
|
||||
- Reseeds list
|
||||
### Fixed
|
||||
- Crash when a destination gets terminated
|
||||
- Expired offline signature upon destination creation
|
||||
- Race condition between local RouterInfo buffer creation and sending it through the transports
|
||||
|
||||
## [2.52.0] - 2024-05-12
|
||||
### Added
|
||||
- Separate threads for persisting RouterInfos and profiles to disk
|
||||
- Give preference to address with direct connection
|
||||
- Exclude addresses with incorrect static or intro key
|
||||
- Avoid two firewalled routers in the row in tunnel
|
||||
- Drop unsolicited database search replies
|
||||
### Changed
|
||||
- Increase number of hashes to 16 in exploratory lookup reply
|
||||
- Reduce number of a RouterInfo lookup attempts to 5
|
||||
- Reset stream RTO if outbound tunnel was changed
|
||||
- Insert previously excluded floodfill back when successfully connected
|
||||
- Increase maximum stream resend attempts to 9
|
||||
- Reply to exploratory lookups with only confirmed routers if low tunnel build rate
|
||||
- Don't accept too old RouterInfo
|
||||
- Build client tunnels through confirmed routers only if low tunnel build rate
|
||||
- Manage netDb requests more frequently
|
||||
- Don't reply with closer than us only floodfills for lookup
|
||||
### Fixed
|
||||
- Crash on router lookup if exploratory pool is not ready
|
||||
- Race condition in excluded peers for next lookup
|
||||
- Excessive number of lookups for same destination
|
||||
- Race condition with transport peers during shutdown
|
||||
- Corrupted RouterInfo files
|
||||
|
||||
## [2.51.0] - 2024-04-06
|
||||
### Added
|
||||
- Non-blocking mode for UDP sockets
|
||||
- Set SSU2 socket buffer size based on bandwidth limit
|
||||
- Encrypted tunnel tests
|
||||
- Support for multiple UDP server tunnels on one destination
|
||||
- Publish medium congestion indication
|
||||
- Local domain sockets for SOCKS proxy upstream
|
||||
- Tunnel status "declined" in web console
|
||||
- SAM error reply "Incompatible crypto" if remote destination has incompatible crypto
|
||||
- Reduce amount of traffic by handling local message drops
|
||||
- Keep SSU2 socket open even if it fails to bind
|
||||
- Lower SSU2 resend traffic spikes
|
||||
- Expiration for messages in SSU2 send queue
|
||||
- Use EWMA for stream RTT estimation
|
||||
- Request choking delay if too many NACKs in stream
|
||||
- Allow 0ms latency for tunnel
|
||||
- Randomize tunnels selection for tests
|
||||
### Changed
|
||||
- Upstream SOCKS proxy from SOCKS4 to SOCKS5
|
||||
- Transit tunnels limit to 4 bytes. Default value to 10K
|
||||
- Reply CANT_REACH_PEER if connect to ourselves in SAM
|
||||
- Don't send already expired I2NP messages
|
||||
- Use monotonic timer to measure tunnel test latency
|
||||
- Standard NTCP2 frame doesn't exceed 16K
|
||||
- Always send request through tunnels in case of restricted routes
|
||||
- Don't delete connected routers from NetDb
|
||||
- Send lookup reply directly to reply tunnel gateway if possible
|
||||
- Reduce unreachable router ban interval to 8 minutes
|
||||
- Don't request banned routers / don't try to connect to unreachable router
|
||||
- Consider 'M' routers as low bandwidth
|
||||
- Limit minimal received SSU2 packet size to 40 bytes
|
||||
- Bob picks peer test session only if Charlie's address supports peer testing
|
||||
- Reject peer test msg 2 if peer testing is not supported
|
||||
- Don't request termination if SSU2 session was not established
|
||||
- Set maximum SSU2 queue size depending on RTT value
|
||||
- New streaming RTT calculation algorithm
|
||||
- Don't double initial RTO for streams when changing tunnels
|
||||
- Restore failed tunnel if test or data for inbound tunnel received
|
||||
- Don't fail last remaining tunnel in pool
|
||||
- Publish LeasetSet again if local destination was not ready or no tunnels
|
||||
- Make more attempts to pick high bandwidth hop for client tunnel
|
||||
- Reduced SSU2 session termination timeout to 165 seconds
|
||||
- Reseeds list
|
||||
### Fixed
|
||||
- ECIESx25519 symmetric key tagset early expiration
|
||||
- Encrypted LeaseSet lookup
|
||||
- Outbound tunnel build fails if it's endpoint is the same as reply tunnel gateway
|
||||
- I2PControl RouterManager returns invalid JSON when unknown params are passed
|
||||
- Mix of data between different UDP sessions on the same server
|
||||
- TARGET_OS_SIMULATOR check
|
||||
- Handling of "reservedrange" param
|
||||
- New NTCP2 session gets teminated upon termination of old one
|
||||
- New SSU2 session gets teminated upon termination of old one
|
||||
- Peer test to non-supporting router
|
||||
- Streaming ackThrough off 1 if number of NACKs exceeds 255
|
||||
- Race condition in ECIESx25519 tags table
|
||||
- Good tunnel becomes failed
|
||||
- Crash when packet comes to terminated stream
|
||||
- Stream hangs during LeaseSet update
|
||||
|
||||
## [2.50.2] - 2024-01-06
|
||||
###Fixed
|
||||
- Crash with OpenSSL 3.2.0
|
||||
- False positive clock skew detection
|
||||
|
||||
## [2.50.1] - 2023-12-23
|
||||
###Fixed
|
||||
- Support for new EdDSA usage behavior in OpenSSL 3.2.0
|
||||
|
||||
|
||||
19
Makefile.bsd
19
Makefile.bsd
@@ -1,13 +1,22 @@
|
||||
CXX = clang++
|
||||
CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misleading-indentation
|
||||
DEFINES = -D_GLIBCXX_USE_NANOSLEEP=1
|
||||
INCFLAGS = -I/usr/include/ -I/usr/local/include/
|
||||
LDFLAGS = ${LD_DEBUG} -Wl,-rpath,/usr/local/lib -L/usr/local/lib
|
||||
LDLIBS = -lcrypto -lssl -lz -lpthread -lboost_system -lboost_program_options
|
||||
|
||||
## NOTE: NEEDED_CXXFLAGS is here so that custom CXXFLAGS can be specified at build time
|
||||
## **without** overwriting the CXXFLAGS which we need in order to build.
|
||||
## For example, when adding 'hardening flags' to the build
|
||||
## (e.g. -fstack-protector-strong -Wformat -Werror=format-security), we do not want to remove
|
||||
## -std=c++11. If you want to remove this variable please do so in a way that allows setting
|
||||
## custom FLAGS to work at build-time.
|
||||
NEEDED_CXXFLAGS = -std=c++11
|
||||
DEFINES = -D_GLIBCXX_USE_NANOSLEEP=1
|
||||
INCFLAGS = -I/usr/include/ -I/usr/local/include/
|
||||
LDFLAGS = ${LD_DEBUG} -Wl,-rpath,/usr/local/lib -L/usr/local/lib
|
||||
LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
|
||||
CXXVER := $(shell $(CXX) -dumpversion|cut -c 1-2)
|
||||
ifeq (${CXXVER}, "4.") # older clang always returned 4.2.1
|
||||
$(error Compiler too old)
|
||||
else ifeq (${CXXVER}, ${filter ${CXXVER},16 17 18 19}) # clang 16 - 19
|
||||
NEEDED_CXXFLAGS = -std=c++20
|
||||
else
|
||||
NEEDED_CXXFLAGS = -std=c++17
|
||||
endif
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
CXX = g++
|
||||
CXXFLAGS := -Wall -std=c++11
|
||||
CXXFLAGS := -Wall -std=c++17
|
||||
INCFLAGS = -I/system/develop/headers
|
||||
DEFINES = -D_DEFAULT_SOURCE -D_GNU_SOURCE
|
||||
LDLIBS = -lbe -lbsd -lnetwork -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
|
||||
LDLIBS = -lbe -lbsd -lnetwork -lz -lcrypto -lssl -lboost_system -lboost_program_options -lpthread
|
||||
|
||||
ifeq ($(USE_UPNP),yes)
|
||||
DEFINES += -DUSE_UPNP
|
||||
|
||||
@@ -1,41 +1,40 @@
|
||||
# root directory holding homebrew
|
||||
BREWROOT = /usr/local
|
||||
BREWROOT = /opt/homebrew
|
||||
BOOSTROOT = ${BREWROOT}/opt/boost
|
||||
SSLROOT = ${BREWROOT}/opt/openssl@1.1
|
||||
UPNPROOT = ${BREWROOT}/opt/miniupnpc
|
||||
CXXFLAGS = ${CXX_DEBUG} -Wall -std=c++11 -DMAC_OSX -Wno-overloaded-virtual
|
||||
INCFLAGS = -I${SSLROOT}/include -I${BOOSTROOT}/include
|
||||
LDFLAGS = ${LD_DEBUG}
|
||||
|
||||
ifndef TRAVIS
|
||||
CXX = clang++
|
||||
endif
|
||||
CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wno-overloaded-virtual
|
||||
NEEDED_CXXFLAGS ?= -std=c++17
|
||||
INCFLAGS ?= -I${SSLROOT}/include -I${BOOSTROOT}/include
|
||||
LDFLAGS ?= ${LD_DEBUG}
|
||||
DEFINES += -DMAC_OSX
|
||||
|
||||
ifeq ($(USE_STATIC),yes)
|
||||
LDLIBS = -lz ${SSLROOT}/lib/libcrypto.a ${SSLROOT}/lib/libssl.a ${BOOSTROOT}/lib/libboost_system.a ${BOOSTROOT}/lib/libboost_date_time.a ${BOOSTROOT}/lib/libboost_filesystem.a ${BOOSTROOT}/lib/libboost_program_options.a -lpthread
|
||||
LDLIBS = -lz ${SSLROOT}/lib/libcrypto.a ${SSLROOT}/lib/libssl.a ${BOOSTROOT}/lib/libboost_system.a ${BOOSTROOT}/lib/libboost_filesystem.a ${BOOSTROOT}/lib/libboost_program_options.a
|
||||
ifeq ($(USE_UPNP),yes)
|
||||
LDLIBS += ${UPNPROOT}/lib/libminiupnpc.a
|
||||
endif
|
||||
LDLIBS += -lpthread -ldl
|
||||
else
|
||||
LDFLAGS += -L${SSLROOT}/lib -L${BOOSTROOT}/lib
|
||||
LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
|
||||
LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_filesystem -lboost_program_options -lpthread
|
||||
ifeq ($(USE_UPNP),yes)
|
||||
LDFLAGS += -L${UPNPROOT}/lib
|
||||
LDLIBS += -lminiupnpc
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(USE_UPNP),yes)
|
||||
LDFLAGS += -ldl
|
||||
CXXFLAGS += -DUSE_UPNP
|
||||
DEFINES += -DUSE_UPNP
|
||||
INCFLAGS += -I${UPNPROOT}/include
|
||||
ifeq ($(USE_STATIC),yes)
|
||||
LDLIBS += ${UPNPROOT}/lib/libminiupnpc.a
|
||||
else
|
||||
LDFLAGS += -L${UPNPROOT}/lib
|
||||
LDLIBS += -lminiupnpc
|
||||
endif
|
||||
endif
|
||||
|
||||
# OSX Notes
|
||||
# http://www.hutsby.net/2011/08/macs-with-aes-ni.html
|
||||
# Seems like all recent Mac's have AES-NI, after firmware upgrade 2.2
|
||||
# Found no good way to detect it from command line. TODO: Might be some osx sysinfo magic
|
||||
ifeq ($(USE_AESNI),yes)
|
||||
CXXFLAGS += -D__AES__ -maes
|
||||
ifneq (, $(findstring i386, $(SYS))$(findstring i686, $(SYS))$(findstring x86_64, $(SYS))) # only x86-based CPU supports that
|
||||
NEEDED_CXXFLAGS += -maes
|
||||
DEFINES += -D__AES__
|
||||
endif
|
||||
endif
|
||||
|
||||
install: all
|
||||
|
||||
@@ -9,24 +9,17 @@ LDFLAGS ?= ${LD_DEBUG}
|
||||
## -std=c++11. If you want to remove this variable please do so in a way that allows setting
|
||||
## custom FDLAGS to work at build-time.
|
||||
|
||||
# detect proper flag for c++11 support by compilers
|
||||
# detect proper flag for c++17 support by compilers
|
||||
CXXVER := $(shell $(CXX) -dumpversion)
|
||||
ifeq ($(shell expr match $(CXX) 'clang'),5)
|
||||
NEEDED_CXXFLAGS += -std=c++11
|
||||
else ifeq ($(shell expr match ${CXXVER} "4\.[0-9][0-9]"),4) # gcc >= 4.10
|
||||
NEEDED_CXXFLAGS += -std=c++11
|
||||
else ifeq ($(shell expr match ${CXXVER} "4\.[8-9]"),3) # gcc 4.8 - 4.9
|
||||
NEEDED_CXXFLAGS += -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1
|
||||
else ifeq ($(shell expr match ${CXXVER} "[5-6]"),1) # gcc 5 - 6
|
||||
NEEDED_CXXFLAGS += -std=c++11
|
||||
LDLIBS = -latomic
|
||||
else ifeq ($(shell expr match ${CXXVER} "[7-9]"),1) # gcc 7 - 9
|
||||
NEEDED_CXXFLAGS += -std=c++17
|
||||
LDLIBS = -latomic
|
||||
else ifeq ($(shell expr match ${CXXVER} "1[0-9]"),2) # gcc 10+
|
||||
# NEEDED_CXXFLAGS += -std=c++20
|
||||
else ifeq ($(shell expr match ${CXXVER} "[8-9]"),1) # gcc 8 - 9
|
||||
NEEDED_CXXFLAGS += -std=c++17
|
||||
LDLIBS = -latomic
|
||||
LDLIBS = -lboost_system -lstdc++fs
|
||||
else ifeq ($(shell expr match ${CXXVER} "1[0-2]"),2) # gcc 10 - 12
|
||||
NEEDED_CXXFLAGS += -std=c++17
|
||||
else ifeq ($(shell expr match ${CXXVER} "1[3-9]"),2) # gcc 13+
|
||||
NEEDED_CXXFLAGS += -std=c++20
|
||||
else # not supported
|
||||
$(error Compiler too old)
|
||||
endif
|
||||
@@ -38,9 +31,6 @@ ifeq ($(USE_STATIC),yes)
|
||||
# Using 'getaddrinfo' in statically linked applications requires at runtime
|
||||
# the shared libraries from the glibc version used for linking
|
||||
LIBDIR := /usr/lib/$(SYS)
|
||||
LDLIBS += $(LIBDIR)/libboost_system.a
|
||||
LDLIBS += $(LIBDIR)/libboost_date_time.a
|
||||
LDLIBS += $(LIBDIR)/libboost_filesystem.a
|
||||
LDLIBS += $(LIBDIR)/libboost_program_options.a
|
||||
LDLIBS += $(LIBDIR)/libssl.a
|
||||
LDLIBS += $(LIBDIR)/libcrypto.a
|
||||
@@ -50,7 +40,7 @@ ifeq ($(USE_UPNP),yes)
|
||||
endif
|
||||
LDLIBS += -lpthread -ldl
|
||||
else
|
||||
LDLIBS += -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
|
||||
LDLIBS += -lcrypto -lssl -lz -lboost_program_options -lpthread -latomic
|
||||
ifeq ($(USE_UPNP),yes)
|
||||
LDLIBS += -lminiupnpc
|
||||
endif
|
||||
|
||||
@@ -7,7 +7,7 @@ CXXFLAGS := $(CXX_DEBUG) -fPIC -msse
|
||||
INCFLAGS := -I$(DAEMON_SRC_DIR) -IWin32
|
||||
LDFLAGS := ${LD_DEBUG} -static -fPIC -msse
|
||||
|
||||
NEEDED_CXXFLAGS += -std=c++17
|
||||
NEEDED_CXXFLAGS += -std=c++20
|
||||
DEFINES += -DWIN32_LEAN_AND_MEAN
|
||||
|
||||
# UPNP Support
|
||||
@@ -16,9 +16,11 @@ ifeq ($(USE_UPNP),yes)
|
||||
LDLIBS = -lminiupnpc
|
||||
endif
|
||||
|
||||
ifeq ($(USE_WINXP_FLAGS), yes)
|
||||
DEFINES += -DWINVER=0x0501 -D_WIN32_WINNT=0x0501
|
||||
endif
|
||||
|
||||
LDLIBS += \
|
||||
$(MINGW_PREFIX)/lib/libboost_system-mt.a \
|
||||
$(MINGW_PREFIX)/lib/libboost_date_time-mt.a \
|
||||
$(MINGW_PREFIX)/lib/libboost_filesystem-mt.a \
|
||||
$(MINGW_PREFIX)/lib/libboost_program_options-mt.a \
|
||||
$(MINGW_PREFIX)/lib/libssl.a \
|
||||
@@ -40,10 +42,6 @@ ifeq ($(USE_WIN32_APP), yes)
|
||||
DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC))
|
||||
endif
|
||||
|
||||
ifeq ($(USE_WINXP_FLAGS), yes)
|
||||
DEFINES += -DWINVER=0x0501 -D_WIN32_WINNT=0x0501
|
||||
endif
|
||||
|
||||
ifeq ($(USE_AESNI),yes)
|
||||
NEEDED_CXXFLAGS += -maes
|
||||
LDFLAGS += -maes
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
CXX = clang++
|
||||
CXXFLAGS := ${CXX_DEBUG} -Wall -std=c++11
|
||||
CXXFLAGS := ${CXX_DEBUG} -Wall -std=c++17
|
||||
INCFLAGS = -I/usr/local/include
|
||||
DEFINES := -DMAC_OSX
|
||||
LDFLAGS := -Wl,-rpath,/usr/local/lib -L/usr/local/lib
|
||||
@@ -7,9 +7,9 @@ LDFLAGS += -Wl,-dead_strip
|
||||
LDFLAGS += -Wl,-dead_strip_dylibs
|
||||
|
||||
ifeq ($(USE_STATIC),yes)
|
||||
LDLIBS = -lz /usr/local/lib/libcrypto.a /usr/local/lib/libssl.a /usr/local/lib/libboost_system.a /usr/local/lib/libboost_date_time.a /usr/local/lib/libboost_filesystem.a /usr/local/lib/libboost_program_options.a -lpthread
|
||||
LDLIBS = -lz /usr/local/lib/libcrypto.a /usr/local/lib/libssl.a /usr/local/lib/libboost_system.a /usr/local/lib/libboost_filesystem.a /usr/local/lib/libboost_program_options.a -lpthread
|
||||
else
|
||||
LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
|
||||
LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_filesystem -lboost_program_options -lpthread
|
||||
endif
|
||||
|
||||
ifeq ($(USE_UPNP),yes)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -145,7 +145,7 @@ namespace win32
|
||||
s << bytes << " Bytes\n";
|
||||
}
|
||||
|
||||
static void ShowNetworkStatus (std::stringstream& s, RouterStatus status, bool testing)
|
||||
static void ShowNetworkStatus (std::stringstream& s, RouterStatus status, bool testing, RouterError error)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
@@ -158,18 +158,24 @@ namespace win32
|
||||
};
|
||||
if (testing)
|
||||
s << " (Test)";
|
||||
if (i2p::context.GetError () != eRouterErrorNone)
|
||||
if (error != eRouterErrorNone)
|
||||
{
|
||||
switch (i2p::context.GetError ())
|
||||
switch (error)
|
||||
{
|
||||
case eRouterErrorClockSkew:
|
||||
s << " - Clock skew";
|
||||
s << " - " << tr("Clock skew");
|
||||
break;
|
||||
case eRouterErrorOffline:
|
||||
s << " - Offline";
|
||||
s << " - " << tr("Offline");
|
||||
break;
|
||||
case eRouterErrorSymmetricNAT:
|
||||
s << " - Symmetric NAT";
|
||||
s << " - " << tr("Symmetric NAT");
|
||||
break;
|
||||
case eRouterErrorFullConeNAT:
|
||||
s << " - " << tr("Full cone NAT");
|
||||
break;
|
||||
case eRouterErrorNoDescriptors:
|
||||
s << " - " << tr("No Descriptors");
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
@@ -180,11 +186,11 @@ namespace win32
|
||||
{
|
||||
s << "\n";
|
||||
s << "Status: ";
|
||||
ShowNetworkStatus (s, i2p::context.GetStatus (), i2p::context.GetTesting ());
|
||||
ShowNetworkStatus (s, i2p::context.GetStatus (), i2p::context.GetTesting(), i2p::context.GetError ());
|
||||
if (i2p::context.SupportsV6 ())
|
||||
{
|
||||
s << " / ";
|
||||
ShowNetworkStatus (s, i2p::context.GetStatusV6 (), i2p::context.GetTestingV6 ());
|
||||
ShowNetworkStatus (s, i2p::context.GetStatusV6 (), i2p::context.GetTestingV6(), i2p::context.GetErrorV6 ());
|
||||
}
|
||||
s << "; ";
|
||||
s << "Success Rate: " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate() << "%\n";
|
||||
@@ -307,7 +313,7 @@ namespace win32
|
||||
}
|
||||
case ID_DATADIR:
|
||||
{
|
||||
std::string datadir(i2p::fs::GetUTF8DataDir());
|
||||
std::string datadir(i2p::fs::GetDataDir());
|
||||
ShellExecute(NULL, "explore", datadir.c_str(), NULL, NULL, SW_SHOWNORMAL);
|
||||
return 0;
|
||||
}
|
||||
@@ -349,9 +355,7 @@ namespace win32
|
||||
}
|
||||
}
|
||||
}
|
||||
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||
[[fallthrough]];
|
||||
#endif
|
||||
}
|
||||
case WM_TRAYICON:
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -73,16 +73,24 @@ void UnSubscribeFromEvents()
|
||||
}
|
||||
|
||||
if (pNetEvent)
|
||||
{
|
||||
pNetEvent->Release();
|
||||
}
|
||||
|
||||
if (pCPContainer)
|
||||
{
|
||||
pCPContainer->Release();
|
||||
}
|
||||
|
||||
if (pNetworkListManager)
|
||||
{
|
||||
pNetworkListManager->Release();
|
||||
}
|
||||
|
||||
if (pUnknown)
|
||||
{
|
||||
pUnknown->Release();
|
||||
}
|
||||
|
||||
CoUninitialize();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -15,10 +15,11 @@
|
||||
#include "Log.h"
|
||||
#include "Transports.h"
|
||||
|
||||
class CNetworkListManagerEvent : public INetworkListManagerEvents
|
||||
class CNetworkListManagerEvent final : public INetworkListManagerEvents
|
||||
{
|
||||
public:
|
||||
CNetworkListManagerEvent() : m_ref(1) { }
|
||||
~CNetworkListManagerEvent() { }
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject)
|
||||
{
|
||||
|
||||
@@ -156,20 +156,6 @@ else()
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -ffunction-sections -fdata-sections")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-Wl,--gc-sections") # -flto is added from above
|
||||
|
||||
# check for c++17 & c++11 support
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++17" CXX17_SUPPORTED)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++11" CXX11_SUPPORTED)
|
||||
|
||||
if(CXX17_SUPPORTED)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
|
||||
elseif(CXX11_SUPPORTED)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
else()
|
||||
message(SEND_ERROR "C++17 nor C++11 standard not seems to be supported by compiler. Too old version?")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
@@ -223,6 +209,10 @@ if(WITH_THREADSANITIZER)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.0 AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0) # gcc 8-9
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES "stdc++fs")
|
||||
endif()
|
||||
|
||||
# Use std::atomic instead of GCC builtins on macOS PowerPC:
|
||||
# For more information refer to: https://github.com/PurpleI2P/i2pd/issues/1726#issuecomment-1306335111
|
||||
# This has been fixed in Boost 1.81, nevertheless we retain the setting for the sake of compatibility.
|
||||
@@ -277,14 +267,14 @@ else()
|
||||
if(NOT MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
||||
endif()
|
||||
add_definitions(-DBOOST_ATOMIC_DYN_LINK -DBOOST_SYSTEM_DYN_LINK -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_PROGRAM_OPTIONS_DYN_LINK -DBOOST_DATE_TIME_DYN_LINK -DBOOST_REGEX_DYN_LINK)
|
||||
add_definitions(-DBOOST_ATOMIC_DYN_LINK -DBOOST_SYSTEM_DYN_LINK -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_PROGRAM_OPTIONS_DYN_LINK)
|
||||
if(WIN32)
|
||||
set(Boost_USE_STATIC_LIBS OFF)
|
||||
set(Boost_USE_STATIC_RUNTIME OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package(Boost REQUIRED COMPONENTS system filesystem program_options date_time OPTIONAL_COMPONENTS atomic)
|
||||
find_package(Boost REQUIRED COMPONENTS system filesystem program_options)
|
||||
if(NOT DEFINED Boost_FOUND)
|
||||
message(SEND_ERROR "Boost is not found, or your boost version was below 1.46. Please download Boost!")
|
||||
endif()
|
||||
@@ -312,6 +302,26 @@ if(ZLIB_FOUND)
|
||||
link_directories(${ZLIB_ROOT}/lib)
|
||||
endif()
|
||||
|
||||
# C++ standard to use, based on compiler and version of boost
|
||||
if(NOT MSVC)
|
||||
# check for c++20 & c++17 support
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
if(Boost_VERSION VERSION_GREATER_EQUAL "1.83") # min boost version for c++20
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++20" CXX20_SUPPORTED)
|
||||
endif()
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++17" CXX17_SUPPORTED)
|
||||
|
||||
|
||||
if(CXX20_SUPPORTED)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20")
|
||||
elseif(CXX17_SUPPORTED)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
|
||||
else()
|
||||
message(SEND_ERROR "C++20 nor C++17 standard not seems to be supported by compiler. Too old version?")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# load includes
|
||||
include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR})
|
||||
|
||||
@@ -322,6 +332,7 @@ message(STATUS "Compiler vendor : ${CMAKE_CXX_COMPILER_ID}")
|
||||
message(STATUS "Compiler version : ${CMAKE_CXX_COMPILER_VERSION}")
|
||||
message(STATUS "Compiler path : ${CMAKE_CXX_COMPILER}")
|
||||
message(STATUS "Architecture : ${ARCHITECTURE}")
|
||||
message(STATUS "Compiler flags : ${CMAKE_CXX_FLAGS}")
|
||||
message(STATUS "Install prefix: : ${CMAKE_INSTALL_PREFIX}")
|
||||
message(STATUS "Options:")
|
||||
message(STATUS " AESNI : ${WITH_AESNI}")
|
||||
|
||||
@@ -8,7 +8,7 @@ INCLUDE(CheckLibraryExists)
|
||||
|
||||
function(check_working_cxx_atomics varname)
|
||||
set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++11")
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++17")
|
||||
CHECK_CXX_SOURCE_COMPILES("
|
||||
#include <atomic>
|
||||
std::atomic<int> x;
|
||||
@@ -25,7 +25,7 @@ endfunction(check_working_cxx_atomics)
|
||||
|
||||
function(check_working_cxx_atomics64 varname)
|
||||
set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
|
||||
set(CMAKE_REQUIRED_FLAGS "-std=c++11 ${CMAKE_REQUIRED_FLAGS}")
|
||||
set(CMAKE_REQUIRED_FLAGS "-std=c++17 ${CMAKE_REQUIRED_FLAGS}")
|
||||
CHECK_CXX_SOURCE_COMPILES("
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
|
||||
@@ -24,7 +24,7 @@ ExtraDiskSpaceRequired=15
|
||||
|
||||
AppID={{621A23E0-3CF4-4BD6-97BC-4835EA5206A2}
|
||||
AppVerName={#I2Pd_AppName}
|
||||
AppCopyright=Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
AppCopyright=Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
AppPublisherURL=http://i2pd.website/
|
||||
AppSupportURL=https://github.com/PurpleI2P/i2pd/issues
|
||||
AppUpdatesURL=https://github.com/PurpleI2P/i2pd/releases
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#
|
||||
#include <tunables/global>
|
||||
|
||||
profile i2pd /{usr/,}sbin/i2pd {
|
||||
profile i2pd /{usr/,}bin/i2pd {
|
||||
#include <abstractions/base>
|
||||
#include <abstractions/openssl>
|
||||
#include <abstractions/nameservice>
|
||||
@@ -14,12 +14,12 @@ profile i2pd /{usr/,}sbin/i2pd {
|
||||
/var/lib/i2pd/** rw,
|
||||
/var/log/i2pd/i2pd.log w,
|
||||
/{var/,}run/i2pd/i2pd.pid rwk,
|
||||
/{usr/,}sbin/i2pd mr,
|
||||
/{usr/,}bin/i2pd mr,
|
||||
@{system_share_dirs}/i2pd/** r,
|
||||
|
||||
# user homedir (if started not by init.d or systemd)
|
||||
owner @{HOME}/.i2pd/ rw,
|
||||
owner @{HOME}/.i2pd/** rwk,
|
||||
|
||||
#include if exists <local/usr.sbin.i2pd>
|
||||
#include if exists <local/usr.bin.i2pd>
|
||||
}
|
||||
34
contrib/certificates/reseed/admin_at_stormycloud.org.crt
Normal file
34
contrib/certificates/reseed/admin_at_stormycloud.org.crt
Normal file
@@ -0,0 +1,34 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIF1zCCA7+gAwIBAgIRAMDqFR09Xuj8ZUu+oetSvAEwDQYJKoZIhvcNAQELBQAw
|
||||
dTELMAkGA1UEBhMCWFgxCzAJBgNVBAcTAlhYMQswCQYDVQQJEwJYWDEeMBwGA1UE
|
||||
ChMVSTJQIEFub255bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxHjAcBgNVBAMM
|
||||
FWFkbWluQHN0b3JteWNsb3VkLm9yZzAeFw0yNDAxMjUxNDE1MzBaFw0zNDAxMjUx
|
||||
NDE1MzBaMHUxCzAJBgNVBAYTAlhYMQswCQYDVQQHEwJYWDELMAkGA1UECRMCWFgx
|
||||
HjAcBgNVBAoTFUkyUCBBbm9ueW1vdXMgTmV0d29yazEMMAoGA1UECxMDSTJQMR4w
|
||||
HAYDVQQDDBVhZG1pbkBzdG9ybXljbG91ZC5vcmcwggIiMA0GCSqGSIb3DQEBAQUA
|
||||
A4ICDwAwggIKAoICAQDbGX+GikPzQXr9zvkrhfO9g0l49KHLNQhUKYqd6T+PfnGo
|
||||
Fm0d3ZZVVQZ045vWgroOXDGGZZWxUIlb2inRaR2DF1TxN3pPYt59RgY9ZQ9+TL7o
|
||||
isY91krCRygY8EcAmHIjlfZQ9dBVcL7CfyT0MYZA5Efee9+NDHSewTfQP9T2faIE
|
||||
83Fcyd93a2mIHYjKUbJnojng/wgsy8srbsEuuTok4MIQmDj+B5nz+za2FgI0/ydh
|
||||
srlMt4aGJF4/DIem9z9d0zBCOkwrmtFIzjNF1mOSA8ES4m5YnKA/y9rZlRidLPGu
|
||||
prbXhPVnqHeOnHMz2QCw1wbVo504kl0bMqyEz2tVWsO9ep7iZoQs2xkFAEaegYNT
|
||||
QLUpwVGlyuq3wXXwopFRffOSimGSazICwWI6j+K0pOtgefNJaWrqKYvtkj1SbK2L
|
||||
LBNUIENz6VnB7KPRckuX6zxC8PpOiBK9BcftfO+xAz/wC6qq3riBPw30KKSym0nC
|
||||
Zp5KciDn4Phtw9PGq8Bkl8SyWl0jtFnfTB1tzJkisf2qKcNHaFTEe2JW763YLbh/
|
||||
AU+8X8evFu40qLgvOgKoyy5DLy6i8zetX+3t9K0Fxt9+Vzzq6lm5V/RS8iIPPn+M
|
||||
q1/3Z5kD0KQBG9h/Gl8BH+lB71ZxPAOZ3SMu8DJZcxBLVmDWqQPCr5CKnoz0swID
|
||||
AQABo2IwYDAOBgNVHQ8BAf8EBAMCAoQwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsG
|
||||
AQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wHgYDVR0OBBcEFWFkbWluQHN0b3JteWNs
|
||||
b3VkLm9yZzANBgkqhkiG9w0BAQsFAAOCAgEARWOJ69vTHMneSXYscha+4Ytjg0RM
|
||||
faewJNEGj8qy/Qvh9si2bWYNPRK6BlbHFS7pRYBLAnhaeLBGVv1CCR6GUMMe74zQ
|
||||
UuMeAoWU6qMDmB3GfYoZJh8sIxpwHqyJeTdeccRbZ4sX4F6u3IHPXYiU/AgbYqH7
|
||||
pYXQg2lCjXZYaDFAlEf5SlYUDOhhXe5kR8Edhlrsu32/JzA1DQK0JjxKCBp+DQmA
|
||||
ltdOpQtAg03fHP4ssdj7VvjIDl28iIlATwBvHrdNm7T0tYWn6TWhvxbRqvfTxfaH
|
||||
MvxnPdIJwNP4/9TyQkwjwHb1h+ucho3CnxI/AxspdOvT1ElMhP6Ce6rcS9pk11Rl
|
||||
x0ChsqpWwDg7KYpg0qZFSKCTBp4zBq9xoMJ6BQcgMfyl736WbsCzFTEyfifp8beg
|
||||
NxUa/Qk7w7cuSPGyMIKNOmOR7FLlFbtocy8sXVsUQdqnp/edelufdNe39U9uNtY6
|
||||
yoXI9//Tc6NgOwy2Oyia0slZ5qHRkB7e4USXMRzJ3p4q9eCVKjAJs81Utp7O2U+9
|
||||
vhbhwWP8CAnNTT1E5WS6EKtfrdqF7wjkV+noPGLDGmrXi01J1fSMAjMfVO+7/LOL
|
||||
UN+G4ybKWnEhhOO27yidN8Xx6UrCS23DBlPPQAeA74dTsTExiOxf1o1EXzcQiMyO
|
||||
LAj3/Ojbi1xkWhI=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,32 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFgTCCA2mgAwIBAgIETWAY1DANBgkqhkiG9w0BAQ0FADBxMQswCQYDVQQGEwJY
|
||||
WDELMAkGA1UECAwCWFgxCzAJBgNVBAcMAlhYMR4wHAYDVQQKDBVJMlAgQW5vbnlt
|
||||
b3VzIE5ldHdvcmsxDDAKBgNVBAsMA0kyUDEaMBgGA1UEAwwRaGlkdXNlcjBAbWFp
|
||||
bC5pMnAwHhcNMjExMjEzMTU0MDI3WhcNMzExMjExMTU0MDI3WjBxMQswCQYDVQQG
|
||||
EwJYWDELMAkGA1UECAwCWFgxCzAJBgNVBAcMAlhYMR4wHAYDVQQKDBVJMlAgQW5v
|
||||
bnltb3VzIE5ldHdvcmsxDDAKBgNVBAsMA0kyUDEaMBgGA1UEAwwRaGlkdXNlcjBA
|
||||
bWFpbC5pMnAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXnjJ8UQ0f
|
||||
lHHpfPMiHofBPSuL4sbOJY6fOXwPhSg/h6THh9DS/ZWmJXQ3qRD0glDVtv4/Dr/9
|
||||
ldGQ5eltF9iCFXCQlMEy2HjQrBKq0nsl7RpYK12cyMaod0kkzCUk9ITLi9CmHM3Z
|
||||
gQZcmG8TWjFEpDR+idx/QkQt2pcO4vzWlDit3Vh4ivnbX5jGQHbsVjQEMQWxr+pX
|
||||
dsS+YQpjZ6RBmrooGTPO8QDOOeYLAn0lCjmffc/kzIH9E/p4/O0rOpyhVYbdxUD1
|
||||
5wkqN9l4yrtxmORG/PudnRQQ0r4TUq8vsxfGY0Euo9IbhgXF2Parel1ZhDxB1WZV
|
||||
VwWtgLIh9jGA1UMa8SYKnEfp8LWNZ3b3mUUnZb3kMrLk6jGYRWNsHmamhd4mC7AZ
|
||||
qf/8lOkEIw3bPd3YguCDRVcLui5BwIEZmqXg8uoESxfO/sW3pBrN/8M7MkTex9kN
|
||||
vjitGDDXvenK27qmNgZxbBlX72yTSfys7XTYTLnxZC8AwdAo2Wz9Z6HhGiPonf2h
|
||||
vZkc9ZxuE0jFIrsbJra4X7iyjXgi4vV4ARNg/9Ft6F4/OIbECgeDcBQqq4TlT2bZ
|
||||
EfWVrBbqXoj5vNsLigIkd+AyUNwPYEcB5IFSiiOh98pC7BH3pg0m8U5YBjxe1i+9
|
||||
EQOOG0Qtx+JigXZHu6bGE0Twy9zy+UzoKQIDAQABoyEwHzAdBgNVHQ4EFgQUGK1b
|
||||
0DkL6aLalcfBc/Uj/SF08C0wDQYJKoZIhvcNAQENBQADggIBAMpXM82bJDpH1TlH
|
||||
TvhU3Z7nfZdvEhOQfujaFUYiuNripuEKcFGn948+DvAG0FUN+uNlJoqOVs8D7InD
|
||||
gWlA9zpqw5Cl5Hij/Wns9QbXuAHJeA23fVUoaM2A6v9ifcIQ1A+rDuRQAo6/64KW
|
||||
ChTg2e99RBpfGOyqgeh7tLLe0lPPekVpKHFuXabokaKRDuBcVHcUL4tWXe3dcyqa
|
||||
Ej/PJrrS+nWL0EGZ4q80CEd2LPuDzPxNGCJt/R7ZfadENWajcgcXGceh1QBzozrB
|
||||
SL/Ya6wF9SrsB7V/r5wX0LM4ZdDaLWbtmUe5Op0h/ZMH25Sa8xAXVz+O9L6sWSoO
|
||||
FaiYTOvAiyyPz+nsxKa3xYryDHno7eKSt+hGOcaurhxbdZaEFY/CegEc73tCt9xK
|
||||
e9qF8O/WkDLmixuErw3f5en4IfzGR7p3lJAwW/8WD8C6HS39h/eE7dVZNaWgtQnZ
|
||||
SgGjgZMTJqTcQ3aZmfuCZefxGFok8w6AIkdbnd1pdMBRjYu8aXgl2hQSB9ZADDE9
|
||||
R5d3rXi0PkSFLIvsNjVa5KXrZk/tB0Hpfmepq7CufBqjP/LG9TieRoXzLYUKFF74
|
||||
QRwjP+y7AJ+VDUTpY1NV1P+k+2raubU2bOnLF3zL5DtyoyieGPhyeMMvp0fRIxdg
|
||||
bSl5VHgPXHNM8mcnndMAuzvl7jEK
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,32 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFdTCCA12gAwIBAgIEQ5vCxzANBgkqhkiG9w0BAQ0FADBrMQswCQYDVQQGEwJY
|
||||
WDELMAkGA1UECAwCWFgxCzAJBgNVBAcMAlhYMR4wHAYDVQQKDBVJMlAgQW5vbnlt
|
||||
b3VzIE5ldHdvcmsxDDAKBgNVBAsMA0kyUDEUMBIGA1UEAwwLbHNAbWFpbC5pMnAw
|
||||
HhcNMjMxMDE2MjAwNTA5WhcNMzMxMDEzMjAwNTA5WjBrMQswCQYDVQQGEwJYWDEL
|
||||
MAkGA1UECAwCWFgxCzAJBgNVBAcMAlhYMR4wHAYDVQQKDBVJMlAgQW5vbnltb3Vz
|
||||
IE5ldHdvcmsxDDAKBgNVBAsMA0kyUDEUMBIGA1UEAwwLbHNAbWFpbC5pMnAwggIi
|
||||
MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDPcbKRtf4PzrDa0iRit0XrwnmA
|
||||
2c1fJhkBipdPor7gMOAlkR82H1lkZSizR7kTZnr7vYqjDrOQr7bl5Dy3qo8/YCbZ
|
||||
jsnUCTIIgIJQUxUlR40RjaSXphqzUEiXKHR6b0RahhFisQ3hlbbgzSch5YgSLKws
|
||||
hOLi+eDSXw+HlwHlWFlT1XOKxSTJ/F3Bv40gxqZVC2pbxiPOeRZHQ6Ojw75lxTSF
|
||||
gww2WzgztiWt4X9BO1yepnVqhAVRPmTfGUMfKzq9jkMzZKeQFV4uZSP9nCqzEpYd
|
||||
WNDUfpTWiAQ9F+BwFXGusXXA3tGVwS7s6IEoiJFM5fsoJYfRoWGh3/1eirhBXW7U
|
||||
M6oubMSTADyrvfjLfJBMmMnc2hNblRlKr0ZKUjMfv8cnyT4kQxlXLAHHXY2P89TM
|
||||
TEVODkU48gnv6tC4t1JCb1/Da+3yVMjNX6rCzQfUwnLFrWthrwiI0NivAKFtiZjq
|
||||
w1/ZQcYke2YyeqcfXMn+NTUA22Sm2mJoMo7jUf+rbM9Pi27/DncJgRGj5qwY0D3S
|
||||
gc7829EjuZNPttGBmae1EmO7WQMB32cqdmItnV2FXpMhnn9h0u5H52kYqwn+mdtc
|
||||
dTJRcbfKG1RTr3UjFISaTwL8qigMIkVXIzcpnr/R/sSeEs8xCqfsJ6rb4dCyFx+M
|
||||
hqQcOCL5tumyd4W/LQIDAQABoyEwHzAdBgNVHQ4EFgQUgfaOG5HCnlW82wZ5BahL
|
||||
GRO06igwDQYJKoZIhvcNAQENBQADggIBAKdVpqS9qF7gGotgXaVA1iP5YNsWlTvG
|
||||
daGqeA/87//U21W6gpq82FhzsmsvUtXZfIeVIlDPI7WNDzS+A3K/KKrwM7dLgSie
|
||||
r9eMl3D8WYPU95QF4mAlRyl7PCCsYoVjyvfro0iq3/iudIA5476rjfLdTXRi5hAT
|
||||
qemPj0S+6sRjKEldRtGXrQATFlvLIWVYpgHijdDDx5M2hAz2y0mFxlDZTlA4BhL4
|
||||
DwtGlVKmbc2x5MvIQM4UhbQqkxYS4gXnzf5Qx9QIytHfTr/hmbrkhKR1GCO31BSk
|
||||
x9LhZxdI8LlwKSo6YgwXEB9E0M/tplaK9iZJFv4HPYLZrVJpb4IklMumyLMrgW5P
|
||||
fR0dgKn+R9lk0emJ1Cu+qyyzf1vsLycYBwaEztINn4VK+/HfDFpnVCvJOyNuDmj5
|
||||
KBLIoGdGoVfylmnc+e8zAXe+DY41fgniHMISOO78P8Bx9vTB+rhqnOUr9MzlUxPB
|
||||
sKGjbXy2YynEqiGb+9g344v/+ukTSDenqTPHVzJ5uOi0iedy+3ASzUNN6GJocovP
|
||||
167VOhwaETM0FwiKe0VdZRLLbbZ79CtJC0tmgcgPQPRa9Ldr6KN7u1J3D6lUp6zl
|
||||
byPom10ueKONRb36t7ai79l2SEUZRSMkx6AXIU0JJ1SMtQtav7b5LkpYJfdL7+vO
|
||||
dDx2/Za0VmdD
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,33 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFyDCCA7CgAwIBAgIRAO8lBnTo+hlvglQwug2jHZkwDQYJKoZIhvcNAQELBQAw
|
||||
cDELMAkGA1UEBhMCWFgxCzAJBgNVBAcTAlhYMQswCQYDVQQJEwJYWDEeMBwGA1UE
|
||||
ChMVSTJQIEFub255bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxGTAXBgNVBAMM
|
||||
EG51bGxAaTJwbWFpbC5vcmcwHhcNMjMwOTIxMjIzMTM2WhcNMzMwOTIxMjIzMTM2
|
||||
WjBwMQswCQYDVQQGEwJYWDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMR4wHAYD
|
||||
VQQKExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEZMBcGA1UE
|
||||
AwwQbnVsbEBpMnBtYWlsLm9yZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
|
||||
ggIBAMMpAvaHwzuZZ6qelRU4jcgpuAIZFH++F1Te4b1t02pRfnQ0Eeh04VC1JxO0
|
||||
XjUr1/iszEyvrI4+AdxaobDyRFPylkOLtfec4d2ciDc1cupj6y2vyYhMVN31rrvE
|
||||
ve7sKoTHJ5Dx+UPGOVZZsSsmK9TXIU23W2bo7k2VnjVBXdWZyNE4twfTYCosDnYA
|
||||
1HIEaIUFVv+COqw2pktxkMmfUAlnDLeVSfsAzEr37K+x0Xk5hO8m6GWQx0NRjjYp
|
||||
gyEcFhWAJjAYaF3gUVR9rVVky1OeFhZgxE/KzVrW7uc84ZCMKITEPwT0qqIpsTJp
|
||||
486YXzuPSc+ef78cKSQf5992l7imySJ24I/5H73HkovGAFGZdwvl6V6Ta5YqO7RR
|
||||
gVDOL1EIVUnMCqFBCE6RmyZqXBVrv4Cacdc6lZ4fj42SRtWZfe6rNCpJzTRtbOyW
|
||||
DBmYpK6q/jddfqI1sX0PXIn9U+Rod5Z4uz82PAjhamqyr5fpAnoQxKppBvQ3tNfn
|
||||
KQhmP73Hdpvl24pRyQLBIRUL86i7TPBBn7n3XZlQfXP7lp8+KJYLkL2/zCVDrwLX
|
||||
kC9hRIxCU9bZbXlkRE2R/PrK53LZecjk2KcgINA4ZlguNgze/Qj8BXelUF4izbpV
|
||||
bTSvniTM46AECvjDcICAOky9Ku4RnmUJxQVf3ahDEuso7/N7AgMBAAGjXTBbMA4G
|
||||
A1UdDwEB/wQEAwIChDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwDwYD
|
||||
VR0TAQH/BAUwAwEB/zAZBgNVHQ4EEgQQbnVsbEBpMnBtYWlsLm9yZzANBgkqhkiG
|
||||
9w0BAQsFAAOCAgEAEUfYJTdDH7uCojnpF0Gs2tXxPJ22UhdqEsXfqR7KhhmmApss
|
||||
q5kiiPIYoy5T/4IM7NVyeeJAMYwQsdJjwZ4QyxLBb9EqMS2krREcPZNRfFzBr2Wj
|
||||
EBhJEYTnbIn4docwJWyXsJVG0CqFXPF1qGd0Sc2u87yj2xZNTnloWKAEQAO7DE39
|
||||
gWfDH6slM/3h3WD3Mjuk7JoYSYmBfvvm2hkBbC6lzD7XY7rdSmIUwJ050e9UrJaV
|
||||
La51dd5r4q8d1cHrVUwLiACAaXJ15AEqUDLHQcvKvyfhkabwRy+v0wsodSMgSMEH
|
||||
xA+kGhkIW7yV7o2exYOYypHCca3IA+pimMpEseNNrHSwbHOMfauiN7jiZLEPg6D6
|
||||
a8XwK7qmMYUq7j6QWuIqI81o29WZRf4LZ0GFoVce+e5VxkVKSItKcJoedIAp1ML8
|
||||
NhFwd9s/nqWidu/StscEEbGzz6ZuDXwshERXC0QR8HjHEPi4U8220juf4cxUahxK
|
||||
heEU91l7VksSZYRUN98h28vovGcukLcnVoLj5H/+Z4r/BgxMrOUJKetxf8fU7FjO
|
||||
j1U6XV36tGi+IOwYQb9D5fTVafC3hHkuUIjlOdUGYadse98ILhn9kaNtqkBtk/EU
|
||||
vK+McnrEv7tcKrbvYEop/KaUayhjFiL+wGWnpxt7gLhIiavnIeUyD7acltw=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,34 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIF7zCCA9egAwIBAgIRANVB/+wEuXS0Ttoh5teJt90wDQYJKoZIhvcNAQELBQAw
|
||||
fTELMAkGA1UEBhMCWFgxCzAJBgNVBAcTAlhYMQswCQYDVQQJEwJYWDEeMBwGA1UE
|
||||
ChMVSTJQIEFub255bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxJjAkBgNVBAMM
|
||||
HXJlaGVhdGVkYnVyZ2VyQHByb3Rvbm1haWwuY29tMB4XDTIzMDkyMTE4MDAyOVoX
|
||||
DTMzMDkyMTE4MDAyOVowfTELMAkGA1UEBhMCWFgxCzAJBgNVBAcTAlhYMQswCQYD
|
||||
VQQJEwJYWDEeMBwGA1UEChMVSTJQIEFub255bW91cyBOZXR3b3JrMQwwCgYDVQQL
|
||||
EwNJMlAxJjAkBgNVBAMMHXJlaGVhdGVkYnVyZ2VyQHByb3Rvbm1haWwuY29tMIIC
|
||||
IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuNwmiIY3MLSBS5sL5PXRDVK6
|
||||
MoSNw4qx0o8nDHvVBxNtzgc0/qjYvsuUggY0tZbPpxhML6GHd4qo7Z3Ip1x0MxhI
|
||||
Ao5MJaflaEdm4+HeMy0IE3aU73KRUwp+nF3cUHZdlps+9mtYs4oncVEWkFQwGsgt
|
||||
4yrLtXf6PmPWfFH28ffeaev90e+hdhQpTvr54Ewx6NTaMQr8mkhXL2utvPpjnPM5
|
||||
UAhOeJCMgfhLzgS4rahG0O8CQMtH5gKZ+6zjoSRatnjj0j1mBO7+e1TL5O7dVS9k
|
||||
P83tmkIDDl4tXBzXr9aXQMJstbM2CEvinVcCsR74GjPcg4iB0Ift71Dx7oGKI06t
|
||||
3bSvll0GZm2mFhIba/4q6f4oAJ2aeq6ejt1Kcm8g5cxtwrRZnXv5JXHZqba3y8J5
|
||||
zWaRHzhc9tyEqRBRkc6c7xMdZQ31iJ6TlxUT8vAJ1N7OnX87oHrCjwyikpyOen4r
|
||||
Uvv1Ge054XPTeoHz+Jyt34t71ty1W13uPHpuvtPVR9MfgGrxd4Z9+LWvAjmMbFsZ
|
||||
lC3Ll+94nUk+O0puU6KisuCGP4hCtdEtebkIqT8zo8LicLAYUMjX7KwnS7681Cu1
|
||||
sY2mB2oZAytN9Zy42oOoNeY5x39kxfwuut/2E1kxKX75O0bwfIXr611abCKc3bbz
|
||||
euMrIsaB/2VFp9nAah8CAwEAAaNqMGgwDgYDVR0PAQH/BAQDAgKEMB0GA1UdJQQW
|
||||
MBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCYGA1UdDgQf
|
||||
BB1yZWhlYXRlZGJ1cmdlckBwcm90b25tYWlsLmNvbTANBgkqhkiG9w0BAQsFAAOC
|
||||
AgEATuHi2Yz52OK7e+sKVdHu2KrSLCGm98BG1UIMHFi3WRBTOFyp+lZ519bJ1rFj
|
||||
tmP9E1a+k/vlbc7FbV4PcV6HJYfGEv/ImtJsEnrzbhrQphC1zMFv7q6JCTUbAzl6
|
||||
ySlJ++mVxQ6AzPNH3TQgL1wPKuLh76/Y4053fg+NI3PmzzhkTUheVDkg0/a9ENSf
|
||||
xMnCa3fIm869735qHk67QlikFvAfWwc4zT1Ncwodh8G4+oX0GFzIl+OZaM1GTMuD
|
||||
UCcFKoqwtjyLCr22xNk8CfyiExPJXQG1HzEvDcxyoxQtnh9occR9PgqXySz26/NM
|
||||
XDyM+l4utLMGBcVY4x9fksRiaWEfxiygYOxY9zDl6clh6S10b3CLut4UMiS1RTtE
|
||||
Mjx2BZN3p0nxpT2leJdGxtBPGrvxuiCOEmTbOMLc3DQtppXO97B3dVMtJ5Ee8Y6p
|
||||
Tq/8eiHI6eQXat6dgFT5X16vzF7w7XO7fAxuqk4Kx1D1aTVyikdo+Fcdg44dWOjq
|
||||
NZu8VcCzZij/Dfjlce6t6h8D+wvDD8AkiivaDljpvbNDx/QQlQXFgH98TZA8Rnvr
|
||||
QcyNNATfz+1yQUiyO6Lrjaw64OJwXYX/llgnDC+qQpP6kqZabi2TsG0EVPukVvr9
|
||||
0HyAUu4lnXtTIDq2yPNenegCloqDL1ZQdaYd2XIItnfZdTY=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -2,7 +2,7 @@ Description: Disable LogsDirectory and LogsDirectoryMode options in service
|
||||
Author: r4sas <r4sas@i2pmail.org>
|
||||
|
||||
Reviewed-By: r4sas <r4sas@i2pmail.org>
|
||||
Last-Update: 2023-05-17
|
||||
Last-Update: 2024-07-19
|
||||
|
||||
--- a/contrib/i2pd.service
|
||||
+++ b/contrib/i2pd.service
|
||||
@@ -15,5 +15,5 @@ Last-Update: 2023-05-17
|
||||
+#LogsDirectory=i2pd
|
||||
+#LogsDirectoryMode=0700
|
||||
Type=forking
|
||||
ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --tunnelsdir=/etc/i2pd/tunnels.conf.d --pidfile=/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
|
||||
ExecStart=/usr/bin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --tunnelsdir=/etc/i2pd/tunnels.conf.d --pidfile=/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
|
||||
ExecReload=/bin/sh -c "kill -HUP $MAINPID"
|
||||
|
||||
@@ -2,7 +2,7 @@ Description: Disable LogsDirectory and LogsDirectoryMode options in service
|
||||
Author: r4sas <r4sas@i2pmail.org>
|
||||
|
||||
Reviewed-By: r4sas <r4sas@i2pmail.org>
|
||||
Last-Update: 2023-05-17
|
||||
Last-Update: 2024-07-19
|
||||
|
||||
--- a/contrib/i2pd.service
|
||||
+++ b/contrib/i2pd.service
|
||||
@@ -15,5 +15,5 @@ Last-Update: 2023-05-17
|
||||
+#LogsDirectory=i2pd
|
||||
+#LogsDirectoryMode=0700
|
||||
Type=forking
|
||||
ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --tunnelsdir=/etc/i2pd/tunnels.conf.d --pidfile=/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
|
||||
ExecStart=/usr/bin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --tunnelsdir=/etc/i2pd/tunnels.conf.d --pidfile=/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
|
||||
ExecReload=/bin/sh -c "kill -HUP $MAINPID"
|
||||
|
||||
@@ -11,7 +11,7 @@ RuntimeDirectoryMode=0700
|
||||
LogsDirectory=i2pd
|
||||
LogsDirectoryMode=0700
|
||||
Type=forking
|
||||
ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --tunnelsdir=/etc/i2pd/tunnels.conf.d --pidfile=/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
|
||||
ExecStart=/usr/bin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --tunnelsdir=/etc/i2pd/tunnels.conf.d --pidfile=/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
|
||||
ExecReload=/bin/sh -c "kill -HUP $MAINPID"
|
||||
PIDFile=/run/i2pd/i2pd.pid
|
||||
### Uncomment, if auto restart needed
|
||||
|
||||
@@ -7,7 +7,7 @@ tunconf="/etc/i2pd/tunnels.conf"
|
||||
tundir="/etc/i2pd/tunnels.conf.d"
|
||||
|
||||
name="i2pd"
|
||||
command="/usr/sbin/i2pd"
|
||||
command="/usr/bin/i2pd"
|
||||
command_args="--service --daemon --log=file --logfile=$logfile --conf=$mainconf --tunconf=$tunconf --tunnelsdir=$tundir --pidfile=$pidfile"
|
||||
description="i2p router written in C++"
|
||||
required_dirs="/var/lib/i2pd"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
%define git_hash %(git rev-parse HEAD | cut -c -7)
|
||||
|
||||
Name: i2pd-git
|
||||
Version: 2.50.1
|
||||
Version: 2.54.0
|
||||
Release: git%{git_hash}%{?dist}
|
||||
Summary: I2P router written in C++
|
||||
Conflicts: i2pd
|
||||
@@ -24,6 +24,10 @@ BuildRequires: openssl-devel
|
||||
BuildRequires: miniupnpc-devel
|
||||
BuildRequires: systemd-units
|
||||
|
||||
%if 0%{?fedora} == 41
|
||||
BuildRequires: openssl-devel-engine
|
||||
%endif
|
||||
|
||||
Requires: logrotate
|
||||
Requires: systemd
|
||||
Requires(pre): %{_sbindir}/useradd %{_sbindir}/groupadd
|
||||
@@ -93,7 +97,7 @@ pushd build
|
||||
%endif
|
||||
|
||||
chrpath -d i2pd
|
||||
%{__install} -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd
|
||||
%{__install} -D -m 755 i2pd %{buildroot}%{_bindir}/i2pd
|
||||
%{__install} -d -m 755 %{buildroot}%{_datadir}/i2pd
|
||||
%{__install} -d -m 700 %{buildroot}%{_sharedstatedir}/i2pd
|
||||
%{__install} -d -m 700 %{buildroot}%{_localstatedir}/log/i2pd
|
||||
@@ -129,7 +133,7 @@ getent passwd i2pd >/dev/null || \
|
||||
|
||||
%files
|
||||
%doc LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf contrib/tunnels.d
|
||||
%{_sbindir}/i2pd
|
||||
%{_bindir}/i2pd
|
||||
%config(noreplace) %{_sysconfdir}/i2pd/*.conf
|
||||
%config(noreplace) %{_sysconfdir}/i2pd/tunnels.conf.d/*.conf
|
||||
%config %{_sysconfdir}/i2pd/subscriptions.txt
|
||||
@@ -144,6 +148,24 @@ getent passwd i2pd >/dev/null || \
|
||||
|
||||
|
||||
%changelog
|
||||
* Sun Oct 6 2024 orignal <orignal@i2pmail.org> - 2.54.0
|
||||
- update to 2.54.0
|
||||
|
||||
* Tue Jul 30 2024 orignal <orignal@i2pmail.org> - 2.53.1
|
||||
- update to 2.53.1
|
||||
|
||||
* Fri Jul 19 2024 orignal <orignal@i2pmail.org> - 2.53.0
|
||||
- update to 2.53.0
|
||||
|
||||
* Sun May 12 2024 orignal <orignal@i2pmail.org> - 2.52.0
|
||||
- update to 2.52.0
|
||||
|
||||
* Sat Apr 06 2024 orignal <orignal@i2pmail.org> - 2.51.0
|
||||
- update to 2.51.0
|
||||
|
||||
* Sat Jan 06 2024 orignal <orignal@i2pmail.org> - 2.50.2
|
||||
- update to 2.50.2
|
||||
|
||||
* Sat Dec 23 2023 r4sas <r4sas@i2pmail.org> - 2.50.1
|
||||
- update to 2.50.1
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name: i2pd
|
||||
Version: 2.50.1
|
||||
Version: 2.54.0
|
||||
Release: 1%{?dist}
|
||||
Summary: I2P router written in C++
|
||||
Conflicts: i2pd-git
|
||||
@@ -22,6 +22,10 @@ BuildRequires: openssl-devel
|
||||
BuildRequires: miniupnpc-devel
|
||||
BuildRequires: systemd-units
|
||||
|
||||
%if 0%{?fedora} == 41
|
||||
BuildRequires: openssl-devel-engine
|
||||
%endif
|
||||
|
||||
Requires: logrotate
|
||||
Requires: systemd
|
||||
Requires(pre): %{_sbindir}/useradd %{_sbindir}/groupadd
|
||||
@@ -91,7 +95,7 @@ pushd build
|
||||
%endif
|
||||
|
||||
chrpath -d i2pd
|
||||
%{__install} -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd
|
||||
%{__install} -D -m 755 i2pd %{buildroot}%{_bindir}/i2pd
|
||||
%{__install} -d -m 755 %{buildroot}%{_datadir}/i2pd
|
||||
%{__install} -d -m 700 %{buildroot}%{_sharedstatedir}/i2pd
|
||||
%{__install} -d -m 700 %{buildroot}%{_localstatedir}/log/i2pd
|
||||
@@ -127,7 +131,7 @@ getent passwd i2pd >/dev/null || \
|
||||
|
||||
%files
|
||||
%doc LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf contrib/tunnels.d
|
||||
%{_sbindir}/i2pd
|
||||
%{_bindir}/i2pd
|
||||
%config(noreplace) %{_sysconfdir}/i2pd/*.conf
|
||||
%config(noreplace) %{_sysconfdir}/i2pd/tunnels.conf.d/*.conf
|
||||
%config %{_sysconfdir}/i2pd/subscriptions.txt
|
||||
@@ -142,6 +146,24 @@ getent passwd i2pd >/dev/null || \
|
||||
|
||||
|
||||
%changelog
|
||||
* Sun Oct 6 2024 orignal <orignal@i2pmail.org> - 2.54.0
|
||||
- update to 2.54.0
|
||||
|
||||
* Tue Jul 30 2024 orignal <orignal@i2pmail.org> - 2.53.1
|
||||
- update to 2.53.1
|
||||
|
||||
* Fri Jul 19 2024 orignal <orignal@i2pmail.org> - 2.53.0
|
||||
- update to 2.53.0
|
||||
|
||||
* Sun May 12 2024 orignal <orignal@i2pmail.org> - 2.52.0
|
||||
- update to 2.52.0
|
||||
|
||||
* Sat Apr 06 2024 orignal <orignal@i2pmail.org> - 2.51.0
|
||||
- update to 2.51.0
|
||||
|
||||
* Sat Jan 06 2024 orignal <orignal@i2pmail.org> - 2.50.2
|
||||
- update to 2.50.2
|
||||
|
||||
* Sat Dec 23 2023 r4sas <r4sas@i2pmail.org> - 2.50.1
|
||||
- update to 2.50.1
|
||||
|
||||
|
||||
@@ -8,4 +8,4 @@ env LOGFILE="/var/log/i2pd/i2pd.log"
|
||||
|
||||
expect fork
|
||||
|
||||
exec /usr/sbin/i2pd --daemon --service --log=file --logfile=$LOGFILE
|
||||
exec /usr/bin/i2pd --daemon --service --log=file --logfile=$LOGFILE
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -160,6 +160,10 @@ namespace util
|
||||
|
||||
int netID; i2p::config::GetOption("netid", netID);
|
||||
i2p::context.SetNetID (netID);
|
||||
|
||||
bool checkReserved; i2p::config::GetOption("reservedrange", checkReserved);
|
||||
i2p::transport::transports.SetCheckReserved(checkReserved);
|
||||
|
||||
i2p::context.Init ();
|
||||
|
||||
i2p::transport::InitTransports ();
|
||||
@@ -175,7 +179,7 @@ namespace util
|
||||
|
||||
bool transit; i2p::config::GetOption("notransit", transit);
|
||||
i2p::context.SetAcceptsTunnels (!transit);
|
||||
uint16_t transitTunnels; i2p::config::GetOption("limits.transittunnels", transitTunnels);
|
||||
uint32_t transitTunnels; i2p::config::GetOption("limits.transittunnels", transitTunnels);
|
||||
if (isFloodfill && i2p::config::IsDefault ("limits.transittunnels"))
|
||||
transitTunnels *= 2; // double default number of transit tunnels for floodfill
|
||||
i2p::tunnel::tunnels.SetMaxNumTransitTunnels (transitTunnels);
|
||||
@@ -184,7 +188,7 @@ namespace util
|
||||
std::string bandwidth; i2p::config::GetOption("bandwidth", bandwidth);
|
||||
if (bandwidth.length () > 0)
|
||||
{
|
||||
if (bandwidth[0] >= 'K' && bandwidth[0] <= 'X')
|
||||
if (bandwidth.length () == 1 && ((bandwidth[0] >= 'K' && bandwidth[0] <= 'P') || bandwidth[0] == 'X' ))
|
||||
{
|
||||
i2p::context.SetBandwidth (bandwidth[0]);
|
||||
LogPrint(eLogInfo, "Daemon: Bandwidth set to ", i2p::context.GetBandwidthLimit (), "KBps");
|
||||
@@ -298,12 +302,10 @@ namespace util
|
||||
|
||||
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
||||
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
|
||||
bool checkInReserved; i2p::config::GetOption("reservedrange", checkInReserved);
|
||||
LogPrint(eLogInfo, "Daemon: Starting Transports");
|
||||
if(!ssu2) LogPrint(eLogInfo, "Daemon: SSU2 disabled");
|
||||
if(!ntcp2) LogPrint(eLogInfo, "Daemon: NTCP2 disabled");
|
||||
|
||||
i2p::transport::transports.SetCheckReserved(checkInReserved);
|
||||
i2p::transport::transports.Start(ntcp2, ssu2);
|
||||
if (i2p::transport::transports.IsBoundSSU2() || i2p::transport::transports.IsBoundNTCP2())
|
||||
LogPrint(eLogInfo, "Daemon: Transports started");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -133,23 +133,19 @@ namespace http {
|
||||
static void ShowTunnelDetails (std::stringstream& s, enum i2p::tunnel::TunnelState eState, bool explr, int bytes)
|
||||
{
|
||||
std::string state, stateText;
|
||||
switch (eState) {
|
||||
switch (eState)
|
||||
{
|
||||
case i2p::tunnel::eTunnelStateBuildReplyReceived :
|
||||
case i2p::tunnel::eTunnelStatePending : state = "building"; break;
|
||||
case i2p::tunnel::eTunnelStateBuildFailed :
|
||||
case i2p::tunnel::eTunnelStateTestFailed :
|
||||
case i2p::tunnel::eTunnelStateBuildFailed : state = "failed"; stateText = "declined"; break;
|
||||
case i2p::tunnel::eTunnelStateTestFailed : state = "failed"; stateText = "test failed"; break;
|
||||
case i2p::tunnel::eTunnelStateFailed : state = "failed"; break;
|
||||
case i2p::tunnel::eTunnelStateExpiring : state = "expiring"; break;
|
||||
case i2p::tunnel::eTunnelStateEstablished : state = "established"; break;
|
||||
default: state = "unknown"; break;
|
||||
}
|
||||
|
||||
if (state == "building") stateText = tr("building");
|
||||
else if (state == "failed") stateText = tr("failed");
|
||||
else if (state == "expiring") stateText = tr("expiring");
|
||||
else if (state == "established") stateText = tr("established");
|
||||
else stateText = tr("unknown");
|
||||
|
||||
if (stateText.empty ()) stateText = tr(state);
|
||||
|
||||
s << "<span class=\"tunnel " << state << "\"> " << stateText << ((explr) ? " (" + tr("exploratory") + ")" : "") << "</span>, ";
|
||||
ShowTraffic(s, bytes);
|
||||
s << "\r\n";
|
||||
@@ -421,6 +417,15 @@ namespace http {
|
||||
}
|
||||
}
|
||||
|
||||
static void ShowHop(std::stringstream& s, const i2p::data::IdentityEx& ident)
|
||||
{
|
||||
auto identHash = ident.GetIdentHash();
|
||||
auto router = i2p::data::netdb.FindRouter(identHash);
|
||||
s << i2p::data::GetIdentHashAbbreviation(identHash);
|
||||
if (router)
|
||||
s << "<small style=\"color:gray\"> " << router->GetBandwidthCap() << "</small>";
|
||||
}
|
||||
|
||||
static void ShowLeaseSetDestination (std::stringstream& s, std::shared_ptr<const i2p::client::LeaseSetDestination> dest, uint32_t token)
|
||||
{
|
||||
s << "<b>Base32:</b><br>\r\n<textarea readonly cols=\"80\" rows=\"1\">";
|
||||
@@ -486,7 +491,9 @@ namespace http {
|
||||
it->VisitTunnelHops(
|
||||
[&s](std::shared_ptr<const i2p::data::IdentityEx> hopIdent)
|
||||
{
|
||||
s << "⇒ " << i2p::data::GetIdentHashAbbreviation (hopIdent->GetIdentHash ()) << " ";
|
||||
s << "⇒ ";
|
||||
ShowHop(s, *hopIdent);
|
||||
s << " ";
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -507,7 +514,9 @@ namespace http {
|
||||
it->VisitTunnelHops(
|
||||
[&s](std::shared_ptr<const i2p::data::IdentityEx> hopIdent)
|
||||
{
|
||||
s << " " << i2p::data::GetIdentHashAbbreviation (hopIdent->GetIdentHash ()) << " ⇒";
|
||||
s << " ";
|
||||
ShowHop(s, *hopIdent);
|
||||
s << " ⇒";
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -692,6 +701,7 @@ namespace http {
|
||||
{
|
||||
s << "<b>" << tr("Tunnels") << ":</b><br>\r\n";
|
||||
s << "<b>" << tr("Queue size") << ":</b> " << i2p::tunnel::tunnels.GetQueueSize () << "<br>\r\n<br>\r\n";
|
||||
s << "<b>" << tr("TBM Queue size") << ":</b> " << i2p::tunnel::tunnels.GetTBMQueueSize () << "<br>\r\n<br>\r\n";
|
||||
|
||||
auto ExplPool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||
|
||||
@@ -703,7 +713,9 @@ namespace http {
|
||||
it->VisitTunnelHops(
|
||||
[&s](std::shared_ptr<const i2p::data::IdentityEx> hopIdent)
|
||||
{
|
||||
s << "⇒ " << i2p::data::GetIdentHashAbbreviation (hopIdent->GetIdentHash ()) << " ";
|
||||
s << "⇒ ";
|
||||
ShowHop(s, *hopIdent);
|
||||
s << " ";
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -724,7 +736,9 @@ namespace http {
|
||||
it->VisitTunnelHops(
|
||||
[&s](std::shared_ptr<const i2p::data::IdentityEx> hopIdent)
|
||||
{
|
||||
s << " " << i2p::data::GetIdentHashAbbreviation (hopIdent->GetIdentHash ()) << " ⇒";
|
||||
s << " ";
|
||||
ShowHop(s, *hopIdent);
|
||||
s << " ⇒";
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -776,7 +790,7 @@ namespace http {
|
||||
s << " <a class=\"button" << (loglevel == eLogInfo ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=info&token=" << token << "\"> info </a> \r\n";
|
||||
s << " <a class=\"button" << (loglevel == eLogDebug ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=debug&token=" << token << "\"> debug </a><br>\r\n<br>\r\n";
|
||||
|
||||
uint16_t maxTunnels = i2p::tunnel::tunnels.GetMaxNumTransitTunnels ();
|
||||
uint32_t maxTunnels = i2p::tunnel::tunnels.GetMaxNumTransitTunnels ();
|
||||
s << "<b>" << tr("Transit tunnels limit") << "</b><br>\r\n";
|
||||
s << "<form method=\"get\" action=\"" << webroot << "\">\r\n";
|
||||
s << " <input type=\"hidden\" name=\"cmd\" value=\"" << HTTP_COMMAND_LIMITTRANSIT << "\">\r\n";
|
||||
@@ -1467,13 +1481,13 @@ namespace http {
|
||||
reply.body = content;
|
||||
|
||||
m_SendBuffer = reply.to_string();
|
||||
boost::asio::async_write (*m_Socket, boost::asio::buffer(m_SendBuffer),
|
||||
boost::asio::async_write (*m_Socket, boost::asio::buffer(m_SendBuffer), boost::asio::transfer_all (),
|
||||
std::bind (&HTTPConnection::Terminate, shared_from_this (), std::placeholders::_1));
|
||||
}
|
||||
|
||||
HTTPServer::HTTPServer (const std::string& address, int port):
|
||||
m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service),
|
||||
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string(address), port)),
|
||||
m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service.get_executor ()),
|
||||
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint (boost::asio::ip::make_address(address), port)),
|
||||
m_Hostname(address)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -25,7 +25,7 @@ namespace http
|
||||
const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192;
|
||||
const int TOKEN_EXPIRATION_TIMEOUT = 30; // in seconds
|
||||
const int COMMAND_REDIRECT_TIMEOUT = 5; // in seconds
|
||||
const int TRANSIT_TUNNELS_LIMIT = 65535;
|
||||
const int TRANSIT_TUNNELS_LIMIT = 1000000;
|
||||
|
||||
class HTTPConnection: public std::enable_shared_from_this<HTTPConnection>
|
||||
{
|
||||
@@ -83,8 +83,8 @@ namespace http
|
||||
|
||||
bool m_IsRunning;
|
||||
std::unique_ptr<std::thread> m_Thread;
|
||||
boost::asio::io_service m_Service;
|
||||
boost::asio::io_service::work m_Work;
|
||||
boost::asio::io_context m_Service;
|
||||
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> m_Work;
|
||||
boost::asio::ip::tcp::acceptor m_Acceptor;
|
||||
std::string m_Hostname;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -8,14 +8,12 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
// Use global placeholders from boost introduced when local_time.hpp is loaded
|
||||
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
|
||||
|
||||
#include <boost/date_time/local_time/local_time.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
@@ -33,7 +31,7 @@ namespace client
|
||||
{
|
||||
I2PControlService::I2PControlService (const std::string& address, int port):
|
||||
m_IsRunning (false), m_Thread (nullptr),
|
||||
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port)),
|
||||
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::make_address(address), port)),
|
||||
m_SSLContext (boost::asio::ssl::context::sslv23),
|
||||
m_ShutdownTimer (m_Service)
|
||||
{
|
||||
@@ -47,15 +45,29 @@ namespace client
|
||||
i2pcp_crt = i2p::fs::DataDirPath(i2pcp_crt);
|
||||
if (i2pcp_key.at(0) != '/')
|
||||
i2pcp_key = i2p::fs::DataDirPath(i2pcp_key);
|
||||
if (!i2p::fs::Exists (i2pcp_crt) || !i2p::fs::Exists (i2pcp_key)) {
|
||||
if (!i2p::fs::Exists (i2pcp_crt) || !i2p::fs::Exists (i2pcp_key))
|
||||
{
|
||||
LogPrint (eLogInfo, "I2PControl: Creating new certificate for control connection");
|
||||
CreateCertificate (i2pcp_crt.c_str(), i2pcp_key.c_str());
|
||||
} else {
|
||||
}
|
||||
else
|
||||
LogPrint(eLogDebug, "I2PControl: Using cert from ", i2pcp_crt);
|
||||
}
|
||||
m_SSLContext.set_options (boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::single_dh_use);
|
||||
m_SSLContext.use_certificate_file (i2pcp_crt, boost::asio::ssl::context::pem);
|
||||
m_SSLContext.use_private_key_file (i2pcp_key, boost::asio::ssl::context::pem);
|
||||
boost::system::error_code ec;
|
||||
m_SSLContext.use_certificate_file (i2pcp_crt, boost::asio::ssl::context::pem, ec);
|
||||
if (!ec)
|
||||
m_SSLContext.use_private_key_file (i2pcp_key, boost::asio::ssl::context::pem, ec);
|
||||
if (ec)
|
||||
{
|
||||
LogPrint (eLogInfo, "I2PControl: Failed to load ceritifcate: ", ec.message (), ". Recreating");
|
||||
CreateCertificate (i2pcp_crt.c_str(), i2pcp_key.c_str());
|
||||
m_SSLContext.use_certificate_file (i2pcp_crt, boost::asio::ssl::context::pem, ec);
|
||||
if (!ec)
|
||||
m_SSLContext.use_private_key_file (i2pcp_key, boost::asio::ssl::context::pem, ec);
|
||||
if (ec)
|
||||
// give up
|
||||
LogPrint (eLogError, "I2PControl: Can't load certificates");
|
||||
}
|
||||
|
||||
// handlers
|
||||
m_MethodHandlers["Authenticate"] = &I2PControlService::AuthenticateHandler;
|
||||
@@ -258,9 +270,9 @@ namespace client
|
||||
header << "Content-Length: " << boost::lexical_cast<std::string>(len) << "\r\n";
|
||||
header << "Content-Type: application/json\r\n";
|
||||
header << "Date: ";
|
||||
auto facet = new boost::local_time::local_time_facet ("%a, %d %b %Y %H:%M:%S GMT");
|
||||
header.imbue(std::locale (header.getloc(), facet));
|
||||
header << boost::posix_time::second_clock::local_time() << "\r\n";
|
||||
std::time_t t = std::time (nullptr);
|
||||
std::tm tm = *std::gmtime (&t);
|
||||
header << std::put_time(&tm, "%a, %d %b %Y %T GMT") << "\r\n";
|
||||
header << "\r\n";
|
||||
offset = header.str ().size ();
|
||||
memcpy (buf->data (), header.str ().c_str (), offset);
|
||||
@@ -338,10 +350,11 @@ namespace client
|
||||
{
|
||||
for (auto it = params.begin (); it != params.end (); it++)
|
||||
{
|
||||
if (it != params.begin ()) results << ",";
|
||||
LogPrint (eLogDebug, "I2PControl: RouterManager request: ", it->first);
|
||||
auto it1 = m_RouterManagerHandlers.find (it->first);
|
||||
if (it1 != m_RouterManagerHandlers.end ()) {
|
||||
if (it1 != m_RouterManagerHandlers.end ())
|
||||
{
|
||||
if (it != params.begin ()) results << ",";
|
||||
(this->*(it1->second))(results);
|
||||
} else
|
||||
LogPrint (eLogError, "I2PControl: RouterManager unknown request: ", it->first);
|
||||
@@ -404,7 +417,7 @@ namespace client
|
||||
X509_NAME_add_entry_by_txt (name, "O", MBSTRING_ASC, (unsigned char *)I2P_CONTROL_CERTIFICATE_ORGANIZATION, -1, -1, 0); // organization
|
||||
X509_NAME_add_entry_by_txt (name, "CN", MBSTRING_ASC, (unsigned char *)I2P_CONTROL_CERTIFICATE_COMMON_NAME, -1, -1, 0); // common name
|
||||
X509_set_issuer_name (x509, name); // set issuer to ourselves
|
||||
X509_sign (x509, pkey, EVP_sha1 ()); // sign
|
||||
X509_sign (x509, pkey, EVP_sha1 ()); // sign, last param must be NULL for EdDSA
|
||||
|
||||
// save cert
|
||||
if ((f = fopen (crt_path, "wb")) != NULL) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -88,7 +88,7 @@ namespace client
|
||||
bool m_IsRunning;
|
||||
std::thread * m_Thread;
|
||||
|
||||
boost::asio::io_service m_Service;
|
||||
boost::asio::io_context m_Service;
|
||||
boost::asio::ip::tcp::acceptor m_Acceptor;
|
||||
boost::asio::ssl::context m_SSLContext;
|
||||
boost::asio::deadline_timer m_ShutdownTimer;
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2024, 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 USE_UPNP
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include "Log.h"
|
||||
|
||||
#include "RouterContext.h"
|
||||
@@ -110,10 +115,16 @@ namespace transport
|
||||
return;
|
||||
}
|
||||
|
||||
#if (MINIUPNPC_API_VERSION >= 18)
|
||||
err = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr),
|
||||
m_externalIPAddress, sizeof (m_externalIPAddress));
|
||||
#else
|
||||
err = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr));
|
||||
#endif
|
||||
m_upnpUrlsInitialized=err!=0;
|
||||
if (err == UPNP_IGD_VALID_CONNECTED)
|
||||
{
|
||||
#if (MINIUPNPC_API_VERSION < 18)
|
||||
err = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);
|
||||
if(err != UPNPCOMMAND_SUCCESS)
|
||||
{
|
||||
@@ -121,6 +132,7 @@ namespace transport
|
||||
return;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
LogPrint (eLogError, "UPnP: Found Internet Gateway Device ", m_upnpUrls.controlURL);
|
||||
if (!m_externalIPAddress[0])
|
||||
@@ -166,11 +178,11 @@ namespace transport
|
||||
if (address && !address->host.is_v6 () && address->port)
|
||||
TryPortMapping (address);
|
||||
}
|
||||
m_Timer.expires_from_now (boost::posix_time::minutes(20)); // every 20 minutes
|
||||
m_Timer.expires_from_now (boost::posix_time::minutes(UPNP_PORT_FORWARDING_INTERVAL)); // every 20 minutes
|
||||
m_Timer.async_wait ([this](const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
PortMapping ();
|
||||
PortMapping ();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -28,7 +28,8 @@ namespace i2p
|
||||
namespace transport
|
||||
{
|
||||
const int UPNP_RESPONSE_TIMEOUT = 2000; // in milliseconds
|
||||
|
||||
const int UPNP_PORT_FORWARDING_INTERVAL = 20; // in minutes
|
||||
|
||||
enum
|
||||
{
|
||||
UPNP_IGD_NONE = 0,
|
||||
@@ -66,7 +67,7 @@ namespace transport
|
||||
std::unique_ptr<std::thread> m_Thread;
|
||||
std::condition_variable m_Started;
|
||||
std::mutex m_StartedMutex;
|
||||
boost::asio::io_service m_Service;
|
||||
boost::asio::io_context m_Service;
|
||||
boost::asio::deadline_timer m_Timer;
|
||||
bool m_upnpUrlsInitialized = false;
|
||||
struct UPNPUrls m_upnpUrls;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "RouterContext.h"
|
||||
#include "ClientContext.h"
|
||||
#include "Transports.h"
|
||||
#include "util.h"
|
||||
|
||||
void handle_signal(int sig)
|
||||
{
|
||||
@@ -162,12 +163,21 @@ namespace i2p
|
||||
|
||||
#ifndef ANDROID
|
||||
if (lockf(pidFH, F_TLOCK, 0) != 0)
|
||||
#else
|
||||
struct flock fl;
|
||||
fl.l_len = 0;
|
||||
fl.l_type = F_WRLCK;
|
||||
fl.l_whence = SEEK_SET;
|
||||
fl.l_start = 0;
|
||||
|
||||
if (fcntl(pidFH, F_SETLK, &fl) != 0)
|
||||
#endif
|
||||
{
|
||||
LogPrint(eLogError, "Daemon: Could not lock pid file ", pidfile, ": ", strerror(errno));
|
||||
std::cerr << "i2pd: Could not lock pid file " << pidfile << ": " << strerror(errno) << std::endl;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
char pid[10];
|
||||
sprintf(pid, "%d\n", getpid());
|
||||
ftruncate(pidFH, 0);
|
||||
@@ -211,6 +221,7 @@ namespace i2p
|
||||
|
||||
void DaemonLinux::run ()
|
||||
{
|
||||
i2p::util::SetThreadName ("i2pd-daemon");
|
||||
while (running)
|
||||
{
|
||||
std::this_thread::sleep_for (std::chrono::seconds(1));
|
||||
|
||||
5
debian/NEWS
vendored
Normal file
5
debian/NEWS
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
i2pd (2.53.0-1) unstable; urgency=medium
|
||||
|
||||
i2pd binary moved from /usr/sbin to /usr/bin. Please check your scripts if you used the old path.
|
||||
|
||||
-- r4sas <r4sas@i2pmail.org> Fri, 19 Jul 2024 16:00:00 +0000
|
||||
37
debian/changelog
vendored
37
debian/changelog
vendored
@@ -1,3 +1,40 @@
|
||||
i2pd (2.54.0-1) unstable; urgency=medium
|
||||
|
||||
* updated to version 2.54.0/0.9.64
|
||||
|
||||
-- orignal <orignal@i2pmail.org> Sun, 6 Oct 2024 16:00:00 +0000
|
||||
|
||||
i2pd (2.53.1-1) unstable; urgency=medium
|
||||
|
||||
* updated to version 2.53.1
|
||||
|
||||
-- orignal <orignal@i2pmail.org> Tue, 30 Jul 2024 16:00:00 +0000
|
||||
|
||||
i2pd (2.53.0-1) unstable; urgency=medium
|
||||
|
||||
* updated to version 2.53.0/0.9.63
|
||||
* binary moved from /usr/sbin to /usr/bin
|
||||
|
||||
-- r4sas <r4sas@i2pmail.org> Sat, 20 Jul 2024 15:10:00 +0000
|
||||
|
||||
i2pd (2.52.0-1) unstable; urgency=medium
|
||||
|
||||
* updated to version 2.52.0
|
||||
|
||||
-- orignal <orignal@i2pmail.org> Sun, 12 May 2024 16:00:00 +0000
|
||||
|
||||
i2pd (2.51.0-1) unstable; urgency=medium
|
||||
|
||||
* updated to version 2.51.0/0.9.62
|
||||
|
||||
-- orignal <orignal@i2pmail.org> Sat, 06 Apr 2024 16:00:00 +0000
|
||||
|
||||
i2pd (2.50.2-1) unstable; urgency=medium
|
||||
|
||||
* updated to version 2.50.2/0.9.61
|
||||
|
||||
-- orignal <orignal@i2pmail.org> Sat, 06 Jan 2024 16:00:00 +0000
|
||||
|
||||
i2pd (2.50.1-1) unstable; urgency=medium
|
||||
|
||||
* updated to version 2.50.1/0.9.61
|
||||
|
||||
2
debian/i2pd.init
vendored
2
debian/i2pd.init
vendored
@@ -13,7 +13,7 @@
|
||||
PATH=/sbin:/usr/sbin:/bin:/usr/bin
|
||||
DESC=i2pd # Introduce a short description here
|
||||
NAME=i2pd # Introduce the short server's name here
|
||||
DAEMON=/usr/sbin/$NAME # Introduce the server's location here
|
||||
DAEMON=/usr/bin/$NAME # Introduce the server's location here
|
||||
DAEMON_OPTS="" # Arguments to run the daemon with
|
||||
PIDFILE=/var/run/$NAME/$NAME.pid
|
||||
I2PCONF=/etc/$NAME/i2pd.conf
|
||||
|
||||
4
debian/i2pd.install
vendored
4
debian/i2pd.install
vendored
@@ -1,6 +1,6 @@
|
||||
i2pd usr/sbin/
|
||||
i2pd usr/bin/
|
||||
contrib/i2pd.conf etc/i2pd/
|
||||
contrib/tunnels.conf etc/i2pd/
|
||||
contrib/certificates/ usr/share/i2pd/
|
||||
contrib/tunnels.d/README etc/i2pd/tunnels.conf.d/
|
||||
contrib/apparmor/usr.sbin.i2pd etc/apparmor.d
|
||||
contrib/apparmor/usr.bin.i2pd etc/apparmor.d
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2022-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -64,11 +64,12 @@ namespace chinese // language namespace
|
||||
{"Full cone NAT", "全锥型NAT"},
|
||||
{"No Descriptors", "无描述符"},
|
||||
{"Uptime", "运行时间"},
|
||||
{"Network status", "IPv4 网络状态"},
|
||||
{"Network status", "网络状态"},
|
||||
{"Network status v6", "IPv6 网络状态"},
|
||||
{"Stopping in", "距停止还有:"},
|
||||
{"Family", "家族"},
|
||||
{"Tunnel creation success rate", "隧道创建成功率"},
|
||||
{"Total tunnel creation success rate", "当前隧道创建成功率"},
|
||||
{"Received", "已接收"},
|
||||
{"%.2f KiB/s", "%.2f KiB/s"},
|
||||
{"Sent", "已发送"},
|
||||
@@ -95,6 +96,7 @@ namespace chinese // language namespace
|
||||
{"Address", "地址"},
|
||||
{"Type", "类型"},
|
||||
{"EncType", "加密类型"},
|
||||
{"Expire LeaseSet", "到期租约集"},
|
||||
{"Inbound tunnels", "入站隧道"},
|
||||
{"%dms", "%dms"},
|
||||
{"Outbound tunnels", "出站隧道"},
|
||||
@@ -151,6 +153,8 @@ namespace chinese // language namespace
|
||||
{"StreamID can't be null", "StreamID 不能为空"},
|
||||
{"Return to destination page", "返回目标页面"},
|
||||
{"You will be redirected in %d seconds", "您将在%d秒内被重定向"},
|
||||
{"LeaseSet expiration time updated", "租约集到期时间已更新"},
|
||||
{"LeaseSet is not found or already expired", "租约集未找到或已过期"},
|
||||
{"Transit tunnels count must not exceed %d", "中转隧道数量限制为 %d"},
|
||||
{"Back to commands list", "返回命令列表"},
|
||||
{"Register at reg.i2p", "在 reg.i2p 注册域名"},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2022-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -36,18 +36,18 @@ namespace czech // language namespace
|
||||
{"%.2f GiB", "%.2f GiB"},
|
||||
{"building", "vytváří se"},
|
||||
{"failed", "selhalo"},
|
||||
{"expiring", "končící"},
|
||||
{"expiring", "vyprší platnost"},
|
||||
{"established", "vytvořeno"},
|
||||
{"unknown", "neznámý"},
|
||||
{"exploratory", "průzkumné"},
|
||||
{"Purple I2P Webconsole", "Purple I2P Webkonsole"},
|
||||
{"<b>i2pd</b> webconsole", "<b>i2pd</b> webkonsole"},
|
||||
{"Purple I2P Webconsole", "Purple I2P webová konzole"},
|
||||
{"<b>i2pd</b> webconsole", "<b>i2pd</b> webová konzole"},
|
||||
{"Main page", "Hlavní stránka"},
|
||||
{"Router commands", "Router příkazy"},
|
||||
{"Local Destinations", "Lokální destinace"},
|
||||
{"LeaseSets", "LeaseSety"},
|
||||
{"Local Destinations", "Místní cíle"},
|
||||
{"LeaseSets", "Sety pronájmu"},
|
||||
{"Tunnels", "Tunely"},
|
||||
{"Transit Tunnels", "Transitní tunely"},
|
||||
{"Transit Tunnels", "Tranzitní tunely"},
|
||||
{"Transports", "Transporty"},
|
||||
{"I2P tunnels", "I2P tunely"},
|
||||
{"SAM sessions", "SAM relace"},
|
||||
@@ -61,18 +61,21 @@ namespace czech // language namespace
|
||||
{"Clock skew", "Časová nesrovnalost"},
|
||||
{"Offline", "Offline"},
|
||||
{"Symmetric NAT", "Symetrický NAT"},
|
||||
{"Full cone NAT", "Full cone NAT"},
|
||||
{"No Descriptors", "Žádné popisovače"},
|
||||
{"Uptime", "Doba provozu"},
|
||||
{"Network status", "Status sítě"},
|
||||
{"Network status v6", "Status sítě v6"},
|
||||
{"Network status", "Stav sítě"},
|
||||
{"Network status v6", "Stav sítě v6"},
|
||||
{"Stopping in", "Zastavuji za"},
|
||||
{"Family", "Rodina"},
|
||||
{"Tunnel creation success rate", "Úspěšnost vytváření tunelů"},
|
||||
{"Total tunnel creation success rate", "Celková míra úspěšnosti vytváření tunelů"},
|
||||
{"Received", "Přijato"},
|
||||
{"%.2f KiB/s", "%.2f KiB/s"},
|
||||
{"Sent", "Odesláno"},
|
||||
{"Transit", "Tranzit"},
|
||||
{"Data path", "Cesta k data souborům"},
|
||||
{"Hidden content. Press on text to see.", "Skrytý kontent. Pro zobrazení, klikni na text."},
|
||||
{"Data path", "Cesta k datovým souborům"},
|
||||
{"Hidden content. Press on text to see.", "Skrytý obsah. Pro zobrazení klikněte sem."},
|
||||
{"Router Ident", "Routerová Identita"},
|
||||
{"Router Family", "Rodina routerů"},
|
||||
{"Router Caps", "Omezení Routerů"},
|
||||
@@ -93,6 +96,7 @@ namespace czech // language namespace
|
||||
{"Address", "Adresa"},
|
||||
{"Type", "Typ"},
|
||||
{"EncType", "EncType"},
|
||||
{"Expire LeaseSet", "Zrušit platnost setu pronájmu"},
|
||||
{"Inbound tunnels", "Příchozí tunely"},
|
||||
{"%dms", "%dms"},
|
||||
{"Outbound tunnels", "Odchozí tunely"},
|
||||
@@ -103,21 +107,24 @@ namespace czech // language namespace
|
||||
{"Amount", "Množství"},
|
||||
{"Incoming Tags", "Příchozí štítky"},
|
||||
{"Tags sessions", "Relace štítků"},
|
||||
{"Status", "Status"},
|
||||
{"Local Destination", "Lokální Destinace"},
|
||||
{"Status", "Stav"},
|
||||
{"Local Destination", "Místní cíl"},
|
||||
{"Streams", "Toky"},
|
||||
{"Close stream", "Uzavřít tok"},
|
||||
{"Such destination is not found", "Takováto destinace nebyla nalezena"},
|
||||
{"I2CP session not found", "I2CP relace nenalezena"},
|
||||
{"I2CP is not enabled", "I2CP není zapnuto"},
|
||||
{"Invalid", "Neplatný"},
|
||||
{"Store type", "Druh uložení"},
|
||||
{"Expires", "Vyprší"},
|
||||
{"Non Expired Leases", "Nevypršené Leasy"},
|
||||
{"Non Expired Leases", "Pronájmy, kterým nevypršela platnost"},
|
||||
{"Gateway", "Brána"},
|
||||
{"TunnelID", "ID tunelu"},
|
||||
{"EndDate", "Datum ukončení"},
|
||||
{"floodfill mode is disabled", "režim floodfill je vypnut"},
|
||||
{"Queue size", "Velikost fronty"},
|
||||
{"Run peer test", "Spustit peer test"},
|
||||
{"Reload tunnels configuration", "Znovu načíst nastavení tunelů"},
|
||||
{"Decline transit tunnels", "Odmítnout tranzitní tunely"},
|
||||
{"Accept transit tunnels", "Přijmout tranzitní tunely"},
|
||||
{"Cancel graceful shutdown", "Zrušit hladké vypnutí"},
|
||||
@@ -145,14 +152,17 @@ namespace czech // language namespace
|
||||
{"Destination not found", "Destinace nenalezena"},
|
||||
{"StreamID can't be null", "StreamID nemůže být null"},
|
||||
{"Return to destination page", "Zpět na stránku destinací"},
|
||||
{"Back to commands list", "Zpět na list příkazů"},
|
||||
{"You will be redirected in %d seconds", "Budete přesměrováni za %d sekund"},
|
||||
{"LeaseSet expiration time updated", "Aktualizován čas vypršení platnosti setu pronájmu"},
|
||||
{"LeaseSet is not found or already expired", "Set pronájmu není k nalezení nebo již vypršela jeho platnost"},
|
||||
{"Transit tunnels count must not exceed %d", "Počet tranzitních tunelů nesmí překročit %d"},
|
||||
{"Back to commands list", "Zpět na seznam příkazů"},
|
||||
{"Register at reg.i2p", "Zaregistrovat na reg.i2p"},
|
||||
{"Description", "Popis"},
|
||||
{"A bit information about service on domain", "Trochu informací o službě na doméně"},
|
||||
{"Submit", "Odeslat"},
|
||||
{"Domain can't end with .b32.i2p", "Doména nesmí končit na .b32.i2p"},
|
||||
{"Domain must end with .i2p", "Doména musí končit s .i2p"},
|
||||
{"Such destination is not found", "Takováto destinace nebyla nalezena"},
|
||||
{"Unknown command", "Neznámý příkaz"},
|
||||
{"Command accepted", "Příkaz přijat"},
|
||||
{"Proxy error", "Chyba proxy serveru"},
|
||||
@@ -162,6 +172,15 @@ namespace czech // language namespace
|
||||
{"You may try to find this host on jump services below", "Můžete se pokusit najít tohoto hostitele na startovacích službách níže"},
|
||||
{"Invalid request", "Neplatný požadavek"},
|
||||
{"Proxy unable to parse your request", "Proxy server nemohl zpracovat váš požadavek"},
|
||||
{"Addresshelper is not supported", "Addresshelper není podporován"},
|
||||
{"Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "Hostitel %s je <font color=red>již v adresáři routeru</font>. <b>Buďte opatrní: zdroj této URL může být škodlivý!</b> Klikněte zde pro aktualizaci záznamu: <a href=\"%s%s%s&update=true\">Pokračovat</a>."},
|
||||
{"Addresshelper forced update rejected", "Addresshelperem vynucená aktualizace zamítnuta"},
|
||||
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Pro přidání hostitele <b>%s</b> do adresáře routeru, klikněte zde: <a href=\"%s%s%s\">Pokračovat</a>."},
|
||||
{"Addresshelper request", "Požadavek Addresshelperu"},
|
||||
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "Hostitel %s přidán do adresáře routeru od pomocníka. Klikněte zde pro pokračování: <a href=\"%s\">Pokračovat</a>."},
|
||||
{"Addresshelper adding", "Addresshelper přidávání"},
|
||||
{"Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "Hostitel %s je <font color=red>již v adresáři routeru</font>. Klikněte zde pro aktualizaci záznamu: <a href=\"%s%s%s&update=true\">Pokračovat</a>."},
|
||||
{"Addresshelper update", "Addresshelper aktualizace"},
|
||||
{"Invalid request URI", "Neplatný URI požadavek"},
|
||||
{"Can't detect destination host from request", "Nelze zjistit cílového hostitele z požadavku"},
|
||||
{"Outproxy failure", "Outproxy selhání"},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2022-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -58,7 +58,7 @@ namespace french // language namespace
|
||||
{"Unknown", "Inconnu"},
|
||||
{"Proxy", "Proxy"},
|
||||
{"Mesh", "Maillé"},
|
||||
{"Clock skew", "Horloge décalée"},
|
||||
{"Clock skew", "Décalage de l'horloge"},
|
||||
{"Offline", "Hors ligne"},
|
||||
{"Symmetric NAT", "NAT symétrique"},
|
||||
{"Full cone NAT", "NAT à cône complet"},
|
||||
@@ -68,8 +68,8 @@ namespace french // language namespace
|
||||
{"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"},
|
||||
{"Total tunnel creation success rate", "Taux de réussite de création de tunnel"},
|
||||
{"Tunnel creation success rate", "Taux de création de tunnel réussie"},
|
||||
{"Total tunnel creation success rate", "Taux total de création de tunnel réussie"},
|
||||
{"Received", "Reçu"},
|
||||
{"%.2f KiB/s", "%.2f Kio/s"},
|
||||
{"Sent", "Envoyé"},
|
||||
|
||||
168
i18n/Polish.cpp
168
i18n/Polish.cpp
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2023, The PurpleI2P Project
|
||||
* Copyright (c) 2023-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -31,22 +31,186 @@ namespace polish // language namespace
|
||||
|
||||
static std::map<std::string, std::string> strings
|
||||
{
|
||||
{"%.2f KiB", "%.2f KiB"},
|
||||
{"%.2f MiB", "%.2f MiB"},
|
||||
{"%.2f GiB", "%.2f GiB"},
|
||||
{"building", "Kompilowanie"},
|
||||
{"failed", "nieudane"},
|
||||
{"expiring", "wygasający"},
|
||||
{"established", "ustanowiony"},
|
||||
{"unknown", "nieznany"},
|
||||
{"exploratory", "eksploracyjny"},
|
||||
{"Purple I2P Webconsole", "Konsola webowa Purple I2P"},
|
||||
{"<b>i2pd</b> webconsole", "<b>i2pd</b> konsola webowa"},
|
||||
{"Main page", "Strona główna"},
|
||||
{"Router commands", "Komendy routera"},
|
||||
{"Local Destinations", "Lokalne miejsca docelowe"},
|
||||
{"LeaseSets", "ZestawyNajmu"},
|
||||
{"Tunnels", "Tunele"},
|
||||
{"Transit Tunnels", "Tunele Tranzytu"},
|
||||
{"Transports", "Transportery"},
|
||||
{"I2P tunnels", "Tunele I2P"},
|
||||
{"SAM sessions", "Sesje SAM"},
|
||||
{"ERROR", "BŁĄD"},
|
||||
{"OK", "Ok"},
|
||||
{"Testing", "Testowanie"},
|
||||
{"Firewalled", "Za zaporą sieciową"},
|
||||
{"Unknown", "Nieznany"},
|
||||
{"Proxy", "Proxy"},
|
||||
{"Mesh", "Sieć"},
|
||||
{"Clock skew", "Przesunięcie czasu"},
|
||||
{"Offline", "Offline"},
|
||||
{"Symmetric NAT", "Symetryczny NAT"},
|
||||
{"Full cone NAT", "Pełny stożek NAT"},
|
||||
{"No Descriptors", "Brak deskryptorów"},
|
||||
{"Uptime", "Czas pracy"},
|
||||
{"Network status", "Stan sieci"},
|
||||
{"Network status v6", "Stan sieci v6"},
|
||||
{"Stopping in", "Zatrzymywanie za"},
|
||||
{"Family", "Rodzina"},
|
||||
{"Tunnel creation success rate", "Wskaźnik sukcesu tworzenia tunelu"},
|
||||
{"Total tunnel creation success rate", "Całkowity wskaźnik sukcesu tworzenia tunelu"},
|
||||
{"Received", "Odebrano"},
|
||||
{"%.2f KiB/s", "%.2f KiB/s"},
|
||||
{"Sent", "Wysłane"},
|
||||
{"Transit", "Tranzyt"},
|
||||
{"Data path", "Ścieżka do danych"},
|
||||
{"Hidden content. Press on text to see.", "Ukryta zawartość. Naciśnij tekst, aby zobaczyć."},
|
||||
{"Router Ident", "Identyfikator routera"},
|
||||
{"Router Family", "Rodzina routera"},
|
||||
{"Router Caps", "Możliwości routera"},
|
||||
{"Version", "Wersja"},
|
||||
{"Our external address", "Nasz zewnętrzny adres"},
|
||||
{"supported", "wspierane"},
|
||||
{"Routers", "Routery"},
|
||||
{"Floodfills", "Floodfille"},
|
||||
{"Client Tunnels", "Tunele Klienta"},
|
||||
{"Services", "Usługi"},
|
||||
{"Enabled", "Aktywny"},
|
||||
{"Disabled", "Wyłączony"},
|
||||
{"Encrypted B33 address", "Zaszyfrowany adres B33"},
|
||||
{"Address registration line", "Linia rejestracji adresu"},
|
||||
{"Domain", "Domena"},
|
||||
{"Generate", "Generuj"},
|
||||
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Uwaga:</b> wynik string może być używany tylko do rejestracji domen 2LD (przykład.i2p). Do rejestracji subdomen należy użyć narzędzi i2pd."},
|
||||
{"Address", "Adres"},
|
||||
{"Type", "Typ"},
|
||||
{"EncType", "TypEnkrypcji"},
|
||||
{"Expire LeaseSet", "Wygaśnij LeaseSet"},
|
||||
{"Inbound tunnels", "Tunele przychodzące"},
|
||||
{"%dms", "%dms"},
|
||||
{"Outbound tunnels", "Tunele wychodzące"},
|
||||
{"Tags", "Tagi"},
|
||||
{"Incoming", "Przychodzące"},
|
||||
{"Outgoing", "Wychodzące"},
|
||||
{"Destination", "Miejsce docelowe"},
|
||||
{"Amount", "Ilość"},
|
||||
{"Incoming Tags", "Przychodzące tagi"},
|
||||
{"Tags sessions", "Sesje tagów"},
|
||||
{"Status", "Status"},
|
||||
{"Local Destination", "Lokalne miejsce docelowe"},
|
||||
{"Streams", "Strumienie"},
|
||||
{"Close stream", "Zamknij strumień"},
|
||||
{"Such destination is not found", "Nie znaleziono takiego miejsca docelowego"},
|
||||
{"I2CP session not found", "Sesja I2CP nie została znaleziona"},
|
||||
{"I2CP is not enabled", "I2CP nie jest włączone"},
|
||||
{"Invalid", "Niepoprawny"},
|
||||
{"Store type", "Rodzaj przechowywania"},
|
||||
{"Expires", "Wygasa za"},
|
||||
{"Non Expired Leases", "Leasingi niewygasłe"},
|
||||
{"Gateway", "Brama"},
|
||||
{"TunnelID", "IDTunelu"},
|
||||
{"EndDate", "DataZakończenia"},
|
||||
{"floodfill mode is disabled", "tryb floodfill jest wyłączony"},
|
||||
{"Queue size", "Wielkość kolejki"},
|
||||
{"Run peer test", "Wykonaj test peer"},
|
||||
{"Reload tunnels configuration", "Załaduj ponownie konfigurację tuneli"},
|
||||
{"Decline transit tunnels", "Odrzuć tunele tranzytowe"},
|
||||
{"Accept transit tunnels", "Akceptuj tunele tranzytowe"},
|
||||
{"Cancel graceful shutdown", "Anuluj łagodne wyłączenie"},
|
||||
{"Start graceful shutdown", "Rozpocznij łagodne wyłączenie"},
|
||||
{"Force shutdown", "Wymuś wyłączenie"},
|
||||
{"Reload external CSS styles", "Odśwież zewnętrzne style CSS"},
|
||||
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Uwaga:</b> każda akcja wykonana tutaj nie jest trwała i nie zmienia Twoich plików konfiguracyjnych."},
|
||||
{"Logging level", "Poziom logowania"},
|
||||
{"Transit tunnels limit", "Limit tuneli tranzytowych"},
|
||||
{"Change", "Zmień"},
|
||||
{"Change language", "Zmień język"},
|
||||
{"no transit tunnels currently built", "brak obecnie zbudowanych tuneli tranzytowych"},
|
||||
{"SAM disabled", "SAM wyłączony"},
|
||||
{"no sessions currently running", "brak aktualnie uruchomionych sesji"},
|
||||
{"SAM session not found", "Sesja SAM nie została znaleziona"},
|
||||
{"SAM Session", "Sesja SAM"},
|
||||
{"Server Tunnels", "Tunele Serwera"},
|
||||
{"Client Forwards", "Przekierowania Klienta"},
|
||||
{"Server Forwards", "Przekierowania Serwera"},
|
||||
{"Unknown page", "Nieznana strona"},
|
||||
{"Invalid token", "Nieprawidłowy token"},
|
||||
{"SUCCESS", "SUKCES"},
|
||||
{"Stream closed", "Strumień zamknięty"},
|
||||
{"Stream not found or already was closed", "Strumień nie został znaleziony lub został już zamknięty"},
|
||||
{"Destination not found", "Nie znaleziono punktu docelowego"},
|
||||
{"StreamID can't be null", "StreamID nie może być null"},
|
||||
{"Return to destination page", "Wróć do strony miejsca docelowego"},
|
||||
{"You will be redirected in %d seconds", "Zostaniesz prekierowany za %d sekund"},
|
||||
{"LeaseSet expiration time updated", "Zaktualizowano czas wygaśnięcia LeaseSet"},
|
||||
{"LeaseSet is not found or already expired", "LeaseSet nie został znaleziony lub już wygasł"},
|
||||
{"Transit tunnels count must not exceed %d", "Liczba tuneli tranzytowych nie może przekraczać %d"},
|
||||
{"Back to commands list", "Powrót do listy poleceń"},
|
||||
{"Register at reg.i2p", "Zarejestruj się na reg.i2p"},
|
||||
{"Description", "Opis"},
|
||||
{"A bit information about service on domain", "Trochę informacji o usłudze w domenie"},
|
||||
{"Submit", "Zatwierdź"},
|
||||
{"Domain can't end with .b32.i2p", "Domena nie może kończyć się na .b32.i2p"},
|
||||
{"Domain must end with .i2p", "Domena musi kończyć się na .i2p"},
|
||||
{"Unknown command", "Nieznana komenda"},
|
||||
{"Command accepted", "Polecenie zaakceptowane"},
|
||||
{"Proxy error", "Błąd serwera proxy"},
|
||||
{"Proxy info", "Informacje o proxy"},
|
||||
{"Proxy error: Host not found", "Błąd proxy: Nie znaleziono hosta"},
|
||||
{"Remote host not found in router's addressbook", "Nie znaleziono zdalnego hosta w książce adresowej routera"},
|
||||
{"You may try to find this host on jump services below", "Możesz znaleźć tego hosta na poniższych usługach skoku"},
|
||||
{"Invalid request", "Nieprawidłowe żądanie"},
|
||||
{"Proxy unable to parse your request", "Serwer proxy nie może przetworzyć Twojego żądania"},
|
||||
{"Addresshelper is not supported", "Adresshelper nie jest obsługiwany"},
|
||||
{"Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "Host %s <font color=red>jest już w książce adresowej routera</font>. <b>Uważaj: źródło tego adresu URL może być szkodliwe!</b> Kliknij tutaj, aby zaktualizować rekord: <a href=\"%s%s%s&update=true\">Kontynuuj</a>."},
|
||||
{"Addresshelper forced update rejected", "Wymuszona aktualizacja Addreshelper odrzucona"},
|
||||
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Aby dodać host <b>%s</b> w książce adresowej routera, kliknij tutaj: <a href=\"%s%s%s\">Kontynuuj</a>."},
|
||||
{"Addresshelper request", "Prośba Addresshelper"},
|
||||
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "Host %s dodany do książki adresowej routera od pomocnika. Kliknij tutaj, aby kontynuować: <a href=\"%s\">Kontynuuj</a>."},
|
||||
{"Addresshelper adding", "Dodawanie Addresshelper"},
|
||||
{"Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "Host %s jest <font color=red>już w książce adresowej routera</font>. Kliknij tutaj, aby zaktualizować rekord: <a href=\"%s%s%s&update=true\">Kontynuuj</a>."},
|
||||
{"Addresshelper update", "Aktualizacja Adresshelper"},
|
||||
{"Invalid request URI", "Nieprawidłowe URI żądania"},
|
||||
{"Can't detect destination host from request", "Nie można wykryć hosta docelowego z żądania"},
|
||||
{"Outproxy failure", "Błąd proxy wyjściowego"},
|
||||
{"Bad outproxy settings", "Błędne ustawienia proxy wyjściowych"},
|
||||
{"Host %s is not inside I2P network, but outproxy is not enabled", "Host %s nie jest wewnątrz sieci I2P, a proxy wyjściowe nie jest włączone"},
|
||||
{"Unknown outproxy URL", "Nieznany adres URL proxy wyjściowego"},
|
||||
{"Cannot resolve upstream proxy", "Nie można rozwiązać serwera proxy upstream"},
|
||||
{"Hostname is too long", "Nazwa hosta jest zbyt długa"},
|
||||
{"Cannot connect to upstream SOCKS proxy", "Nie można połączyć się z proxy SOCKS upstream"},
|
||||
{"Cannot negotiate with SOCKS proxy", "Nie można negocjować z proxy SOCKS"},
|
||||
{"CONNECT error", "Błąd POŁĄCZENIE"},
|
||||
{"Failed to connect", "Nie udało się połączyć"},
|
||||
{"SOCKS proxy error", "Błąd proxy SOCKS"},
|
||||
{"Failed to send request to upstream", "Nie udało się wysłać żądania do upstream"},
|
||||
{"No reply from SOCKS proxy", "Brak odpowiedzi od serwera proxy SOCKS"},
|
||||
{"Cannot connect", "Nie można się połączyć"},
|
||||
{"HTTP out proxy not implemented", "Serwer wyjściowy proxy HTTP nie został zaimplementowany"},
|
||||
{"Cannot connect to upstream HTTP proxy", "Nie można połączyć się z proxy HTTP upstream"},
|
||||
{"Host is down", "Host jest niedostępny"},
|
||||
{"Can't create connection to requested host, it may be down. Please try again later.", "Nie można utworzyć połączenia z żądanym hostem, może być wyłączony. Spróbuj ponownie później."},
|
||||
{"", ""},
|
||||
};
|
||||
|
||||
static std::map<std::string, std::vector<std::string>> plurals
|
||||
{
|
||||
{"", {"", "", ""}},
|
||||
{"%d days", {"%d dzień", "%d dni", "%d dni", "%d dni"}},
|
||||
{"%d hours", {"%d godzina", "%d godziny", "%d godzin", "%d godzin"}},
|
||||
{"%d minutes", {"%d minuta", "%d minuty", "%d minut", "%d minut"}},
|
||||
{"%d seconds", {"%d sekunda", "%d sekundy", "%d sekund", "%d sekund"}},
|
||||
{"", {"", "", "", ""}},
|
||||
};
|
||||
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2023, The PurpleI2P Project
|
||||
* Copyright (c) 2023-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -58,7 +58,7 @@ namespace portuguese // language namespace
|
||||
{"Unknown", "Desconhecido"},
|
||||
{"Proxy", "Proxy"},
|
||||
{"Mesh", "Malha"},
|
||||
{"Clock skew", "Defasagem do Relógio"},
|
||||
{"Clock skew", "Desvio de Relógio"},
|
||||
{"Offline", "Desligado"},
|
||||
{"Symmetric NAT", "NAT Simétrico"},
|
||||
{"Full cone NAT", "Full cone NAT"},
|
||||
@@ -74,7 +74,7 @@ namespace portuguese // language namespace
|
||||
{"%.2f KiB/s", "%.2f KiB/s"},
|
||||
{"Sent", "Enviado"},
|
||||
{"Transit", "Trânsito"},
|
||||
{"Data path", "Diretório dos dados"},
|
||||
{"Data path", "Diretório de dados"},
|
||||
{"Hidden content. Press on text to see.", "Conteúdo oculto. Clique no texto para revelar."},
|
||||
{"Router Ident", "Identidade do Roteador"},
|
||||
{"Router Family", "Família do Roteador"},
|
||||
@@ -106,9 +106,9 @@ namespace portuguese // language namespace
|
||||
{"Destination", "Destinos"},
|
||||
{"Amount", "Quantidade"},
|
||||
{"Incoming Tags", "Etiquetas de Entrada"},
|
||||
{"Tags sessions", "Sessões de etiquetas"},
|
||||
{"Tags sessions", "Sessões de Etiquetas"},
|
||||
{"Status", "Estado"},
|
||||
{"Local Destination", "Destinos Locais"},
|
||||
{"Local Destination", "Destino Local"},
|
||||
{"Streams", "Fluxos"},
|
||||
{"Close stream", "Fechar fluxo"},
|
||||
{"Such destination is not found", "Tal destino não foi encontrado"},
|
||||
@@ -148,7 +148,7 @@ namespace portuguese // language namespace
|
||||
{"Invalid token", "Token Inválido"},
|
||||
{"SUCCESS", "SUCESSO"},
|
||||
{"Stream closed", "Fluxo fechado"},
|
||||
{"Stream not found or already was closed", "Fluxo não encontrado ou já encerrado"},
|
||||
{"Stream not found or already was closed", "Fluxo não encontrado ou já fechado"},
|
||||
{"Destination not found", "Destino não encontrado"},
|
||||
{"StreamID can't be null", "StreamID não pode ser nulo"},
|
||||
{"Return to destination page", "Retornar para à página de destino"},
|
||||
@@ -157,7 +157,7 @@ namespace portuguese // language namespace
|
||||
{"LeaseSet is not found or already expired", "LeaseSet não foi encontrado ou já expirou"},
|
||||
{"Transit tunnels count must not exceed %d", "A contagem de túneis de trânsito não deve exceder %d"},
|
||||
{"Back to commands list", "Voltar para a lista de comandos"},
|
||||
{"Register at reg.i2p", "Registrar na reg.i2p"},
|
||||
{"Register at reg.i2p", "Registrar em reg.i2p"},
|
||||
{"Description", "Descrição"},
|
||||
{"A bit information about service on domain", "Algumas informações sobre o serviço no domínio"},
|
||||
{"Submit", "Enviar"},
|
||||
@@ -169,22 +169,22 @@ namespace portuguese // language namespace
|
||||
{"Proxy info", "Informações do proxy"},
|
||||
{"Proxy error: Host not found", "Erro no proxy: Host não encontrado"},
|
||||
{"Remote host not found in router's addressbook", "O host remoto não foi encontrado no livro de endereços do roteador"},
|
||||
{"You may try to find this host on jump services below", "Você pode tentar encontrar este host nos jump services abaixo"},
|
||||
{"You may try to find this host on jump services below", "Você pode tentar encontrar este host nos serviços de jump abaixo"},
|
||||
{"Invalid request", "Requisição inválida"},
|
||||
{"Proxy unable to parse your request", "O proxy foi incapaz de processar a sua requisição"},
|
||||
{"Addresshelper is not supported", "O Auxiliar de Endereços não é suportado"},
|
||||
{"Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "O host %s já <font color=red>está no catálogo de endereços do roteador</font>. <b>Cuidado: a fonte desta URL pode ser perigosa!</b> Clique aqui para atualizar o registro: <a href=\"%s%s%s&update=true\">Continuar</a>."},
|
||||
{"Addresshelper forced update rejected", "A atualização forçada do Auxiliar de Endereços foi rejeitada"},
|
||||
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Para adicionar o host <b> %s </b> ao catálogo de endereços do roteador, clique aqui: <a href='%s%s%s'>Continuar </a>."},
|
||||
{"Addresshelper request", "Requisição do Auxiliar de Endereços"},
|
||||
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "O host %s foi adicionado ao catálogo de endereços do roteador por um auxiliar. Clique aqui para proceder: <a href='%s'> Continuar </a>."},
|
||||
{"Addresshelper request", "Requisição ao Auxiliar de Endereços"},
|
||||
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "O host %s foi adicionado ao catálogo de endereços do roteador por um auxiliar. Clique aqui para prosseguir: <a href='%s'> Continuar </a>."},
|
||||
{"Addresshelper adding", "Auxiliar de Endereço adicionando"},
|
||||
{"Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "O host %s já <font color=red>está no catálogo de endereços do roteador </font>. Clique aqui para atualizar o registro: <a href=\"%s%s%s&update=true\">Continuar</a>."},
|
||||
{"Addresshelper update", "Atualização do Auxiliar de Endereços"},
|
||||
{"Invalid request URI", "A URI de requisição é inválida"},
|
||||
{"Can't detect destination host from request", "Incapaz de detectar o host de destino da requisição"},
|
||||
{"Outproxy failure", "Falha no outproxy"},
|
||||
{"Bad outproxy settings", "Configurações ruins de outproxy"},
|
||||
{"Bad outproxy settings", "Má configurações do outproxy"},
|
||||
{"Host %s is not inside I2P network, but outproxy is not enabled", "O host %s não está dentro da rede I2P, mas o outproxy não está ativado"},
|
||||
{"Unknown outproxy URL", "URL de outproxy desconhecida"},
|
||||
{"Cannot resolve upstream proxy", "Não é possível resolver o proxy de entrada"},
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* Kovri go write your own code
|
||||
*
|
||||
*/
|
||||
|
||||
#include "I2PEndian.h"
|
||||
#include "ChaCha20.h"
|
||||
|
||||
#if !OPENSSL_AEAD_CHACHA20_POLY1305
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
namespace chacha
|
||||
{
|
||||
void u32t8le(uint32_t v, uint8_t * p)
|
||||
{
|
||||
p[0] = v & 0xff;
|
||||
p[1] = (v >> 8) & 0xff;
|
||||
p[2] = (v >> 16) & 0xff;
|
||||
p[3] = (v >> 24) & 0xff;
|
||||
}
|
||||
|
||||
uint32_t u8t32le(const uint8_t * p)
|
||||
{
|
||||
uint32_t value = p[3];
|
||||
|
||||
value = (value << 8) | p[2];
|
||||
value = (value << 8) | p[1];
|
||||
value = (value << 8) | p[0];
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
uint32_t rotl32(uint32_t x, int n)
|
||||
{
|
||||
return x << n | (x >> (-n & 31));
|
||||
}
|
||||
|
||||
void quarterround(uint32_t *x, int a, int b, int c, int d)
|
||||
{
|
||||
x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 16);
|
||||
x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 12);
|
||||
x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 8);
|
||||
x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 7);
|
||||
}
|
||||
|
||||
|
||||
void Chacha20Block::operator << (const Chacha20State & st)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 16; i++)
|
||||
u32t8le(st.data[i], data + (i << 2));
|
||||
}
|
||||
|
||||
void block (Chacha20State &input, int rounds)
|
||||
{
|
||||
int i;
|
||||
Chacha20State x;
|
||||
x.Copy(input);
|
||||
|
||||
for (i = rounds; i > 0; i -= 2)
|
||||
{
|
||||
quarterround(x.data, 0, 4, 8, 12);
|
||||
quarterround(x.data, 1, 5, 9, 13);
|
||||
quarterround(x.data, 2, 6, 10, 14);
|
||||
quarterround(x.data, 3, 7, 11, 15);
|
||||
quarterround(x.data, 0, 5, 10, 15);
|
||||
quarterround(x.data, 1, 6, 11, 12);
|
||||
quarterround(x.data, 2, 7, 8, 13);
|
||||
quarterround(x.data, 3, 4, 9, 14);
|
||||
}
|
||||
x += input;
|
||||
input.block << x;
|
||||
}
|
||||
|
||||
void Chacha20Init (Chacha20State& state, const uint8_t * nonce, const uint8_t * key, uint32_t counter)
|
||||
{
|
||||
state.data[0] = 0x61707865;
|
||||
state.data[1] = 0x3320646e;
|
||||
state.data[2] = 0x79622d32;
|
||||
state.data[3] = 0x6b206574;
|
||||
for (size_t i = 0; i < 8; i++)
|
||||
state.data[4 + i] = chacha::u8t32le(key + i * 4);
|
||||
|
||||
state.data[12] = htole32 (counter);
|
||||
for (size_t i = 0; i < 3; i++)
|
||||
state.data[13 + i] = chacha::u8t32le(nonce + i * 4);
|
||||
}
|
||||
|
||||
void Chacha20SetCounter (Chacha20State& state, uint32_t counter)
|
||||
{
|
||||
state.data[12] = htole32 (counter);
|
||||
state.offset = 0;
|
||||
}
|
||||
|
||||
void Chacha20Encrypt (Chacha20State& state, uint8_t * buf, size_t sz)
|
||||
{
|
||||
if (state.offset > 0)
|
||||
{
|
||||
// previous block if any
|
||||
auto s = chacha::blocksize - state.offset;
|
||||
if (sz < s) s = sz;
|
||||
for (size_t i = 0; i < s; i++)
|
||||
buf[i] ^= state.block.data[state.offset + i];
|
||||
buf += s;
|
||||
sz -= s;
|
||||
state.offset += s;
|
||||
if (state.offset >= chacha::blocksize) state.offset = 0;
|
||||
}
|
||||
for (size_t i = 0; i < sz; i += chacha::blocksize)
|
||||
{
|
||||
chacha::block(state, chacha::rounds);
|
||||
state.data[12]++;
|
||||
for (size_t j = i; j < i + chacha::blocksize; j++)
|
||||
{
|
||||
if (j >= sz)
|
||||
{
|
||||
state.offset = j & 0x3F; // % 64
|
||||
break;
|
||||
}
|
||||
buf[j] ^= state.block.data[j - i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace chacha
|
||||
} // namespace crypto
|
||||
} // namespace i2p
|
||||
|
||||
#endif
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* Kovri go write your own code
|
||||
*
|
||||
*/
|
||||
#ifndef LIBI2PD_CHACHA20_H
|
||||
#define LIBI2PD_CHACHA20_H
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include "Crypto.h"
|
||||
|
||||
#if !OPENSSL_AEAD_CHACHA20_POLY1305
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
const std::size_t CHACHA20_KEY_BYTES = 32;
|
||||
const std::size_t CHACHA20_NOUNCE_BYTES = 12;
|
||||
|
||||
namespace chacha
|
||||
{
|
||||
constexpr std::size_t blocksize = 64;
|
||||
constexpr int rounds = 20;
|
||||
|
||||
struct Chacha20State;
|
||||
struct Chacha20Block
|
||||
{
|
||||
Chacha20Block () {};
|
||||
Chacha20Block (Chacha20Block &&) = delete;
|
||||
|
||||
uint8_t data[blocksize];
|
||||
|
||||
void operator << (const Chacha20State & st);
|
||||
};
|
||||
|
||||
struct Chacha20State
|
||||
{
|
||||
Chacha20State (): offset (0) {};
|
||||
Chacha20State (Chacha20State &&) = delete;
|
||||
|
||||
Chacha20State & operator += (const Chacha20State & other)
|
||||
{
|
||||
for(int i = 0; i < 16; i++)
|
||||
data[i] += other.data[i];
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Copy(const Chacha20State & other)
|
||||
{
|
||||
memcpy(data, other.data, sizeof(uint32_t) * 16);
|
||||
}
|
||||
uint32_t data[16];
|
||||
Chacha20Block block;
|
||||
size_t offset;
|
||||
};
|
||||
|
||||
void Chacha20Init (Chacha20State& state, const uint8_t * nonce, const uint8_t * key, uint32_t counter);
|
||||
void Chacha20SetCounter (Chacha20State& state, uint32_t counter);
|
||||
void Chacha20Encrypt (Chacha20State& state, uint8_t * buf, size_t sz); // encrypt buf in place
|
||||
} // namespace chacha
|
||||
} // namespace crypto
|
||||
} // namespace i2p
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -77,7 +77,7 @@ namespace config {
|
||||
limits.add_options()
|
||||
("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(5000), "Maximum active transit tunnels (default:5000)")
|
||||
("limits.transittunnels", value<uint32_t>()->default_value(10000), "Maximum active transit tunnels (default:10000)")
|
||||
("limits.zombies", value<double>()->default_value(0), "Minimum percentage of successfully created tunnels under which tunnel cleanup is paused (default [%]: 0.00)")
|
||||
("limits.ntcpsoft", value<uint16_t>()->default_value(0), "Ignored")
|
||||
("limits.ntcphard", value<uint16_t>()->default_value(0), "Ignored")
|
||||
@@ -117,9 +117,14 @@ namespace config {
|
||||
("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")
|
||||
("httpproxy.addresshelper", value<bool>()->default_value(true), "Enable or disable addresshelper")
|
||||
("httpproxy.senduseragent", value<bool>()->default_value(false), "Pass through user's User-Agent if enabled. Disabled by deafult")
|
||||
("httpproxy.i2cp.leaseSetType", value<std::string>()->default_value("3"), "Local destination's LeaseSet type")
|
||||
("httpproxy.i2cp.leaseSetEncType", value<std::string>()->default_value("0,4"), "Local destination's LeaseSet encryption type")
|
||||
("httpproxy.i2cp.leaseSetPrivKey", value<std::string>()->default_value(""), "LeaseSet private key")
|
||||
("httpproxy.i2p.streaming.maxOutboundSpeed", value<std::string>()->default_value("1730000000"), "Max outbound speed of HTTP proxy stream in bytes/sec")
|
||||
("httpproxy.i2p.streaming.maxInboundSpeed", value<std::string>()->default_value("1730000000"), "Max inbound speed of HTTP proxy stream in bytes/sec")
|
||||
("httpproxy.i2p.streaming.profile", value<std::string>()->default_value("1"), "HTTP Proxy bandwidth usage profile. 1 - bulk(high), 2- interactive(low)")
|
||||
|
||||
;
|
||||
|
||||
options_description socksproxy("SOCKS Proxy options");
|
||||
@@ -144,6 +149,9 @@ namespace config {
|
||||
("socksproxy.i2cp.leaseSetType", value<std::string>()->default_value("3"), "Local destination's LeaseSet type")
|
||||
("socksproxy.i2cp.leaseSetEncType", value<std::string>()->default_value("0,4"), "Local destination's LeaseSet encryption type")
|
||||
("socksproxy.i2cp.leaseSetPrivKey", value<std::string>()->default_value(""), "LeaseSet private key")
|
||||
("socksproxy.i2p.streaming.maxOutboundSpeed", value<std::string>()->default_value("1730000000"), "Max outbound speed of SOCKS proxy stream in bytes/sec")
|
||||
("socksproxy.i2p.streaming.maxInboundSpeed", value<std::string>()->default_value("1730000000"), "Max inbound speed of SOCKS proxy stream in bytes/sec")
|
||||
("socksproxy.i2p.streaming.profile", value<std::string>()->default_value("1"), "SOCKS Proxy bandwidth usage profile. 1 - bulk(high), 2- interactive(low)")
|
||||
;
|
||||
|
||||
options_description sam("SAM bridge options");
|
||||
@@ -168,6 +176,8 @@ namespace config {
|
||||
("i2cp.address", value<std::string>()->default_value("127.0.0.1"), "I2CP listen address")
|
||||
("i2cp.port", value<uint16_t>()->default_value(7654), "I2CP listen port")
|
||||
("i2cp.singlethread", value<bool>()->default_value(true), "Destinations run in the I2CP server's thread")
|
||||
("i2cp.inboundlimit", value<uint32_t>()->default_value(0), "Client inbound limit in KBps to return in BandwidthLimitsMessage. Router's bandwidth by default")
|
||||
("i2cp.outboundlimit", value<uint32_t>()->default_value(0), "Client outbound limit in KBps to return in BandwidthLimitsMessage. Router's bandwidth by default")
|
||||
;
|
||||
|
||||
options_description i2pcontrol("I2PControl options");
|
||||
@@ -205,7 +215,7 @@ namespace config {
|
||||
reseed.add_options()
|
||||
("reseed.verify", value<bool>()->default_value(false), "Verify .su3 signature")
|
||||
("reseed.threshold", value<uint16_t>()->default_value(25), "Minimum number of known routers before requesting reseed")
|
||||
("reseed.floodfill", value<std::string>()->default_value(""), "Path to router info of floodfill to reseed from")
|
||||
("reseed.floodfill", value<std::string>()->default_value(""), "Ignored. Always empty")
|
||||
("reseed.file", value<std::string>()->default_value(""), "Path to local .su3 file or HTTPS URL to reseed from")
|
||||
("reseed.zipfile", value<std::string>()->default_value(""), "Path to local .zip file to reseed from")
|
||||
("reseed.proxy", value<std::string>()->default_value(""), "url for reseed proxy, supports http/socks")
|
||||
@@ -222,16 +232,13 @@ namespace config {
|
||||
"https://www2.mk16.de/,"
|
||||
"https://i2p.ghativega.in/,"
|
||||
"https://i2p.novg.net/,"
|
||||
"https://reseed.is.prestium.org/,"
|
||||
"https://reseed.us.prestium.org/"
|
||||
"https://reseed.stormycloud.org/"
|
||||
), "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://[316:f9e0:f22e:a74f::216]/,"
|
||||
"http://[300:eaff:7fab:181b::e621]:7170"
|
||||
"http://[316:f9e0:f22e:a74f::216]/"
|
||||
), "Reseed URLs through the Yggdrasil, separated by comma")
|
||||
;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -19,16 +19,11 @@
|
||||
#if OPENSSL_HKDF
|
||||
#include <openssl/kdf.h>
|
||||
#endif
|
||||
#if !OPENSSL_AEAD_CHACHA20_POLY1305
|
||||
#include "ChaCha20.h"
|
||||
#include "Poly1305.h"
|
||||
#endif
|
||||
#include "Crypto.h"
|
||||
#include "Ed25519.h"
|
||||
#include "I2PEndian.h"
|
||||
#include "Log.h"
|
||||
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
@@ -245,17 +240,12 @@ namespace crypto
|
||||
// x25519
|
||||
X25519Keys::X25519Keys ()
|
||||
{
|
||||
#if OPENSSL_X25519
|
||||
m_Ctx = EVP_PKEY_CTX_new_id (NID_X25519, NULL);
|
||||
m_Pkey = nullptr;
|
||||
#else
|
||||
m_Ctx = BN_CTX_new ();
|
||||
#endif
|
||||
}
|
||||
|
||||
X25519Keys::X25519Keys (const uint8_t * priv, const uint8_t * pub)
|
||||
{
|
||||
#if OPENSSL_X25519
|
||||
m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_X25519, NULL, priv, 32);
|
||||
m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL);
|
||||
if (pub)
|
||||
@@ -265,29 +255,16 @@ namespace crypto
|
||||
size_t len = 32;
|
||||
EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len);
|
||||
}
|
||||
#else
|
||||
m_Ctx = BN_CTX_new ();
|
||||
memcpy (m_PrivateKey, priv, 32);
|
||||
if (pub)
|
||||
memcpy (m_PublicKey, pub, 32);
|
||||
else
|
||||
GetEd25519 ()->ScalarMulB (m_PrivateKey, m_PublicKey, m_Ctx);
|
||||
#endif
|
||||
}
|
||||
|
||||
X25519Keys::~X25519Keys ()
|
||||
{
|
||||
#if OPENSSL_X25519
|
||||
EVP_PKEY_CTX_free (m_Ctx);
|
||||
if (m_Pkey) EVP_PKEY_free (m_Pkey);
|
||||
#else
|
||||
BN_CTX_free (m_Ctx);
|
||||
#endif
|
||||
}
|
||||
|
||||
void X25519Keys::GenerateKeys ()
|
||||
{
|
||||
#if OPENSSL_X25519
|
||||
if (m_Pkey)
|
||||
{
|
||||
EVP_PKEY_free (m_Pkey);
|
||||
@@ -299,16 +276,11 @@ namespace crypto
|
||||
m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL); // TODO: do we really need to re-create m_Ctx?
|
||||
size_t len = 32;
|
||||
EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len);
|
||||
#else
|
||||
RAND_bytes (m_PrivateKey, 32);
|
||||
GetEd25519 ()->ScalarMulB (m_PrivateKey, m_PublicKey, m_Ctx);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool X25519Keys::Agree (const uint8_t * pub, uint8_t * shared)
|
||||
{
|
||||
if (!pub || (pub[31] & 0x80)) return false; // not x25519 key
|
||||
#if OPENSSL_X25519
|
||||
EVP_PKEY_derive_init (m_Ctx);
|
||||
auto pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_X25519, NULL, pub, 32);
|
||||
if (!pkey) return false;
|
||||
@@ -316,25 +288,17 @@ namespace crypto
|
||||
size_t len = 32;
|
||||
EVP_PKEY_derive (m_Ctx, shared, &len);
|
||||
EVP_PKEY_free (pkey);
|
||||
#else
|
||||
GetEd25519 ()->ScalarMul (pub, m_PrivateKey, shared, m_Ctx);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void X25519Keys::GetPrivateKey (uint8_t * priv) const
|
||||
{
|
||||
#if OPENSSL_X25519
|
||||
size_t len = 32;
|
||||
EVP_PKEY_get_raw_private_key (m_Pkey, priv, &len);
|
||||
#else
|
||||
memcpy (priv, m_PrivateKey, 32);
|
||||
#endif
|
||||
}
|
||||
|
||||
void X25519Keys::SetPrivateKey (const uint8_t * priv, bool calculatePublic)
|
||||
{
|
||||
#if OPENSSL_X25519
|
||||
if (m_Ctx) EVP_PKEY_CTX_free (m_Ctx);
|
||||
if (m_Pkey) EVP_PKEY_free (m_Pkey);
|
||||
m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_X25519, NULL, priv, 32);
|
||||
@@ -344,11 +308,6 @@ namespace crypto
|
||||
size_t len = 32;
|
||||
EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len);
|
||||
}
|
||||
#else
|
||||
memcpy (m_PrivateKey, priv, 32);
|
||||
if (calculatePublic)
|
||||
GetEd25519 ()->ScalarMulB (m_PrivateKey, m_PublicKey, m_Ctx);
|
||||
#endif
|
||||
}
|
||||
|
||||
// ElGamal
|
||||
@@ -988,7 +947,6 @@ namespace crypto
|
||||
if (len < msgLen) return false;
|
||||
if (encrypt && len < msgLen + 16) return false;
|
||||
bool ret = true;
|
||||
#if OPENSSL_AEAD_CHACHA20_POLY1305
|
||||
int outlen = 0;
|
||||
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new ();
|
||||
if (encrypt)
|
||||
@@ -1003,6 +961,15 @@ namespace crypto
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x4000000fL
|
||||
std::vector<uint8_t> m(msgLen + 16);
|
||||
if (msg == buf)
|
||||
{
|
||||
// we have to use different buffers otherwise verification fails
|
||||
memcpy (m.data (), msg, msgLen + 16);
|
||||
msg = m.data ();
|
||||
}
|
||||
#endif
|
||||
EVP_DecryptInit_ex(ctx, EVP_chacha20_poly1305(), 0, 0, 0);
|
||||
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, 0);
|
||||
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, (uint8_t *)(msg + msgLen));
|
||||
@@ -1013,73 +980,12 @@ namespace crypto
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX_free (ctx);
|
||||
#else
|
||||
chacha::Chacha20State state;
|
||||
// generate one time poly key
|
||||
chacha::Chacha20Init (state, nonce, key, 0);
|
||||
uint64_t polyKey[8];
|
||||
memset(polyKey, 0, sizeof(polyKey));
|
||||
chacha::Chacha20Encrypt (state, (uint8_t *)polyKey, 64);
|
||||
// create Poly1305 hash
|
||||
Poly1305 polyHash (polyKey);
|
||||
if (!ad) adLen = 0;
|
||||
uint8_t padding[16]; memset (padding, 0, 16);
|
||||
if (ad)
|
||||
{
|
||||
polyHash.Update (ad, adLen);// additional authenticated data
|
||||
auto rem = adLen & 0x0F; // %16
|
||||
if (rem)
|
||||
{
|
||||
// padding1
|
||||
rem = 16 - rem;
|
||||
polyHash.Update (padding, rem);
|
||||
}
|
||||
}
|
||||
// encrypt/decrypt data and add to hash
|
||||
Chacha20SetCounter (state, 1);
|
||||
if (buf != msg)
|
||||
memcpy (buf, msg, msgLen);
|
||||
if (encrypt)
|
||||
{
|
||||
chacha::Chacha20Encrypt (state, buf, msgLen); // encrypt
|
||||
polyHash.Update (buf, msgLen); // after encryption
|
||||
}
|
||||
else
|
||||
{
|
||||
polyHash.Update (buf, msgLen); // before decryption
|
||||
chacha::Chacha20Encrypt (state, buf, msgLen); // decrypt
|
||||
}
|
||||
|
||||
auto rem = msgLen & 0x0F; // %16
|
||||
if (rem)
|
||||
{
|
||||
// padding2
|
||||
rem = 16 - rem;
|
||||
polyHash.Update (padding, rem);
|
||||
}
|
||||
// adLen and msgLen
|
||||
htole64buf (padding, adLen);
|
||||
htole64buf (padding + 8, msgLen);
|
||||
polyHash.Update (padding, 16);
|
||||
|
||||
if (encrypt)
|
||||
// calculate Poly1305 tag and write in after encrypted data
|
||||
polyHash.Finish ((uint64_t *)(buf + msgLen));
|
||||
else
|
||||
{
|
||||
uint64_t tag[4];
|
||||
// calculate Poly1305 tag
|
||||
polyHash.Finish (tag);
|
||||
if (memcmp (tag, msg + msgLen, 16)) ret = false; // compare with provided
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AEADChaCha20Poly1305Encrypt (const std::vector<std::pair<uint8_t *, size_t> >& bufs, const uint8_t * key, const uint8_t * nonce, uint8_t * mac)
|
||||
{
|
||||
if (bufs.empty ()) return;
|
||||
#if OPENSSL_AEAD_CHACHA20_POLY1305
|
||||
int outlen = 0;
|
||||
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new ();
|
||||
EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), 0, 0, 0);
|
||||
@@ -1090,45 +996,10 @@ namespace crypto
|
||||
EVP_EncryptFinal_ex(ctx, NULL, &outlen);
|
||||
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, mac);
|
||||
EVP_CIPHER_CTX_free (ctx);
|
||||
#else
|
||||
chacha::Chacha20State state;
|
||||
// generate one time poly key
|
||||
chacha::Chacha20Init (state, nonce, key, 0);
|
||||
uint64_t polyKey[8];
|
||||
memset(polyKey, 0, sizeof(polyKey));
|
||||
chacha::Chacha20Encrypt (state, (uint8_t *)polyKey, 64);
|
||||
Poly1305 polyHash (polyKey);
|
||||
// encrypt buffers
|
||||
Chacha20SetCounter (state, 1);
|
||||
size_t size = 0;
|
||||
for (const auto& it: bufs)
|
||||
{
|
||||
chacha::Chacha20Encrypt (state, it.first, it.second);
|
||||
polyHash.Update (it.first, it.second); // after encryption
|
||||
size += it.second;
|
||||
}
|
||||
// padding
|
||||
uint8_t padding[16];
|
||||
memset (padding, 0, 16);
|
||||
auto rem = size & 0x0F; // %16
|
||||
if (rem)
|
||||
{
|
||||
// padding2
|
||||
rem = 16 - rem;
|
||||
polyHash.Update (padding, rem);
|
||||
}
|
||||
// adLen and msgLen
|
||||
// adLen is always zero
|
||||
htole64buf (padding + 8, size);
|
||||
polyHash.Update (padding, 16);
|
||||
// MAC
|
||||
polyHash.Finish ((uint64_t *)mac);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ChaCha20 (const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out)
|
||||
{
|
||||
#if OPENSSL_AEAD_CHACHA20_POLY1305
|
||||
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new ();
|
||||
uint32_t iv[4];
|
||||
iv[0] = htole32 (1); memcpy (iv + 1, nonce, 12); // counter | nonce
|
||||
@@ -1137,12 +1008,6 @@ namespace crypto
|
||||
EVP_EncryptUpdate(ctx, out, &outlen, msg, msgLen);
|
||||
EVP_EncryptFinal_ex(ctx, NULL, &outlen);
|
||||
EVP_CIPHER_CTX_free (ctx);
|
||||
#else
|
||||
chacha::Chacha20State state;
|
||||
chacha::Chacha20Init (state, nonce, key, 1);
|
||||
if (out != msg) memcpy (out, msg, msgLen);
|
||||
chacha::Chacha20Encrypt (state, out, msgLen);
|
||||
#endif
|
||||
}
|
||||
|
||||
void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, const std::string& info,
|
||||
@@ -1295,9 +1160,6 @@ namespace crypto
|
||||
void InitCrypto (bool precomputation, bool aesni, bool force)
|
||||
{
|
||||
i2p::cpu::Detect (aesni, force);
|
||||
#if LEGACY_OPENSSL
|
||||
SSL_library_init ();
|
||||
#endif
|
||||
/* auto numLocks = CRYPTO_num_locks();
|
||||
for (int i = 0; i < numLocks; i++)
|
||||
m_OpenSSLMutexes.emplace_back (new std::mutex);
|
||||
|
||||
106
libi2pd/Crypto.h
106
libi2pd/Crypto.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -21,7 +21,6 @@
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/engine.h>
|
||||
#include <openssl/opensslv.h>
|
||||
|
||||
#include "Base.h"
|
||||
@@ -29,24 +28,11 @@
|
||||
#include "CPU.h"
|
||||
|
||||
// recognize openssl version and features
|
||||
#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
|
||||
# endif
|
||||
# endif
|
||||
# if !defined OPENSSL_NO_CHACHA && !defined OPENSSL_NO_POLY1305 // some builds might not include them
|
||||
# define OPENSSL_AEAD_CHACHA20_POLY1305 1
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1
|
||||
# define OPENSSL_HKDF 1
|
||||
# define OPENSSL_EDDSA 1
|
||||
# if (!defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER != 0x030000000)) // 3.0.0, regression in SipHash, not implemented in LibreSSL
|
||||
# define OPENSSL_SIPHASH 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@@ -83,13 +69,8 @@ namespace crypto
|
||||
private:
|
||||
|
||||
uint8_t m_PublicKey[32];
|
||||
#if OPENSSL_X25519
|
||||
EVP_PKEY_CTX * m_Ctx;
|
||||
EVP_PKEY * m_Pkey;
|
||||
#else
|
||||
BN_CTX * m_Ctx;
|
||||
uint8_t m_PrivateKey[32];
|
||||
#endif
|
||||
bool m_IsElligatorIneligible = false; // true if definitely ineligible
|
||||
};
|
||||
|
||||
@@ -312,79 +293,4 @@ namespace crypto
|
||||
}
|
||||
}
|
||||
|
||||
// take care about openssl below 1.1.0
|
||||
#if LEGACY_OPENSSL
|
||||
// define getters and setters introduced in 1.1.0
|
||||
inline int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
|
||||
{
|
||||
if (d->p) BN_free (d->p);
|
||||
if (d->q) BN_free (d->q);
|
||||
if (d->g) BN_free (d->g);
|
||||
d->p = p; d->q = q; d->g = g; return 1;
|
||||
}
|
||||
inline int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
|
||||
{
|
||||
if (d->pub_key) BN_free (d->pub_key);
|
||||
if (d->priv_key) BN_free (d->priv_key);
|
||||
d->pub_key = pub_key; d->priv_key = priv_key; return 1;
|
||||
}
|
||||
inline void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key)
|
||||
{ *pub_key = d->pub_key; *priv_key = d->priv_key; }
|
||||
inline int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s)
|
||||
{
|
||||
if (sig->r) BN_free (sig->r);
|
||||
if (sig->s) BN_free (sig->s);
|
||||
sig->r = r; sig->s = s; return 1;
|
||||
}
|
||||
inline void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
|
||||
{ *pr = sig->r; *ps = sig->s; }
|
||||
|
||||
inline int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
|
||||
{
|
||||
if (sig->r) BN_free (sig->r);
|
||||
if (sig->s) BN_free (sig->s);
|
||||
sig->r = r; sig->s = s; return 1;
|
||||
}
|
||||
inline void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
|
||||
{ *pr = sig->r; *ps = sig->s; }
|
||||
|
||||
inline int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
|
||||
{
|
||||
if (r->n) BN_free (r->n);
|
||||
if (r->e) BN_free (r->e);
|
||||
if (r->d) BN_free (r->d);
|
||||
r->n = n; r->e = e; r->d = d; return 1;
|
||||
}
|
||||
inline void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
|
||||
{ *n = r->n; *e = r->e; *d = r->d; }
|
||||
|
||||
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;
|
||||
}
|
||||
inline int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
|
||||
{
|
||||
if (dh->pub_key) BN_free (dh->pub_key);
|
||||
if (dh->priv_key) BN_free (dh->priv_key);
|
||||
dh->pub_key = pub_key; dh->priv_key = priv_key; return 1;
|
||||
}
|
||||
inline void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key)
|
||||
{ *pub_key = dh->pub_key; *priv_key = dh->priv_key; }
|
||||
|
||||
inline RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey)
|
||||
{ return pkey->pkey.rsa; }
|
||||
|
||||
inline EVP_MD_CTX *EVP_MD_CTX_new ()
|
||||
{ return EVP_MD_CTX_create(); }
|
||||
inline void EVP_MD_CTX_free (EVP_MD_CTX *ctx)
|
||||
{ EVP_MD_CTX_destroy (ctx); }
|
||||
|
||||
// ssl
|
||||
#define TLS_method TLSv1_method
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -19,7 +19,7 @@ namespace i2p
|
||||
namespace datagram
|
||||
{
|
||||
DatagramDestination::DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner, bool gzip):
|
||||
m_Owner (owner), m_Receiver (nullptr), m_RawReceiver (nullptr), m_Gzip (gzip)
|
||||
m_Owner (owner), m_DefaultReceiver (nullptr), m_DefaultRawReceiver (nullptr), m_Gzip (gzip)
|
||||
{
|
||||
if (m_Gzip)
|
||||
m_Deflator.reset (new i2p::data::GzipDeflator);
|
||||
@@ -119,19 +119,79 @@ namespace datagram
|
||||
|
||||
void DatagramDestination::HandleRawDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
|
||||
{
|
||||
if (m_RawReceiver)
|
||||
m_RawReceiver (fromPort, toPort, buf, len);
|
||||
auto r = FindRawReceiver(toPort);
|
||||
|
||||
if (r)
|
||||
r (fromPort, toPort, buf, len);
|
||||
else
|
||||
LogPrint (eLogWarning, "DatagramDestination: no receiver for raw datagram");
|
||||
}
|
||||
|
||||
void DatagramDestination::SetReceiver (const Receiver& receiver, uint16_t port)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_ReceiversMutex);
|
||||
m_ReceiversByPorts[port] = receiver;
|
||||
if (!m_DefaultReceiver) {
|
||||
m_DefaultReceiver = receiver;
|
||||
m_DefaultReceiverPort = port;
|
||||
}
|
||||
}
|
||||
|
||||
void DatagramDestination::ResetReceiver (uint16_t port)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_ReceiversMutex);
|
||||
m_ReceiversByPorts.erase (port);
|
||||
if (m_DefaultReceiverPort == port) {
|
||||
m_DefaultReceiver = nullptr;
|
||||
m_DefaultReceiverPort = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DatagramDestination::SetRawReceiver (const RawReceiver& receiver, uint16_t port)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_RawReceiversMutex);
|
||||
m_RawReceiversByPorts[port] = receiver;
|
||||
if (!m_DefaultRawReceiver) {
|
||||
m_DefaultRawReceiver = receiver;
|
||||
m_DefaultRawReceiverPort = port;
|
||||
}
|
||||
}
|
||||
|
||||
void DatagramDestination::ResetRawReceiver (uint16_t port)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_RawReceiversMutex);
|
||||
m_RawReceiversByPorts.erase (port);
|
||||
if (m_DefaultRawReceiverPort == port) {
|
||||
m_DefaultRawReceiver = nullptr;
|
||||
m_DefaultRawReceiverPort = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DatagramDestination::Receiver DatagramDestination::FindReceiver(uint16_t port)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_ReceiversMutex);
|
||||
Receiver r = m_Receiver;
|
||||
Receiver r = nullptr;
|
||||
auto itr = m_ReceiversByPorts.find(port);
|
||||
if (itr != m_ReceiversByPorts.end())
|
||||
r = itr->second;
|
||||
else {
|
||||
r = m_DefaultReceiver;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
DatagramDestination::RawReceiver DatagramDestination::FindRawReceiver(uint16_t port)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_RawReceiversMutex);
|
||||
RawReceiver r = nullptr;
|
||||
auto itr = m_RawReceiversByPorts.find(port);
|
||||
if (itr != m_RawReceiversByPorts.end())
|
||||
r = itr->second;
|
||||
else {
|
||||
r = m_DefaultRawReceiver;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -228,8 +288,8 @@ namespace datagram
|
||||
|
||||
DatagramSession::DatagramSession(std::shared_ptr<i2p::client::ClientDestination> localDestination,
|
||||
const i2p::data::IdentHash & remoteIdent) :
|
||||
m_LocalDestination(localDestination),
|
||||
m_RemoteIdent(remoteIdent),
|
||||
m_LocalDestination(localDestination), m_RemoteIdent(remoteIdent),
|
||||
m_LastUse (0), m_LastFlush (0),
|
||||
m_RequestingLS(false)
|
||||
{
|
||||
}
|
||||
@@ -250,8 +310,12 @@ namespace datagram
|
||||
if (msg || m_SendQueue.empty ())
|
||||
m_SendQueue.push_back(msg);
|
||||
// flush queue right away if full
|
||||
if (!msg || m_SendQueue.size() >= DATAGRAM_SEND_QUEUE_MAX_SIZE)
|
||||
if (!msg || m_SendQueue.size() >= DATAGRAM_SEND_QUEUE_MAX_SIZE ||
|
||||
m_LastUse > m_LastFlush + DATAGRAM_MAX_FLUSH_INTERVAL)
|
||||
{
|
||||
FlushSendQueue();
|
||||
m_LastFlush = m_LastUse;
|
||||
}
|
||||
}
|
||||
|
||||
DatagramSession::Info DatagramSession::GetSessionInfo() const
|
||||
@@ -284,7 +348,7 @@ namespace datagram
|
||||
if(path)
|
||||
path->updateTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
if (IsRatchets ())
|
||||
SendMsg (nullptr); // send empty message in case if we have some data to send
|
||||
SendMsg (nullptr); // send empty message in case if we don't have some data to send
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::garlic::GarlicRoutingPath> DatagramSession::GetSharedRoutingPath ()
|
||||
@@ -323,8 +387,8 @@ namespace datagram
|
||||
}
|
||||
|
||||
auto path = m_RoutingSession->GetSharedRoutingPath();
|
||||
if (path && m_RoutingSession->IsRatchets () &&
|
||||
m_LastUse > m_RoutingSession->GetLastActivityTimestamp ()*1000 + DATAGRAM_SESSION_PATH_TIMEOUT)
|
||||
if (path && m_RoutingSession->IsRatchets () && (m_RoutingSession->CleanupUnconfirmedTags () ||
|
||||
m_LastUse > m_RoutingSession->GetLastActivityTimestamp ()*1000 + DATAGRAM_SESSION_PATH_TIMEOUT))
|
||||
{
|
||||
m_RoutingSession->SetSharedRoutingPath (nullptr);
|
||||
path = nullptr;
|
||||
@@ -353,7 +417,14 @@ namespace datagram
|
||||
auto sz = ls.size();
|
||||
if (sz)
|
||||
{
|
||||
auto idx = rand() % sz;
|
||||
int idx = -1;
|
||||
if (m_LocalDestination)
|
||||
{
|
||||
auto pool = m_LocalDestination->GetTunnelPool ();
|
||||
if (pool)
|
||||
idx = pool->GetRng ()() % sz;
|
||||
}
|
||||
if (idx < 0) idx = rand () % sz;
|
||||
path->remoteLease = ls[idx];
|
||||
}
|
||||
else
|
||||
@@ -379,7 +450,14 @@ namespace datagram
|
||||
auto sz = ls.size();
|
||||
if (sz)
|
||||
{
|
||||
auto idx = rand() % sz;
|
||||
int idx = -1;
|
||||
if (m_LocalDestination)
|
||||
{
|
||||
auto pool = m_LocalDestination->GetTunnelPool ();
|
||||
if (pool)
|
||||
idx = pool->GetRng ()() % sz;
|
||||
}
|
||||
if (idx < 0) idx = rand () % sz;
|
||||
path->remoteLease = ls[idx];
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -43,6 +43,7 @@ namespace datagram
|
||||
const uint64_t DATAGRAM_SESSION_PATH_MIN_LIFETIME = 5 * 1000;
|
||||
// max 64 messages buffered in send queue for each datagram session
|
||||
const size_t DATAGRAM_SEND_QUEUE_MAX_SIZE = 64;
|
||||
const uint64_t DATAGRAM_MAX_FLUSH_INTERVAL = 5; // in milliseconds
|
||||
|
||||
class DatagramSession : public std::enable_shared_from_this<DatagramSession>
|
||||
{
|
||||
@@ -98,7 +99,7 @@ namespace datagram
|
||||
std::shared_ptr<i2p::garlic::GarlicRoutingSession> m_RoutingSession;
|
||||
std::vector<std::shared_ptr<i2p::garlic::GarlicRoutingSession> > m_PendingRoutingSessions;
|
||||
std::vector<std::shared_ptr<I2NPMessage> > m_SendQueue;
|
||||
uint64_t m_LastUse;
|
||||
uint64_t m_LastUse, m_LastFlush; // milliseconds
|
||||
bool m_RequestingLS;
|
||||
};
|
||||
|
||||
@@ -126,14 +127,12 @@ namespace datagram
|
||||
|
||||
void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw = false);
|
||||
|
||||
void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; };
|
||||
void ResetReceiver () { m_Receiver = nullptr; };
|
||||
|
||||
void SetReceiver (const Receiver& receiver, uint16_t port) { std::lock_guard<std::mutex> lock(m_ReceiversMutex); m_ReceiversByPorts[port] = receiver; };
|
||||
void ResetReceiver (uint16_t port) { std::lock_guard<std::mutex> lock(m_ReceiversMutex); m_ReceiversByPorts.erase (port); };
|
||||
void SetReceiver (const Receiver& receiver, uint16_t port);
|
||||
void ResetReceiver (uint16_t port);
|
||||
|
||||
void SetRawReceiver (const RawReceiver& receiver) { m_RawReceiver = receiver; };
|
||||
void ResetRawReceiver () { m_RawReceiver = nullptr; };
|
||||
void SetRawReceiver (const RawReceiver& receiver, uint16_t port);
|
||||
void ResetRawReceiver (uint16_t port);
|
||||
|
||||
std::shared_ptr<DatagramSession::Info> GetInfoForRemote(const i2p::data::IdentHash & remote);
|
||||
|
||||
@@ -150,20 +149,26 @@ namespace datagram
|
||||
void HandleDatagram (uint16_t fromPort, uint16_t toPort, uint8_t *const& buf, size_t len);
|
||||
void HandleRawDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
||||
|
||||
/** find a receiver by port, if none by port is found try default receiever, otherwise returns nullptr */
|
||||
Receiver FindReceiver(uint16_t port);
|
||||
RawReceiver FindRawReceiver(uint16_t port);
|
||||
|
||||
private:
|
||||
|
||||
std::shared_ptr<i2p::client::ClientDestination> m_Owner;
|
||||
Receiver m_Receiver; // default
|
||||
RawReceiver m_RawReceiver; // default
|
||||
bool m_Gzip; // gzip compression of data messages
|
||||
|
||||
std::mutex m_SessionsMutex;
|
||||
std::map<i2p::data::IdentHash, DatagramSession_ptr > m_Sessions;
|
||||
std::mutex m_ReceiversMutex;
|
||||
std::map<uint16_t, Receiver> m_ReceiversByPorts;
|
||||
|
||||
Receiver m_DefaultReceiver;
|
||||
RawReceiver m_DefaultRawReceiver;
|
||||
uint16_t m_DefaultReceiverPort;
|
||||
uint16_t m_DefaultRawReceiverPort;
|
||||
std::mutex m_ReceiversMutex;
|
||||
std::mutex m_RawReceiversMutex;
|
||||
std::unordered_map<uint16_t, Receiver> m_ReceiversByPorts;
|
||||
std::unordered_map<uint16_t, RawReceiver> m_RawReceiversByPorts;
|
||||
|
||||
bool m_Gzip; // gzip compression of data messages
|
||||
i2p::data::GzipInflator m_Inflator;
|
||||
std::unique_ptr<i2p::data::GzipDeflator> m_Deflator;
|
||||
std::vector<uint8_t> m_From, m_Signature;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -23,7 +23,7 @@ namespace i2p
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
LeaseSetDestination::LeaseSetDestination (boost::asio::io_service& service,
|
||||
LeaseSetDestination::LeaseSetDestination (boost::asio::io_context& service,
|
||||
bool isPublic, const std::map<std::string, std::string> * params):
|
||||
m_Service (service), m_IsPublic (isPublic), m_PublishReplyToken (0),
|
||||
m_LastSubmissionTime (0), m_PublishConfirmationTimer (m_Service),
|
||||
@@ -37,6 +37,7 @@ namespace client
|
||||
int inVar = DEFAULT_INBOUND_TUNNELS_LENGTH_VARIANCE;
|
||||
int outVar = DEFAULT_OUTBOUND_TUNNELS_LENGTH_VARIANCE;
|
||||
int numTags = DEFAULT_TAGS_TO_SEND;
|
||||
bool isHighBandwidth = true;
|
||||
std::shared_ptr<std::vector<i2p::data::IdentHash> > explicitPeers;
|
||||
try
|
||||
{
|
||||
@@ -92,7 +93,7 @@ namespace client
|
||||
it = params->find (I2CP_PARAM_DONT_PUBLISH_LEASESET);
|
||||
if (it != params->end ())
|
||||
{
|
||||
// oveeride isPublic
|
||||
// override isPublic
|
||||
m_IsPublic = (it->second != "true");
|
||||
}
|
||||
it = params->find (I2CP_PARAM_LEASESET_TYPE);
|
||||
@@ -121,6 +122,9 @@ namespace client
|
||||
m_LeaseSetPrivKey.reset (nullptr);
|
||||
}
|
||||
}
|
||||
it = params->find (I2CP_PARAM_STREAMING_PROFILE);
|
||||
if (it != params->end ())
|
||||
isHighBandwidth = std::stoi (it->second) != STREAMING_PROFILE_INTERACTIVE;
|
||||
}
|
||||
}
|
||||
catch (std::exception & ex)
|
||||
@@ -128,7 +132,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, inVar, outVar);
|
||||
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (inLen, outLen, inQty, outQty, inVar, outVar, isHighBandwidth);
|
||||
if (explicitPeers)
|
||||
m_Pool->SetExplicitPeers (explicitPeers);
|
||||
if(params)
|
||||
@@ -164,7 +168,7 @@ namespace client
|
||||
LoadTags ();
|
||||
m_Pool->SetLocalDestination (shared_from_this ());
|
||||
m_Pool->SetActive (true);
|
||||
m_CleanupTimer.expires_from_now (boost::posix_time::minutes (DESTINATION_CLEANUP_TIMEOUT));
|
||||
m_CleanupTimer.expires_from_now (boost::posix_time::seconds (DESTINATION_CLEANUP_TIMEOUT));
|
||||
m_CleanupTimer.async_wait (std::bind (&LeaseSetDestination::HandleCleanupTimer,
|
||||
shared_from_this (), std::placeholders::_1));
|
||||
}
|
||||
@@ -290,7 +294,7 @@ namespace client
|
||||
if (m_IsPublic)
|
||||
{
|
||||
auto s = shared_from_this ();
|
||||
m_Service.post ([s](void)
|
||||
boost::asio::post (m_Service, [s](void)
|
||||
{
|
||||
s->m_PublishVerificationTimer.cancel ();
|
||||
s->Publish ();
|
||||
@@ -318,7 +322,7 @@ namespace client
|
||||
memcpy (data.k, key, 32);
|
||||
memcpy (data.t, tag, 32);
|
||||
auto s = shared_from_this ();
|
||||
m_Service.post ([s,data](void)
|
||||
boost::asio::post (m_Service, [s,data](void)
|
||||
{
|
||||
s->AddSessionKey (data.k, data.t);
|
||||
});
|
||||
@@ -335,7 +339,7 @@ namespace client
|
||||
memcpy (data.k, key, 32);
|
||||
data.t = tag;
|
||||
auto s = shared_from_this ();
|
||||
m_Service.post ([s,data](void)
|
||||
boost::asio::post (m_Service, [s,data](void)
|
||||
{
|
||||
s->AddECIESx25519Key (data.k, data.t);
|
||||
});
|
||||
@@ -343,13 +347,30 @@ namespace client
|
||||
|
||||
void LeaseSetDestination::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
m_Service.post (std::bind (&LeaseSetDestination::HandleGarlicMessage, shared_from_this (), msg));
|
||||
if (!msg) return;
|
||||
bool empty = false;
|
||||
{
|
||||
std::lock_guard<std::mutex> l(m_IncomingMsgsQueueMutex);
|
||||
empty = m_IncomingMsgsQueue.empty ();
|
||||
m_IncomingMsgsQueue.push_back (msg);
|
||||
}
|
||||
if (empty)
|
||||
boost::asio::post (m_Service, [s = shared_from_this ()]()
|
||||
{
|
||||
std::list<std::shared_ptr<I2NPMessage> > receivedMsgs;
|
||||
{
|
||||
std::lock_guard<std::mutex> l(s->m_IncomingMsgsQueueMutex);
|
||||
s->m_IncomingMsgsQueue.swap (receivedMsgs);
|
||||
}
|
||||
for (auto& it: receivedMsgs)
|
||||
s->HandleGarlicMessage (it);
|
||||
});
|
||||
}
|
||||
|
||||
void LeaseSetDestination::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
uint32_t msgID = bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET);
|
||||
m_Service.post (std::bind (&LeaseSetDestination::HandleDeliveryStatusMessage, shared_from_this (), msgID));
|
||||
boost::asio::post (m_Service, std::bind (&LeaseSetDestination::HandleDeliveryStatusMessage, shared_from_this (), msgID));
|
||||
}
|
||||
|
||||
void LeaseSetDestination::HandleI2NPMessage (const uint8_t * buf, size_t len)
|
||||
@@ -367,9 +388,12 @@ namespace client
|
||||
HandleDataMessage (payload, len);
|
||||
break;
|
||||
case eI2NPDeliveryStatus:
|
||||
// we assume tunnel tests non-encrypted
|
||||
HandleDeliveryStatusMessage (bufbe32toh (payload + DELIVERY_STATUS_MSGID_OFFSET));
|
||||
break;
|
||||
case eI2NPTunnelTest:
|
||||
if (m_Pool)
|
||||
m_Pool->ProcessTunnelTest (bufbe32toh (payload + TUNNEL_TEST_MSGID_OFFSET), bufbe64toh (payload + TUNNEL_TEST_TIMESTAMP_OFFSET));
|
||||
break;
|
||||
case eI2NPDatabaseStore:
|
||||
HandleDatabaseStoreMessage (payload, len);
|
||||
break;
|
||||
@@ -407,6 +431,7 @@ namespace client
|
||||
}
|
||||
i2p::data::IdentHash key (buf + DATABASE_STORE_KEY_OFFSET);
|
||||
std::shared_ptr<i2p::data::LeaseSet> leaseSet;
|
||||
std::shared_ptr<LeaseSetRequest> request;
|
||||
switch (buf[DATABASE_STORE_TYPE_OFFSET])
|
||||
{
|
||||
case i2p::data::NETDB_STORE_TYPE_LEASESET: // 1
|
||||
@@ -462,34 +487,59 @@ namespace client
|
||||
case i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2: // 5
|
||||
{
|
||||
auto it2 = m_LeaseSetRequests.find (key);
|
||||
if (it2 != m_LeaseSetRequests.end () && it2->second->requestedBlindedKey)
|
||||
if (it2 != m_LeaseSetRequests.end ())
|
||||
{
|
||||
auto ls2 = std::make_shared<i2p::data::LeaseSet2> (buf + offset, len - offset,
|
||||
it2->second->requestedBlindedKey, m_LeaseSetPrivKey ? ((const uint8_t *)*m_LeaseSetPrivKey) : nullptr , GetPreferredCryptoType ());
|
||||
if (ls2->IsValid () && !ls2->IsExpired ())
|
||||
request = it2->second;
|
||||
m_LeaseSetRequests.erase (it2);
|
||||
if (request->requestedBlindedKey)
|
||||
{
|
||||
leaseSet = ls2;
|
||||
std::lock_guard<std::mutex> lock(m_RemoteLeaseSetsMutex);
|
||||
m_RemoteLeaseSets[ls2->GetIdentHash ()] = ls2; // ident is not key
|
||||
m_RemoteLeaseSets[key] = ls2; // also store as key for next lookup
|
||||
auto ls2 = std::make_shared<i2p::data::LeaseSet2> (buf + offset, len - offset,
|
||||
request->requestedBlindedKey, m_LeaseSetPrivKey ? ((const uint8_t *)*m_LeaseSetPrivKey) : nullptr , GetPreferredCryptoType ());
|
||||
if (ls2->IsValid () && !ls2->IsExpired ())
|
||||
{
|
||||
leaseSet = ls2;
|
||||
std::lock_guard<std::mutex> lock(m_RemoteLeaseSetsMutex);
|
||||
m_RemoteLeaseSets[ls2->GetIdentHash ()] = ls2; // ident is not key
|
||||
m_RemoteLeaseSets[key] = ls2; // also store as key for next lookup
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Destination: New remote encrypted LeaseSet2 failed");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Destination: New remote encrypted LeaseSet2 failed");
|
||||
{
|
||||
// publishing verification doesn't have requestedBlindedKey
|
||||
auto localLeaseSet = GetLeaseSetMt ();
|
||||
if (localLeaseSet->GetStoreHash () == key)
|
||||
{
|
||||
auto ls = std::make_shared<i2p::data::LeaseSet2> (i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2,
|
||||
localLeaseSet->GetBuffer (), localLeaseSet->GetBufferLen (), false);
|
||||
leaseSet = ls;
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Destination: Encrypted LeaseSet2 received for request without blinded key");
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogInfo, "Destination: Couldn't find request for encrypted LeaseSet2");
|
||||
LogPrint (eLogWarning, "Destination: Couldn't find request for encrypted LeaseSet2");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LogPrint (eLogError, "Destination: Unexpected client's DatabaseStore type ", buf[DATABASE_STORE_TYPE_OFFSET], ", dropped");
|
||||
}
|
||||
|
||||
auto it1 = m_LeaseSetRequests.find (key);
|
||||
if (it1 != m_LeaseSetRequests.end ())
|
||||
if (!request)
|
||||
{
|
||||
it1->second->requestTimeoutTimer.cancel ();
|
||||
if (it1->second) it1->second->Complete (leaseSet);
|
||||
m_LeaseSetRequests.erase (it1);
|
||||
auto it1 = m_LeaseSetRequests.find (key);
|
||||
if (it1 != m_LeaseSetRequests.end ())
|
||||
{
|
||||
request = it1->second;
|
||||
m_LeaseSetRequests.erase (it1);
|
||||
}
|
||||
}
|
||||
if (request)
|
||||
{
|
||||
request->requestTimeoutTimer.cancel ();
|
||||
request->Complete (leaseSet);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -502,38 +552,43 @@ namespace client
|
||||
if (it != m_LeaseSetRequests.end ())
|
||||
{
|
||||
auto request = it->second;
|
||||
bool found = false;
|
||||
if (request->excluded.size () < MAX_NUM_FLOODFILLS_PER_REQUEST)
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
for (int i = 0; i < num; i++)
|
||||
i2p::data::IdentHash peerHash (buf + 33 + i*32);
|
||||
if (!request->excluded.count (peerHash) && !i2p::data::netdb.FindRouter (peerHash))
|
||||
{
|
||||
i2p::data::IdentHash peerHash (buf + 33 + i*32);
|
||||
if (!request->excluded.count (peerHash) && !i2p::data::netdb.FindRouter (peerHash))
|
||||
{
|
||||
LogPrint (eLogInfo, "Destination: Found new floodfill, request it");
|
||||
i2p::data::netdb.RequestDestination (peerHash, nullptr, false); // through exploratory
|
||||
}
|
||||
}
|
||||
|
||||
auto floodfill = i2p::data::netdb.GetClosestFloodfill (key, request->excluded);
|
||||
if (floodfill)
|
||||
{
|
||||
LogPrint (eLogInfo, "Destination: Requesting ", key.ToBase64 (), " at ", floodfill->GetIdentHash ().ToBase64 ());
|
||||
if (SendLeaseSetRequest (key, floodfill, request))
|
||||
found = true;
|
||||
LogPrint (eLogInfo, "Destination: Found new floodfill, request it");
|
||||
i2p::data::netdb.RequestDestination (peerHash, nullptr, false); // through exploratory
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
LogPrint (eLogInfo, "Destination: ", key.ToBase64 (), " was not found on ", MAX_NUM_FLOODFILLS_PER_REQUEST, " floodfills");
|
||||
request->Complete (nullptr);
|
||||
m_LeaseSetRequests.erase (key);
|
||||
}
|
||||
SendNextLeaseSetRequest (key, request);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Destination: Request for ", key.ToBase64 (), " not found");
|
||||
}
|
||||
|
||||
void LeaseSetDestination::SendNextLeaseSetRequest (const i2p::data::IdentHash& key,
|
||||
std::shared_ptr<LeaseSetRequest> request)
|
||||
{
|
||||
bool found = false;
|
||||
if (request->excluded.size () < MAX_NUM_FLOODFILLS_PER_REQUEST)
|
||||
{
|
||||
auto floodfill = i2p::data::netdb.GetClosestFloodfill (key, request->excluded);
|
||||
if (floodfill)
|
||||
{
|
||||
LogPrint (eLogInfo, "Destination: Requesting ", key.ToBase64 (), " at ", floodfill->GetIdentHash ().ToBase64 ());
|
||||
if (SendLeaseSetRequest (key, floodfill, request))
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
LogPrint (eLogInfo, "Destination: ", key.ToBase64 (), " was not found on ", MAX_NUM_FLOODFILLS_PER_REQUEST, " floodfills");
|
||||
request->Complete (nullptr);
|
||||
m_LeaseSetRequests.erase (key);
|
||||
}
|
||||
}
|
||||
|
||||
void LeaseSetDestination::HandleDeliveryStatusMessage (uint32_t msgID)
|
||||
{
|
||||
if (msgID == m_PublishReplyToken)
|
||||
@@ -550,9 +605,12 @@ namespace client
|
||||
i2p::garlic::GarlicDestination::HandleDeliveryStatusMessage (msgID);
|
||||
}
|
||||
|
||||
void LeaseSetDestination::SetLeaseSetUpdated ()
|
||||
void LeaseSetDestination::SetLeaseSetUpdated (bool post)
|
||||
{
|
||||
UpdateLeaseSet ();
|
||||
if (post)
|
||||
boost::asio::post (m_Service, [s = shared_from_this ()]() { s->UpdateLeaseSet (); });
|
||||
else
|
||||
UpdateLeaseSet ();
|
||||
}
|
||||
|
||||
void LeaseSetDestination::Publish ()
|
||||
@@ -578,12 +636,7 @@ namespace client
|
||||
shared_from_this (), std::placeholders::_1));
|
||||
return;
|
||||
}
|
||||
if (!m_Pool->GetInboundTunnels ().size () || !m_Pool->GetOutboundTunnels ().size ())
|
||||
{
|
||||
LogPrint (eLogError, "Destination: Can't publish LeaseSet. Destination is not ready");
|
||||
return;
|
||||
}
|
||||
auto floodfill = i2p::data::netdb.GetClosestFloodfill (leaseSet->GetIdentHash (), m_ExcludedFloodfills);
|
||||
auto floodfill = i2p::data::netdb.GetClosestFloodfill (leaseSet->GetStoreHash (), m_ExcludedFloodfills);
|
||||
if (!floodfill)
|
||||
{
|
||||
LogPrint (eLogError, "Destination: Can't publish LeaseSet, no more floodfills found");
|
||||
@@ -594,26 +647,39 @@ namespace client
|
||||
auto inbound = m_Pool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true));
|
||||
if (!outbound || !inbound)
|
||||
{
|
||||
LogPrint (eLogInfo, "Destination: No compatible tunnels with ", floodfill->GetIdentHash ().ToBase64 (), ". Trying another floodfill");
|
||||
m_ExcludedFloodfills.insert (floodfill->GetIdentHash ());
|
||||
floodfill = i2p::data::netdb.GetClosestFloodfill (leaseSet->GetIdentHash (), m_ExcludedFloodfills);
|
||||
if (floodfill)
|
||||
if (!m_Pool->GetInboundTunnels ().empty () && !m_Pool->GetOutboundTunnels ().empty ())
|
||||
{
|
||||
outbound = m_Pool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false));
|
||||
if (outbound)
|
||||
LogPrint (eLogInfo, "Destination: No compatible tunnels with ", floodfill->GetIdentHash ().ToBase64 (), ". Trying another floodfill");
|
||||
m_ExcludedFloodfills.insert (floodfill->GetIdentHash ());
|
||||
floodfill = i2p::data::netdb.GetClosestFloodfill (leaseSet->GetStoreHash (), m_ExcludedFloodfills);
|
||||
if (floodfill)
|
||||
{
|
||||
inbound = m_Pool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true));
|
||||
if (!inbound)
|
||||
LogPrint (eLogError, "Destination: Can't publish LeaseSet. No inbound tunnels");
|
||||
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 outbound tunnels");
|
||||
LogPrint (eLogError, "Destination: Can't publish LeaseSet, no more floodfills found");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Destination: Can't publish LeaseSet, no more floodfills found");
|
||||
LogPrint (eLogDebug, "Destination: No tunnels in pool");
|
||||
|
||||
if (!floodfill || !outbound || !inbound)
|
||||
{
|
||||
// we can't publish now
|
||||
m_ExcludedFloodfills.clear ();
|
||||
m_PublishReplyToken = 1; // dummy non-zero value
|
||||
// try again after a while
|
||||
LogPrint (eLogInfo, "Destination: Can't publish LeasetSet because destination is not ready. Try publishing again after ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds");
|
||||
m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT));
|
||||
m_PublishConfirmationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishConfirmationTimer,
|
||||
shared_from_this (), std::placeholders::_1));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -621,6 +687,15 @@ namespace client
|
||||
LogPrint (eLogDebug, "Destination: Publish LeaseSet of ", GetIdentHash ().ToBase32 ());
|
||||
RAND_bytes ((uint8_t *)&m_PublishReplyToken, 4);
|
||||
auto msg = WrapMessageForRouter (floodfill, i2p::CreateDatabaseStoreMsg (leaseSet, m_PublishReplyToken, inbound));
|
||||
auto s = shared_from_this ();
|
||||
msg->onDrop = [s]()
|
||||
{
|
||||
boost::asio::post (s->GetService (), [s]()
|
||||
{
|
||||
s->m_PublishConfirmationTimer.cancel ();
|
||||
s->HandlePublishConfirmationTimer (boost::system::error_code());
|
||||
});
|
||||
};
|
||||
m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT));
|
||||
m_PublishConfirmationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishConfirmationTimer,
|
||||
shared_from_this (), std::placeholders::_1));
|
||||
@@ -637,7 +712,7 @@ namespace client
|
||||
m_PublishReplyToken = 0;
|
||||
if (GetIdentity ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ELGAMAL)
|
||||
{
|
||||
LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds, will try again");
|
||||
LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds or failed. will try again");
|
||||
Publish ();
|
||||
}
|
||||
else
|
||||
@@ -700,10 +775,10 @@ namespace client
|
||||
if (!m_Pool || !IsReady ())
|
||||
{
|
||||
if (requestComplete)
|
||||
m_Service.post ([requestComplete](void){requestComplete (nullptr);});
|
||||
boost::asio::post (m_Service, [requestComplete](void){requestComplete (nullptr);});
|
||||
return false;
|
||||
}
|
||||
m_Service.post (std::bind (&LeaseSetDestination::RequestLeaseSet, shared_from_this (), dest, requestComplete, nullptr));
|
||||
boost::asio::post (m_Service, std::bind (&LeaseSetDestination::RequestLeaseSet, shared_from_this (), dest, requestComplete, nullptr));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -712,7 +787,7 @@ namespace client
|
||||
if (!dest || !m_Pool || !IsReady ())
|
||||
{
|
||||
if (requestComplete)
|
||||
m_Service.post ([requestComplete](void){requestComplete (nullptr);});
|
||||
boost::asio::post (m_Service, [requestComplete](void){requestComplete (nullptr);});
|
||||
return false;
|
||||
}
|
||||
auto storeHash = dest->GetStoreHash ();
|
||||
@@ -720,17 +795,17 @@ namespace client
|
||||
if (leaseSet)
|
||||
{
|
||||
if (requestComplete)
|
||||
m_Service.post ([requestComplete, leaseSet](void){requestComplete (leaseSet);});
|
||||
boost::asio::post (m_Service, [requestComplete, leaseSet](void){requestComplete (leaseSet);});
|
||||
return true;
|
||||
}
|
||||
m_Service.post (std::bind (&LeaseSetDestination::RequestLeaseSet, shared_from_this (), storeHash, requestComplete, dest));
|
||||
boost::asio::post (m_Service, std::bind (&LeaseSetDestination::RequestLeaseSet, shared_from_this (), storeHash, requestComplete, dest));
|
||||
return true;
|
||||
}
|
||||
|
||||
void LeaseSetDestination::CancelDestinationRequest (const i2p::data::IdentHash& dest, bool notify)
|
||||
{
|
||||
auto s = shared_from_this ();
|
||||
m_Service.post ([dest, notify, s](void)
|
||||
boost::asio::post (m_Service, [dest, notify, s](void)
|
||||
{
|
||||
auto it = s->m_LeaseSetRequests.find (dest);
|
||||
if (it != s->m_LeaseSetRequests.end ())
|
||||
@@ -750,7 +825,7 @@ namespace client
|
||||
|
||||
void LeaseSetDestination::RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> requestedBlindedKey)
|
||||
{
|
||||
std::set<i2p::data::IdentHash> excluded;
|
||||
std::unordered_set<i2p::data::IdentHash> excluded;
|
||||
auto floodfill = i2p::data::netdb.GetClosestFloodfill (dest, excluded);
|
||||
if (floodfill)
|
||||
{
|
||||
@@ -822,8 +897,17 @@ namespace client
|
||||
AddECIESx25519Key (replyKey, replyTag);
|
||||
else
|
||||
AddSessionKey (replyKey, replyTag);
|
||||
auto msg = WrapMessageForRouter (nextFloodfill, CreateLeaseSetDatabaseLookupMsg (dest,
|
||||
request->excluded, request->replyTunnel, replyKey, replyTag, isECIES));
|
||||
|
||||
auto msg = WrapMessageForRouter (nextFloodfill,
|
||||
CreateLeaseSetDatabaseLookupMsg (dest, request->excluded, request->replyTunnel, replyKey, replyTag, isECIES));
|
||||
auto s = shared_from_this ();
|
||||
msg->onDrop = [s, dest, request]()
|
||||
{
|
||||
boost::asio::post (s->GetService (), [s, dest, request]()
|
||||
{
|
||||
s->SendNextLeaseSetRequest (dest, request);
|
||||
});
|
||||
};
|
||||
request->outboundTunnel->SendTunnelDataMsgs (
|
||||
{
|
||||
i2p::tunnel::TunnelMessageBlock
|
||||
@@ -886,7 +970,8 @@ namespace client
|
||||
CleanupExpiredTags ();
|
||||
CleanupRemoteLeaseSets ();
|
||||
CleanupDestination ();
|
||||
m_CleanupTimer.expires_from_now (boost::posix_time::minutes (DESTINATION_CLEANUP_TIMEOUT));
|
||||
m_CleanupTimer.expires_from_now (boost::posix_time::seconds (DESTINATION_CLEANUP_TIMEOUT +
|
||||
(m_Pool ? m_Pool->GetRng ()() % DESTINATION_CLEANUP_TIMEOUT_VARIANCE : 0)));
|
||||
m_CleanupTimer.async_wait (std::bind (&LeaseSetDestination::HandleCleanupTimer,
|
||||
shared_from_this (), std::placeholders::_1));
|
||||
}
|
||||
@@ -900,7 +985,7 @@ namespace client
|
||||
{
|
||||
if (it->second->IsEmpty () || ts > it->second->GetExpirationTime ()) // leaseset expired
|
||||
{
|
||||
LogPrint (eLogWarning, "Destination: Remote LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired");
|
||||
LogPrint (eLogDebug, "Destination: Remote LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired");
|
||||
it = m_RemoteLeaseSets.erase (it);
|
||||
}
|
||||
else
|
||||
@@ -915,12 +1000,15 @@ namespace client
|
||||
return i2p::data::CRYPTO_KEY_TYPE_ELGAMAL;
|
||||
}
|
||||
|
||||
ClientDestination::ClientDestination (boost::asio::io_service& service, const i2p::data::PrivateKeys& keys,
|
||||
ClientDestination::ClientDestination (boost::asio::io_context& service, const i2p::data::PrivateKeys& keys,
|
||||
bool isPublic, const std::map<std::string, std::string> * params):
|
||||
LeaseSetDestination (service, isPublic, params),
|
||||
m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY),
|
||||
m_StreamingOutboundSpeed (DEFAULT_MAX_OUTBOUND_SPEED),
|
||||
m_StreamingInboundSpeed (DEFAULT_MAX_INBOUND_SPEED),
|
||||
m_StreamingMaxConcurrentStreams (DEFAULT_MAX_CONCURRENT_STREAMS),
|
||||
m_IsStreamingAnswerPings (DEFAULT_ANSWER_PINGS), m_LastPort (0),
|
||||
m_DatagramDestination (nullptr), m_RefCounter (0),
|
||||
m_DatagramDestination (nullptr), m_RefCounter (0), m_LastPublishedTimestamp (0),
|
||||
m_ReadyChecker(service)
|
||||
{
|
||||
if (keys.IsOfflineSignature () && GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET)
|
||||
@@ -951,18 +1039,15 @@ namespace client
|
||||
}
|
||||
}
|
||||
// if no param or valid crypto type use from identity
|
||||
bool isSingleKey = false;
|
||||
if (encryptionKeyTypes.empty ())
|
||||
{
|
||||
isSingleKey = true;
|
||||
encryptionKeyTypes.insert (GetIdentity ()->GetCryptoKeyType ());
|
||||
}
|
||||
encryptionKeyTypes.insert ( { GetIdentity ()->GetCryptoKeyType (),
|
||||
i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD }); // usually 0,4
|
||||
|
||||
for (auto& it: encryptionKeyTypes)
|
||||
{
|
||||
auto encryptionKey = new EncryptionKey (it);
|
||||
if (IsPublic ())
|
||||
PersistTemporaryKeys (encryptionKey, isSingleKey);
|
||||
PersistTemporaryKeys (encryptionKey);
|
||||
else
|
||||
encryptionKey->GenerateKeys ();
|
||||
encryptionKey->CreateDecryptor ();
|
||||
@@ -987,6 +1072,14 @@ namespace client
|
||||
auto it = params->find (I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY);
|
||||
if (it != params->end ())
|
||||
m_StreamingAckDelay = std::stoi(it->second);
|
||||
it = params->find (I2CP_PARAM_STREAMING_MAX_OUTBOUND_SPEED);
|
||||
if (it != params->end ())
|
||||
m_StreamingOutboundSpeed = std::stoi(it->second);
|
||||
it = params->find (I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED);
|
||||
if (it != params->end ())
|
||||
m_StreamingInboundSpeed = std::stoi(it->second);
|
||||
if (it != params->end ())
|
||||
m_StreamingMaxConcurrentStreams = std::stoi(it->second);
|
||||
it = params->find (I2CP_PARAM_STREAMING_ANSWER_PINGS);
|
||||
if (it != params->end ())
|
||||
m_IsStreamingAnswerPings = std::stoi (it->second); // 1 for true
|
||||
@@ -1037,7 +1130,6 @@ namespace client
|
||||
void ClientDestination::Stop ()
|
||||
{
|
||||
LogPrint(eLogDebug, "Destination: Stopping destination ", GetIdentHash().ToBase32(), ".b32.i2p");
|
||||
LeaseSetDestination::Stop ();
|
||||
m_ReadyChecker.cancel();
|
||||
LogPrint(eLogDebug, "Destination: -> Stopping Streaming Destination");
|
||||
m_StreamingDestination->Stop ();
|
||||
@@ -1059,6 +1151,7 @@ namespace client
|
||||
delete m_DatagramDestination;
|
||||
m_DatagramDestination = nullptr;
|
||||
}
|
||||
LeaseSetDestination::Stop ();
|
||||
LogPrint(eLogDebug, "Destination: -> Stopping done");
|
||||
}
|
||||
|
||||
@@ -1122,7 +1215,7 @@ namespace client
|
||||
if (leaseSet)
|
||||
{
|
||||
auto stream = CreateStream (leaseSet, port);
|
||||
GetService ().post ([streamRequestComplete, stream]()
|
||||
boost::asio::post (GetService (), [streamRequestComplete, stream]()
|
||||
{
|
||||
streamRequestComplete(stream);
|
||||
});
|
||||
@@ -1315,12 +1408,11 @@ namespace client
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ClientDestination::PersistTemporaryKeys (EncryptionKey * keys, bool isSingleKey)
|
||||
void ClientDestination::PersistTemporaryKeys (EncryptionKey * keys)
|
||||
{
|
||||
if (!keys) return;
|
||||
std::string ident = GetIdentHash().ToBase32();
|
||||
std::string path = i2p::fs::DataDirPath("destinations",
|
||||
isSingleKey ? (ident + ".dat") : (ident + "." + std::to_string (keys->keyType) + ".dat"));
|
||||
std::string path = i2p::fs::DataDirPath("destinations", ident + "." + std::to_string (keys->keyType) + ".dat");
|
||||
std::ifstream f(path, std::ifstream::binary);
|
||||
|
||||
if (f) {
|
||||
@@ -1366,12 +1458,19 @@ namespace client
|
||||
if (m_StandardEncryptionKey)
|
||||
keySections.push_back ({m_StandardEncryptionKey->keyType, (uint16_t)m_StandardEncryptionKey->decryptor->GetPublicKeyLen (), m_StandardEncryptionKey->pub} );
|
||||
|
||||
auto publishedTimestamp = i2p::util::GetSecondsSinceEpoch ();
|
||||
if (publishedTimestamp <= m_LastPublishedTimestamp)
|
||||
{
|
||||
LogPrint (eLogDebug, "Destination: LeaseSet update at the same second");
|
||||
publishedTimestamp++; // force newer timestamp
|
||||
}
|
||||
bool isPublishedEncrypted = GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2;
|
||||
auto ls2 = std::make_shared<i2p::data::LocalLeaseSet2> (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2,
|
||||
m_Keys, keySections, tunnels, IsPublic (), isPublishedEncrypted);
|
||||
m_Keys, keySections, tunnels, IsPublic (), publishedTimestamp, isPublishedEncrypted);
|
||||
if (isPublishedEncrypted) // encrypt if type 5
|
||||
ls2 = std::make_shared<i2p::data::LocalEncryptedLeaseSet2> (ls2, m_Keys, GetAuthType (), m_AuthKeys);
|
||||
leaseSet = ls2;
|
||||
m_LastPublishedTimestamp = publishedTimestamp;
|
||||
}
|
||||
SetLeaseSet (leaseSet);
|
||||
}
|
||||
@@ -1436,6 +1535,8 @@ namespace client
|
||||
RunnableService ("Destination"),
|
||||
ClientDestination (GetIOService (), keys, isPublic, params)
|
||||
{
|
||||
if (!GetNickname ().empty ())
|
||||
RunnableService::SetName (GetNickname ());
|
||||
}
|
||||
|
||||
RunnableClientDestination::~RunnableClientDestination ()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -15,7 +15,7 @@
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <boost/asio.hpp>
|
||||
@@ -42,7 +42,8 @@ namespace client
|
||||
const int PUBLISH_REGULAR_VERIFICATION_INTERNAL = 100; // in seconds periodically
|
||||
const int LEASESET_REQUEST_TIMEOUT = 5; // in seconds
|
||||
const int MAX_LEASESET_REQUEST_TIMEOUT = 40; // in seconds
|
||||
const int DESTINATION_CLEANUP_TIMEOUT = 3; // in minutes
|
||||
const int DESTINATION_CLEANUP_TIMEOUT = 44; // in seconds
|
||||
const int DESTINATION_CLEANUP_TIMEOUT_VARIANCE = 30; // in seconds
|
||||
const unsigned int MAX_NUM_FLOODFILLS_PER_REQUEST = 7;
|
||||
|
||||
// I2CP
|
||||
@@ -84,9 +85,19 @@ namespace client
|
||||
// streaming
|
||||
const char I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY[] = "i2p.streaming.initialAckDelay";
|
||||
const int DEFAULT_INITIAL_ACK_DELAY = 200; // milliseconds
|
||||
const char I2CP_PARAM_STREAMING_MAX_OUTBOUND_SPEED[] = "i2p.streaming.maxOutboundSpeed"; // bytes/sec
|
||||
const int DEFAULT_MAX_OUTBOUND_SPEED = 1730000000; // no more than 1.73 Gbytes/s
|
||||
const char I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED[] = "i2p.streaming.maxInboundSpeed"; // bytes/sec
|
||||
const int DEFAULT_MAX_INBOUND_SPEED = 1730000000; // no more than 1.73 Gbytes/s
|
||||
const char I2CP_PARAM_STREAMING_ANSWER_PINGS[] = "i2p.streaming.answerPings";
|
||||
const int DEFAULT_ANSWER_PINGS = true;
|
||||
|
||||
const char I2CP_PARAM_STREAMING_PROFILE[] = "i2p.streaming.profile";
|
||||
const int STREAMING_PROFILE_BULK = 1; // high bandwidth
|
||||
const int STREAMING_PROFILE_INTERACTIVE = 2; // low bandwidth
|
||||
const int DEFAULT_STREAMING_PROFILE = STREAMING_PROFILE_BULK;
|
||||
const char I2CP_PARAM_STREAMING_MAX_CONCURRENT_STREAMS[] = "i2p.streaming.maxConcurrentStreams";
|
||||
const int DEFAULT_MAX_CONCURRENT_STREAMS = 2048;
|
||||
|
||||
typedef std::function<void (std::shared_ptr<i2p::stream::Stream> stream)> StreamRequestComplete;
|
||||
|
||||
class LeaseSetDestination: public i2p::garlic::GarlicDestination,
|
||||
@@ -96,8 +107,8 @@ namespace client
|
||||
// leaseSet = nullptr means not found
|
||||
struct LeaseSetRequest
|
||||
{
|
||||
LeaseSetRequest (boost::asio::io_service& service): requestTime (0), requestTimeoutTimer (service) {};
|
||||
std::set<i2p::data::IdentHash> excluded;
|
||||
LeaseSetRequest (boost::asio::io_context& service): requestTime (0), requestTimeoutTimer (service) {};
|
||||
std::unordered_set<i2p::data::IdentHash> excluded;
|
||||
uint64_t requestTime;
|
||||
boost::asio::deadline_timer requestTimeoutTimer;
|
||||
std::list<RequestComplete> requestComplete;
|
||||
@@ -114,10 +125,10 @@ namespace client
|
||||
|
||||
public:
|
||||
|
||||
LeaseSetDestination (boost::asio::io_service& service, bool isPublic, const std::map<std::string, std::string> * params = nullptr);
|
||||
LeaseSetDestination (boost::asio::io_context& service, bool isPublic, const std::map<std::string, std::string> * params = nullptr);
|
||||
~LeaseSetDestination ();
|
||||
const std::string& GetNickname () const { return m_Nickname; };
|
||||
boost::asio::io_service& GetService () { return m_Service; };
|
||||
auto& GetService () { return m_Service; };
|
||||
|
||||
virtual void Start ();
|
||||
virtual void Stop ();
|
||||
@@ -134,15 +145,15 @@ namespace client
|
||||
void CancelDestinationRequestWithEncryptedLeaseSet (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, bool notify = true);
|
||||
|
||||
// implements GarlicDestination
|
||||
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet ();
|
||||
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const { return m_Pool; }
|
||||
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet () override;
|
||||
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const override { return m_Pool; }
|
||||
|
||||
// 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 ();
|
||||
bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag) override;
|
||||
void SubmitECIESx25519Key (const uint8_t * key, uint64_t tag) override;
|
||||
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg) override;
|
||||
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg) override;
|
||||
void SetLeaseSetUpdated (bool post) override;
|
||||
|
||||
bool IsPublic () const { return m_IsPublic; };
|
||||
void SetPublic (bool pub) { m_IsPublic = pub; };
|
||||
@@ -150,8 +161,8 @@ namespace client
|
||||
protected:
|
||||
|
||||
// implements GarlicDestination
|
||||
void HandleI2NPMessage (const uint8_t * buf, size_t len);
|
||||
bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len, uint32_t msgID);
|
||||
void HandleI2NPMessage (const uint8_t * buf, size_t len) override;
|
||||
bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len, uint32_t msgID) override;
|
||||
|
||||
void SetLeaseSet (std::shared_ptr<const i2p::data::LocalLeaseSet> newLeaseSet);
|
||||
int GetLeaseSetType () const { return m_LeaseSetType; };
|
||||
@@ -176,6 +187,7 @@ namespace client
|
||||
|
||||
void RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> requestedBlindedKey = nullptr);
|
||||
bool SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request);
|
||||
void SendNextLeaseSetRequest (const i2p::data::IdentHash& key, std::shared_ptr<LeaseSetRequest> request);
|
||||
void HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest);
|
||||
void HandleCleanupTimer (const boost::system::error_code& ecode);
|
||||
void CleanupRemoteLeaseSets ();
|
||||
@@ -183,18 +195,21 @@ namespace client
|
||||
|
||||
private:
|
||||
|
||||
boost::asio::io_service& m_Service;
|
||||
boost::asio::io_context& m_Service;
|
||||
mutable std::mutex m_RemoteLeaseSetsMutex;
|
||||
std::unordered_map<i2p::data::IdentHash, std::shared_ptr<i2p::data::LeaseSet> > m_RemoteLeaseSets;
|
||||
std::unordered_map<i2p::data::IdentHash, std::shared_ptr<LeaseSetRequest> > m_LeaseSetRequests;
|
||||
|
||||
std::list<std::shared_ptr<I2NPMessage> > m_IncomingMsgsQueue;
|
||||
mutable std::mutex m_IncomingMsgsQueueMutex;
|
||||
|
||||
std::shared_ptr<i2p::tunnel::TunnelPool> m_Pool;
|
||||
std::mutex m_LeaseSetMutex;
|
||||
std::shared_ptr<const i2p::data::LocalLeaseSet> m_LeaseSet;
|
||||
bool m_IsPublic;
|
||||
uint32_t m_PublishReplyToken;
|
||||
uint64_t m_LastSubmissionTime; // in seconds
|
||||
std::set<i2p::data::IdentHash> m_ExcludedFloodfills; // for publishing
|
||||
std::unordered_set<i2p::data::IdentHash> m_ExcludedFloodfills; // for publishing
|
||||
|
||||
boost::asio::deadline_timer m_PublishConfirmationTimer, m_PublishVerificationTimer,
|
||||
m_PublishDelayTimer, m_CleanupTimer;
|
||||
@@ -226,7 +241,7 @@ namespace client
|
||||
|
||||
public:
|
||||
|
||||
ClientDestination (boost::asio::io_service& service, const i2p::data::PrivateKeys& keys,
|
||||
ClientDestination (boost::asio::io_context& service, const i2p::data::PrivateKeys& keys,
|
||||
bool isPublic, const std::map<std::string, std::string> * params = nullptr);
|
||||
~ClientDestination ();
|
||||
|
||||
@@ -258,6 +273,9 @@ namespace client
|
||||
bool IsAcceptingStreams () const;
|
||||
void AcceptOnce (const i2p::stream::StreamingDestination::Acceptor& acceptor);
|
||||
int GetStreamingAckDelay () const { return m_StreamingAckDelay; }
|
||||
int GetStreamingOutboundSpeed () const { return m_StreamingOutboundSpeed; }
|
||||
int GetStreamingInboundSpeed () const { return m_StreamingInboundSpeed; }
|
||||
int GetStreamingMaxConcurrentStreams () const { return m_StreamingMaxConcurrentStreams; }
|
||||
bool IsStreamingAnswerPings () const { return m_IsStreamingAnswerPings; }
|
||||
|
||||
// datagram
|
||||
@@ -282,7 +300,7 @@ namespace client
|
||||
std::shared_ptr<ClientDestination> GetSharedFromThis () {
|
||||
return std::static_pointer_cast<ClientDestination>(shared_from_this ());
|
||||
}
|
||||
void PersistTemporaryKeys (EncryptionKey * keys, bool isSingleKey);
|
||||
void PersistTemporaryKeys (EncryptionKey * keys);
|
||||
void ReadAuthKey (const std::string& group, const std::map<std::string, std::string> * params);
|
||||
|
||||
template<typename Dest>
|
||||
@@ -294,13 +312,14 @@ namespace client
|
||||
std::unique_ptr<EncryptionKey> m_StandardEncryptionKey;
|
||||
std::unique_ptr<EncryptionKey> m_ECIESx25519EncryptionKey;
|
||||
|
||||
int m_StreamingAckDelay;
|
||||
int m_StreamingAckDelay,m_StreamingOutboundSpeed, m_StreamingInboundSpeed, m_StreamingMaxConcurrentStreams;
|
||||
bool m_IsStreamingAnswerPings;
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> m_StreamingDestination; // default
|
||||
std::map<uint16_t, std::shared_ptr<i2p::stream::StreamingDestination> > m_StreamingDestinationsByPorts;
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> m_LastStreamingDestination; uint16_t m_LastPort; // for server tunnels
|
||||
i2p::datagram::DatagramDestination * m_DatagramDestination;
|
||||
int m_RefCounter; // how many clients(tunnels) use this destination
|
||||
uint64_t m_LastPublishedTimestamp;
|
||||
|
||||
boost::asio::deadline_timer m_ReadyChecker;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -117,6 +117,12 @@ namespace garlic
|
||||
return session->HandleNextMessage (buf, len, shared_from_this (), index);
|
||||
}
|
||||
|
||||
bool ReceiveRatchetTagSet::IsSessionTerminated () const
|
||||
{
|
||||
return !m_Session || m_Session->IsTerminated ();
|
||||
}
|
||||
|
||||
|
||||
SymmetricKeyTagSet::SymmetricKeyTagSet (GarlicDestination * destination, const uint8_t * key):
|
||||
ReceiveRatchetTagSet (nullptr), m_Destination (destination)
|
||||
{
|
||||
@@ -223,6 +229,29 @@ namespace garlic
|
||||
tagsetNsr->NextSessionTagRatchet ();
|
||||
}
|
||||
|
||||
bool ECIESX25519AEADRatchetSession::MessageConfirmed (uint32_t msgID)
|
||||
{
|
||||
auto ret = GarlicRoutingSession::MessageConfirmed (msgID); // LeaseSet
|
||||
if (m_AckRequestMsgID && m_AckRequestMsgID == msgID)
|
||||
{
|
||||
m_AckRequestMsgID = 0;
|
||||
m_AckRequestNumAttempts = 0;
|
||||
ret = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ECIESX25519AEADRatchetSession::CleanupUnconfirmedTags ()
|
||||
{
|
||||
if (m_AckRequestMsgID && m_AckRequestNumAttempts > ECIESX25519_ACK_REQUEST_MAX_NUM_ATTEMPTS)
|
||||
{
|
||||
m_AckRequestMsgID = 0;
|
||||
m_AckRequestNumAttempts = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ECIESX25519AEADRatchetSession::HandleNewIncomingSession (const uint8_t * buf, size_t len)
|
||||
{
|
||||
if (!GetOwner ()) return false;
|
||||
@@ -327,8 +356,9 @@ namespace garlic
|
||||
auto offset1 = offset;
|
||||
for (auto i = 0; i < numAcks; i++)
|
||||
{
|
||||
offset1 += 2; // tagsetid
|
||||
MessageConfirmed (bufbe16toh (buf + offset1)); offset1 += 2; // N
|
||||
uint32_t tagsetid = bufbe16toh (buf + offset1); offset1 += 2; // tagsetid
|
||||
uint16_t n = bufbe16toh (buf + offset1); offset1 += 2; // N
|
||||
MessageConfirmed ((tagsetid << 16) + n); // msgid = (tagsetid << 16) + N
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -391,7 +421,6 @@ namespace garlic
|
||||
{
|
||||
uint16_t keyID = bufbe16toh (buf); buf += 2; // keyID
|
||||
bool newKey = flag & ECIESX25519_NEXT_KEY_REQUEST_REVERSE_KEY_FLAG;
|
||||
m_SendReverseKey = true;
|
||||
if (!m_NextReceiveRatchet)
|
||||
m_NextReceiveRatchet.reset (new DHRatchet ());
|
||||
else
|
||||
@@ -403,15 +432,14 @@ namespace garlic
|
||||
}
|
||||
m_NextReceiveRatchet->keyID = keyID;
|
||||
}
|
||||
int tagsetID = 2*keyID;
|
||||
if (newKey)
|
||||
{
|
||||
m_NextReceiveRatchet->key = i2p::transport::transports.GetNextX25519KeysPair ();
|
||||
m_NextReceiveRatchet->newKey = true;
|
||||
tagsetID++;
|
||||
}
|
||||
else
|
||||
m_NextReceiveRatchet->newKey = false;
|
||||
auto tagsetID = m_NextReceiveRatchet->GetReceiveTagSetID ();
|
||||
if (flag & ECIESX25519_NEXT_KEY_KEY_PRESENT_FLAG)
|
||||
memcpy (m_NextReceiveRatchet->remote, buf, 32);
|
||||
|
||||
@@ -425,7 +453,9 @@ namespace garlic
|
||||
GenerateMoreReceiveTags (newTagset, (GetOwner () && GetOwner ()->GetNumRatchetInboundTags () > 0) ?
|
||||
GetOwner ()->GetNumRatchetInboundTags () : ECIESX25519_MAX_NUM_GENERATED_TAGS);
|
||||
receiveTagset->Expire ();
|
||||
|
||||
LogPrint (eLogDebug, "Garlic: Next receive tagset ", tagsetID, " created");
|
||||
m_SendReverseKey = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -747,7 +777,8 @@ namespace garlic
|
||||
}
|
||||
else
|
||||
{
|
||||
moreTags = ECIESX25519_MIN_NUM_GENERATED_TAGS + (index >> 2); // N/4
|
||||
moreTags = (receiveTagset->GetTagSetID () > 0) ? ECIESX25519_MAX_NUM_GENERATED_TAGS : // for non first tagset
|
||||
(ECIESX25519_MIN_NUM_GENERATED_TAGS + (index >> 1)); // N/2
|
||||
if (moreTags > ECIESX25519_MAX_NUM_GENERATED_TAGS) moreTags = ECIESX25519_MAX_NUM_GENERATED_TAGS;
|
||||
moreTags -= (receiveTagset->GetNextIndex () - index);
|
||||
index -= ECIESX25519_MAX_NUM_GENERATED_TAGS; // trim behind
|
||||
@@ -770,10 +801,10 @@ namespace garlic
|
||||
m_State = eSessionStateEstablished;
|
||||
m_NSRSendTagset = nullptr;
|
||||
m_EphemeralKeys = nullptr;
|
||||
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||
[[fallthrough]];
|
||||
#endif
|
||||
case eSessionStateEstablished:
|
||||
if (m_SendReverseKey && receiveTagset->GetTagSetID () == m_NextReceiveRatchet->GetReceiveTagSetID ())
|
||||
m_SendReverseKey = false; // tag received on new tagset
|
||||
if (receiveTagset->IsNS ())
|
||||
{
|
||||
// our of sequence NSR
|
||||
@@ -851,13 +882,14 @@ namespace garlic
|
||||
{
|
||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
size_t payloadLen = 0;
|
||||
bool sendAckRequest = false;
|
||||
if (first) payloadLen += 7;// datatime
|
||||
if (msg)
|
||||
{
|
||||
payloadLen += msg->GetPayloadLength () + 13;
|
||||
if (m_Destination) payloadLen += 32;
|
||||
}
|
||||
if (GetLeaseSetUpdateStatus () == eLeaseSetSubmitted && ts > GetLeaseSetSubmissionTime () + LEASET_CONFIRMATION_TIMEOUT)
|
||||
if (GetLeaseSetUpdateStatus () == eLeaseSetSubmitted && ts > GetLeaseSetSubmissionTime () + LEASESET_CONFIRMATION_TIMEOUT)
|
||||
{
|
||||
// resubmit non-confirmed LeaseSet
|
||||
SetLeaseSetUpdateStatus (eLeaseSetUpdated);
|
||||
@@ -869,13 +901,28 @@ namespace garlic
|
||||
payloadLen += leaseSet->GetBufferLen () + DATABASE_STORE_HEADER_SIZE + 13;
|
||||
if (!first)
|
||||
{
|
||||
// ack request
|
||||
// ack request for LeaseSet
|
||||
m_AckRequestMsgID = m_SendTagset->GetMsgID ();
|
||||
sendAckRequest = true;
|
||||
// update LeaseSet status
|
||||
SetLeaseSetUpdateStatus (eLeaseSetSubmitted);
|
||||
SetLeaseSetUpdateMsgID (m_SendTagset->GetNextIndex ());
|
||||
SetLeaseSetUpdateMsgID (m_AckRequestMsgID);
|
||||
SetLeaseSetSubmissionTime (ts);
|
||||
payloadLen += 4;
|
||||
}
|
||||
}
|
||||
if (!sendAckRequest && !first &&
|
||||
((!m_AckRequestMsgID && ts > m_LastAckRequestSendTime + ECIESX25519_ACK_REQUEST_INTERVAL) || // regular request
|
||||
(m_AckRequestMsgID && ts > m_LastAckRequestSendTime + LEASESET_CONFIRMATION_TIMEOUT))) // previous request failed. try again
|
||||
{
|
||||
// not LeaseSet
|
||||
m_AckRequestMsgID = m_SendTagset->GetMsgID ();
|
||||
if (m_AckRequestMsgID)
|
||||
{
|
||||
m_AckRequestNumAttempts++;
|
||||
sendAckRequest = true;
|
||||
}
|
||||
}
|
||||
if (sendAckRequest) payloadLen += 4;
|
||||
if (m_AckRequests.size () > 0)
|
||||
payloadLen += m_AckRequests.size ()*4 + 3;
|
||||
if (m_SendReverseKey)
|
||||
@@ -927,16 +974,15 @@ namespace garlic
|
||||
}
|
||||
// LeaseSet
|
||||
if (leaseSet)
|
||||
{
|
||||
offset += CreateLeaseSetClove (leaseSet, ts, payload + offset, payloadLen - offset);
|
||||
if (!first)
|
||||
{
|
||||
// ack request
|
||||
payload[offset] = eECIESx25519BlkAckRequest; offset++;
|
||||
htobe16buf (payload + offset, 1); offset += 2;
|
||||
payload[offset] = 0; offset++; // flags
|
||||
}
|
||||
}
|
||||
// ack request
|
||||
if (sendAckRequest)
|
||||
{
|
||||
payload[offset] = eECIESx25519BlkAckRequest; offset++;
|
||||
htobe16buf (payload + offset, 1); offset += 2;
|
||||
payload[offset] = 0; offset++; // flags
|
||||
m_LastAckRequestSendTime = ts;
|
||||
}
|
||||
// msg
|
||||
if (msg)
|
||||
offset += CreateGarlicClove (msg, payload + offset, payloadLen - offset);
|
||||
@@ -971,7 +1017,6 @@ namespace garlic
|
||||
memcpy (payload + offset, m_NextReceiveRatchet->key->GetPublicKey (), 32);
|
||||
offset += 32; // public key
|
||||
}
|
||||
m_SendReverseKey = false;
|
||||
}
|
||||
if (m_SendForwardKey)
|
||||
{
|
||||
@@ -1067,6 +1112,8 @@ namespace garlic
|
||||
bool ECIESX25519AEADRatchetSession::CheckExpired (uint64_t ts)
|
||||
{
|
||||
CleanupUnconfirmedLeaseSet (ts);
|
||||
if (!m_Destination && ts > m_LastActivityTimestamp + ECIESX25519_SESSION_CREATE_TIMEOUT) return true; // m_LastActivityTimestamp is NS receive time
|
||||
if (m_State != eSessionStateEstablished && m_SessionCreatedTimestamp && ts > m_SessionCreatedTimestamp + ECIESX25519_SESSION_ESTABLISH_TIMEOUT) return true;
|
||||
return ts > m_LastActivityTimestamp + ECIESX25519_RECEIVE_EXPIRATION_TIMEOUT && // seconds
|
||||
ts*1000 > m_LastSentTimestamp + ECIESX25519_SEND_EXPIRATION_TIMEOUT*1000; // milliseconds
|
||||
}
|
||||
@@ -1148,7 +1195,7 @@ namespace garlic
|
||||
return len;
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> WrapECIESX25519Message (std::shared_ptr<const I2NPMessage> msg, const uint8_t * key, uint64_t tag)
|
||||
std::shared_ptr<I2NPMessage> WrapECIESX25519Message (std::shared_ptr<I2NPMessage> msg, const uint8_t * key, uint64_t tag)
|
||||
{
|
||||
auto m = NewI2NPMessage ((msg ? msg->GetPayloadLength () : 0) + 128);
|
||||
m->Align (12); // in order to get buf aligned to 16 (12 + 4)
|
||||
@@ -1168,10 +1215,16 @@ namespace garlic
|
||||
htobe32buf (m->GetPayload (), offset);
|
||||
m->len += offset + 4;
|
||||
m->FillI2NPMessageHeader (eI2NPGarlic);
|
||||
if (msg->onDrop)
|
||||
{
|
||||
// move onDrop to the wrapping I2NP messages
|
||||
m->onDrop = msg->onDrop;
|
||||
msg->onDrop = nullptr;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> WrapECIESX25519MessageForRouter (std::shared_ptr<const I2NPMessage> msg, const uint8_t * routerPublicKey)
|
||||
std::shared_ptr<I2NPMessage> WrapECIESX25519MessageForRouter (std::shared_ptr<I2NPMessage> msg, const uint8_t * routerPublicKey)
|
||||
{
|
||||
// Noise_N, we are Alice, routerPublicKey is Bob's
|
||||
i2p::crypto::NoiseSymmetricState noiseState;
|
||||
@@ -1205,6 +1258,12 @@ namespace garlic
|
||||
htobe32buf (m->GetPayload (), offset);
|
||||
m->len += offset + 4;
|
||||
m->FillI2NPMessageHeader (eI2NPGarlic);
|
||||
if (msg->onDrop)
|
||||
{
|
||||
// move onDrop to the wrapping I2NP messages
|
||||
m->onDrop = msg->onDrop;
|
||||
msg->onDrop = nullptr;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -30,10 +30,14 @@ namespace garlic
|
||||
const int ECIESX25519_SEND_INACTIVITY_TIMEOUT = 5000; // number of milliseconds we can send empty(pyaload only) packet after
|
||||
const int ECIESX25519_SEND_EXPIRATION_TIMEOUT = 480; // in seconds
|
||||
const int ECIESX25519_RECEIVE_EXPIRATION_TIMEOUT = 600; // in seconds
|
||||
const int ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT = 180; // 180
|
||||
const int ECIESX25519_SESSION_CREATE_TIMEOUT = 3; // in seconds, NSR must be send after NS received
|
||||
const int ECIESX25519_SESSION_ESTABLISH_TIMEOUT = 15; // in seconds
|
||||
const int ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT = 180; // in seconds
|
||||
const int ECIESX25519_ACK_REQUEST_INTERVAL = 33000; // in milliseconds
|
||||
const int ECIESX25519_ACK_REQUEST_MAX_NUM_ATTEMPTS = 3;
|
||||
const int ECIESX25519_TAGSET_MAX_NUM_TAGS = 8192; // number of tags we request new tagset after
|
||||
const int ECIESX25519_MIN_NUM_GENERATED_TAGS = 24;
|
||||
const int ECIESX25519_MAX_NUM_GENERATED_TAGS = 320;
|
||||
const int ECIESX25519_MAX_NUM_GENERATED_TAGS = 800;
|
||||
const int ECIESX25519_NSR_NUM_GENERATED_TAGS = 12;
|
||||
|
||||
const size_t ECIESX25519_OPTIMAL_PAYLOAD_SIZE = 1912; // 1912 = 1956 /* to fit 2 tunnel messages */
|
||||
@@ -57,6 +61,8 @@ namespace garlic
|
||||
int GetTagSetID () const { return m_TagSetID; };
|
||||
void SetTagSetID (int tagsetID) { m_TagSetID = tagsetID; };
|
||||
|
||||
uint32_t GetMsgID () const { return (m_TagSetID << 16) + m_NextIndex; }; // (tagsetid << 16) + N
|
||||
|
||||
private:
|
||||
|
||||
i2p::data::Tag<64> m_SessionTagKeyData;
|
||||
@@ -86,7 +92,8 @@ namespace garlic
|
||||
|
||||
virtual bool IsIndexExpired (int index) const;
|
||||
virtual bool HandleNextMessage (uint8_t * buf, size_t len, int index);
|
||||
|
||||
virtual bool IsSessionTerminated () const;
|
||||
|
||||
private:
|
||||
|
||||
int m_TrimBehindIndex = 0;
|
||||
@@ -101,9 +108,10 @@ namespace garlic
|
||||
|
||||
SymmetricKeyTagSet (GarlicDestination * destination, const uint8_t * key);
|
||||
|
||||
bool IsIndexExpired (int index) const { return false; };
|
||||
bool HandleNextMessage (uint8_t * buf, size_t len, int index);
|
||||
|
||||
bool IsIndexExpired (int index) const override { return false; };
|
||||
bool HandleNextMessage (uint8_t * buf, size_t len, int index) override;
|
||||
bool IsSessionTerminated () const override { return false; }
|
||||
|
||||
private:
|
||||
|
||||
GarlicDestination * m_Destination;
|
||||
@@ -147,6 +155,7 @@ namespace garlic
|
||||
std::shared_ptr<i2p::crypto::X25519Keys> key;
|
||||
uint8_t remote[32]; // last remote public key
|
||||
bool newKey = true;
|
||||
int GetReceiveTagSetID () const { return newKey ? (2*keyID + 1) : 2*keyID; }
|
||||
};
|
||||
|
||||
public:
|
||||
@@ -162,7 +171,7 @@ namespace garlic
|
||||
void SetRemoteStaticKey (const uint8_t * key) { memcpy (m_RemoteStaticKey, key, 32); }
|
||||
|
||||
void Terminate () { m_IsTerminated = true; }
|
||||
void SetDestination (const i2p::data::IdentHash& dest) // TODO:
|
||||
void SetDestination (const i2p::data::IdentHash& dest)
|
||||
{
|
||||
if (!m_Destination) m_Destination.reset (new i2p::data::IdentHash (dest));
|
||||
}
|
||||
@@ -175,14 +184,16 @@ namespace garlic
|
||||
bool IsReadyToSend () const { return m_State != eSessionStateNewSessionSent; };
|
||||
bool IsTerminated () const { return m_IsTerminated; }
|
||||
uint64_t GetLastActivityTimestamp () const { return m_LastActivityTimestamp; };
|
||||
|
||||
bool CleanupUnconfirmedTags (); // return true if unaswered Ack requests, called from I2CP
|
||||
|
||||
protected:
|
||||
|
||||
i2p::crypto::NoiseSymmetricState& GetNoiseState () { return *this; };
|
||||
void SetNoiseState (const i2p::crypto::NoiseSymmetricState& state) { GetNoiseState () = state; };
|
||||
void CreateNonce (uint64_t seqn, uint8_t * nonce);
|
||||
void HandlePayload (const uint8_t * buf, size_t len, const std::shared_ptr<ReceiveRatchetTagSet>& receiveTagset, int index);
|
||||
|
||||
bool MessageConfirmed (uint32_t msgID);
|
||||
|
||||
private:
|
||||
|
||||
bool GenerateEphemeralKeysAndEncode (uint8_t * buf); // buf is 32 bytes
|
||||
@@ -215,12 +226,16 @@ namespace garlic
|
||||
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
|
||||
std::list<std::pair<uint16_t, int> > m_AckRequests; // (tagsetid, index)
|
||||
std::unique_ptr<i2p::data::IdentHash> m_Destination;// must be set for NS if outgoing and NSR if incoming
|
||||
std::list<std::pair<uint16_t, int> > m_AckRequests; // incoming (tagsetid, index)
|
||||
bool m_SendReverseKey = false, m_SendForwardKey = false, m_IsTerminated = false;
|
||||
std::unique_ptr<DHRatchet> m_NextReceiveRatchet, m_NextSendRatchet;
|
||||
uint8_t m_PaddingSizes[32], m_NextPaddingSize;
|
||||
|
||||
uint64_t m_LastAckRequestSendTime = 0; // milliseconds
|
||||
uint32_t m_AckRequestMsgID = 0;
|
||||
int m_AckRequestNumAttempts = 0;
|
||||
|
||||
public:
|
||||
|
||||
// for HTTP only
|
||||
@@ -245,8 +260,8 @@ namespace garlic
|
||||
i2p::crypto::NoiseSymmetricState m_CurrentNoiseState;
|
||||
};
|
||||
|
||||
std::shared_ptr<I2NPMessage> WrapECIESX25519Message (std::shared_ptr<const I2NPMessage> msg, const uint8_t * key, uint64_t tag);
|
||||
std::shared_ptr<I2NPMessage> WrapECIESX25519MessageForRouter (std::shared_ptr<const I2NPMessage> msg, const uint8_t * routerPublicKey);
|
||||
std::shared_ptr<I2NPMessage> WrapECIESX25519Message (std::shared_ptr<I2NPMessage> msg, const uint8_t * key, uint64_t tag);
|
||||
std::shared_ptr<I2NPMessage> WrapECIESX25519MessageForRouter (std::shared_ptr<I2NPMessage> msg, const uint8_t * routerPublicKey);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -457,86 +457,6 @@ namespace crypto
|
||||
}
|
||||
}
|
||||
|
||||
#if !OPENSSL_X25519
|
||||
BIGNUM * Ed25519::ScalarMul (const BIGNUM * u, const BIGNUM * k, BN_CTX * ctx) const
|
||||
{
|
||||
BN_CTX_start (ctx);
|
||||
auto x1 = BN_CTX_get (ctx); BN_copy (x1, u);
|
||||
auto x2 = BN_CTX_get (ctx); BN_one (x2);
|
||||
auto z2 = BN_CTX_get (ctx); BN_zero (z2);
|
||||
auto x3 = BN_CTX_get (ctx); BN_copy (x3, u);
|
||||
auto z3 = BN_CTX_get (ctx); BN_one (z3);
|
||||
auto c121666 = BN_CTX_get (ctx); BN_set_word (c121666, 121666);
|
||||
auto tmp0 = BN_CTX_get (ctx); auto tmp1 = BN_CTX_get (ctx);
|
||||
unsigned int swap = 0;
|
||||
auto bits = BN_num_bits (k);
|
||||
while(bits)
|
||||
{
|
||||
--bits;
|
||||
auto k_t = BN_is_bit_set(k, bits) ? 1 : 0;
|
||||
swap ^= k_t;
|
||||
if (swap)
|
||||
{
|
||||
std::swap (x2, x3);
|
||||
std::swap (z2, z3);
|
||||
}
|
||||
swap = k_t;
|
||||
BN_mod_sub(tmp0, x3, z3, q, ctx);
|
||||
BN_mod_sub(tmp1, x2, z2, q, ctx);
|
||||
BN_mod_add(x2, x2, z2, q, ctx);
|
||||
BN_mod_add(z2, x3, z3, q, ctx);
|
||||
BN_mod_mul(z3, tmp0, x2, q, ctx);
|
||||
BN_mod_mul(z2, z2, tmp1, q, ctx);
|
||||
BN_mod_sqr(tmp0, tmp1, q, ctx);
|
||||
BN_mod_sqr(tmp1, x2, q, ctx);
|
||||
BN_mod_add(x3, z3, z2, q, ctx);
|
||||
BN_mod_sub(z2, z3, z2, q, ctx);
|
||||
BN_mod_mul(x2, tmp1, tmp0, q, ctx);
|
||||
BN_mod_sub(tmp1, tmp1, tmp0, q, ctx);
|
||||
BN_mod_sqr(z2, z2, q, ctx);
|
||||
BN_mod_mul(z3, tmp1, c121666, q, ctx);
|
||||
BN_mod_sqr(x3, x3, q, ctx);
|
||||
BN_mod_add(tmp0, tmp0, z3, q, ctx);
|
||||
BN_mod_mul(z3, x1, z2, q, ctx);
|
||||
BN_mod_mul(z2, tmp1, tmp0, q, ctx);
|
||||
}
|
||||
if (swap)
|
||||
{
|
||||
std::swap (x2, x3);
|
||||
std::swap (z2, z3);
|
||||
}
|
||||
BN_mod_inverse (z2, z2, q, 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
|
||||
{
|
||||
BIGNUM * p1 = DecodeBN<32> (p);
|
||||
uint8_t k[32];
|
||||
memcpy (k, e, 32);
|
||||
k[0] &= 248; k[31] &= 127; k[31] |= 64;
|
||||
BIGNUM * n = DecodeBN<32> (k);
|
||||
BIGNUM * q1 = ScalarMul (p1, n, ctx);
|
||||
EncodeBN (q1, buf, 32);
|
||||
BN_free (p1); BN_free (n); BN_free (q1);
|
||||
}
|
||||
|
||||
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];
|
||||
memcpy (k, e, 32);
|
||||
k[0] &= 248; k[31] &= 127; k[31] |= 64;
|
||||
BIGNUM * n = DecodeBN<32> (k);
|
||||
BIGNUM * q1 = ScalarMul (p1, n, ctx);
|
||||
EncodeBN (q1, buf, 32);
|
||||
BN_free (p1); BN_free (n); BN_free (q1);
|
||||
}
|
||||
#endif
|
||||
|
||||
void Ed25519::BlindPublicKey (const uint8_t * pub, const uint8_t * seed, uint8_t * blinded)
|
||||
{
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -84,10 +84,7 @@ namespace crypto
|
||||
EDDSAPoint GeneratePublicKey (const uint8_t * expandedPrivateKey, BN_CTX * ctx) const;
|
||||
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;
|
||||
#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
|
||||
|
||||
@@ -115,11 +112,6 @@ namespace crypto
|
||||
BIGNUM * DecodeBN (const uint8_t * buf) const;
|
||||
void EncodeBN (const BIGNUM * bn, uint8_t * buf, size_t len) const;
|
||||
|
||||
#if !OPENSSL_X25519
|
||||
// for x25519
|
||||
BIGNUM * ScalarMul (const BIGNUM * p, const BIGNUM * e, BN_CTX * ctx) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
BIGNUM * q, * l, * d, * I;
|
||||
|
||||
135
libi2pd/FS.cpp
135
libi2pd/FS.cpp
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -7,7 +7,13 @@
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#if defined(MAC_OSX)
|
||||
#if !STD_FILESYSTEM
|
||||
#include <boost/system/system_error.hpp>
|
||||
#endif
|
||||
#include <TargetConditionals.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <shlobj.h>
|
||||
@@ -20,6 +26,14 @@
|
||||
#include "Log.h"
|
||||
#include "Garlic.h"
|
||||
|
||||
#if STD_FILESYSTEM
|
||||
#include <filesystem>
|
||||
namespace fs_lib = std::filesystem;
|
||||
#else
|
||||
#include <boost/filesystem.hpp>
|
||||
namespace fs_lib = boost::filesystem;
|
||||
#endif
|
||||
|
||||
namespace i2p {
|
||||
namespace fs {
|
||||
std::string appName = "i2pd";
|
||||
@@ -49,11 +63,17 @@ namespace fs {
|
||||
|
||||
const std::string GetUTF8DataDir () {
|
||||
#ifdef _WIN32
|
||||
boost::filesystem::wpath path (dataDir);
|
||||
auto loc = boost::filesystem::path::imbue(std::locale( std::locale(), new std::codecvt_utf8_utf16<wchar_t>() ) ); // convert path to UTF-8
|
||||
auto dataDirUTF8 = path.string();
|
||||
boost::filesystem::path::imbue(loc); // Return locale settings back
|
||||
return dataDirUTF8;
|
||||
int size = MultiByteToWideChar(CP_ACP, 0,
|
||||
dataDir.c_str(), dataDir.size(), nullptr, 0);
|
||||
std::wstring utf16Str(size, L'\0');
|
||||
MultiByteToWideChar(CP_ACP, 0,
|
||||
dataDir.c_str(), dataDir.size(), &utf16Str[0], size);
|
||||
int utf8Size = WideCharToMultiByte(CP_UTF8, 0,
|
||||
utf16Str.c_str(), utf16Str.size(), nullptr, 0, nullptr, nullptr);
|
||||
std::string utf8Str(utf8Size, '\0');
|
||||
WideCharToMultiByte(CP_UTF8, 0,
|
||||
utf16Str.c_str(), utf16Str.size(), &utf8Str[0], utf8Size, nullptr, nullptr);
|
||||
return utf8Str;
|
||||
#else
|
||||
return dataDir; // linux, osx, android uses UTF-8 by default
|
||||
#endif
|
||||
@@ -82,7 +102,11 @@ namespace fs {
|
||||
}
|
||||
else
|
||||
{
|
||||
dataDir = boost::filesystem::wpath(commonAppData).string() + "\\" + appName;
|
||||
#if ((BOOST_VERSION >= 108500) || STD_FILESYSTEM)
|
||||
dataDir = fs_lib::path(commonAppData).string() + "\\" + appName;
|
||||
#else
|
||||
dataDir = fs_lib::wpath(commonAppData).string() + "\\" + appName;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
dataDir = "/var/lib/" + appName;
|
||||
@@ -107,10 +131,14 @@ namespace fs {
|
||||
}
|
||||
else
|
||||
{
|
||||
auto execPath = boost::filesystem::wpath(localAppData).parent_path();
|
||||
#if ((BOOST_VERSION >= 108500) || STD_FILESYSTEM)
|
||||
auto execPath = fs_lib::path(localAppData).parent_path();
|
||||
#else
|
||||
auto execPath = fs_lib::wpath(localAppData).parent_path();
|
||||
#endif
|
||||
|
||||
// if config file exists in .exe's folder use it
|
||||
if(boost::filesystem::exists(execPath/"i2pd.conf")) // TODO: magic string
|
||||
if(fs_lib::exists(execPath/"i2pd.conf")) // TODO: magic string
|
||||
{
|
||||
dataDir = execPath.string ();
|
||||
} else // otherwise %appdata%
|
||||
@@ -126,7 +154,11 @@ namespace fs {
|
||||
}
|
||||
else
|
||||
{
|
||||
dataDir = boost::filesystem::wpath(localAppData).string() + "\\" + appName;
|
||||
#if ((BOOST_VERSION >= 108500) || STD_FILESYSTEM)
|
||||
dataDir = fs_lib::path(localAppData).string() + "\\" + appName;
|
||||
#else
|
||||
dataDir = fs_lib::wpath(localAppData).string() + "\\" + appName;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -148,7 +180,7 @@ namespace fs {
|
||||
#if defined(ANDROID)
|
||||
const char * ext = getenv("EXTERNAL_STORAGE");
|
||||
if (!ext) ext = "/sdcard";
|
||||
if (boost::filesystem::exists(ext))
|
||||
if (fs_lib::exists(ext))
|
||||
{
|
||||
dataDir = std::string (ext) + "/" + appName;
|
||||
return;
|
||||
@@ -181,16 +213,16 @@ namespace fs {
|
||||
}
|
||||
|
||||
bool Init() {
|
||||
if (!boost::filesystem::exists(dataDir))
|
||||
boost::filesystem::create_directory(dataDir);
|
||||
if (!fs_lib::exists(dataDir))
|
||||
fs_lib::create_directory(dataDir);
|
||||
|
||||
std::string destinations = DataDirPath("destinations");
|
||||
if (!boost::filesystem::exists(destinations))
|
||||
boost::filesystem::create_directory(destinations);
|
||||
if (!fs_lib::exists(destinations))
|
||||
fs_lib::create_directory(destinations);
|
||||
|
||||
std::string tags = DataDirPath("tags");
|
||||
if (!boost::filesystem::exists(tags))
|
||||
boost::filesystem::create_directory(tags);
|
||||
if (!fs_lib::exists(tags))
|
||||
fs_lib::create_directory(tags);
|
||||
else
|
||||
i2p::garlic::CleanUpTagsFiles ();
|
||||
|
||||
@@ -198,13 +230,13 @@ namespace fs {
|
||||
}
|
||||
|
||||
bool ReadDir(const std::string & path, std::vector<std::string> & files) {
|
||||
if (!boost::filesystem::exists(path))
|
||||
if (!fs_lib::exists(path))
|
||||
return false;
|
||||
boost::filesystem::directory_iterator it(path);
|
||||
boost::filesystem::directory_iterator end;
|
||||
fs_lib::directory_iterator it(path);
|
||||
fs_lib::directory_iterator end;
|
||||
|
||||
for ( ; it != end; it++) {
|
||||
if (!boost::filesystem::is_regular_file(it->status()))
|
||||
if (!fs_lib::is_regular_file(it->status()))
|
||||
continue;
|
||||
files.push_back(it->path().string());
|
||||
}
|
||||
@@ -213,29 +245,42 @@ namespace fs {
|
||||
}
|
||||
|
||||
bool Exists(const std::string & path) {
|
||||
return boost::filesystem::exists(path);
|
||||
return fs_lib::exists(path);
|
||||
}
|
||||
|
||||
uint32_t GetLastUpdateTime (const std::string & path)
|
||||
{
|
||||
if (!boost::filesystem::exists(path))
|
||||
if (!fs_lib::exists(path))
|
||||
return 0;
|
||||
#if STD_FILESYSTEM
|
||||
std::error_code ec;
|
||||
auto t = std::filesystem::last_write_time (path, ec);
|
||||
if (ec) return 0;
|
||||
/*#if __cplusplus >= 202002L // C++ 20 or higher
|
||||
const auto sctp = std::chrono::clock_cast<std::chrono::system_clock>(t);
|
||||
#else */ // TODO: wait until implemented
|
||||
const auto sctp = std::chrono::time_point_cast<std::chrono::system_clock::duration>(
|
||||
t - decltype(t)::clock::now() + std::chrono::system_clock::now());
|
||||
/*#endif */
|
||||
return std::chrono::system_clock::to_time_t(sctp);
|
||||
#else
|
||||
boost::system::error_code ec;
|
||||
auto t = boost::filesystem::last_write_time (path, ec);
|
||||
return ec ? 0 : t;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Remove(const std::string & path) {
|
||||
if (!boost::filesystem::exists(path))
|
||||
if (!fs_lib::exists(path))
|
||||
return false;
|
||||
return boost::filesystem::remove(path);
|
||||
return fs_lib::remove(path);
|
||||
}
|
||||
|
||||
bool CreateDirectory (const std::string& path)
|
||||
{
|
||||
if (boost::filesystem::exists(path) && boost::filesystem::is_directory (boost::filesystem::status (path)))
|
||||
if (fs_lib::exists(path) && fs_lib::is_directory (fs_lib::status (path)))
|
||||
return true;
|
||||
return boost::filesystem::create_directory(path);
|
||||
return fs_lib::create_directory(path);
|
||||
}
|
||||
|
||||
void HashedStorage::SetPlace(const std::string &path) {
|
||||
@@ -243,16 +288,30 @@ namespace fs {
|
||||
}
|
||||
|
||||
bool HashedStorage::Init(const char * chars, size_t count) {
|
||||
if (!boost::filesystem::exists(root)) {
|
||||
boost::filesystem::create_directories(root);
|
||||
if (!fs_lib::exists(root)) {
|
||||
fs_lib::create_directories(root);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
auto p = root + i2p::fs::dirSep + prefix1 + chars[i];
|
||||
if (boost::filesystem::exists(p))
|
||||
if (fs_lib::exists(p))
|
||||
continue;
|
||||
if (boost::filesystem::create_directory(p))
|
||||
#if TARGET_OS_SIMULATOR
|
||||
// ios simulator fs says it is case sensitive, but it is not
|
||||
boost::system::error_code ec;
|
||||
if (fs_lib::create_directory(p, ec))
|
||||
continue;
|
||||
switch (ec.value()) {
|
||||
case boost::system::errc::file_exists:
|
||||
case boost::system::errc::success:
|
||||
continue;
|
||||
default:
|
||||
throw boost::system::system_error( ec, __func__ );
|
||||
}
|
||||
#else
|
||||
if (fs_lib::create_directory(p))
|
||||
continue; /* ^ throws exception on failure */
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -273,9 +332,9 @@ namespace fs {
|
||||
|
||||
void HashedStorage::Remove(const std::string & ident) {
|
||||
std::string path = Path(ident);
|
||||
if (!boost::filesystem::exists(path))
|
||||
if (!fs_lib::exists(path))
|
||||
return;
|
||||
boost::filesystem::remove(path);
|
||||
fs_lib::remove(path);
|
||||
}
|
||||
|
||||
void HashedStorage::Traverse(std::vector<std::string> & files) {
|
||||
@@ -286,12 +345,12 @@ namespace fs {
|
||||
|
||||
void HashedStorage::Iterate(FilenameVisitor v)
|
||||
{
|
||||
boost::filesystem::path p(root);
|
||||
boost::filesystem::recursive_directory_iterator it(p);
|
||||
boost::filesystem::recursive_directory_iterator end;
|
||||
fs_lib::path p(root);
|
||||
fs_lib::recursive_directory_iterator it(p);
|
||||
fs_lib::recursive_directory_iterator end;
|
||||
|
||||
for ( ; it != end; it++) {
|
||||
if (!boost::filesystem::is_regular_file( it->status() ))
|
||||
if (!fs_lib::is_regular_file( it->status() ))
|
||||
continue;
|
||||
const std::string & t = it->path().string();
|
||||
v(t);
|
||||
|
||||
12
libi2pd/FS.h
12
libi2pd/FS.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -15,6 +15,16 @@
|
||||
#include <sstream>
|
||||
#include <functional>
|
||||
|
||||
#ifndef STD_FILESYSTEM
|
||||
# if (_WIN32 && __GNUG__) // MinGW GCC somehow incorrectly converts paths
|
||||
# define STD_FILESYSTEM 0
|
||||
# elif (!TARGET_OS_SIMULATOR && __has_include(<filesystem>)) // supports std::filesystem
|
||||
# define STD_FILESYSTEM 1
|
||||
# else
|
||||
# define STD_FILESYSTEM 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace i2p {
|
||||
namespace fs {
|
||||
extern std::string dirSep;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include "Crypto.h"
|
||||
#include "FS.h"
|
||||
@@ -25,6 +24,8 @@ namespace data
|
||||
|
||||
Families::~Families ()
|
||||
{
|
||||
for (auto it : m_SigningKeys)
|
||||
if (it.second.first) EVP_PKEY_free (it.second.first);
|
||||
}
|
||||
|
||||
void Families::LoadCertificate (const std::string& filename)
|
||||
@@ -47,48 +48,16 @@ namespace data
|
||||
cn += 3;
|
||||
char * family = strstr (cn, ".family");
|
||||
if (family) family[0] = 0;
|
||||
}
|
||||
auto pkey = X509_get_pubkey (cert);
|
||||
int keyType = EVP_PKEY_base_id (pkey);
|
||||
switch (keyType)
|
||||
{
|
||||
case EVP_PKEY_DSA:
|
||||
// TODO:
|
||||
break;
|
||||
case EVP_PKEY_EC:
|
||||
{
|
||||
EC_KEY * ecKey = EVP_PKEY_get1_EC_KEY (pkey);
|
||||
if (ecKey)
|
||||
auto pkey = X509_get_pubkey (cert);
|
||||
if (pkey)
|
||||
{
|
||||
if (!m_SigningKeys.emplace (cn, std::make_pair(pkey, (int)m_SigningKeys.size () + 1)).second)
|
||||
{
|
||||
auto group = EC_KEY_get0_group (ecKey);
|
||||
if (group)
|
||||
{
|
||||
int curve = EC_GROUP_get_curve_name (group);
|
||||
if (curve == NID_X9_62_prime256v1)
|
||||
{
|
||||
uint8_t signingKey[64];
|
||||
BIGNUM * x = BN_new(), * y = BN_new();
|
||||
EC_POINT_get_affine_coordinates_GFp (group,
|
||||
EC_KEY_get0_public_key (ecKey), x, y, NULL);
|
||||
i2p::crypto::bn2buf (x, signingKey, 32);
|
||||
i2p::crypto::bn2buf (y, signingKey + 32, 32);
|
||||
BN_free (x); BN_free (y);
|
||||
verifier = std::make_shared<i2p::crypto::ECDSAP256Verifier>();
|
||||
verifier->SetPublicKey (signingKey);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported");
|
||||
}
|
||||
EC_KEY_free (ecKey);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LogPrint (eLogWarning, "Family: Certificate key type ", keyType, " is not supported");
|
||||
EVP_PKEY_free (pkey);
|
||||
LogPrint (eLogError, "Family: Duplicated family name ", cn);
|
||||
}
|
||||
}
|
||||
}
|
||||
EVP_PKEY_free (pkey);
|
||||
if (verifier && cn)
|
||||
m_SigningKeys.emplace (cn, std::make_pair(verifier, (int)m_SigningKeys.size () + 1));
|
||||
}
|
||||
SSL_free (ssl);
|
||||
}
|
||||
@@ -130,14 +99,22 @@ namespace data
|
||||
LogPrint (eLogError, "Family: ", family, " is too long");
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy (buf, family.c_str (), len);
|
||||
memcpy (buf + len, (const uint8_t *)ident, 32);
|
||||
len += 32;
|
||||
Base64ToByteStream (signature, signatureLen, signatureBuf, 64);
|
||||
auto it = m_SigningKeys.find (family);
|
||||
if (it != m_SigningKeys.end ())
|
||||
return it->second.first->Verify (buf, len, signatureBuf);
|
||||
if (it != m_SigningKeys.end () && it->second.first)
|
||||
{
|
||||
memcpy (buf, family.c_str (), len);
|
||||
memcpy (buf + len, (const uint8_t *)ident, 32);
|
||||
len += 32;
|
||||
auto signatureBufLen = Base64ToByteStream (signature, signatureLen, signatureBuf, 64);
|
||||
if (signatureBufLen)
|
||||
{
|
||||
EVP_MD_CTX * ctx = EVP_MD_CTX_create ();
|
||||
EVP_DigestVerifyInit (ctx, NULL, NULL, NULL, it->second.first);
|
||||
auto ret = EVP_DigestVerify (ctx, signatureBuf, signatureBufLen, buf, len);
|
||||
EVP_MD_CTX_destroy (ctx);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
// TODO: process key
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include "Signature.h"
|
||||
#include <openssl/evp.h>
|
||||
#include "Identity.h"
|
||||
|
||||
namespace i2p
|
||||
@@ -37,7 +37,7 @@ namespace data
|
||||
|
||||
private:
|
||||
|
||||
std::map<std::string, std::pair<std::shared_ptr<i2p::crypto::Verifier>, FamilyID> > m_SigningKeys; // family -> (verifier, id)
|
||||
std::map<std::string, std::pair<EVP_PKEY *, FamilyID> > m_SigningKeys; // family -> (verification pkey, id)
|
||||
};
|
||||
|
||||
std::string CreateFamilySignature (const std::string& family, const IdentHash& ident);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -45,22 +45,17 @@ namespace garlic
|
||||
{
|
||||
if (!m_SharedRoutingPath) return nullptr;
|
||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
if (m_SharedRoutingPath->numTimesUsed >= ROUTING_PATH_MAX_NUM_TIMES_USED ||
|
||||
!m_SharedRoutingPath->outboundTunnel->IsEstablished () ||
|
||||
if (!m_SharedRoutingPath->outboundTunnel->IsEstablished () ||
|
||||
ts*1000LL > m_SharedRoutingPath->remoteLease->endDate ||
|
||||
ts > m_SharedRoutingPath->updateTime + ROUTING_PATH_EXPIRATION_TIMEOUT)
|
||||
m_SharedRoutingPath = nullptr;
|
||||
if (m_SharedRoutingPath) m_SharedRoutingPath->numTimesUsed++;
|
||||
return m_SharedRoutingPath;
|
||||
}
|
||||
|
||||
void GarlicRoutingSession::SetSharedRoutingPath (std::shared_ptr<GarlicRoutingPath> path)
|
||||
{
|
||||
if (path && path->outboundTunnel && path->remoteLease)
|
||||
{
|
||||
path->updateTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
path->numTimesUsed = 0;
|
||||
}
|
||||
else
|
||||
path = nullptr;
|
||||
m_SharedRoutingPath = path;
|
||||
@@ -80,7 +75,7 @@ namespace garlic
|
||||
|
||||
void GarlicRoutingSession::CleanupUnconfirmedLeaseSet (uint64_t ts)
|
||||
{
|
||||
if (m_LeaseSetUpdateMsgID && ts*1000LL > m_LeaseSetSubmissionTime + LEASET_CONFIRMATION_TIMEOUT)
|
||||
if (m_LeaseSetUpdateMsgID && ts*1000LL > m_LeaseSetSubmissionTime + LEASESET_CONFIRMATION_TIMEOUT)
|
||||
{
|
||||
if (GetOwner ())
|
||||
GetOwner ()->RemoveDeliveryStatusSession (m_LeaseSetUpdateMsgID);
|
||||
@@ -232,7 +227,7 @@ namespace garlic
|
||||
if (GetOwner ())
|
||||
{
|
||||
// resubmit non-confirmed LeaseSet
|
||||
if (GetLeaseSetUpdateStatus () == eLeaseSetSubmitted && ts > GetLeaseSetSubmissionTime () + LEASET_CONFIRMATION_TIMEOUT)
|
||||
if (GetLeaseSetUpdateStatus () == eLeaseSetSubmitted && ts > GetLeaseSetSubmissionTime () + LEASESET_CONFIRMATION_TIMEOUT)
|
||||
{
|
||||
SetLeaseSetUpdateStatus (eLeaseSetUpdated);
|
||||
SetSharedRoutingPath (nullptr); // invalidate path since leaseset was not confirmed
|
||||
@@ -431,7 +426,8 @@ namespace garlic
|
||||
}
|
||||
|
||||
GarlicDestination::GarlicDestination (): m_NumTags (32), // 32 tags by default
|
||||
m_PayloadBuffer (nullptr), m_NumRatchetInboundTags (0) // 0 means standard
|
||||
m_PayloadBuffer (nullptr), m_LastIncomingSessionTimestamp (0),
|
||||
m_NumRatchetInboundTags (0) // 0 means standard
|
||||
{
|
||||
}
|
||||
|
||||
@@ -544,36 +540,17 @@ namespace garlic
|
||||
else if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD))
|
||||
{
|
||||
// otherwise ECIESx25519
|
||||
auto session = std::make_shared<ECIESX25519AEADRatchetSession> (this, false); // incoming
|
||||
if (!session->HandleNextMessage (buf, length, nullptr, 0))
|
||||
{
|
||||
// try to generate more tags for last tagset
|
||||
if (m_LastTagset && (m_LastTagset->GetNextIndex () - m_LastTagset->GetTrimBehind () < 3*ECIESX25519_MAX_NUM_GENERATED_TAGS))
|
||||
{
|
||||
uint64_t missingTag; memcpy (&missingTag, buf, 8);
|
||||
auto maxTags = std::max (m_NumRatchetInboundTags, ECIESX25519_MAX_NUM_GENERATED_TAGS);
|
||||
LogPrint (eLogWarning, "Garlic: Trying to generate more ECIES-X25519-AEAD-Ratchet tags");
|
||||
for (int i = 0; i < maxTags; i++)
|
||||
{
|
||||
auto nextTag = AddECIESx25519SessionNextTag (m_LastTagset);
|
||||
if (!nextTag)
|
||||
{
|
||||
LogPrint (eLogError, "Garlic: Can't create new ECIES-X25519-AEAD-Ratchet tag for last tagset");
|
||||
break;
|
||||
}
|
||||
if (nextTag == missingTag)
|
||||
{
|
||||
LogPrint (eLogDebug, "Garlic: Missing ECIES-X25519-AEAD-Ratchet tag was generated");
|
||||
if (m_LastTagset->HandleNextMessage (buf, length, m_ECIESx25519Tags[nextTag].index))
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) m_LastTagset = nullptr;
|
||||
}
|
||||
if (!found)
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
if (ts > m_LastIncomingSessionTimestamp + INCOMING_SESSIONS_MINIMAL_INTERVAL)
|
||||
{
|
||||
auto session = std::make_shared<ECIESX25519AEADRatchetSession> (this, false); // incoming
|
||||
if (session->HandleNextMessage (buf, length, nullptr, 0))
|
||||
m_LastIncomingSessionTimestamp = ts;
|
||||
else
|
||||
LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Garlic: Incoming sessions come too ofter");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Garlic: Failed to decrypt message");
|
||||
@@ -588,9 +565,7 @@ namespace garlic
|
||||
auto it = m_ECIESx25519Tags.find (tag);
|
||||
if (it != m_ECIESx25519Tags.end ())
|
||||
{
|
||||
if (it->second.tagset && it->second.tagset->HandleNextMessage (buf, len, it->second.index))
|
||||
m_LastTagset = it->second.tagset;
|
||||
else
|
||||
if (!it->second.tagset || !it->second.tagset->HandleNextMessage (buf, len, it->second.index))
|
||||
LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message");
|
||||
m_ECIESx25519Tags.erase (it);
|
||||
return true;
|
||||
@@ -771,7 +746,8 @@ namespace garlic
|
||||
}
|
||||
|
||||
std::shared_ptr<GarlicRoutingSession> GarlicDestination::GetRoutingSession (
|
||||
std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet)
|
||||
std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet,
|
||||
bool requestNewIfNotFound)
|
||||
{
|
||||
if (destination->GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD &&
|
||||
SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD))
|
||||
@@ -786,16 +762,17 @@ namespace garlic
|
||||
if (session->IsInactive (i2p::util::GetSecondsSinceEpoch ()))
|
||||
{
|
||||
LogPrint (eLogDebug, "Garlic: Session restarted");
|
||||
requestNewIfNotFound = true; // it's not a new session
|
||||
session = nullptr;
|
||||
}
|
||||
}
|
||||
if (!session)
|
||||
if (!session && requestNewIfNotFound)
|
||||
{
|
||||
session = std::make_shared<ECIESX25519AEADRatchetSession> (this, true);
|
||||
session->SetRemoteStaticKey (staticKey);
|
||||
}
|
||||
if (destination->IsDestination ())
|
||||
session->SetDestination (destination->GetIdentHash ()); // TODO: remove
|
||||
if (session && destination->IsDestination ())
|
||||
session->SetDestination (destination->GetIdentHash ()); // NS or NSR
|
||||
return session;
|
||||
}
|
||||
else
|
||||
@@ -887,8 +864,7 @@ namespace garlic
|
||||
}
|
||||
else
|
||||
{
|
||||
auto session = it->second.tagset->GetSession ();
|
||||
if (!session || session->IsTerminated())
|
||||
if (it->second.tagset->IsSessionTerminated ())
|
||||
{
|
||||
it = m_ECIESx25519Tags.erase (it);
|
||||
numExpiredTags++;
|
||||
@@ -899,8 +875,6 @@ namespace garlic
|
||||
}
|
||||
if (numExpiredTags > 0)
|
||||
LogPrint (eLogDebug, "Garlic: ", numExpiredTags, " ECIESx25519 tags expired for ", GetIdentHash().ToBase64 ());
|
||||
if (m_LastTagset && m_LastTagset->IsExpired (ts))
|
||||
m_LastTagset = nullptr;
|
||||
}
|
||||
|
||||
void GarlicDestination::RemoveDeliveryStatusSession (uint32_t msgID)
|
||||
@@ -934,7 +908,7 @@ namespace garlic
|
||||
}
|
||||
}
|
||||
|
||||
void GarlicDestination::SetLeaseSetUpdated ()
|
||||
void GarlicDestination::SetLeaseSetUpdated (bool post)
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_SessionsMutex);
|
||||
@@ -1037,9 +1011,7 @@ namespace garlic
|
||||
case eGarlicDeliveryTypeDestination:
|
||||
LogPrint (eLogDebug, "Garlic: Type destination");
|
||||
buf += 32; // TODO: check destination
|
||||
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||
[[fallthrough]];
|
||||
#endif
|
||||
// no break here
|
||||
case eGarlicDeliveryTypeLocal:
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -50,9 +50,9 @@ namespace garlic
|
||||
const int INCOMING_TAGS_EXPIRATION_TIMEOUT = 960; // 16 minutes
|
||||
const int OUTGOING_TAGS_EXPIRATION_TIMEOUT = 720; // 12 minutes
|
||||
const int OUTGOING_TAGS_CONFIRMATION_TIMEOUT = 10; // 10 seconds
|
||||
const int LEASET_CONFIRMATION_TIMEOUT = 4000; // in milliseconds
|
||||
const int ROUTING_PATH_EXPIRATION_TIMEOUT = 30; // 30 seconds
|
||||
const int ROUTING_PATH_MAX_NUM_TIMES_USED = 100; // how many times might be used
|
||||
const int LEASESET_CONFIRMATION_TIMEOUT = 4000; // in milliseconds
|
||||
const int ROUTING_PATH_EXPIRATION_TIMEOUT = 120; // in seconds
|
||||
const int INCOMING_SESSIONS_MINIMAL_INTERVAL = 200; // in milliseconds
|
||||
|
||||
struct SessionTag: public i2p::data::Tag<32>
|
||||
{
|
||||
@@ -89,7 +89,6 @@ namespace garlic
|
||||
std::shared_ptr<const i2p::data::Lease> remoteLease;
|
||||
int rtt; // RTT
|
||||
uint32_t updateTime; // seconds since epoch
|
||||
int numTimesUsed;
|
||||
};
|
||||
|
||||
class GarlicDestination;
|
||||
@@ -111,7 +110,7 @@ namespace garlic
|
||||
GarlicRoutingSession ();
|
||||
virtual ~GarlicRoutingSession ();
|
||||
virtual std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg) = 0;
|
||||
virtual bool CleanupUnconfirmedTags () { return false; }; // for I2CP, override in ElGamalAESSession
|
||||
virtual bool CleanupUnconfirmedTags () { return false; }; // for I2CP, override in ElGamalAESSession and ECIESX25519AEADRatchetSession
|
||||
virtual bool MessageConfirmed (uint32_t msgID);
|
||||
virtual bool IsRatchets () const { return false; };
|
||||
virtual bool IsReadyToSend () const { return true; };
|
||||
@@ -221,7 +220,7 @@ namespace garlic
|
||||
struct ECIESX25519AEADRatchetIndexTagset
|
||||
{
|
||||
int index;
|
||||
ReceiveRatchetTagSetPtr tagset;
|
||||
ReceiveRatchetTagSetPtr tagset; // null if used
|
||||
};
|
||||
|
||||
class GarlicDestination: public i2p::data::LocalDestination
|
||||
@@ -236,7 +235,8 @@ namespace garlic
|
||||
int GetNumTags () const { return m_NumTags; };
|
||||
void SetNumRatchetInboundTags (int numTags) { m_NumRatchetInboundTags = numTags; };
|
||||
int GetNumRatchetInboundTags () const { return m_NumRatchetInboundTags; };
|
||||
std::shared_ptr<GarlicRoutingSession> GetRoutingSession (std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet);
|
||||
std::shared_ptr<GarlicRoutingSession> GetRoutingSession (std::shared_ptr<const i2p::data::RoutingDestination> destination,
|
||||
bool attachLeaseSet, bool requestNewIfNotFound = true);
|
||||
void CleanupExpiredTags ();
|
||||
void RemoveDeliveryStatusSession (uint32_t msgID);
|
||||
std::shared_ptr<I2NPMessage> WrapMessageForRouter (std::shared_ptr<const i2p::data::RouterInfo> router,
|
||||
@@ -255,7 +255,7 @@ namespace garlic
|
||||
|
||||
virtual void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
virtual void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
virtual void SetLeaseSetUpdated ();
|
||||
virtual void SetLeaseSetUpdated (bool post = false);
|
||||
|
||||
virtual std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet () = 0; // TODO
|
||||
virtual std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const = 0;
|
||||
@@ -286,11 +286,11 @@ namespace garlic
|
||||
std::unordered_map<i2p::data::IdentHash, ElGamalAESSessionPtr> m_Sessions;
|
||||
std::unordered_map<i2p::data::Tag<32>, ECIESX25519AEADRatchetSessionPtr> m_ECIESx25519Sessions; // static key -> session
|
||||
uint8_t * m_PayloadBuffer; // for ECIESX25519AEADRatchet
|
||||
uint64_t m_LastIncomingSessionTimestamp; // in millseconds
|
||||
// incoming
|
||||
int m_NumRatchetInboundTags;
|
||||
std::unordered_map<SessionTag, std::shared_ptr<AESDecryption>, std::hash<i2p::data::Tag<32> > > m_Tags;
|
||||
std::unordered_map<uint64_t, ECIESX25519AEADRatchetIndexTagset> m_ECIESx25519Tags; // session tag -> session
|
||||
ReceiveRatchetTagSetPtr m_LastTagset; // tagset last message came for
|
||||
// DeliveryStatus
|
||||
std::mutex m_DeliveryStatusSessionsMutex;
|
||||
std::unordered_map<uint32_t, GarlicRoutingSessionPtr> m_DeliveryStatusSessions; // msgID -> session
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -40,12 +40,13 @@ namespace http
|
||||
inline bool is_http_method(const std::string & str) {
|
||||
return std::find(HTTP_METHODS.begin(), HTTP_METHODS.end(), str) != std::end(HTTP_METHODS);
|
||||
}
|
||||
|
||||
void strsplit(const std::string & line, std::vector<std::string> &tokens, char delim, std::size_t limit = 0) {
|
||||
|
||||
static void strsplit(std::stringstream& ss, std::vector<std::string> &tokens, char delim, std::size_t limit = 0)
|
||||
{
|
||||
std::size_t count = 0;
|
||||
std::stringstream ss(line);
|
||||
std::string token;
|
||||
while (1) {
|
||||
while (1)
|
||||
{
|
||||
count++;
|
||||
if (limit > 0 && count >= limit)
|
||||
delim = '\n'; /* reset delimiter */
|
||||
@@ -55,21 +56,33 @@ namespace http
|
||||
}
|
||||
}
|
||||
|
||||
static std::pair<std::string, std::string> parse_header_line(const std::string& line)
|
||||
static void strsplit(const std::string & line, std::vector<std::string> &tokens, char delim, std::size_t limit = 0)
|
||||
{
|
||||
std::stringstream ss{line};
|
||||
strsplit (ss, tokens, delim, limit);
|
||||
}
|
||||
|
||||
static void strsplit(std::string_view line, std::vector<std::string> &tokens, char delim, std::size_t limit = 0)
|
||||
{
|
||||
std::stringstream ss{std::string(line)};
|
||||
strsplit (ss, tokens, delim, limit);
|
||||
}
|
||||
|
||||
static std::pair<std::string, std::string> parse_header_line(std::string_view line)
|
||||
{
|
||||
std::size_t pos = 0;
|
||||
std::size_t len = 1; /*: */
|
||||
std::size_t max = line.length();
|
||||
if ((pos = line.find(':', pos)) == std::string::npos)
|
||||
return std::make_pair("", ""); // no ':' found
|
||||
return std::pair{"", ""}; // no ':' found
|
||||
if (pos + 1 < max) // ':' at the end of header is valid
|
||||
{
|
||||
while ((pos + len) < max && isspace(line.at(pos + len)))
|
||||
len++;
|
||||
if (len == 1)
|
||||
return std::make_pair("", ""); // no following space, but something else
|
||||
return std::pair{"", ""}; // no following space, but something else
|
||||
}
|
||||
return std::make_pair(line.substr(0, pos), line.substr(pos + len));
|
||||
return std::pair{std::string (line.substr(0, pos)), std::string (line.substr(pos + len))};
|
||||
}
|
||||
|
||||
void gen_rfc7231_date(std::string & out) {
|
||||
@@ -83,15 +96,18 @@ namespace http
|
||||
out = buf;
|
||||
}
|
||||
|
||||
bool URL::parse(const char *str, std::size_t len) {
|
||||
std::string url(str, len ? len : strlen(str));
|
||||
return parse(url);
|
||||
bool URL::parse(const char *str, std::size_t len)
|
||||
{
|
||||
return parse({str, len ? len : strlen(str)});
|
||||
}
|
||||
|
||||
bool URL::parse(const std::string& url) {
|
||||
bool URL::parse(std::string_view url)
|
||||
{
|
||||
if (url.empty ()) return false;
|
||||
std::size_t pos_p = 0; /* < current parse position */
|
||||
std::size_t pos_c = 0; /* < work position */
|
||||
if(url.at(0) != '/' || pos_p > 0) {
|
||||
if(url.at(0) != '/' || pos_p > 0)
|
||||
{
|
||||
std::size_t pos_s = 0;
|
||||
|
||||
/* schema */
|
||||
@@ -141,7 +157,7 @@ namespace http
|
||||
/* port[/path] */
|
||||
pos_p = pos_c + 1;
|
||||
pos_c = url.find('/', pos_p);
|
||||
std::string port_str = (pos_c == std::string::npos)
|
||||
std::string_view port_str = (pos_c == std::string::npos)
|
||||
? url.substr(pos_p, std::string::npos)
|
||||
: url.substr(pos_p, pos_c - pos_p);
|
||||
/* stoi throws exception on failure, we don't need it */
|
||||
@@ -253,7 +269,7 @@ namespace http
|
||||
return host.rfind(".i2p") == ( host.size() - 4 );
|
||||
}
|
||||
|
||||
void HTTPMsg::add_header(const char *name, std::string & value, bool replace) {
|
||||
void HTTPMsg::add_header(const char *name, const std::string & value, bool replace) {
|
||||
add_header(name, value.c_str(), replace);
|
||||
}
|
||||
|
||||
@@ -272,12 +288,13 @@ namespace http
|
||||
headers.erase(name);
|
||||
}
|
||||
|
||||
int HTTPReq::parse(const char *buf, size_t len) {
|
||||
std::string str(buf, len);
|
||||
return parse(str);
|
||||
int HTTPReq::parse(const char *buf, size_t len)
|
||||
{
|
||||
return parse({buf, len});
|
||||
}
|
||||
|
||||
int HTTPReq::parse(const std::string& str) {
|
||||
int HTTPReq::parse(std::string_view str)
|
||||
{
|
||||
enum { REQ_LINE, HEADER_LINE } expect = REQ_LINE;
|
||||
std::size_t eoh = str.find(HTTP_EOH); /* request head size */
|
||||
std::size_t eol = 0, pos = 0;
|
||||
@@ -286,9 +303,11 @@ namespace http
|
||||
if (eoh == std::string::npos)
|
||||
return 0; /* str not contains complete request */
|
||||
|
||||
while ((eol = str.find(CRLF, pos)) != std::string::npos) {
|
||||
if (expect == REQ_LINE) {
|
||||
std::string line = str.substr(pos, eol - pos);
|
||||
while ((eol = str.find(CRLF, pos)) != std::string::npos)
|
||||
{
|
||||
if (expect == REQ_LINE)
|
||||
{
|
||||
std::string_view line = str.substr(pos, eol - pos);
|
||||
std::vector<std::string> tokens;
|
||||
strsplit(line, tokens, ' ');
|
||||
if (tokens.size() != 3)
|
||||
@@ -307,7 +326,7 @@ namespace http
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string line = str.substr(pos, eol - pos);
|
||||
std::string_view line = str.substr(pos, eol - pos);
|
||||
auto p = parse_header_line(line);
|
||||
if (p.first.length () > 0)
|
||||
headers.push_back (p);
|
||||
@@ -413,12 +432,13 @@ namespace http
|
||||
return length;
|
||||
}
|
||||
|
||||
int HTTPRes::parse(const char *buf, size_t len) {
|
||||
std::string str(buf, len);
|
||||
return parse(str);
|
||||
int HTTPRes::parse(const char *buf, size_t len)
|
||||
{
|
||||
return parse({buf,len});
|
||||
}
|
||||
|
||||
int HTTPRes::parse(const std::string& str) {
|
||||
int HTTPRes::parse(std::string_view str)
|
||||
{
|
||||
enum { RES_LINE, HEADER_LINE } expect = RES_LINE;
|
||||
std::size_t eoh = str.find(HTTP_EOH); /* request head size */
|
||||
std::size_t eol = 0, pos = 0;
|
||||
@@ -426,9 +446,11 @@ namespace http
|
||||
if (eoh == std::string::npos)
|
||||
return 0; /* str not contains complete request */
|
||||
|
||||
while ((eol = str.find(CRLF, pos)) != std::string::npos) {
|
||||
if (expect == RES_LINE) {
|
||||
std::string line = str.substr(pos, eol - pos);
|
||||
while ((eol = str.find(CRLF, pos)) != std::string::npos)
|
||||
{
|
||||
if (expect == RES_LINE)
|
||||
{
|
||||
std::string_view line = str.substr(pos, eol - pos);
|
||||
std::vector<std::string> tokens;
|
||||
strsplit(line, tokens, ' ', 3);
|
||||
if (tokens.size() != 3)
|
||||
@@ -442,8 +464,10 @@ namespace http
|
||||
version = tokens[0];
|
||||
status = tokens[2];
|
||||
expect = HEADER_LINE;
|
||||
} else {
|
||||
std::string line = str.substr(pos, eol - pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string_view line = str.substr(pos, eol - pos);
|
||||
auto p = parse_header_line(line);
|
||||
if (p.first.length () > 0)
|
||||
headers.insert (p);
|
||||
@@ -508,14 +532,14 @@ namespace http
|
||||
return ptr;
|
||||
}
|
||||
|
||||
std::string UrlDecode(const std::string& data, bool allow_null)
|
||||
std::string UrlDecode(std::string_view data, bool allow_null)
|
||||
{
|
||||
std::string decoded(data);
|
||||
size_t pos = 0;
|
||||
while ((pos = decoded.find('%', pos)) != std::string::npos)
|
||||
{
|
||||
char c = strtol(decoded.substr(pos + 1, 2).c_str(), NULL, 16);
|
||||
if (c == '\0' && !allow_null)
|
||||
char c = std::stol(decoded.substr(pos + 1, 2), nullptr, 16);
|
||||
if (!c && !allow_null)
|
||||
{
|
||||
pos += 3;
|
||||
continue;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <list>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace i2p
|
||||
@@ -45,7 +46,7 @@ namespace http
|
||||
* @return true on success, false on invalid url
|
||||
*/
|
||||
bool parse (const char *str, std::size_t len = 0);
|
||||
bool parse (const std::string& url);
|
||||
bool parse (std::string_view url);
|
||||
|
||||
/**
|
||||
* @brief Parse query part of url to key/value map
|
||||
@@ -69,7 +70,7 @@ namespace http
|
||||
{
|
||||
std::map<std::string, std::string> headers;
|
||||
|
||||
void add_header(const char *name, std::string & value, bool replace = false);
|
||||
void add_header(const char *name, const std::string & value, bool replace = false);
|
||||
void add_header(const char *name, const char *value, bool replace = false);
|
||||
void del_header(const char *name);
|
||||
|
||||
@@ -92,7 +93,7 @@ namespace http
|
||||
* @note Positive return value is a size of header
|
||||
*/
|
||||
int parse(const char *buf, size_t len);
|
||||
int parse(const std::string& buf);
|
||||
int parse(std::string_view buf);
|
||||
|
||||
/** @brief Serialize HTTP request to string */
|
||||
std::string to_string();
|
||||
@@ -128,7 +129,7 @@ namespace http
|
||||
* @note Positive return value is a size of header
|
||||
*/
|
||||
int parse(const char *buf, size_t len);
|
||||
int parse(const std::string& buf);
|
||||
int parse(const std::string_view buf);
|
||||
|
||||
/**
|
||||
* @brief Serialize HTTP response to string
|
||||
@@ -161,7 +162,7 @@ namespace http
|
||||
* @param null If set to true - decode also %00 sequence, otherwise - skip
|
||||
* @return Decoded string
|
||||
*/
|
||||
std::string UrlDecode(const std::string& data, bool null = false);
|
||||
std::string UrlDecode(std::string_view data, bool null = false);
|
||||
|
||||
/**
|
||||
* @brief Merge HTTP response content with Transfer-Encoding: chunked
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -10,20 +10,15 @@
|
||||
#include <atomic>
|
||||
#include "Base.h"
|
||||
#include "Log.h"
|
||||
#include "Crypto.h"
|
||||
#include "I2PEndian.h"
|
||||
#include "Timestamp.h"
|
||||
#include "RouterContext.h"
|
||||
#include "NetDb.hpp"
|
||||
#include "Tunnel.h"
|
||||
#include "Transports.h"
|
||||
#include "Garlic.h"
|
||||
#include "ECIESX25519AEADRatchetSession.h"
|
||||
#include "TransitTunnel.h"
|
||||
#include "I2NPProtocol.h"
|
||||
#include "version.h"
|
||||
|
||||
using namespace i2p::transport;
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
std::shared_ptr<I2NPMessage> NewI2NPMessage ()
|
||||
@@ -72,11 +67,15 @@ namespace i2p
|
||||
SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + I2NP_MESSAGE_EXPIRATION_TIMEOUT);
|
||||
}
|
||||
|
||||
bool I2NPMessage::IsExpired () const
|
||||
bool I2NPMessage::IsExpired (uint64_t ts) const
|
||||
{
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
auto exp = GetExpiration ();
|
||||
return (ts > exp + I2NP_MESSAGE_CLOCK_SKEW) || (ts < exp - 3*I2NP_MESSAGE_CLOCK_SKEW); // check if expired or too far in future
|
||||
}
|
||||
|
||||
bool I2NPMessage::IsExpired () const
|
||||
{
|
||||
return IsExpired (i2p::util::GetMillisecondsSinceEpoch ());
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, size_t len, uint32_t replyMsgID)
|
||||
@@ -111,6 +110,17 @@ namespace i2p
|
||||
return newMsg;
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateTunnelTestMsg (uint32_t msgID)
|
||||
{
|
||||
auto m = NewI2NPShortMessage ();
|
||||
uint8_t * buf = m->GetPayload ();
|
||||
htobe32buf (buf + TUNNEL_TEST_MSGID_OFFSET, msgID);
|
||||
htobe64buf (buf + TUNNEL_TEST_TIMESTAMP_OFFSET, i2p::util::GetMonotonicMicroseconds ());
|
||||
m->len += TUNNEL_TEST_SIZE;
|
||||
m->FillI2NPMessageHeader (eI2NPTunnelTest);
|
||||
return m;
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID)
|
||||
{
|
||||
auto m = NewI2NPShortMessage ();
|
||||
@@ -132,7 +142,7 @@ namespace i2p
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
|
||||
uint32_t replyTunnelID, bool exploratory, std::set<i2p::data::IdentHash> * excludedPeers)
|
||||
uint32_t replyTunnelID, bool exploratory, std::unordered_set<i2p::data::IdentHash> * excludedPeers)
|
||||
{
|
||||
int cnt = excludedPeers ? excludedPeers->size () : 0;
|
||||
auto m = cnt > 7 ? NewI2NPMessage () : NewI2NPShortMessage ();
|
||||
@@ -177,7 +187,7 @@ namespace i2p
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
|
||||
const std::set<i2p::data::IdentHash>& excludedFloodfills,
|
||||
const std::unordered_set<i2p::data::IdentHash>& excludedFloodfills,
|
||||
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, const uint8_t * replyKey,
|
||||
const uint8_t * replyTag, bool replyECIES)
|
||||
{
|
||||
@@ -361,302 +371,6 @@ namespace i2p
|
||||
return !msg->GetPayload ()[DATABASE_STORE_TYPE_OFFSET]; // 0- RouterInfo
|
||||
}
|
||||
|
||||
static bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText)
|
||||
{
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
uint8_t * record = records + i*TUNNEL_BUILD_RECORD_SIZE;
|
||||
if (!memcmp (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)i2p::context.GetRouterInfo ().GetIdentHash (), 16))
|
||||
{
|
||||
LogPrint (eLogDebug, "I2NP: Build request record ", i, " is ours");
|
||||
if (!i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText)) return false;
|
||||
uint8_t retCode = 0;
|
||||
// replace record to reply
|
||||
if (i2p::context.AcceptsTunnels () && !i2p::context.IsHighCongestion ())
|
||||
{
|
||||
auto transitTunnel = i2p::tunnel::CreateTransitTunnel (
|
||||
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
|
||||
clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||
clearText + ECIES_BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET,
|
||||
clearText + ECIES_BUILD_REQUEST_RECORD_IV_KEY_OFFSET,
|
||||
clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG,
|
||||
clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG);
|
||||
if (!i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel))
|
||||
retCode = 30;
|
||||
}
|
||||
else
|
||||
retCode = 30; // always reject with bandwidth reason (30)
|
||||
|
||||
memset (record + ECIES_BUILD_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options
|
||||
record[ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET] = retCode;
|
||||
// encrypt reply
|
||||
i2p::crypto::CBCEncryption encryption;
|
||||
for (int j = 0; j < num; j++)
|
||||
{
|
||||
uint8_t * reply = records + j*TUNNEL_BUILD_RECORD_SIZE;
|
||||
if (j == i)
|
||||
{
|
||||
uint8_t nonce[12];
|
||||
memset (nonce, 0, 12);
|
||||
auto& noiseState = i2p::context.GetCurrentNoiseState ();
|
||||
if (!i2p::crypto::AEADChaCha20Poly1305 (reply, TUNNEL_BUILD_RECORD_SIZE - 16,
|
||||
noiseState.m_H, 32, noiseState.m_CK, nonce, reply, TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt
|
||||
{
|
||||
LogPrint (eLogWarning, "I2NP: Reply AEAD encryption failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
encryption.SetKey (clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET);
|
||||
encryption.SetIV (clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_IV_OFFSET);
|
||||
encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len)
|
||||
{
|
||||
int num = buf[0];
|
||||
LogPrint (eLogDebug, "I2NP: VariableTunnelBuild ", num, " records");
|
||||
if (num > i2p::tunnel::MAX_NUM_RECORDS)
|
||||
{
|
||||
LogPrint (eLogError, "I2NP: Too many records in VaribleTunnelBuild message ", num);
|
||||
return;
|
||||
}
|
||||
if (len < num*TUNNEL_BUILD_RECORD_SIZE + 1)
|
||||
{
|
||||
LogPrint (eLogError, "I2NP: VaribleTunnelBuild message of ", num, " records is too short ", len);
|
||||
return;
|
||||
}
|
||||
|
||||
auto tunnel = i2p::tunnel::tunnels.GetPendingInboundTunnel (replyMsgID);
|
||||
if (tunnel)
|
||||
{
|
||||
// endpoint of inbound tunnel
|
||||
LogPrint (eLogDebug, "I2NP: VariableTunnelBuild reply for tunnel ", tunnel->GetTunnelID ());
|
||||
if (tunnel->HandleTunnelBuildResponse (buf, len))
|
||||
{
|
||||
LogPrint (eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID (), " has been created");
|
||||
tunnel->SetState (i2p::tunnel::eTunnelStateEstablished);
|
||||
i2p::tunnel::tunnels.AddInboundTunnel (tunnel);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID (), " has been declined");
|
||||
tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t clearText[ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE];
|
||||
if (HandleBuildRequestRecords (num, buf + 1, clearText))
|
||||
{
|
||||
if (clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG) // we are endpoint of outboud tunnel
|
||||
{
|
||||
// so we send it to reply tunnel
|
||||
transports.SendMessage (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
CreateTunnelGatewayMsg (bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||
eI2NPVariableTunnelBuildReply, buf, len,
|
||||
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
}
|
||||
else
|
||||
transports.SendMessage (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len,
|
||||
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void HandleTunnelBuildMsg (uint8_t * buf, size_t len)
|
||||
{
|
||||
LogPrint (eLogWarning, "I2NP: TunnelBuild is too old for ECIES router");
|
||||
}
|
||||
|
||||
static void HandleTunnelBuildReplyMsg (uint32_t replyMsgID, uint8_t * buf, size_t len, bool isShort)
|
||||
{
|
||||
int num = buf[0];
|
||||
LogPrint (eLogDebug, "I2NP: TunnelBuildReplyMsg of ", num, " records replyMsgID=", replyMsgID);
|
||||
if (num > i2p::tunnel::MAX_NUM_RECORDS)
|
||||
{
|
||||
LogPrint (eLogError, "I2NP: Too many records in TunnelBuildReply message ", num);
|
||||
return;
|
||||
}
|
||||
size_t recordSize = isShort ? SHORT_TUNNEL_BUILD_RECORD_SIZE : TUNNEL_BUILD_RECORD_SIZE;
|
||||
if (len < num*recordSize + 1)
|
||||
{
|
||||
LogPrint (eLogError, "I2NP: TunnelBuildReply message of ", num, " records is too short ", len);
|
||||
return;
|
||||
}
|
||||
|
||||
auto tunnel = i2p::tunnel::tunnels.GetPendingOutboundTunnel (replyMsgID);
|
||||
if (tunnel)
|
||||
{
|
||||
// reply for outbound tunnel
|
||||
if (tunnel->HandleTunnelBuildResponse (buf, len))
|
||||
{
|
||||
LogPrint (eLogInfo, "I2NP: Outbound tunnel ", tunnel->GetTunnelID (), " has been created");
|
||||
tunnel->SetState (i2p::tunnel::eTunnelStateEstablished);
|
||||
i2p::tunnel::tunnels.AddOutboundTunnel (tunnel);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogInfo, "I2NP: Outbound tunnel ", tunnel->GetTunnelID (), " has been declined");
|
||||
tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed);
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "I2NP: Pending tunnel for message ", replyMsgID, " not found");
|
||||
}
|
||||
|
||||
static void HandleShortTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len)
|
||||
{
|
||||
int num = buf[0];
|
||||
LogPrint (eLogDebug, "I2NP: ShortTunnelBuild ", num, " records");
|
||||
if (num > i2p::tunnel::MAX_NUM_RECORDS)
|
||||
{
|
||||
LogPrint (eLogError, "I2NP: Too many records in ShortTunnelBuild message ", num);
|
||||
return;
|
||||
}
|
||||
if (len < num*SHORT_TUNNEL_BUILD_RECORD_SIZE + 1)
|
||||
{
|
||||
LogPrint (eLogError, "I2NP: ShortTunnelBuild message of ", num, " records is too short ", len);
|
||||
return;
|
||||
}
|
||||
auto tunnel = i2p::tunnel::tunnels.GetPendingInboundTunnel (replyMsgID);
|
||||
if (tunnel)
|
||||
{
|
||||
// endpoint of inbound tunnel
|
||||
LogPrint (eLogDebug, "I2NP: ShortTunnelBuild reply for tunnel ", tunnel->GetTunnelID ());
|
||||
if (tunnel->HandleTunnelBuildResponse (buf, len))
|
||||
{
|
||||
LogPrint (eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID (), " has been created");
|
||||
tunnel->SetState (i2p::tunnel::eTunnelStateEstablished);
|
||||
i2p::tunnel::tunnels.AddInboundTunnel (tunnel);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID (), " has been declined");
|
||||
tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const uint8_t * record = buf + 1;
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
if (!memcmp (record, (const uint8_t *)i2p::context.GetRouterInfo ().GetIdentHash (), 16))
|
||||
{
|
||||
LogPrint (eLogDebug, "I2NP: Short request record ", i, " is ours");
|
||||
uint8_t clearText[SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE];
|
||||
if (!i2p::context.DecryptTunnelShortRequestRecord (record + SHORT_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText))
|
||||
{
|
||||
LogPrint (eLogWarning, "I2NP: Can't decrypt short request record ", i);
|
||||
return;
|
||||
}
|
||||
if (clearText[SHORT_REQUEST_RECORD_LAYER_ENCRYPTION_TYPE]) // not AES
|
||||
{
|
||||
LogPrint (eLogWarning, "I2NP: Unknown layer encryption type ", clearText[SHORT_REQUEST_RECORD_LAYER_ENCRYPTION_TYPE], " in short request record");
|
||||
return;
|
||||
}
|
||||
auto& noiseState = i2p::context.GetCurrentNoiseState ();
|
||||
uint8_t replyKey[32]; // AEAD/Chacha20/Poly1305
|
||||
i2p::crypto::AESKey layerKey, ivKey; // AES
|
||||
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "SMTunnelReplyKey", noiseState.m_CK);
|
||||
memcpy (replyKey, noiseState.m_CK + 32, 32);
|
||||
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "SMTunnelLayerKey", noiseState.m_CK);
|
||||
memcpy (layerKey, noiseState.m_CK + 32, 32);
|
||||
bool isEndpoint = clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG;
|
||||
if (isEndpoint)
|
||||
{
|
||||
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "TunnelLayerIVKey", noiseState.m_CK);
|
||||
memcpy (ivKey, noiseState.m_CK + 32, 32);
|
||||
}
|
||||
else
|
||||
memcpy (ivKey, noiseState.m_CK , 32);
|
||||
|
||||
// check if we accept this tunnel
|
||||
uint8_t retCode = 0;
|
||||
if (!i2p::context.AcceptsTunnels () || i2p::context.IsHighCongestion ())
|
||||
retCode = 30;
|
||||
if (!retCode)
|
||||
{
|
||||
// create new transit tunnel
|
||||
auto transitTunnel = i2p::tunnel::CreateTransitTunnel (
|
||||
bufbe32toh (clearText + SHORT_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
|
||||
clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||
layerKey, ivKey,
|
||||
clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG,
|
||||
clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG);
|
||||
if (!i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel))
|
||||
retCode = 30;
|
||||
}
|
||||
|
||||
// encrypt reply
|
||||
uint8_t nonce[12];
|
||||
memset (nonce, 0, 12);
|
||||
uint8_t * reply = buf + 1;
|
||||
for (int j = 0; j < num; j++)
|
||||
{
|
||||
nonce[4] = j; // nonce is record #
|
||||
if (j == i)
|
||||
{
|
||||
memset (reply + SHORT_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options
|
||||
reply[SHORT_RESPONSE_RECORD_RET_OFFSET] = retCode;
|
||||
if (!i2p::crypto::AEADChaCha20Poly1305 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE - 16,
|
||||
noiseState.m_H, 32, replyKey, nonce, reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt
|
||||
{
|
||||
LogPrint (eLogWarning, "I2NP: Short reply AEAD encryption failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
i2p::crypto::ChaCha20 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, replyKey, nonce, reply);
|
||||
reply += SHORT_TUNNEL_BUILD_RECORD_SIZE;
|
||||
}
|
||||
// send reply
|
||||
if (isEndpoint)
|
||||
{
|
||||
auto replyMsg = NewI2NPShortMessage ();
|
||||
replyMsg->Concat (buf, len);
|
||||
replyMsg->FillI2NPMessageHeader (eI2NPShortTunnelBuildReply, bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET));
|
||||
if (memcmp ((const uint8_t *)i2p::context.GetIdentHash (),
|
||||
clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32)) // reply IBGW is not local?
|
||||
{
|
||||
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "RGarlicKeyAndTag", noiseState.m_CK);
|
||||
uint64_t tag;
|
||||
memcpy (&tag, noiseState.m_CK, 8);
|
||||
// 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)));
|
||||
}
|
||||
else
|
||||
{
|
||||
// IBGW is local
|
||||
uint32_t tunnelID = bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET);
|
||||
auto tunnel = i2p::tunnel::tunnels.GetTunnel (tunnelID);
|
||||
if (tunnel)
|
||||
tunnel->SendTunnelDataMsg (replyMsg);
|
||||
else
|
||||
LogPrint (eLogWarning, "I2NP: Tunnel ", tunnelID, " not found for short tunnel build reply");
|
||||
}
|
||||
}
|
||||
else
|
||||
transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
CreateI2NPMessage (eI2NPShortTunnelBuild, buf, len,
|
||||
bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
return;
|
||||
}
|
||||
record += SHORT_TUNNEL_BUILD_RECORD_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (const uint8_t * buf)
|
||||
{
|
||||
auto msg = NewI2NPTunnelMessage (false);
|
||||
@@ -710,7 +424,11 @@ namespace i2p
|
||||
return msg;
|
||||
}
|
||||
else
|
||||
return CreateTunnelGatewayMsg (tunnelID, msg->GetBuffer (), msg->GetLength ());
|
||||
{
|
||||
auto newMsg = CreateTunnelGatewayMsg (tunnelID, msg->GetBuffer (), msg->GetLength ());
|
||||
if (msg->onDrop) newMsg->onDrop = msg->onDrop;
|
||||
return newMsg;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType,
|
||||
@@ -748,41 +466,6 @@ namespace i2p
|
||||
return l;
|
||||
}
|
||||
|
||||
void HandleTunnelBuildI2NPMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
if (msg)
|
||||
{
|
||||
uint8_t typeID = msg->GetTypeID();
|
||||
uint32_t msgID = msg->GetMsgID();
|
||||
LogPrint (eLogDebug, "I2NP: Handling tunnel build message with len=", msg->GetLength(),", type=", (int)typeID, ", msgID=", (unsigned int)msgID);
|
||||
uint8_t * payload = msg->GetPayload();
|
||||
auto size = msg->GetPayloadLength();
|
||||
switch (typeID)
|
||||
{
|
||||
case eI2NPVariableTunnelBuild:
|
||||
HandleVariableTunnelBuildMsg (msgID, payload, size);
|
||||
break;
|
||||
case eI2NPShortTunnelBuild:
|
||||
HandleShortTunnelBuildMsg (msgID, payload, size);
|
||||
break;
|
||||
case eI2NPVariableTunnelBuildReply:
|
||||
HandleTunnelBuildReplyMsg (msgID, payload, size, false);
|
||||
break;
|
||||
case eI2NPShortTunnelBuildReply:
|
||||
HandleTunnelBuildReplyMsg (msgID, payload, size, true);
|
||||
break;
|
||||
case eI2NPTunnelBuild:
|
||||
HandleTunnelBuildMsg (payload, size);
|
||||
break;
|
||||
case eI2NPTunnelBuildReply:
|
||||
// TODO:
|
||||
break;
|
||||
default:
|
||||
LogPrint (eLogError, "I2NP: Unexpected message with type", (int)typeID, " during handling TBM; skipping");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HandleI2NPMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
if (msg)
|
||||
@@ -808,12 +491,14 @@ namespace i2p
|
||||
break;
|
||||
}
|
||||
case eI2NPDatabaseStore:
|
||||
case eI2NPDatabaseSearchReply:
|
||||
// forward to netDb if came directly or through exploratory tunnel as response to our request
|
||||
if (!msg->from || !msg->from->GetTunnelPool () || msg->from->GetTunnelPool ()->IsExploratory ())
|
||||
i2p::data::netdb.PostI2NPMsg (msg);
|
||||
break;
|
||||
|
||||
case eI2NPDatabaseSearchReply:
|
||||
if (!msg->from || !msg->from->GetTunnelPool () || msg->from->GetTunnelPool ()->IsExploratory ())
|
||||
i2p::data::netdb.PostDatabaseSearchReplyMsg (msg);
|
||||
break;
|
||||
case eI2NPDatabaseLookup:
|
||||
// forward to netDb if floodfill and came directly
|
||||
if (!msg->from && i2p::context.IsFloodfill ())
|
||||
@@ -827,6 +512,10 @@ namespace i2p
|
||||
i2p::context.ProcessDeliveryStatusMessage (msg);
|
||||
break;
|
||||
}
|
||||
case eI2NPTunnelTest:
|
||||
if (msg->from && msg->from->GetTunnelPool ())
|
||||
msg->from->GetTunnelPool ()->ProcessTunnelTest (msg);
|
||||
break;
|
||||
case eI2NPVariableTunnelBuild:
|
||||
case eI2NPTunnelBuild:
|
||||
case eI2NPShortTunnelBuild:
|
||||
@@ -872,14 +561,8 @@ namespace i2p
|
||||
void I2NPMessagesHandler::Flush ()
|
||||
{
|
||||
if (!m_TunnelMsgs.empty ())
|
||||
{
|
||||
i2p::tunnel::tunnels.PostTunnelData (m_TunnelMsgs);
|
||||
m_TunnelMsgs.clear ();
|
||||
}
|
||||
if (!m_TunnelGatewayMsgs.empty ())
|
||||
{
|
||||
i2p::tunnel::tunnels.PostTunnelData (m_TunnelGatewayMsgs);
|
||||
m_TunnelGatewayMsgs.clear ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -11,8 +11,10 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
#include <memory>
|
||||
#include <list>
|
||||
#include <functional>
|
||||
#include "Crypto.h"
|
||||
#include "I2PEndian.h"
|
||||
#include "Identity.h"
|
||||
@@ -47,6 +49,11 @@ namespace i2p
|
||||
const size_t DELIVERY_STATUS_TIMESTAMP_OFFSET = DELIVERY_STATUS_MSGID_OFFSET + 4;
|
||||
const size_t DELIVERY_STATUS_SIZE = DELIVERY_STATUS_TIMESTAMP_OFFSET + 8;
|
||||
|
||||
// TunnelTest
|
||||
const size_t TUNNEL_TEST_MSGID_OFFSET = 0;
|
||||
const size_t TUNNEL_TEST_TIMESTAMP_OFFSET = TUNNEL_TEST_MSGID_OFFSET + 4;
|
||||
const size_t TUNNEL_TEST_SIZE = TUNNEL_TEST_TIMESTAMP_OFFSET + 8;
|
||||
|
||||
// DatabaseStore
|
||||
const size_t DATABASE_STORE_KEY_OFFSET = 0;
|
||||
const size_t DATABASE_STORE_TYPE_OFFSET = DATABASE_STORE_KEY_OFFSET + 32;
|
||||
@@ -101,7 +108,6 @@ namespace i2p
|
||||
|
||||
enum I2NPMessageType
|
||||
{
|
||||
eI2NPDummyMsg = 0,
|
||||
eI2NPDatabaseStore = 1,
|
||||
eI2NPDatabaseLookup = 2,
|
||||
eI2NPDatabaseSearchReply = 3,
|
||||
@@ -115,7 +121,8 @@ namespace i2p
|
||||
eI2NPVariableTunnelBuild = 23,
|
||||
eI2NPVariableTunnelBuildReply = 24,
|
||||
eI2NPShortTunnelBuild = 25,
|
||||
eI2NPShortTunnelBuildReply = 26
|
||||
eI2NPShortTunnelBuildReply = 26,
|
||||
eI2NPTunnelTest = 231
|
||||
};
|
||||
|
||||
const uint8_t TUNNEL_BUILD_RECORD_GATEWAY_FLAG = 0x80;
|
||||
@@ -138,9 +145,16 @@ namespace tunnel
|
||||
class TunnelPool;
|
||||
}
|
||||
|
||||
const int CONGESTION_LEVEL_MEDIUM = 70;
|
||||
const int CONGESTION_LEVEL_HIGH = 90;
|
||||
const int CONGESTION_LEVEL_FULL = 100;
|
||||
|
||||
const size_t I2NP_MAX_MESSAGE_SIZE = 62708;
|
||||
const size_t I2NP_MAX_SHORT_MESSAGE_SIZE = 4096;
|
||||
const size_t I2NP_MAX_MEDIUM_MESSAGE_SIZE = 16384;
|
||||
const unsigned int I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_FACTOR = 3; // multiples of RTT
|
||||
const unsigned int I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_MIN = 200000; // in microseconds
|
||||
const unsigned int I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_MAX = 2000000; // in microseconds
|
||||
const unsigned int I2NP_MESSAGE_EXPIRATION_TIMEOUT = 8000; // in milliseconds (as initial RTT)
|
||||
const unsigned int I2NP_MESSAGE_CLOCK_SKEW = 60*1000; // 1 minute in milliseconds
|
||||
|
||||
@@ -149,9 +163,11 @@ namespace tunnel
|
||||
uint8_t * buf;
|
||||
size_t len, offset, maxLen;
|
||||
std::shared_ptr<i2p::tunnel::InboundTunnel> from;
|
||||
std::function<void ()> onDrop;
|
||||
uint64_t enqueueTime; // monotonic microseconds
|
||||
|
||||
I2NPMessage (): buf (nullptr),len (I2NP_HEADER_SIZE + 2),
|
||||
offset(2), maxLen (0), from (nullptr) {}; // reserve 2 bytes for NTCP header
|
||||
I2NPMessage (): buf (nullptr), len (I2NP_HEADER_SIZE + 2),
|
||||
offset(2), maxLen (0), from (nullptr), enqueueTime (0) {}; // reserve 2 bytes for NTCP header
|
||||
|
||||
// header accessors
|
||||
uint8_t * GetHeader () { return GetBuffer (); };
|
||||
@@ -161,7 +177,9 @@ namespace tunnel
|
||||
void SetMsgID (uint32_t msgID) { htobe32buf (GetHeader () + I2NP_HEADER_MSGID_OFFSET, msgID); };
|
||||
uint32_t GetMsgID () const { return bufbe32toh (GetHeader () + I2NP_HEADER_MSGID_OFFSET); };
|
||||
void SetExpiration (uint64_t expiration) { htobe64buf (GetHeader () + I2NP_HEADER_EXPIRATION_OFFSET, expiration); };
|
||||
void SetEnqueueTime (uint64_t mts) { enqueueTime = mts; };
|
||||
uint64_t GetExpiration () const { return bufbe64toh (GetHeader () + I2NP_HEADER_EXPIRATION_OFFSET); };
|
||||
uint64_t GetEnqueueTime () const { return enqueueTime; };
|
||||
void SetSize (uint16_t size) { htobe16buf (GetHeader () + I2NP_HEADER_SIZE_OFFSET, size); };
|
||||
uint16_t GetSize () const { return bufbe16toh (GetHeader () + I2NP_HEADER_SIZE_OFFSET); };
|
||||
void UpdateSize () { SetSize (GetPayloadLength ()); };
|
||||
@@ -241,7 +259,6 @@ namespace tunnel
|
||||
SetSize (len - offset - I2NP_HEADER_SIZE);
|
||||
SetChks (0);
|
||||
}
|
||||
|
||||
void ToNTCP2 ()
|
||||
{
|
||||
uint8_t * ntcp2 = GetNTCP2Header ();
|
||||
@@ -252,6 +269,9 @@ namespace tunnel
|
||||
void FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID = 0, bool checksum = true);
|
||||
void RenewI2NPMessageHeader ();
|
||||
bool IsExpired () const;
|
||||
bool IsExpired (uint64_t ts) const; // in milliseconds
|
||||
|
||||
void Drop () { if (onDrop) { onDrop (); onDrop = nullptr; }; }
|
||||
};
|
||||
|
||||
template<int sz>
|
||||
@@ -271,11 +291,12 @@ namespace tunnel
|
||||
std::shared_ptr<I2NPMessage> CreateI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from = nullptr);
|
||||
std::shared_ptr<I2NPMessage> CopyI2NPMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateTunnelTestMsg (uint32_t msgID);
|
||||
std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID);
|
||||
std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
|
||||
uint32_t replyTunnelID, bool exploratory = false, std::set<i2p::data::IdentHash> * excludedPeers = nullptr);
|
||||
uint32_t replyTunnelID, bool exploratory = false, std::unordered_set<i2p::data::IdentHash> * excludedPeers = nullptr);
|
||||
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
|
||||
const std::set<i2p::data::IdentHash>& excludedFloodfills,
|
||||
const std::unordered_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<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector<i2p::data::IdentHash> routers);
|
||||
@@ -295,7 +316,6 @@ namespace tunnel
|
||||
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
size_t GetI2NPMessageLength (const uint8_t * msg, size_t len);
|
||||
void HandleTunnelBuildI2NPMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
void HandleI2NPMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
class I2NPMessagesHandler
|
||||
@@ -308,7 +328,7 @@ namespace tunnel
|
||||
|
||||
private:
|
||||
|
||||
std::vector<std::shared_ptr<I2NPMessage> > m_TunnelMsgs, m_TunnelGatewayMsgs;
|
||||
std::list<std::shared_ptr<I2NPMessage> > m_TunnelMsgs, m_TunnelGatewayMsgs;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -420,6 +420,14 @@ namespace data
|
||||
return CreateEncryptor (GetCryptoKeyType (), key);
|
||||
}
|
||||
|
||||
size_t GetIdentityBufferLen (const uint8_t * buf, size_t len)
|
||||
{
|
||||
if (len < DEFAULT_IDENTITY_SIZE) return 0;
|
||||
size_t l = DEFAULT_IDENTITY_SIZE + bufbe16toh (buf + DEFAULT_IDENTITY_SIZE - 2);
|
||||
if (l > len) return 0;
|
||||
return l;
|
||||
}
|
||||
|
||||
PrivateKeys& PrivateKeys::operator=(const Keys& keys)
|
||||
{
|
||||
m_Public = std::make_shared<IdentityEx>(Identity (keys));
|
||||
@@ -479,7 +487,12 @@ namespace data
|
||||
{
|
||||
// offline information
|
||||
const uint8_t * offlineInfo = buf + ret;
|
||||
ret += 4; // expires timestamp
|
||||
uint32_t expires = bufbe32toh (buf + ret); ret += 4; // expires timestamp
|
||||
if (expires < i2p::util::GetSecondsSinceEpoch ())
|
||||
{
|
||||
LogPrint (eLogError, "Identity: Offline signature expired");
|
||||
return 0;
|
||||
}
|
||||
SigningKeyType keyType = bufbe16toh (buf + ret); ret += 2; // key type
|
||||
std::unique_ptr<i2p::crypto::Verifier> transientVerifier (IdentityEx::CreateVerifier (keyType));
|
||||
if (!transientVerifier) return 0;
|
||||
@@ -790,11 +803,14 @@ namespace data
|
||||
return keys;
|
||||
}
|
||||
|
||||
IdentHash CreateRoutingKey (const IdentHash& ident)
|
||||
IdentHash CreateRoutingKey (const IdentHash& ident, bool nextDay)
|
||||
{
|
||||
uint8_t buf[41]; // ident + yyyymmdd
|
||||
memcpy (buf, (const uint8_t *)ident, 32);
|
||||
i2p::util::GetCurrentDate ((char *)(buf + 32));
|
||||
if (nextDay)
|
||||
i2p::util::GetNextDayDate ((char *)(buf + 32));
|
||||
else
|
||||
i2p::util::GetCurrentDate ((char *)(buf + 32));
|
||||
IdentHash key;
|
||||
SHA256(buf, 40, key);
|
||||
return key;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -136,6 +136,8 @@ namespace data
|
||||
uint8_t m_ExtendedBuffer[MAX_EXTENDED_BUFFER_SIZE];
|
||||
};
|
||||
|
||||
size_t GetIdentityBufferLen (const uint8_t * buf, size_t len); // return actual identity length in buffer
|
||||
|
||||
class PrivateKeys // for eepsites
|
||||
{
|
||||
public:
|
||||
@@ -206,7 +208,7 @@ namespace data
|
||||
bool operator< (const XORMetric& other) const { return memcmp (metric, other.metric, 32) < 0; };
|
||||
};
|
||||
|
||||
IdentHash CreateRoutingKey (const IdentHash& ident);
|
||||
IdentHash CreateRoutingKey (const IdentHash& ident, bool nextDay = false);
|
||||
XORMetric operator^(const IdentHash& key1, const IdentHash& key2);
|
||||
|
||||
// destination for delivery instructions
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -425,6 +425,16 @@ namespace data
|
||||
if (offset + 1 > len) return 0;
|
||||
int numLeases = buf[offset]; offset++;
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
if (GetExpirationTime () > ts + LEASESET_EXPIRATION_TIME_THRESHOLD)
|
||||
{
|
||||
LogPrint (eLogWarning, "LeaseSet2: Expiration time is from future ", GetExpirationTime ()/1000LL);
|
||||
return 0;
|
||||
}
|
||||
if (ts > m_PublishedTimestamp*1000LL + LEASESET_EXPIRATION_TIME_THRESHOLD)
|
||||
{
|
||||
LogPrint (eLogWarning, "LeaseSet2: Published time is too old ", m_PublishedTimestamp);
|
||||
return 0;
|
||||
}
|
||||
if (IsStoreLeases ())
|
||||
{
|
||||
UpdateLeasesBegin ();
|
||||
@@ -435,6 +445,11 @@ namespace data
|
||||
lease.tunnelGateway = buf + offset; offset += 32; // gateway
|
||||
lease.tunnelID = bufbe32toh (buf + offset); offset += 4; // tunnel ID
|
||||
lease.endDate = bufbe32toh (buf + offset)*1000LL; offset += 4; // end date
|
||||
if (lease.endDate > ts + LEASESET_EXPIRATION_TIME_THRESHOLD)
|
||||
{
|
||||
LogPrint (eLogWarning, "LeaseSet2: Lease end date is from future ", lease.endDate);
|
||||
return 0;
|
||||
}
|
||||
UpdateLease (lease, ts);
|
||||
}
|
||||
UpdateLeasesEnd ();
|
||||
@@ -728,25 +743,41 @@ namespace data
|
||||
memset (m_Buffer + offset, 0, signingKeyLen);
|
||||
offset += signingKeyLen;
|
||||
// num leases
|
||||
auto numLeasesPos = offset;
|
||||
m_Buffer[offset] = num;
|
||||
offset++;
|
||||
// leases
|
||||
m_Leases = m_Buffer + offset;
|
||||
auto currentTime = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
int skipped = 0;
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
uint64_t ts = tunnels[i]->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD; // 1 minute before expiration
|
||||
ts *= 1000; // in milliseconds
|
||||
if (ts <= currentTime)
|
||||
{
|
||||
// already expired, skip
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
if (ts > m_ExpirationTime) m_ExpirationTime = ts;
|
||||
// make sure leaseset is newer than previous, but adding some time to expiration date
|
||||
ts += (currentTime - tunnels[i]->GetCreationTime ()*1000LL)*2/i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT; // up to 2 secs
|
||||
memcpy (m_Buffer + offset, tunnels[i]->GetNextIdentHash (), 32);
|
||||
offset += 32; // gateway id
|
||||
htobe32buf (m_Buffer + offset, tunnels[i]->GetNextTunnelID ());
|
||||
offset += 4; // tunnel id
|
||||
uint64_t ts = tunnels[i]->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD; // 1 minute before expiration
|
||||
ts *= 1000; // in milliseconds
|
||||
if (ts > m_ExpirationTime) m_ExpirationTime = ts;
|
||||
// make sure leaseset is newer than previous, but adding some time to expiration date
|
||||
ts += (currentTime - tunnels[i]->GetCreationTime ()*1000LL)*2/i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT; // up to 2 secs
|
||||
htobe64buf (m_Buffer + offset, ts);
|
||||
offset += 8; // end date
|
||||
}
|
||||
if (skipped > 0)
|
||||
{
|
||||
// adjust num leases
|
||||
if (skipped > num) skipped = num;
|
||||
num -= skipped;
|
||||
m_BufferLen -= skipped*LEASE_SIZE;
|
||||
m_Buffer[numLeasesPos] = num;
|
||||
}
|
||||
// we don't sign it yet. must be signed later on
|
||||
}
|
||||
|
||||
@@ -808,7 +839,7 @@ namespace data
|
||||
|
||||
LocalLeaseSet2::LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys,
|
||||
const KeySections& encryptionKeys, const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> >& tunnels,
|
||||
bool isPublic, bool isPublishedEncrypted):
|
||||
bool isPublic, uint64_t publishedTimestamp, bool isPublishedEncrypted):
|
||||
LocalLeaseSet (keys.GetPublic (), nullptr, 0)
|
||||
{
|
||||
auto identity = keys.GetPublic ();
|
||||
@@ -837,8 +868,7 @@ namespace data
|
||||
m_Buffer[0] = storeType;
|
||||
// LS2 header
|
||||
auto offset = identity->ToBuffer (m_Buffer + 1, m_BufferLen) + 1;
|
||||
auto timestamp = i2p::util::GetSecondsSinceEpoch ();
|
||||
htobe32buf (m_Buffer + offset, timestamp); offset += 4; // published timestamp (seconds)
|
||||
htobe32buf (m_Buffer + offset, publishedTimestamp); offset += 4; // published timestamp (seconds)
|
||||
uint8_t * expiresBuf = m_Buffer + offset; offset += 2; // expires, fill later
|
||||
htobe16buf (m_Buffer + offset, flags); offset += 2; // flags
|
||||
if (keys.IsOfflineSignature ())
|
||||
@@ -859,29 +889,44 @@ namespace data
|
||||
}
|
||||
// leases
|
||||
uint32_t expirationTime = 0; // in seconds
|
||||
int skipped = 0; auto numLeasesPos = offset;
|
||||
m_Buffer[offset] = num; offset++; // num leases
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
auto ts = tunnels[i]->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD; // in seconds, 1 minute before expiration
|
||||
if (ts <= publishedTimestamp)
|
||||
{
|
||||
// already expired, skip
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
if (ts > expirationTime) expirationTime = ts;
|
||||
memcpy (m_Buffer + offset, tunnels[i]->GetNextIdentHash (), 32);
|
||||
offset += 32; // gateway id
|
||||
htobe32buf (m_Buffer + offset, tunnels[i]->GetNextTunnelID ());
|
||||
offset += 4; // tunnel id
|
||||
auto ts = tunnels[i]->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD; // in seconds, 1 minute before expiration
|
||||
if (ts > expirationTime) expirationTime = ts;
|
||||
htobe32buf (m_Buffer + offset, ts);
|
||||
offset += 4; // end date
|
||||
}
|
||||
if (skipped > 0)
|
||||
{
|
||||
// adjust num leases
|
||||
if (skipped > num) skipped = num;
|
||||
num -= skipped;
|
||||
m_BufferLen -= skipped*LEASE2_SIZE;
|
||||
m_Buffer[numLeasesPos] = num;
|
||||
}
|
||||
// update expiration
|
||||
if (expirationTime)
|
||||
{
|
||||
SetExpirationTime (expirationTime*1000LL);
|
||||
auto expires = (int)expirationTime - timestamp;
|
||||
auto expires = (int)expirationTime - publishedTimestamp;
|
||||
htobe16buf (expiresBuf, expires > 0 ? expires : 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no tunnels or withdraw
|
||||
SetExpirationTime (timestamp*1000LL);
|
||||
SetExpirationTime (publishedTimestamp*1000LL);
|
||||
memset (expiresBuf, 0, 2); // expires immeditely
|
||||
}
|
||||
// sign
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -62,7 +62,8 @@ namespace data
|
||||
const size_t LEASE_SIZE = 44; // 32 + 4 + 8
|
||||
const size_t LEASE2_SIZE = 40; // 32 + 4 + 4
|
||||
const uint8_t MAX_NUM_LEASES = 16;
|
||||
|
||||
const uint64_t LEASESET_EXPIRATION_TIME_THRESHOLD = 12*60*1000; // in milliseconds
|
||||
|
||||
const uint8_t NETDB_STORE_TYPE_LEASESET = 1;
|
||||
class LeaseSet: public RoutingDestination
|
||||
{
|
||||
@@ -180,7 +181,7 @@ namespace data
|
||||
private:
|
||||
|
||||
uint8_t m_StoreType;
|
||||
uint32_t m_PublishedTimestamp = 0;
|
||||
uint32_t m_PublishedTimestamp = 0; // seconds
|
||||
bool m_IsPublic = true, m_IsPublishedEncrypted = false;
|
||||
std::shared_ptr<i2p::crypto::Verifier> m_TransientVerifier;
|
||||
CryptoKeyType m_EncryptionType;
|
||||
@@ -256,7 +257,8 @@ namespace data
|
||||
LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys,
|
||||
const KeySections& encryptionKeys,
|
||||
const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> >& tunnels,
|
||||
bool isPublic, bool isPublishedEncrypted = false);
|
||||
bool isPublic, uint64_t publishedTimestamp,
|
||||
bool isPublishedEncrypted = false);
|
||||
|
||||
LocalLeaseSet2 (uint8_t storeType, std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len); // from I2CP
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -87,8 +87,8 @@ namespace log {
|
||||
Log ();
|
||||
~Log ();
|
||||
|
||||
LogType GetLogType () { return m_Destination; };
|
||||
LogLevel GetLogLevel () { return m_MinLevel; };
|
||||
LogType GetLogType () const { return m_Destination; };
|
||||
LogLevel GetLogLevel () const { return m_MinLevel; };
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
@@ -160,6 +160,11 @@ namespace log {
|
||||
} // log
|
||||
} // i2p
|
||||
|
||||
inline bool CheckLogLevel (LogLevel level) noexcept
|
||||
{
|
||||
return level <= i2p::log::Logger().GetLogLevel ();
|
||||
}
|
||||
|
||||
/** internal usage only -- folding args array to single string */
|
||||
template<typename TValue>
|
||||
void LogPrint (std::stringstream& s, TValue&& arg) noexcept
|
||||
@@ -167,16 +172,6 @@ void LogPrint (std::stringstream& s, TValue&& arg) noexcept
|
||||
s << std::forward<TValue>(arg);
|
||||
}
|
||||
|
||||
#if (__cplusplus < 201703L) // below C++ 17
|
||||
/** internal usage only -- folding args array to single string */
|
||||
template<typename TValue, typename... TArgs>
|
||||
void LogPrint (std::stringstream& s, TValue&& arg, TArgs&&... args) noexcept
|
||||
{
|
||||
LogPrint (s, std::forward<TValue>(arg));
|
||||
LogPrint (s, std::forward<TArgs>(args)...);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Create log message and send it to queue
|
||||
* @param level Message level (eLogError, eLogInfo, ...)
|
||||
@@ -185,22 +180,14 @@ void LogPrint (std::stringstream& s, TValue&& arg, TArgs&&... args) noexcept
|
||||
template<typename... TArgs>
|
||||
void LogPrint (LogLevel level, TArgs&&... args) noexcept
|
||||
{
|
||||
i2p::log::Log &log = i2p::log::Logger();
|
||||
if (level > log.GetLogLevel ())
|
||||
return;
|
||||
if (!CheckLogLevel (level)) return;
|
||||
|
||||
// fold message to single string
|
||||
std::stringstream ss;
|
||||
|
||||
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||
(LogPrint (ss, std::forward<TArgs>(args)), ...);
|
||||
#else
|
||||
LogPrint (ss, std::forward<TArgs>(args)...);
|
||||
#endif
|
||||
|
||||
auto msg = std::make_shared<i2p::log::LogMsg>(level, std::time(nullptr), std::move(ss).str());
|
||||
msg->tid = std::this_thread::get_id();
|
||||
log.Append(msg);
|
||||
i2p::log::Logger().Append(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -214,11 +201,7 @@ void ThrowFatal (TArgs&&... args) noexcept
|
||||
if (!f) return;
|
||||
// fold message to single string
|
||||
std::stringstream ss("");
|
||||
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||
(LogPrint (ss, std::forward<TArgs>(args)), ...);
|
||||
#else
|
||||
LogPrint (ss, std::forward<TArgs>(args)...);
|
||||
#endif
|
||||
f (ss.str ());
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <array>
|
||||
#include <random>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <boost/asio.hpp>
|
||||
@@ -28,14 +29,17 @@ namespace transport
|
||||
{
|
||||
|
||||
const size_t NTCP2_UNENCRYPTED_FRAME_MAX_SIZE = 65519;
|
||||
const size_t NTCP2_SEND_AFTER_FRAME_SIZE = 16386; // send frame when exceeds this size
|
||||
const size_t NTCP2_SESSION_REQUEST_MAX_SIZE = 287;
|
||||
const size_t NTCP2_SESSION_CREATED_MAX_SIZE = 287;
|
||||
const int NTCP2_MAX_PADDING_RATIO = 6; // in %
|
||||
|
||||
const int NTCP2_CONNECT_TIMEOUT = 5; // 5 seconds
|
||||
const int NTCP2_ESTABLISH_TIMEOUT = 10; // 10 seconds
|
||||
const int NTCP2_TERMINATION_TIMEOUT = 120; // 2 minutes
|
||||
const int NTCP2_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds
|
||||
const int NTCP2_TERMINATION_TIMEOUT = 115; // 2 minutes - 5 seconds
|
||||
const int NTCP2_TERMINATION_TIMEOUT_VARIANCE = 10; // 10 seconds
|
||||
const int NTCP2_TERMINATION_CHECK_TIMEOUT = 28; // 28 seconds
|
||||
const int NTCP2_TERMINATION_CHECK_TIMEOUT_VARIANCE = 5; // 5 seconds
|
||||
const int NTCP2_RECEIVE_BUFFER_DELETION_TIMEOUT = 3; // 3 seconds
|
||||
const int NTCP2_ROUTERINFO_RESEND_INTERVAL = 25*60; // 25 minuntes in seconds
|
||||
const int NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD = 25*60; // 25 minuntes
|
||||
@@ -91,21 +95,21 @@ namespace transport
|
||||
const uint8_t * GetCK () const { return m_CK; };
|
||||
const uint8_t * GetH () const { return m_H; };
|
||||
|
||||
void KDF1Alice ();
|
||||
void KDF1Bob ();
|
||||
void KDF2Alice ();
|
||||
void KDF2Bob ();
|
||||
void KDF3Alice (); // for SessionConfirmed part 2
|
||||
void KDF3Bob ();
|
||||
bool KDF1Alice ();
|
||||
bool KDF1Bob ();
|
||||
bool KDF2Alice ();
|
||||
bool KDF2Bob ();
|
||||
bool KDF3Alice (); // for SessionConfirmed part 2
|
||||
bool KDF3Bob ();
|
||||
|
||||
void KeyDerivationFunction1 (const uint8_t * pub, i2p::crypto::X25519Keys& priv, const uint8_t * rs, const uint8_t * epub); // for SessionRequest, (pub, priv) for DH
|
||||
void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub); // for SessionCreate
|
||||
bool KeyDerivationFunction1 (const uint8_t * pub, i2p::crypto::X25519Keys& priv, const uint8_t * rs, const uint8_t * epub); // for SessionRequest, (pub, priv) for DH
|
||||
bool KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub); // for SessionCreate
|
||||
void CreateEphemeralKey ();
|
||||
|
||||
void CreateSessionRequestMessage ();
|
||||
void CreateSessionCreatedMessage ();
|
||||
bool CreateSessionRequestMessage (std::mt19937& rng);
|
||||
bool CreateSessionCreatedMessage (std::mt19937& rng);
|
||||
void CreateSessionConfirmedMessagePart1 (const uint8_t * nonce);
|
||||
void CreateSessionConfirmedMessagePart2 (const uint8_t * nonce);
|
||||
bool CreateSessionConfirmedMessagePart2 (const uint8_t * nonce);
|
||||
|
||||
bool ProcessSessionRequestMessage (uint16_t& paddingLen, bool& clockSkew);
|
||||
bool ProcessSessionCreatedMessage (uint16_t& paddingLen);
|
||||
@@ -149,8 +153,9 @@ namespace transport
|
||||
void ServerLogin (); // Bob
|
||||
|
||||
void SendLocalRouterInfo (bool update) override; // after handshake or by update
|
||||
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) override;
|
||||
|
||||
void SendI2NPMessages (std::list<std::shared_ptr<I2NPMessage> >& msgs) override;
|
||||
void MoveSendQueue (std::shared_ptr<NTCP2Session> other);
|
||||
|
||||
private:
|
||||
|
||||
void Established ();
|
||||
@@ -167,13 +172,17 @@ namespace transport
|
||||
|
||||
void HandleSessionRequestSent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||
void HandleSessionRequestReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||
void ProcessSessionRequest (size_t len);
|
||||
void HandleSessionRequestPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||
void HandleSessionCreatedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||
void HandleSessionCreatedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||
void ProcessSessionCreated (size_t len);
|
||||
void HandleSessionCreatedPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||
void HandleSessionConfirmedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||
void HandleSessionConfirmedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||
|
||||
void ProcessSessionConfirmed ();
|
||||
void EstablishSessionAfterSessionConfirmed (std::shared_ptr<std::vector<uint8_t> > buf, size_t size);
|
||||
|
||||
// data
|
||||
void ReceiveLength ();
|
||||
void HandleReceivedLength (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||
@@ -191,7 +200,7 @@ namespace transport
|
||||
void SendRouterInfo ();
|
||||
void SendTermination (NTCP2TerminationReason reason);
|
||||
void SendTerminationAndTerminate (NTCP2TerminationReason reason);
|
||||
void PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs);
|
||||
void PostI2NPMessages ();
|
||||
|
||||
private:
|
||||
|
||||
@@ -224,13 +233,28 @@ namespace transport
|
||||
bool m_IsSending, m_IsReceiving;
|
||||
std::list<std::shared_ptr<I2NPMessage> > m_SendQueue;
|
||||
uint64_t m_NextRouterInfoResendTime; // seconds since epoch
|
||||
|
||||
|
||||
std::list<std::shared_ptr<I2NPMessage> > m_IntermediateQueue; // from transports
|
||||
mutable std::mutex m_IntermediateQueueMutex;
|
||||
|
||||
uint16_t m_PaddingSizes[16];
|
||||
int m_NextPaddingSize;
|
||||
};
|
||||
|
||||
class NTCP2Server: private i2p::util::RunnableServiceWithWork
|
||||
{
|
||||
private:
|
||||
|
||||
class EstablisherService: public i2p::util::RunnableServiceWithWork
|
||||
{
|
||||
public:
|
||||
|
||||
EstablisherService (): RunnableServiceWithWork ("NTCP2e") {};
|
||||
auto& GetService () { return GetIOService (); };
|
||||
void Start () { StartIOService (); };
|
||||
void Stop () { StopIOService (); };
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
enum ProxyType
|
||||
@@ -239,13 +263,15 @@ namespace transport
|
||||
eSocksProxy,
|
||||
eHTTPProxy
|
||||
};
|
||||
|
||||
|
||||
NTCP2Server ();
|
||||
~NTCP2Server ();
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
boost::asio::io_service& GetService () { return GetIOService (); };
|
||||
auto& GetService () { return GetIOService (); };
|
||||
auto& GetEstablisherService () { return m_EstablisherService.GetService (); };
|
||||
std::mt19937& GetRng () { return m_Rng; };
|
||||
|
||||
bool AddNTCP2Session (std::shared_ptr<NTCP2Session> session, bool incoming = false);
|
||||
void RemoveNTCP2Session (std::shared_ptr<NTCP2Session> session);
|
||||
@@ -266,8 +292,7 @@ namespace transport
|
||||
|
||||
void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer);
|
||||
void HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer);
|
||||
void AfterSocksHandshake(std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer);
|
||||
|
||||
|
||||
// timer
|
||||
void ScheduleTermination ();
|
||||
void HandleTerminationTimer (const boost::system::error_code& ecode);
|
||||
@@ -285,7 +310,9 @@ namespace transport
|
||||
boost::asio::ip::tcp::resolver m_Resolver;
|
||||
std::unique_ptr<boost::asio::ip::tcp::endpoint> m_ProxyEndpoint;
|
||||
std::shared_ptr<boost::asio::ip::tcp::endpoint> m_Address4, m_Address6, m_YggdrasilAddress;
|
||||
|
||||
std::mt19937 m_Rng;
|
||||
EstablisherService m_EstablisherService;
|
||||
|
||||
public:
|
||||
|
||||
// for HTTP/I2PControl
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -10,11 +10,12 @@
|
||||
#define NETDB_H__
|
||||
// this file is called NetDb.hpp to resolve conflict with libc's netdb.h on case insensitive fs
|
||||
#include <inttypes.h>
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <future>
|
||||
|
||||
#include "Base.h"
|
||||
#include "Gzip.h"
|
||||
@@ -38,16 +39,24 @@ namespace data
|
||||
{
|
||||
const int NETDB_MIN_ROUTERS = 90;
|
||||
const int NETDB_MIN_FLOODFILLS = 5;
|
||||
const int NETDB_NUM_FLOODFILLS_THRESHOLD = 1500;
|
||||
const int NETDB_MIN_TRANSPORTS = 10 ; // otherwise assume offline
|
||||
const int NETDB_NUM_FLOODFILLS_THRESHOLD = 1200;
|
||||
const int NETDB_NUM_ROUTERS_THRESHOLD = 4*NETDB_NUM_FLOODFILLS_THRESHOLD;
|
||||
const int NETDB_TUNNEL_CREATION_RATE_THRESHOLD = 10; // in %
|
||||
const int NETDB_CHECK_FOR_EXPIRATION_UPTIME = 600; // 10 minutes, in seconds
|
||||
const int NETDB_FLOODFILL_EXPIRATION_TIMEOUT = 60 * 60; // 1 hour, in seconds
|
||||
const int NETDB_MIN_EXPIRATION_TIMEOUT = 90 * 60; // 1.5 hours
|
||||
const int NETDB_MAX_EXPIRATION_TIMEOUT = 27 * 60 * 60; // 27 hours
|
||||
const int NETDB_MAX_OFFLINE_EXPIRATION_TIMEOUT = 180; // in days
|
||||
const int NETDB_EXPIRATION_TIMEOUT_THRESHOLD = 2*60; // 2 minutes
|
||||
const int NETDB_MIN_HIGHBANDWIDTH_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51
|
||||
const int NETDB_MIN_FLOODFILL_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51
|
||||
const int NETDB_MIN_HIGHBANDWIDTH_VERSION = MAKE_VERSION_NUMBER(0, 9, 58); // 0.9.58
|
||||
const int NETDB_MIN_FLOODFILL_VERSION = MAKE_VERSION_NUMBER(0, 9, 59); // 0.9.59
|
||||
const int NETDB_MIN_SHORT_TUNNEL_BUILD_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51
|
||||
const size_t NETDB_MAX_NUM_SEARCH_REPLY_PEER_HASHES = 16;
|
||||
const size_t NETDB_MAX_EXPLORATORY_SELECTION_SIZE = 500;
|
||||
const int NETDB_EXPLORATORY_SELECTION_UPDATE_INTERVAL = 82; // in seconds. for floodfill
|
||||
const int NETDB_NEXT_DAY_ROUTER_INFO_THRESHOLD = 45; // in minutes
|
||||
const int NETDB_NEXT_DAY_LEASESET_THRESHOLD = 10; // in minutes
|
||||
|
||||
/** function for visiting a leaseset stored in a floodfill */
|
||||
typedef std::function<void(const IdentHash, std::shared_ptr<LeaseSet>)> LeaseSetVisitor;
|
||||
@@ -77,27 +86,22 @@ namespace data
|
||||
std::shared_ptr<RouterProfile> FindRouterProfile (const IdentHash& ident) const;
|
||||
|
||||
void RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete = nullptr, bool direct = true);
|
||||
void RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploritory, RequestedDestination::RequestComplete requestComplete = nullptr);
|
||||
|
||||
void HandleDatabaseStoreMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||
void HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||
void HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||
void HandleNTCP2RouterInfoMsg (std::shared_ptr<const I2NPMessage> m);
|
||||
|
||||
|
||||
std::shared_ptr<const RouterInfo> GetRandomRouter () const;
|
||||
std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse, bool endpoint) const;
|
||||
std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse, bool endpoint, bool clientTunnel) const;
|
||||
std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse, bool endpoint) const;
|
||||
std::shared_ptr<const RouterInfo> GetRandomSSU2PeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const;
|
||||
std::shared_ptr<const RouterInfo> GetRandomSSU2Introducer (bool v4, const std::set<IdentHash>& excluded) const;
|
||||
std::shared_ptr<const RouterInfo> GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
|
||||
std::shared_ptr<const RouterInfo> GetRandomSSU2PeerTestRouter (bool v4, const std::unordered_set<IdentHash>& excluded) const;
|
||||
std::shared_ptr<const RouterInfo> GetRandomSSU2Introducer (bool v4, const std::unordered_set<IdentHash>& excluded) const;
|
||||
std::shared_ptr<const RouterInfo> GetClosestFloodfill (const IdentHash& destination, const std::unordered_set<IdentHash>& excluded, bool nextDay = 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::unordered_set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
|
||||
std::vector<IdentHash> GetExploratoryNonFloodfill (const IdentHash& destination, size_t num, const std::unordered_set<IdentHash>& excluded);
|
||||
std::shared_ptr<const RouterInfo> GetRandomRouterInFamily (FamilyID fam) const;
|
||||
void SetUnreachable (const IdentHash& ident, bool unreachable);
|
||||
void ExcludeReachableTransports (const IdentHash& ident, RouterInfo::CompatibleTransports transports);
|
||||
|
||||
void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||
void PostDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg); // to NetdbReq thread
|
||||
|
||||
void Reseed ();
|
||||
Families& GetFamilies () { return m_Families; };
|
||||
@@ -117,30 +121,33 @@ namespace data
|
||||
size_t VisitRandomRouterInfos(RouterInfoFilter f, RouterInfoVisitor v, size_t n);
|
||||
|
||||
void ClearRouterInfos () { m_RouterInfos.clear (); };
|
||||
std::shared_ptr<RouterInfo::Buffer> NewRouterInfoBuffer () { return m_RouterInfoBuffersPool.AcquireSharedMt (); };
|
||||
template<typename... TArgs>
|
||||
std::shared_ptr<RouterInfo::Buffer> NewRouterInfoBuffer (TArgs&&... args)
|
||||
{
|
||||
return m_RouterInfoBuffersPool.AcquireSharedMt (std::forward<TArgs>(args)...);
|
||||
}
|
||||
bool PopulateRouterInfoBuffer (std::shared_ptr<RouterInfo> r);
|
||||
std::shared_ptr<RouterInfo::Address> NewRouterInfoAddress () { return m_RouterInfoAddressesPool.AcquireSharedMt (); };
|
||||
boost::shared_ptr<RouterInfo::Addresses> NewRouterInfoAddresses ()
|
||||
RouterInfo::AddressesPtr NewRouterInfoAddresses ()
|
||||
{
|
||||
return boost::shared_ptr<RouterInfo::Addresses>(m_RouterInfoAddressVectorsPool.AcquireMt (),
|
||||
return RouterInfo::AddressesPtr{m_RouterInfoAddressVectorsPool.AcquireMt (),
|
||||
std::bind <void (i2p::util::MemoryPoolMt<RouterInfo::Addresses>::*)(RouterInfo::Addresses *)>
|
||||
(&i2p::util::MemoryPoolMt<RouterInfo::Addresses>::ReleaseMt,
|
||||
&m_RouterInfoAddressVectorsPool, std::placeholders::_1));
|
||||
&m_RouterInfoAddressVectorsPool, std::placeholders::_1)};
|
||||
};
|
||||
std::shared_ptr<Lease> NewLease (const Lease& lease) { return m_LeasesPool.AcquireSharedMt (lease); };
|
||||
std::shared_ptr<IdentityEx> NewIdentity (const uint8_t * buf, size_t len) { return m_IdentitiesPool.AcquireSharedMt (buf, len); };
|
||||
std::shared_ptr<RouterProfile> NewRouterProfile () { return m_RouterProfilesPool.AcquireSharedMt (); };
|
||||
|
||||
uint32_t GetPublishReplyToken () const { return m_PublishReplyToken; };
|
||||
|
||||
private:
|
||||
|
||||
void Load ();
|
||||
bool LoadRouterInfo (const std::string& path, uint64_t ts);
|
||||
void SaveUpdated ();
|
||||
void Run (); // exploratory thread
|
||||
void Explore (int numDestinations);
|
||||
void Flood (const IdentHash& ident, std::shared_ptr<I2NPMessage> floodMsg);
|
||||
void PersistRouters (std::list<std::pair<std::string, std::shared_ptr<RouterInfo::Buffer> > >&& update,
|
||||
std::list<std::string>&& remove);
|
||||
void Run ();
|
||||
void Flood (const IdentHash& ident, std::shared_ptr<I2NPMessage> floodMsg, bool andNextDay = false);
|
||||
void ManageRouterInfos ();
|
||||
void ManageLeaseSets ();
|
||||
void ManageRequests ();
|
||||
@@ -153,6 +160,10 @@ namespace data
|
||||
template<typename Filter>
|
||||
std::shared_ptr<const RouterInfo> GetRandomRouter (Filter filter) const;
|
||||
|
||||
void HandleDatabaseStoreMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||
void HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||
void HandleNTCP2RouterInfoMsg (std::shared_ptr<const I2NPMessage> m);
|
||||
|
||||
private:
|
||||
|
||||
mutable std::mutex m_LeaseSetsMutex;
|
||||
@@ -171,16 +182,13 @@ namespace data
|
||||
Families m_Families;
|
||||
i2p::fs::HashedStorage m_Storage;
|
||||
|
||||
friend class NetDbRequests;
|
||||
NetDbRequests m_Requests;
|
||||
std::shared_ptr<NetDbRequests> m_Requests;
|
||||
|
||||
bool m_PersistProfiles;
|
||||
std::future<void> m_SavingProfiles, m_DeletingProfiles, m_PersistingRouters;
|
||||
|
||||
/** router info we are bootstrapping from or nullptr if we are not currently doing that*/
|
||||
std::shared_ptr<RouterInfo> m_FloodfillBootstrap;
|
||||
|
||||
std::set<IdentHash> m_PublishExcluded;
|
||||
uint32_t m_PublishReplyToken = 0;
|
||||
std::vector<std::shared_ptr<const RouterInfo> > m_ExploratorySelection;
|
||||
uint64_t m_LastExploratorySelectionUpdateTime; // in monotonic seconds
|
||||
|
||||
i2p::util::MemoryPoolMt<RouterInfo::Buffer> m_RouterInfoBuffersPool;
|
||||
i2p::util::MemoryPoolMt<RouterInfo::Address> m_RouterInfoAddressesPool;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -10,12 +10,28 @@
|
||||
#include "I2NPProtocol.h"
|
||||
#include "Transports.h"
|
||||
#include "NetDb.hpp"
|
||||
#include "ECIESX25519AEADRatchetSession.h"
|
||||
#include "RouterContext.h"
|
||||
#include "Timestamp.h"
|
||||
#include "NetDbRequests.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
RequestedDestination::RequestedDestination (const IdentHash& destination, bool isExploratory, bool direct):
|
||||
m_Destination (destination), m_IsExploratory (isExploratory), m_IsDirect (direct), m_IsActive (true),
|
||||
m_CreationTime (i2p::util::GetSecondsSinceEpoch ()), m_LastRequestTime (0), m_NumAttempts (0)
|
||||
{
|
||||
if (i2p::context.IsFloodfill ())
|
||||
m_ExcludedPeers.insert (i2p::context.GetIdentHash ()); // exclude self if floodfill
|
||||
}
|
||||
|
||||
RequestedDestination::~RequestedDestination ()
|
||||
{
|
||||
InvokeRequestComplete (nullptr);
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> RequestedDestination::CreateRequestMessage (std::shared_ptr<const RouterInfo> router,
|
||||
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel)
|
||||
{
|
||||
@@ -28,7 +44,8 @@ namespace data
|
||||
msg = i2p::CreateRouterInfoDatabaseLookupMsg(m_Destination, i2p::context.GetIdentHash(), 0, m_IsExploratory, &m_ExcludedPeers);
|
||||
if(router)
|
||||
m_ExcludedPeers.insert (router->GetIdentHash ());
|
||||
m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
m_LastRequestTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
m_NumAttempts++;
|
||||
return msg;
|
||||
}
|
||||
|
||||
@@ -37,80 +54,154 @@ namespace data
|
||||
auto msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination,
|
||||
i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers);
|
||||
m_ExcludedPeers.insert (floodfill);
|
||||
m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
m_NumAttempts++;
|
||||
m_LastRequestTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
return msg;
|
||||
}
|
||||
|
||||
bool RequestedDestination::IsExcluded (const IdentHash& ident) const
|
||||
{
|
||||
return m_ExcludedPeers.count (ident);
|
||||
}
|
||||
|
||||
void RequestedDestination::ClearExcludedPeers ()
|
||||
{
|
||||
m_ExcludedPeers.clear ();
|
||||
}
|
||||
|
||||
void RequestedDestination::InvokeRequestComplete (std::shared_ptr<RouterInfo> r)
|
||||
{
|
||||
if (!m_RequestComplete.empty ())
|
||||
{
|
||||
for (auto it: m_RequestComplete)
|
||||
if (it != nullptr) it (r);
|
||||
m_RequestComplete.clear ();
|
||||
}
|
||||
}
|
||||
|
||||
void RequestedDestination::Success (std::shared_ptr<RouterInfo> r)
|
||||
{
|
||||
if (m_RequestComplete)
|
||||
{
|
||||
m_RequestComplete (r);
|
||||
m_RequestComplete = nullptr;
|
||||
}
|
||||
if (m_IsActive)
|
||||
{
|
||||
m_IsActive = false;
|
||||
InvokeRequestComplete (r);
|
||||
}
|
||||
}
|
||||
|
||||
void RequestedDestination::Fail ()
|
||||
{
|
||||
if (m_RequestComplete)
|
||||
{
|
||||
m_RequestComplete (nullptr);
|
||||
m_RequestComplete = nullptr;
|
||||
}
|
||||
if (m_IsActive)
|
||||
{
|
||||
m_IsActive = false;
|
||||
InvokeRequestComplete (nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
NetDbRequests::NetDbRequests ():
|
||||
RunnableServiceWithWork ("NetDbReq"),
|
||||
m_ManageRequestsTimer (GetIOService ()), m_ExploratoryTimer (GetIOService ()),
|
||||
m_CleanupTimer (GetIOService ()), m_DiscoveredRoutersTimer (GetIOService ()),
|
||||
m_Rng(i2p::util::GetMonotonicMicroseconds () % 1000000LL)
|
||||
{
|
||||
}
|
||||
|
||||
NetDbRequests::~NetDbRequests ()
|
||||
{
|
||||
Stop ();
|
||||
}
|
||||
|
||||
void NetDbRequests::Start ()
|
||||
{
|
||||
if (!IsRunning ())
|
||||
{
|
||||
StartIOService ();
|
||||
ScheduleManageRequests ();
|
||||
ScheduleCleanup ();
|
||||
if (!i2p::context.IsHidden ())
|
||||
ScheduleExploratory (EXPLORATORY_REQUEST_INTERVAL);
|
||||
}
|
||||
}
|
||||
|
||||
void NetDbRequests::Stop ()
|
||||
{
|
||||
m_RequestedDestinations.clear ();
|
||||
if (IsRunning ())
|
||||
{
|
||||
m_ManageRequestsTimer.cancel ();
|
||||
m_ExploratoryTimer.cancel ();
|
||||
m_CleanupTimer.cancel ();
|
||||
StopIOService ();
|
||||
|
||||
m_RequestedDestinations.clear ();
|
||||
m_RequestedDestinationsPool.CleanUpMt ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<RequestedDestination> NetDbRequests::CreateRequest (const IdentHash& destination, bool isExploratory, RequestedDestination::RequestComplete requestComplete)
|
||||
void NetDbRequests::ScheduleCleanup ()
|
||||
{
|
||||
m_CleanupTimer.expires_from_now (boost::posix_time::seconds(REQUESTED_DESTINATIONS_POOL_CLEANUP_INTERVAL));
|
||||
m_CleanupTimer.async_wait (std::bind (&NetDbRequests::HandleCleanupTimer,
|
||||
this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
void NetDbRequests::HandleCleanupTimer (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
m_RequestedDestinationsPool.CleanUpMt ();
|
||||
ScheduleCleanup ();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<RequestedDestination> NetDbRequests::CreateRequest (const IdentHash& destination,
|
||||
bool isExploratory, bool direct, RequestedDestination::RequestComplete requestComplete)
|
||||
{
|
||||
// request RouterInfo directly
|
||||
auto dest = std::make_shared<RequestedDestination> (destination, isExploratory);
|
||||
dest->SetRequestComplete (requestComplete);
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
|
||||
if (!m_RequestedDestinations.insert (std::make_pair (destination, dest)).second) // not inserted
|
||||
return nullptr;
|
||||
}
|
||||
auto dest = m_RequestedDestinationsPool.AcquireSharedMt (destination, isExploratory, direct);
|
||||
if (requestComplete)
|
||||
dest->AddRequestComplete (requestComplete);
|
||||
|
||||
auto ret = m_RequestedDestinations.emplace (destination, dest);
|
||||
if (!ret.second) // not inserted
|
||||
{
|
||||
dest->ResetRequestComplete (); // don't call requestComplete in destructor
|
||||
dest = ret.first->second; // existing one
|
||||
if (requestComplete)
|
||||
{
|
||||
if (dest->IsActive ())
|
||||
dest->AddRequestComplete (requestComplete);
|
||||
else
|
||||
requestComplete (nullptr);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
void NetDbRequests::RequestComplete (const IdentHash& ident, std::shared_ptr<RouterInfo> r)
|
||||
{
|
||||
std::shared_ptr<RequestedDestination> request;
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
|
||||
auto it = m_RequestedDestinations.find (ident);
|
||||
if (it != m_RequestedDestinations.end ())
|
||||
{
|
||||
request = it->second;
|
||||
m_RequestedDestinations.erase (it);
|
||||
}
|
||||
}
|
||||
if (request)
|
||||
{
|
||||
if (r)
|
||||
request->Success (r);
|
||||
else
|
||||
request->Fail ();
|
||||
}
|
||||
boost::asio::post (GetIOService (), [this, ident, r]()
|
||||
{
|
||||
std::shared_ptr<RequestedDestination> request;
|
||||
auto it = m_RequestedDestinations.find (ident);
|
||||
if (it != m_RequestedDestinations.end ())
|
||||
{
|
||||
request = it->second;
|
||||
if (request->IsExploratory ())
|
||||
m_RequestedDestinations.erase (it);
|
||||
// otherwise cache for a while
|
||||
}
|
||||
if (request)
|
||||
{
|
||||
if (r)
|
||||
request->Success (r);
|
||||
else
|
||||
request->Fail ();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
std::shared_ptr<RequestedDestination> NetDbRequests::FindRequest (const IdentHash& ident) const
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
|
||||
auto it = m_RequestedDestinations.find (ident);
|
||||
if (it != m_RequestedDestinations.end ())
|
||||
return it->second;
|
||||
@@ -120,49 +211,345 @@ namespace data
|
||||
void NetDbRequests::ManageRequests ()
|
||||
{
|
||||
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
|
||||
for (auto it = m_RequestedDestinations.begin (); it != m_RequestedDestinations.end ();)
|
||||
{
|
||||
auto& dest = it->second;
|
||||
bool done = false;
|
||||
if (ts < dest->GetCreationTime () + 60) // request is worthless after 1 minute
|
||||
{
|
||||
if (ts > dest->GetCreationTime () + 5) // no response for 5 seconds
|
||||
{
|
||||
auto count = dest->GetExcludedPeers ().size ();
|
||||
if (!dest->IsExploratory () && count < 7)
|
||||
if (dest->IsActive () || ts < dest->GetCreationTime () + REQUEST_CACHE_TIME)
|
||||
{
|
||||
if (!dest->IsExploratory ())
|
||||
{
|
||||
// regular request
|
||||
bool done = false;
|
||||
if (ts < dest->GetCreationTime () + MAX_REQUEST_TIME)
|
||||
{
|
||||
auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||
auto outbound = pool->GetNextOutboundTunnel ();
|
||||
auto inbound = pool->GetNextInboundTunnel ();
|
||||
auto nextFloodfill = netdb.GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ());
|
||||
if (nextFloodfill && outbound && inbound)
|
||||
outbound->SendTunnelDataMsgTo (nextFloodfill->GetIdentHash (), 0,
|
||||
dest->CreateRequestMessage (nextFloodfill, inbound));
|
||||
else
|
||||
{
|
||||
done = true;
|
||||
if (!inbound) LogPrint (eLogWarning, "NetDbReq: No inbound tunnels");
|
||||
if (!outbound) LogPrint (eLogWarning, "NetDbReq: No outbound tunnels");
|
||||
if (!nextFloodfill) LogPrint (eLogWarning, "NetDbReq: No more floodfills");
|
||||
}
|
||||
if (ts > dest->GetLastRequestTime () + MIN_REQUEST_TIME) // try next floodfill if no response after min interval
|
||||
done = !SendNextRequest (dest);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!dest->IsExploratory ())
|
||||
LogPrint (eLogWarning, "NetDbReq: ", dest->GetDestination ().ToBase64 (), " not found after 7 attempts");
|
||||
else // request is expired
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // delete obsolete request
|
||||
done = true;
|
||||
|
||||
if (done)
|
||||
it = m_RequestedDestinations.erase (it);
|
||||
if (done)
|
||||
dest->Fail ();
|
||||
it++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// exploratory
|
||||
if (ts >= dest->GetCreationTime () + MAX_EXPLORATORY_REQUEST_TIME)
|
||||
{
|
||||
dest->Fail ();
|
||||
it = m_RequestedDestinations.erase (it); // delete expired exploratory request right a way
|
||||
}
|
||||
else
|
||||
it++;
|
||||
}
|
||||
}
|
||||
else
|
||||
++it;
|
||||
it = m_RequestedDestinations.erase (it);
|
||||
}
|
||||
}
|
||||
|
||||
bool NetDbRequests::SendNextRequest (std::shared_ptr<RequestedDestination> dest)
|
||||
{
|
||||
if (!dest || !dest->IsActive ()) return false;
|
||||
bool ret = true;
|
||||
auto count = dest->GetNumAttempts ();
|
||||
if (!dest->IsExploratory () && count < MAX_NUM_REQUEST_ATTEMPTS)
|
||||
{
|
||||
auto nextFloodfill = netdb.GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ());
|
||||
if (nextFloodfill)
|
||||
{
|
||||
bool direct = dest->IsDirect ();
|
||||
if (direct && !nextFloodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) &&
|
||||
!i2p::transport::transports.IsConnected (nextFloodfill->GetIdentHash ()))
|
||||
direct = false; // floodfill can't be reached directly
|
||||
auto s = shared_from_this ();
|
||||
auto onDrop = [s, dest]()
|
||||
{
|
||||
if (dest->IsActive ())
|
||||
{
|
||||
boost::asio::post (s->GetIOService (), [s, dest]()
|
||||
{
|
||||
if (dest->IsActive ()) s->SendNextRequest (dest);
|
||||
});
|
||||
}
|
||||
};
|
||||
if (direct)
|
||||
{
|
||||
if (CheckLogLevel (eLogDebug))
|
||||
LogPrint (eLogDebug, "NetDbReq: Try ", dest->GetDestination ().ToBase64 (), " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 (), " directly");
|
||||
auto msg = dest->CreateRequestMessage (nextFloodfill->GetIdentHash ());
|
||||
msg->onDrop = onDrop;
|
||||
i2p::transport::transports.SendMessage (nextFloodfill->GetIdentHash (), msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||
if (pool)
|
||||
{
|
||||
auto outbound = pool->GetNextOutboundTunnel ();
|
||||
auto inbound = pool->GetNextInboundTunnel ();
|
||||
if (nextFloodfill && outbound && inbound)
|
||||
{
|
||||
if (CheckLogLevel (eLogDebug))
|
||||
LogPrint (eLogDebug, "NetDbReq: Try ", dest->GetDestination ().ToBase64 (), " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 (), " through tunnels");
|
||||
auto msg = dest->CreateRequestMessage (nextFloodfill, inbound);
|
||||
msg->onDrop = onDrop;
|
||||
outbound->SendTunnelDataMsgTo (nextFloodfill->GetIdentHash (), 0,
|
||||
i2p::garlic::WrapECIESX25519MessageForRouter (msg, nextFloodfill->GetIdentity ()->GetEncryptionPublicKey ()));
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = false;
|
||||
if (!inbound) LogPrint (eLogWarning, "NetDbReq: No inbound tunnels");
|
||||
if (!outbound) LogPrint (eLogWarning, "NetDbReq: No outbound tunnels");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = false;
|
||||
LogPrint (eLogWarning, "NetDbReq: Exploratory pool is not ready");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = false;
|
||||
LogPrint (eLogWarning, "NetDbReq: No more floodfills for ", dest->GetDestination ().ToBase64 (), " after ", count, "attempts");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!dest->IsExploratory ())
|
||||
LogPrint (eLogWarning, "NetDbReq: ", dest->GetDestination ().ToBase64 (), " not found after ", MAX_NUM_REQUEST_ATTEMPTS," attempts");
|
||||
ret = false;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void NetDbRequests::ScheduleManageRequests ()
|
||||
{
|
||||
m_ManageRequestsTimer.expires_from_now (boost::posix_time::seconds(MANAGE_REQUESTS_INTERVAL));
|
||||
m_ManageRequestsTimer.async_wait (std::bind (&NetDbRequests::HandleManageRequestsTimer,
|
||||
this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
void NetDbRequests::HandleManageRequestsTimer (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
if (i2p::tunnel::tunnels.GetExploratoryPool ()) // expolratory pool is ready?
|
||||
ManageRequests ();
|
||||
ScheduleManageRequests ();
|
||||
}
|
||||
}
|
||||
|
||||
void NetDbRequests::PostDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg)
|
||||
{
|
||||
boost::asio::post (GetIOService (), [this, msg]()
|
||||
{
|
||||
HandleDatabaseSearchReplyMsg (msg);
|
||||
});
|
||||
}
|
||||
|
||||
void NetDbRequests::HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg)
|
||||
{
|
||||
const uint8_t * buf = msg->GetPayload ();
|
||||
char key[48];
|
||||
int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48);
|
||||
key[l] = 0;
|
||||
size_t num = buf[32]; // num
|
||||
LogPrint (eLogDebug, "NetDbReq: DatabaseSearchReply for ", key, " num=", num);
|
||||
IdentHash ident (buf);
|
||||
bool isExploratory = false;
|
||||
auto dest = FindRequest (ident);
|
||||
if (dest && dest->IsActive ())
|
||||
{
|
||||
isExploratory = dest->IsExploratory ();
|
||||
if (!isExploratory && (num > 0 || dest->GetNumAttempts () < 3)) // before 3-rd attempt might be just bad luck
|
||||
{
|
||||
// try to send next requests
|
||||
if (!SendNextRequest (dest))
|
||||
RequestComplete (ident, nullptr);
|
||||
}
|
||||
else
|
||||
// no more requests for destination possible. delete it
|
||||
RequestComplete (ident, nullptr);
|
||||
}
|
||||
else /*if (!m_FloodfillBootstrap)*/
|
||||
{
|
||||
LogPrint (eLogInfo, "NetDbReq: Unsolicited or late database search reply for ", key);
|
||||
return;
|
||||
}
|
||||
|
||||
// try responses
|
||||
if (num > NETDB_MAX_NUM_SEARCH_REPLY_PEER_HASHES)
|
||||
{
|
||||
LogPrint (eLogWarning, "NetDbReq: Too many peer hashes ", num, " in database search reply, Reduced to ", NETDB_MAX_NUM_SEARCH_REPLY_PEER_HASHES);
|
||||
num = NETDB_MAX_NUM_SEARCH_REPLY_PEER_HASHES;
|
||||
}
|
||||
if (isExploratory && !m_DiscoveredRouterHashes.empty ())
|
||||
{
|
||||
// request outstanding routers
|
||||
for (auto it: m_DiscoveredRouterHashes)
|
||||
RequestRouter (it);
|
||||
m_DiscoveredRouterHashes.clear ();
|
||||
m_DiscoveredRoutersTimer.cancel ();
|
||||
}
|
||||
for (size_t i = 0; i < num; i++)
|
||||
{
|
||||
IdentHash router (buf + 33 + i*32);
|
||||
if (CheckLogLevel (eLogDebug))
|
||||
LogPrint (eLogDebug, "NetDbReq: ", i, ": ", router.ToBase64 ());
|
||||
|
||||
if (isExploratory)
|
||||
// postpone request
|
||||
m_DiscoveredRouterHashes.push_back (router);
|
||||
else
|
||||
// send request right a way
|
||||
RequestRouter (router);
|
||||
}
|
||||
if (isExploratory && !m_DiscoveredRouterHashes.empty ())
|
||||
ScheduleDiscoveredRoutersRequest ();
|
||||
}
|
||||
|
||||
void NetDbRequests::RequestRouter (const IdentHash& router)
|
||||
{
|
||||
auto r = netdb.FindRouter (router);
|
||||
if (!r || i2p::util::GetMillisecondsSinceEpoch () > r->GetTimestamp () + 3600*1000LL)
|
||||
{
|
||||
// router with ident not found or too old (1 hour)
|
||||
LogPrint (eLogDebug, "NetDbReq: Found new/outdated router. Requesting RouterInfo...");
|
||||
if (!IsRouterBanned (router))
|
||||
RequestDestination (router, nullptr, true);
|
||||
else
|
||||
LogPrint (eLogDebug, "NetDbReq: Router ", router.ToBase64 (), " is banned. Skipped");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogDebug, "NetDbReq: [:|||:]");
|
||||
}
|
||||
|
||||
void NetDbRequests::PostRequestDestination (const IdentHash& destination,
|
||||
const RequestedDestination::RequestComplete& requestComplete, bool direct)
|
||||
{
|
||||
boost::asio::post (GetIOService (), [this, destination, requestComplete, direct]()
|
||||
{
|
||||
RequestDestination (destination, requestComplete, direct);
|
||||
});
|
||||
}
|
||||
|
||||
void NetDbRequests::RequestDestination (const IdentHash& destination, const RequestedDestination::RequestComplete& requestComplete, bool direct)
|
||||
{
|
||||
auto dest = CreateRequest (destination, false, direct, requestComplete); // non-exploratory
|
||||
if (dest)
|
||||
{
|
||||
if (!SendNextRequest (dest))
|
||||
RequestComplete (destination, nullptr);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "NetDbReq: Destination ", destination.ToBase64(), " is requested already or cached");
|
||||
}
|
||||
|
||||
void NetDbRequests::Explore (int numDestinations)
|
||||
{
|
||||
// new requests
|
||||
auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||
auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel () : nullptr;
|
||||
auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel () : nullptr;
|
||||
bool throughTunnels = outbound && inbound;
|
||||
|
||||
uint8_t randomHash[32];
|
||||
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
|
||||
LogPrint (eLogInfo, "NetDbReq: Exploring new ", numDestinations, " routers ...");
|
||||
for (int i = 0; i < numDestinations; i++)
|
||||
{
|
||||
RAND_bytes (randomHash, 32);
|
||||
auto dest = CreateRequest (randomHash, true, !throughTunnels); // exploratory
|
||||
if (!dest)
|
||||
{
|
||||
LogPrint (eLogWarning, "NetDbReq: Exploratory destination is requested already");
|
||||
return;
|
||||
}
|
||||
auto floodfill = netdb.GetClosestFloodfill (randomHash, dest->GetExcludedPeers ());
|
||||
if (floodfill)
|
||||
{
|
||||
if (i2p::transport::transports.IsConnected (floodfill->GetIdentHash ()))
|
||||
throughTunnels = false;
|
||||
if (throughTunnels)
|
||||
{
|
||||
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
||||
{
|
||||
i2p::tunnel::eDeliveryTypeRouter,
|
||||
floodfill->GetIdentHash (), 0,
|
||||
CreateDatabaseStoreMsg () // tell floodfill about us
|
||||
});
|
||||
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
||||
{
|
||||
i2p::tunnel::eDeliveryTypeRouter,
|
||||
floodfill->GetIdentHash (), 0,
|
||||
dest->CreateRequestMessage (floodfill, inbound) // explore
|
||||
});
|
||||
}
|
||||
else
|
||||
i2p::transport::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
|
||||
}
|
||||
else
|
||||
RequestComplete (randomHash, nullptr);
|
||||
}
|
||||
if (throughTunnels && msgs.size () > 0)
|
||||
outbound->SendTunnelDataMsgs (msgs);
|
||||
}
|
||||
|
||||
void NetDbRequests::ScheduleExploratory (uint64_t interval)
|
||||
{
|
||||
m_ExploratoryTimer.expires_from_now (boost::posix_time::seconds(interval));
|
||||
m_ExploratoryTimer.async_wait (std::bind (&NetDbRequests::HandleExploratoryTimer,
|
||||
this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
void NetDbRequests::HandleExploratoryTimer (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
auto numRouters = netdb.GetNumRouters ();
|
||||
auto nextExploratoryInterval = numRouters < 2500 ? (EXPLORATORY_REQUEST_INTERVAL + m_Rng () % EXPLORATORY_REQUEST_INTERVAL)/2 :
|
||||
EXPLORATORY_REQUEST_INTERVAL + m_Rng () % EXPLORATORY_REQUEST_INTERVAL_VARIANCE;
|
||||
if (numRouters)
|
||||
{
|
||||
if (i2p::transport::transports.IsOnline () && i2p::transport::transports.IsRunning ())
|
||||
{
|
||||
// explore only if online
|
||||
numRouters = 800/numRouters;
|
||||
if (numRouters < 1) numRouters = 1;
|
||||
if (numRouters > 9) numRouters = 9;
|
||||
Explore (numRouters);
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "NetDbReq: No known routers, reseed seems to be totally failed");
|
||||
ScheduleExploratory (nextExploratoryInterval);
|
||||
}
|
||||
}
|
||||
|
||||
void NetDbRequests::ScheduleDiscoveredRoutersRequest ()
|
||||
{
|
||||
m_DiscoveredRoutersTimer.expires_from_now (boost::posix_time::milliseconds(
|
||||
DISCOVERED_REQUEST_INTERVAL + m_Rng () % DISCOVERED_REQUEST_INTERVAL_VARIANCE));
|
||||
m_DiscoveredRoutersTimer.async_wait (std::bind (&NetDbRequests::HandleDiscoveredRoutersTimer,
|
||||
this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
void NetDbRequests::HandleDiscoveredRoutersTimer (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
if (!m_DiscoveredRouterHashes.empty ())
|
||||
{
|
||||
RequestRouter (m_DiscoveredRouterHashes.front ());
|
||||
m_DiscoveredRouterHashes.pop_front ();
|
||||
if (!m_DiscoveredRouterHashes.empty ()) // more hashes to request
|
||||
ScheduleDiscoveredRoutersRequest ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -9,66 +9,118 @@
|
||||
#ifndef NETDB_REQUESTS_H__
|
||||
#define NETDB_REQUESTS_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <random>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
#include "Identity.h"
|
||||
#include "RouterInfo.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
const int MAX_NUM_REQUEST_ATTEMPTS = 5;
|
||||
const uint64_t MANAGE_REQUESTS_INTERVAL = 1; // in seconds
|
||||
const uint64_t MIN_REQUEST_TIME = 5; // in seconds
|
||||
const uint64_t MAX_REQUEST_TIME = MAX_NUM_REQUEST_ATTEMPTS * (MIN_REQUEST_TIME + MANAGE_REQUESTS_INTERVAL);
|
||||
const uint64_t EXPLORATORY_REQUEST_INTERVAL = 55; // in seconds
|
||||
const uint64_t EXPLORATORY_REQUEST_INTERVAL_VARIANCE = 170; // in seconds
|
||||
const uint64_t DISCOVERED_REQUEST_INTERVAL = 360; // in milliseconds
|
||||
const uint64_t DISCOVERED_REQUEST_INTERVAL_VARIANCE = 540; // in milliseconds
|
||||
const uint64_t MAX_EXPLORATORY_REQUEST_TIME = 30; // in seconds
|
||||
const uint64_t REQUEST_CACHE_TIME = MAX_REQUEST_TIME + 40; // in seconds
|
||||
const uint64_t REQUESTED_DESTINATIONS_POOL_CLEANUP_INTERVAL = 191; // in seconds
|
||||
|
||||
class RequestedDestination
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::function<void (std::shared_ptr<RouterInfo>)> RequestComplete;
|
||||
|
||||
RequestedDestination (const IdentHash& destination, bool isExploratory = false):
|
||||
m_Destination (destination), m_IsExploratory (isExploratory), m_CreationTime (0) {};
|
||||
~RequestedDestination () { if (m_RequestComplete) m_RequestComplete (nullptr); };
|
||||
RequestedDestination (const IdentHash& destination, bool isExploratory = false, bool direct = true);
|
||||
~RequestedDestination ();
|
||||
|
||||
const IdentHash& GetDestination () const { return m_Destination; };
|
||||
int GetNumExcludedPeers () const { return m_ExcludedPeers.size (); };
|
||||
const std::set<IdentHash>& GetExcludedPeers () { return m_ExcludedPeers; };
|
||||
const std::unordered_set<IdentHash>& GetExcludedPeers () const { return m_ExcludedPeers; };
|
||||
int GetNumAttempts () const { return m_NumAttempts; };
|
||||
void ClearExcludedPeers ();
|
||||
bool IsExploratory () const { return m_IsExploratory; };
|
||||
bool IsExcluded (const IdentHash& ident) const { return m_ExcludedPeers.count (ident); };
|
||||
bool IsDirect () const { return m_IsDirect; };
|
||||
bool IsActive () const { return m_IsActive; };
|
||||
bool IsExcluded (const IdentHash& ident) const;
|
||||
uint64_t GetCreationTime () const { return m_CreationTime; };
|
||||
uint64_t GetLastRequestTime () const { return m_LastRequestTime; };
|
||||
std::shared_ptr<I2NPMessage> CreateRequestMessage (std::shared_ptr<const RouterInfo>, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel);
|
||||
std::shared_ptr<I2NPMessage> CreateRequestMessage (const IdentHash& floodfill);
|
||||
|
||||
void SetRequestComplete (const RequestComplete& requestComplete) { m_RequestComplete = requestComplete; };
|
||||
bool IsRequestComplete () const { return m_RequestComplete != nullptr; };
|
||||
void AddRequestComplete (const RequestComplete& requestComplete) { m_RequestComplete.push_back (requestComplete); };
|
||||
void ResetRequestComplete () { m_RequestComplete.clear (); };
|
||||
void Success (std::shared_ptr<RouterInfo> r);
|
||||
void Fail ();
|
||||
|
||||
private:
|
||||
|
||||
void InvokeRequestComplete (std::shared_ptr<RouterInfo> r);
|
||||
|
||||
private:
|
||||
|
||||
IdentHash m_Destination;
|
||||
bool m_IsExploratory;
|
||||
std::set<IdentHash> m_ExcludedPeers;
|
||||
uint64_t m_CreationTime;
|
||||
RequestComplete m_RequestComplete;
|
||||
bool m_IsExploratory, m_IsDirect, m_IsActive;
|
||||
std::unordered_set<IdentHash> m_ExcludedPeers;
|
||||
uint64_t m_CreationTime, m_LastRequestTime; // in seconds
|
||||
std::list<RequestComplete> m_RequestComplete;
|
||||
int m_NumAttempts;
|
||||
};
|
||||
|
||||
class NetDbRequests
|
||||
class NetDbRequests: public std::enable_shared_from_this<NetDbRequests>,
|
||||
private i2p::util::RunnableServiceWithWork
|
||||
{
|
||||
public:
|
||||
|
||||
NetDbRequests ();
|
||||
~NetDbRequests ();
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
|
||||
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 ();
|
||||
void PostDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||
void PostRequestDestination (const IdentHash& destination, const RequestedDestination::RequestComplete& requestComplete, bool direct);
|
||||
|
||||
private:
|
||||
|
||||
std::shared_ptr<RequestedDestination> CreateRequest (const IdentHash& destination, bool isExploratory,
|
||||
bool direct = false, RequestedDestination::RequestComplete requestComplete = nullptr);
|
||||
std::shared_ptr<RequestedDestination> FindRequest (const IdentHash& ident) const;
|
||||
bool SendNextRequest (std::shared_ptr<RequestedDestination> dest);
|
||||
|
||||
void HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||
void RequestRouter (const IdentHash& router);
|
||||
void RequestDestination (const IdentHash& destination, const RequestedDestination::RequestComplete& requestComplete, bool direct);
|
||||
void Explore (int numDestinations);
|
||||
void ManageRequests ();
|
||||
// timer
|
||||
void ScheduleManageRequests ();
|
||||
void HandleManageRequestsTimer (const boost::system::error_code& ecode);
|
||||
void ScheduleExploratory (uint64_t interval);
|
||||
void HandleExploratoryTimer (const boost::system::error_code& ecode);
|
||||
void ScheduleCleanup ();
|
||||
void HandleCleanupTimer (const boost::system::error_code& ecode);
|
||||
void ScheduleDiscoveredRoutersRequest ();
|
||||
void HandleDiscoveredRoutersTimer (const boost::system::error_code& ecode);
|
||||
|
||||
private:
|
||||
|
||||
mutable std::mutex m_RequestedDestinationsMutex;
|
||||
std::map<IdentHash, std::shared_ptr<RequestedDestination> > m_RequestedDestinations;
|
||||
std::unordered_map<IdentHash, std::shared_ptr<RequestedDestination> > m_RequestedDestinations;
|
||||
std::list<IdentHash> m_DiscoveredRouterHashes;
|
||||
i2p::util::MemoryPoolMt<RequestedDestination> m_RequestedDestinationsPool;
|
||||
boost::asio::deadline_timer m_ManageRequestsTimer, m_ExploratoryTimer,
|
||||
m_CleanupTimer, m_DiscoveredRoutersTimer;
|
||||
std::mt19937 m_Rng;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
void Poly1305HMAC(uint64_t * out, const uint64_t * key, const uint8_t * buf, std::size_t sz)
|
||||
{
|
||||
Poly1305 p(key);
|
||||
p.Update(buf, sz);
|
||||
p.Finish(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,261 +0,0 @@
|
||||
/**
|
||||
* This code is licensed under the MCGSI Public License
|
||||
* Copyright 2018 Jeff Becker
|
||||
*
|
||||
* Kovri go write your own code
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LIBI2PD_POLY1305_H
|
||||
#define LIBI2PD_POLY1305_H
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include "Crypto.h"
|
||||
|
||||
#if !OPENSSL_AEAD_CHACHA20_POLY1305
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
const std::size_t POLY1305_DIGEST_BYTES = 16;
|
||||
const std::size_t POLY1305_DIGEST_DWORDS = 4;
|
||||
const std::size_t POLY1305_KEY_BYTES = 32;
|
||||
const std::size_t POLY1305_KEY_DWORDS = 8;
|
||||
const std::size_t POLY1305_BLOCK_BYTES = 16;
|
||||
|
||||
namespace poly1305
|
||||
{
|
||||
struct LongBlock
|
||||
{
|
||||
unsigned long data[17];
|
||||
operator unsigned long * ()
|
||||
{
|
||||
return data;
|
||||
}
|
||||
};
|
||||
|
||||
struct Block
|
||||
{
|
||||
unsigned char data[17];
|
||||
|
||||
void Zero()
|
||||
{
|
||||
memset(data, 0, sizeof(data));
|
||||
}
|
||||
|
||||
operator uint8_t * ()
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
Block & operator += (const Block & other)
|
||||
{
|
||||
unsigned short u;
|
||||
unsigned int i;
|
||||
for(u = 0, i = 0; i < 17; i++)
|
||||
{
|
||||
u += (unsigned short) data[i] + (unsigned short) other.data[i];
|
||||
data[i] = (unsigned char) u & 0xff;
|
||||
u >>= 8;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Block & operator %=(const LongBlock & other)
|
||||
{
|
||||
unsigned long u;
|
||||
unsigned int i;
|
||||
u = 0;
|
||||
for (i = 0; i < 16; i++) {
|
||||
u += other.data[i];
|
||||
data[i] = (unsigned char)u & 0xff;
|
||||
u >>= 8;
|
||||
}
|
||||
u += other.data[16];
|
||||
data[16] = (unsigned char)u & 0x03;
|
||||
u >>= 2;
|
||||
u += (u << 2);
|
||||
for (i = 0; i < 16; i++) {
|
||||
u += data[i];
|
||||
data[i] = (unsigned char)u & 0xff;
|
||||
u >>= 8;
|
||||
}
|
||||
data[16] += (unsigned char)u;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Block & operator = (const Block & other)
|
||||
{
|
||||
memcpy(data, other.data, sizeof(data));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Block & operator ~ ()
|
||||
{
|
||||
static const Block minusp = {
|
||||
0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0xfc
|
||||
};
|
||||
Block orig;
|
||||
unsigned char neg;
|
||||
unsigned int i;
|
||||
orig = *this;
|
||||
*this += minusp;
|
||||
neg = -(data[16] >> 7);
|
||||
for(i = 0; i < 17; i++)
|
||||
data[i] ^= neg & (orig.data[i] ^ data[i]);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void PutKey(const uint64_t * key_l)
|
||||
{
|
||||
const uint8_t * key = (const uint8_t*) key_l;
|
||||
data[0] = key[0] & 0xff;
|
||||
data[1] = key[1] & 0xff;
|
||||
data[2] = key[2] & 0xff;
|
||||
data[3] = key[3] & 0x0f;
|
||||
data[4] = key[4] & 0xfc;
|
||||
data[5] = key[5] & 0xff;
|
||||
data[6] = key[6] & 0xff;
|
||||
data[7] = key[7] & 0x0f;
|
||||
data[8] = key[8] & 0xfc;
|
||||
data[9] = key[9] & 0xff;
|
||||
data[10] = key[10] & 0xff;
|
||||
data[11] = key[11] & 0x0f;
|
||||
data[12] = key[12] & 0xfc;
|
||||
data[13] = key[13] & 0xff;
|
||||
data[14] = key[14] & 0xff;
|
||||
data[15] = key[15] & 0x0f;
|
||||
data[16] = 0;
|
||||
}
|
||||
|
||||
template<typename Int_t>
|
||||
void Put(const Int_t * d, uint8_t last=0)
|
||||
{
|
||||
memcpy(data, d, 16);
|
||||
data[16] = last;
|
||||
}
|
||||
};
|
||||
|
||||
struct Buffer
|
||||
{
|
||||
uint8_t data[POLY1305_BLOCK_BYTES];
|
||||
|
||||
operator uint8_t * ()
|
||||
{
|
||||
return data;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
struct Poly1305
|
||||
{
|
||||
Poly1305(const uint64_t * key)
|
||||
{
|
||||
m_Leftover = 0;
|
||||
m_H.Zero();
|
||||
m_Final = 0;
|
||||
m_R.PutKey(key);
|
||||
m_Pad.Put(key + 2);
|
||||
}
|
||||
|
||||
void Update(const uint8_t * buf, size_t sz)
|
||||
{
|
||||
// process leftover
|
||||
if(m_Leftover)
|
||||
{
|
||||
size_t want = POLY1305_BLOCK_BYTES - m_Leftover;
|
||||
if(want > sz) want = sz;
|
||||
memcpy(m_Buffer + m_Leftover, buf, want);
|
||||
sz -= want;
|
||||
buf += want;
|
||||
m_Leftover += want;
|
||||
if(m_Leftover < POLY1305_BLOCK_BYTES) return;
|
||||
Blocks(m_Buffer, POLY1305_BLOCK_BYTES);
|
||||
m_Leftover = 0;
|
||||
}
|
||||
// process blocks
|
||||
if(sz >= POLY1305_BLOCK_BYTES)
|
||||
{
|
||||
size_t want = (sz & ~(POLY1305_BLOCK_BYTES - 1));
|
||||
Blocks(buf, want);
|
||||
buf += want;
|
||||
sz -= want;
|
||||
}
|
||||
// leftover
|
||||
if(sz)
|
||||
{
|
||||
memcpy(m_Buffer+m_Leftover, buf, sz);
|
||||
m_Leftover += sz;
|
||||
}
|
||||
}
|
||||
|
||||
void Blocks(const uint8_t * buf, size_t sz)
|
||||
{
|
||||
const unsigned char hi = m_Final ^ 1;
|
||||
while (sz >= POLY1305_BLOCK_BYTES) {
|
||||
unsigned long u;
|
||||
unsigned int i, j;
|
||||
m_Msg.Put(buf, hi);
|
||||
/* h += m */
|
||||
m_H += m_Msg;
|
||||
|
||||
/* h *= r */
|
||||
for (i = 0; i < 17; i++) {
|
||||
u = 0;
|
||||
for (j = 0; j <= i ; j++) {
|
||||
u += (unsigned short)m_H.data[j] * m_R.data[i - j];
|
||||
}
|
||||
for (j = i + 1; j < 17; j++) {
|
||||
unsigned long v = (unsigned short)m_H.data[j] * m_R.data[i + 17 - j];
|
||||
v = ((v << 8) + (v << 6)); /* v *= (5 << 6); */
|
||||
u += v;
|
||||
}
|
||||
m_HR[i] = u;
|
||||
}
|
||||
/* (partial) h %= p */
|
||||
m_H %= m_HR;
|
||||
buf += POLY1305_BLOCK_BYTES;
|
||||
sz -= POLY1305_BLOCK_BYTES;
|
||||
}
|
||||
}
|
||||
|
||||
void Finish(uint64_t * out)
|
||||
{
|
||||
// process leftovers
|
||||
if(m_Leftover)
|
||||
{
|
||||
size_t idx = m_Leftover;
|
||||
m_Buffer[idx++] = 1;
|
||||
for(; idx < POLY1305_BLOCK_BYTES; idx++)
|
||||
m_Buffer[idx] = 0;
|
||||
m_Final = 1;
|
||||
Blocks(m_Buffer, POLY1305_BLOCK_BYTES);
|
||||
}
|
||||
|
||||
// freeze H
|
||||
~m_H;
|
||||
// add pad
|
||||
m_H += m_Pad;
|
||||
// copy digest
|
||||
memcpy(out, m_H, 16);
|
||||
}
|
||||
|
||||
size_t m_Leftover;
|
||||
poly1305::Buffer m_Buffer;
|
||||
poly1305::Block m_H;
|
||||
poly1305::Block m_R;
|
||||
poly1305::Block m_Pad;
|
||||
poly1305::Block m_Msg;
|
||||
poly1305::LongBlock m_HR;
|
||||
uint8_t m_Final;
|
||||
};
|
||||
|
||||
void Poly1305HMAC(uint64_t * out, const uint64_t * key, const uint8_t * buf, std::size_t sz);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
#include <thread>
|
||||
#include <iomanip>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/property_tree/ini_parser.hpp>
|
||||
#include "Base.h"
|
||||
@@ -27,22 +28,18 @@ namespace data
|
||||
static std::unordered_map<i2p::data::IdentHash, std::shared_ptr<RouterProfile> > g_Profiles;
|
||||
static std::mutex g_ProfilesMutex;
|
||||
|
||||
static boost::posix_time::ptime GetTime ()
|
||||
{
|
||||
return boost::posix_time::second_clock::local_time();
|
||||
}
|
||||
|
||||
RouterProfile::RouterProfile ():
|
||||
m_LastUpdateTime (GetTime ()), m_IsUpdated (false),
|
||||
m_LastDeclineTime (0), m_LastUnreachableTime (0),
|
||||
m_IsUpdated (false), m_LastDeclineTime (0), m_LastUnreachableTime (0),
|
||||
m_LastUpdateTime (i2p::util::GetSecondsSinceEpoch ()),
|
||||
m_NumTunnelsAgreed (0), m_NumTunnelsDeclined (0), m_NumTunnelsNonReplied (0),
|
||||
m_NumTimesTaken (0), m_NumTimesRejected (0), m_HasConnected (false)
|
||||
m_NumTimesTaken (0), m_NumTimesRejected (0), m_HasConnected (false),
|
||||
m_IsDuplicated (false)
|
||||
{
|
||||
}
|
||||
|
||||
void RouterProfile::UpdateTime ()
|
||||
{
|
||||
m_LastUpdateTime = GetTime ();
|
||||
m_LastUpdateTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
m_IsUpdated = true;
|
||||
}
|
||||
|
||||
@@ -57,9 +54,11 @@ namespace data
|
||||
usage.put (PEER_PROFILE_USAGE_TAKEN, m_NumTimesTaken);
|
||||
usage.put (PEER_PROFILE_USAGE_REJECTED, m_NumTimesRejected);
|
||||
usage.put (PEER_PROFILE_USAGE_CONNECTED, m_HasConnected);
|
||||
if (m_IsDuplicated)
|
||||
usage.put (PEER_PROFILE_USAGE_DUPLICATED, true);
|
||||
// fill property tree
|
||||
boost::property_tree::ptree pt;
|
||||
pt.put (PEER_PROFILE_LAST_UPDATE_TIME, boost::posix_time::to_simple_string (m_LastUpdateTime));
|
||||
pt.put (PEER_PROFILE_LAST_UPDATE_TIMESTAMP, m_LastUpdateTime);
|
||||
if (m_LastUnreachableTime)
|
||||
pt.put (PEER_PROFILE_LAST_UNREACHABLE_TIME, m_LastUnreachableTime);
|
||||
pt.put_child (PEER_PROFILE_SECTION_PARTICIPATION, participation);
|
||||
@@ -101,10 +100,22 @@ namespace data
|
||||
|
||||
try
|
||||
{
|
||||
auto t = pt.get (PEER_PROFILE_LAST_UPDATE_TIME, "");
|
||||
if (t.length () > 0)
|
||||
m_LastUpdateTime = boost::posix_time::time_from_string (t);
|
||||
if ((GetTime () - m_LastUpdateTime).hours () < PEER_PROFILE_EXPIRATION_TIMEOUT)
|
||||
auto ts = pt.get (PEER_PROFILE_LAST_UPDATE_TIMESTAMP, 0);
|
||||
if (ts)
|
||||
m_LastUpdateTime = ts;
|
||||
else
|
||||
{
|
||||
// try old lastupdatetime
|
||||
auto ut = pt.get (PEER_PROFILE_LAST_UPDATE_TIME, "");
|
||||
if (ut.length () > 0)
|
||||
{
|
||||
std::istringstream ss (ut); std::tm t;
|
||||
ss >> std::get_time(&t, "%Y-%b-%d %H:%M:%S");
|
||||
if (!ss.fail())
|
||||
m_LastUpdateTime = mktime (&t); // t is local time
|
||||
}
|
||||
}
|
||||
if (i2p::util::GetSecondsSinceEpoch () - m_LastUpdateTime < PEER_PROFILE_EXPIRATION_TIMEOUT)
|
||||
{
|
||||
m_LastUnreachableTime = pt.get (PEER_PROFILE_LAST_UNREACHABLE_TIME, 0);
|
||||
try
|
||||
@@ -126,6 +137,7 @@ namespace data
|
||||
m_NumTimesTaken = usage.get (PEER_PROFILE_USAGE_TAKEN, 0);
|
||||
m_NumTimesRejected = usage.get (PEER_PROFILE_USAGE_REJECTED, 0);
|
||||
m_HasConnected = usage.get (PEER_PROFILE_USAGE_CONNECTED, false);
|
||||
m_IsDuplicated = usage.get (PEER_PROFILE_USAGE_DUPLICATED, false);
|
||||
}
|
||||
catch (boost::property_tree::ptree_bad_path& ex)
|
||||
{
|
||||
@@ -178,6 +190,11 @@ namespace data
|
||||
UpdateTime ();
|
||||
}
|
||||
|
||||
void RouterProfile::Duplicated ()
|
||||
{
|
||||
m_IsDuplicated = true;
|
||||
}
|
||||
|
||||
bool RouterProfile::IsLowPartcipationRate () const
|
||||
{
|
||||
return 4*m_NumTunnelsAgreed < m_NumTunnelsDeclined; // < 20% rate
|
||||
@@ -189,10 +206,9 @@ namespace data
|
||||
return m_NumTunnelsNonReplied > 10*(total + 1);
|
||||
}
|
||||
|
||||
bool RouterProfile::IsDeclinedRecently ()
|
||||
bool RouterProfile::IsDeclinedRecently (uint64_t ts)
|
||||
{
|
||||
if (!m_LastDeclineTime) return false;
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
if (ts > m_LastDeclineTime + PEER_PROFILE_DECLINED_RECENTLY_INTERVAL ||
|
||||
ts + PEER_PROFILE_DECLINED_RECENTLY_INTERVAL < m_LastDeclineTime)
|
||||
m_LastDeclineTime = 0;
|
||||
@@ -201,7 +217,10 @@ namespace data
|
||||
|
||||
bool RouterProfile::IsBad ()
|
||||
{
|
||||
if (IsDeclinedRecently () || IsUnreachable ()) return true;
|
||||
if (IsUnreachable () || m_IsDuplicated) return true;
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
if (ts > PEER_PROFILE_MAX_DECLINED_INTERVAL + m_LastDeclineTime) return false;
|
||||
if (IsDeclinedRecently (ts)) return true;
|
||||
auto isBad = IsAlwaysDeclining () || IsLowPartcipationRate () /*|| IsLowReplyRate ()*/;
|
||||
if (isBad && m_NumTimesRejected > 10*(m_NumTimesTaken + 1))
|
||||
{
|
||||
@@ -245,21 +264,36 @@ namespace data
|
||||
return profile;
|
||||
}
|
||||
|
||||
bool IsRouterBanned (const IdentHash& identHash)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(g_ProfilesMutex);
|
||||
auto it = g_Profiles.find (identHash);
|
||||
if (it != g_Profiles.end ())
|
||||
return it->second->IsUnreachable ();
|
||||
return false;
|
||||
}
|
||||
|
||||
void InitProfilesStorage ()
|
||||
{
|
||||
g_ProfilesStorage.SetPlace(i2p::fs::GetDataDir());
|
||||
g_ProfilesStorage.Init(i2p::data::GetBase64SubstitutionTable(), 64);
|
||||
}
|
||||
|
||||
void PersistProfiles ()
|
||||
static void SaveProfilesToDisk (std::list<std::pair<i2p::data::IdentHash, std::shared_ptr<RouterProfile> > >&& profiles)
|
||||
{
|
||||
auto ts = GetTime ();
|
||||
for (auto& it: profiles)
|
||||
if (it.second) it.second->Save (it.first);
|
||||
}
|
||||
|
||||
std::future<void> PersistProfiles ()
|
||||
{
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
std::list<std::pair<i2p::data::IdentHash, std::shared_ptr<RouterProfile> > > tmp;
|
||||
{
|
||||
std::unique_lock<std::mutex> l(g_ProfilesMutex);
|
||||
for (auto it = g_Profiles.begin (); it != g_Profiles.end ();)
|
||||
{
|
||||
if ((ts - it->second->GetLastUpdateTime ()).total_seconds () > PEER_PROFILE_PERSIST_INTERVAL)
|
||||
if (ts - it->second->GetLastUpdateTime () > PEER_PROFILE_PERSIST_INTERVAL)
|
||||
{
|
||||
if (it->second->IsUpdated ())
|
||||
tmp.push_back (std::make_pair (it->first, it->second));
|
||||
@@ -269,8 +303,9 @@ namespace data
|
||||
it++;
|
||||
}
|
||||
}
|
||||
for (auto& it: tmp)
|
||||
if (it.second) it.second->Save (it.first);
|
||||
if (!tmp.empty ())
|
||||
return std::async (std::launch::async, SaveProfilesToDisk, std::move (tmp));
|
||||
return std::future<void>();
|
||||
}
|
||||
|
||||
void SaveProfiles ()
|
||||
@@ -278,44 +313,51 @@ namespace data
|
||||
std::unordered_map<i2p::data::IdentHash, std::shared_ptr<RouterProfile> > tmp;
|
||||
{
|
||||
std::unique_lock<std::mutex> l(g_ProfilesMutex);
|
||||
tmp = g_Profiles;
|
||||
g_Profiles.clear ();
|
||||
std::swap (tmp, g_Profiles);
|
||||
}
|
||||
auto ts = GetTime ();
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
for (auto& it: tmp)
|
||||
if (it.second->IsUseful() && (it.second->IsUpdated () || (ts - it.second->GetLastUpdateTime ()).total_seconds () < PEER_PROFILE_EXPIRATION_TIMEOUT*3600))
|
||||
if (it.second->IsUseful() && (it.second->IsUpdated () || ts - it.second->GetLastUpdateTime () < PEER_PROFILE_EXPIRATION_TIMEOUT))
|
||||
it.second->Save (it.first);
|
||||
}
|
||||
|
||||
void DeleteObsoleteProfiles ()
|
||||
static void DeleteFilesFromDisk ()
|
||||
{
|
||||
std::vector<std::string> files;
|
||||
g_ProfilesStorage.Traverse(files);
|
||||
|
||||
struct stat st;
|
||||
std::time_t now = std::time(nullptr);
|
||||
for (const auto& path: files)
|
||||
{
|
||||
if (stat(path.c_str(), &st) != 0)
|
||||
{
|
||||
LogPrint(eLogWarning, "Profiling: Can't stat(): ", path);
|
||||
continue;
|
||||
}
|
||||
if (now - st.st_mtime >= PEER_PROFILE_EXPIRATION_TIMEOUT)
|
||||
{
|
||||
LogPrint(eLogDebug, "Profiling: Removing expired peer profile: ", path);
|
||||
i2p::fs::Remove(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::future<void> DeleteObsoleteProfiles ()
|
||||
{
|
||||
{
|
||||
auto ts = GetTime ();
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
std::unique_lock<std::mutex> l(g_ProfilesMutex);
|
||||
for (auto it = g_Profiles.begin (); it != g_Profiles.end ();)
|
||||
{
|
||||
if ((ts - it->second->GetLastUpdateTime ()).total_seconds () >= PEER_PROFILE_EXPIRATION_TIMEOUT*3600)
|
||||
if (ts - it->second->GetLastUpdateTime () >= PEER_PROFILE_EXPIRATION_TIMEOUT)
|
||||
it = g_Profiles.erase (it);
|
||||
else
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
struct stat st;
|
||||
std::time_t now = std::time(nullptr);
|
||||
|
||||
std::vector<std::string> files;
|
||||
g_ProfilesStorage.Traverse(files);
|
||||
for (const auto& path: files) {
|
||||
if (stat(path.c_str(), &st) != 0) {
|
||||
LogPrint(eLogWarning, "Profiling: Can't stat(): ", path);
|
||||
continue;
|
||||
}
|
||||
if (now - st.st_mtime >= PEER_PROFILE_EXPIRATION_TIMEOUT*3600) {
|
||||
LogPrint(eLogDebug, "Profiling: Removing expired peer profile: ", path);
|
||||
i2p::fs::Remove(path);
|
||||
}
|
||||
}
|
||||
return std::async (std::launch::async, DeleteFilesFromDisk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -10,7 +10,8 @@
|
||||
#define PROFILING_H__
|
||||
|
||||
#include <memory>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <future>
|
||||
#include <boost/asio.hpp>
|
||||
#include "Identity.h"
|
||||
|
||||
namespace i2p
|
||||
@@ -21,7 +22,8 @@ namespace data
|
||||
const char PEER_PROFILE_SECTION_PARTICIPATION[] = "participation";
|
||||
const char PEER_PROFILE_SECTION_USAGE[] = "usage";
|
||||
// params
|
||||
const char PEER_PROFILE_LAST_UPDATE_TIME[] = "lastupdatetime";
|
||||
const char PEER_PROFILE_LAST_UPDATE_TIME[] = "lastupdatetime"; // deprecated
|
||||
const char PEER_PROFILE_LAST_UPDATE_TIMESTAMP[] = "lastupdatetimestamp";
|
||||
const char PEER_PROFILE_LAST_UNREACHABLE_TIME[] = "lastunreachabletime";
|
||||
const char PEER_PROFILE_PARTICIPATION_AGREED[] = "agreed";
|
||||
const char PEER_PROFILE_PARTICIPATION_DECLINED[] = "declined";
|
||||
@@ -29,15 +31,20 @@ namespace data
|
||||
const char PEER_PROFILE_USAGE_TAKEN[] = "taken";
|
||||
const char PEER_PROFILE_USAGE_REJECTED[] = "rejected";
|
||||
const char PEER_PROFILE_USAGE_CONNECTED[] = "connected";
|
||||
const char PEER_PROFILE_USAGE_DUPLICATED[] = "duplicated";
|
||||
|
||||
const int PEER_PROFILE_EXPIRATION_TIMEOUT = 36; // in hours (1.5 days)
|
||||
const int PEER_PROFILE_AUTOCLEAN_TIMEOUT = 3 * 3600; // in seconds (3 hours)
|
||||
const int PEER_PROFILE_AUTOCLEAN_VARIANCE = 3600; // in seconds (1 hour)
|
||||
const int PEER_PROFILE_DECLINED_RECENTLY_INTERVAL = 150; // in seconds (2.5 minutes)
|
||||
const int PEER_PROFILE_EXPIRATION_TIMEOUT = 36*60*60; // in seconds (1.5 days)
|
||||
const int PEER_PROFILE_AUTOCLEAN_TIMEOUT = 1500; // in seconds (25 minutes)
|
||||
const int PEER_PROFILE_AUTOCLEAN_VARIANCE = 900; // in seconds (15 minutes)
|
||||
const int PEER_PROFILE_OBSOLETE_PROFILES_CLEAN_TIMEOUT = 5400; // in seconds (1.5 hours)
|
||||
const int PEER_PROFILE_OBSOLETE_PROFILES_CLEAN_VARIANCE = 2400; // in seconds (40 minutes)
|
||||
const int PEER_PROFILE_DECLINED_RECENTLY_INTERVAL = 330; // in seconds (5.5 minutes)
|
||||
const int PEER_PROFILE_MAX_DECLINED_INTERVAL = 4400; // in second (1.5 hours)
|
||||
const int PEER_PROFILE_PERSIST_INTERVAL = 3300; // in seconds (55 minutes)
|
||||
const int PEER_PROFILE_UNREACHABLE_INTERVAL = 2*3600; // on seconds (2 hours)
|
||||
const int PEER_PROFILE_UNREACHABLE_INTERVAL = 480; // in seconds (8 minutes)
|
||||
const int PEER_PROFILE_USEFUL_THRESHOLD = 3;
|
||||
|
||||
const int PEER_PROFILE_ALWAYS_DECLINING_NUM = 5; // num declines in row to consider always declined
|
||||
|
||||
class RouterProfile
|
||||
{
|
||||
public:
|
||||
@@ -56,11 +63,18 @@ namespace data
|
||||
|
||||
void Unreachable (bool unreachable);
|
||||
void Connected ();
|
||||
void Duplicated ();
|
||||
|
||||
boost::posix_time::ptime GetLastUpdateTime () const { return m_LastUpdateTime; };
|
||||
uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; };
|
||||
bool IsUpdated () const { return m_IsUpdated; };
|
||||
|
||||
bool IsUseful() const;
|
||||
bool IsDuplicated () const { return m_IsDuplicated; };
|
||||
|
||||
const boost::asio::ip::udp::endpoint& GetLastEndpoint () const { return m_LastEndpoint; }
|
||||
void SetLastEndpoint (const boost::asio::ip::udp::endpoint& ep) { m_LastEndpoint = ep; }
|
||||
bool HasLastEndpoint (bool v4) const { return !m_LastEndpoint.address ().is_unspecified () && m_LastEndpoint.port () &&
|
||||
((v4 && m_LastEndpoint.address ().is_v4 ()) || (!v4 && m_LastEndpoint.address ().is_v6 ())); }
|
||||
|
||||
private:
|
||||
|
||||
@@ -69,13 +83,12 @@ namespace data
|
||||
bool IsAlwaysDeclining () const { return !m_NumTunnelsAgreed && m_NumTunnelsDeclined >= 5; };
|
||||
bool IsLowPartcipationRate () const;
|
||||
bool IsLowReplyRate () const;
|
||||
bool IsDeclinedRecently ();
|
||||
bool IsDeclinedRecently (uint64_t ts);
|
||||
|
||||
private:
|
||||
|
||||
boost::posix_time::ptime m_LastUpdateTime; // TODO: use std::chrono
|
||||
bool m_IsUpdated;
|
||||
uint64_t m_LastDeclineTime, m_LastUnreachableTime; // in seconds
|
||||
uint64_t m_LastDeclineTime, m_LastUnreachableTime, m_LastUpdateTime; // in seconds
|
||||
// participation
|
||||
uint32_t m_NumTunnelsAgreed;
|
||||
uint32_t m_NumTunnelsDeclined;
|
||||
@@ -84,13 +97,17 @@ namespace data
|
||||
uint32_t m_NumTimesTaken;
|
||||
uint32_t m_NumTimesRejected;
|
||||
bool m_HasConnected; // successful trusted(incoming or NTCP2) connection
|
||||
bool m_IsDuplicated;
|
||||
// connectivity
|
||||
boost::asio::ip::udp::endpoint m_LastEndpoint; // SSU2 for non-published addresses
|
||||
};
|
||||
|
||||
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash);
|
||||
bool IsRouterBanned (const IdentHash& identHash); // check only existing profiles
|
||||
void InitProfilesStorage ();
|
||||
void DeleteObsoleteProfiles ();
|
||||
std::future<void> DeleteObsoleteProfiles ();
|
||||
void SaveProfiles ();
|
||||
void PersistProfiles ();
|
||||
std::future<void> PersistProfiles ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -9,8 +9,7 @@
|
||||
#ifndef QUEUE_H__
|
||||
#define QUEUE_H__
|
||||
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <condition_variable>
|
||||
@@ -29,22 +28,20 @@ namespace util
|
||||
void Put (Element e)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||
m_Queue.push (std::move(e));
|
||||
m_Queue.push_back (std::move(e));
|
||||
m_NonEmpty.notify_one ();
|
||||
}
|
||||
|
||||
template<template<typename, typename...>class Container, typename... R>
|
||||
void Put (const Container<Element, R...>& vec)
|
||||
void Put (std::list<Element>& list)
|
||||
{
|
||||
if (!vec.empty ())
|
||||
if (!list.empty ())
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||
for (const auto& it: vec)
|
||||
m_Queue.push (std::move(it));
|
||||
m_Queue.splice (m_Queue.end (), list);
|
||||
m_NonEmpty.notify_one ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Element GetNext ()
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||
@@ -87,7 +84,7 @@ namespace util
|
||||
return m_Queue.empty ();
|
||||
}
|
||||
|
||||
int GetSize ()
|
||||
int GetSize () const
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||
return m_Queue.size ();
|
||||
@@ -107,15 +104,28 @@ namespace util
|
||||
return GetNonThreadSafe (true);
|
||||
}
|
||||
|
||||
private:
|
||||
void GetWholeQueue (std::list<Element>& queue)
|
||||
{
|
||||
if (!queue.empty ())
|
||||
{
|
||||
std::list<Element> newQueue;
|
||||
queue.swap (newQueue);
|
||||
}
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||
m_Queue.swap (queue);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Element GetNonThreadSafe (bool peek = false)
|
||||
{
|
||||
if (!m_Queue.empty ())
|
||||
{
|
||||
auto el = m_Queue.front ();
|
||||
if (!peek)
|
||||
m_Queue.pop ();
|
||||
m_Queue.pop_front ();
|
||||
return el;
|
||||
}
|
||||
return nullptr;
|
||||
@@ -123,8 +133,8 @@ namespace util
|
||||
|
||||
private:
|
||||
|
||||
std::queue<Element> m_Queue;
|
||||
std::mutex m_QueueMutex;
|
||||
std::list<Element> m_Queue;
|
||||
mutable std::mutex m_QueueMutex;
|
||||
std::condition_variable m_NonEmpty;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "HTTP.h"
|
||||
#include "util.h"
|
||||
#include "Config.h"
|
||||
#include "Socks5.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
@@ -551,7 +552,7 @@ namespace data
|
||||
if (!url.port)
|
||||
url.port = 443;
|
||||
|
||||
boost::asio::io_service service;
|
||||
boost::asio::io_context service;
|
||||
boost::system::error_code ecode;
|
||||
|
||||
boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
|
||||
@@ -561,11 +562,10 @@ namespace data
|
||||
if(proxyUrl.schema.size())
|
||||
{
|
||||
// proxy connection
|
||||
auto it = boost::asio::ip::tcp::resolver(service).resolve (
|
||||
boost::asio::ip::tcp::resolver::query (proxyUrl.host, std::to_string(proxyUrl.port)), ecode);
|
||||
auto it = boost::asio::ip::tcp::resolver(service).resolve (proxyUrl.host, std::to_string(proxyUrl.port), ecode);
|
||||
if(!ecode)
|
||||
{
|
||||
s.lowest_layer().connect(*it, ecode);
|
||||
s.lowest_layer().connect(*it.begin (), ecode);
|
||||
if(!ecode)
|
||||
{
|
||||
auto & sock = s.next_layer();
|
||||
@@ -598,7 +598,7 @@ namespace data
|
||||
LogPrint(eLogError, "Reseed: HTTP CONNECT read error: ", ecode.message());
|
||||
return "";
|
||||
}
|
||||
if(proxyRes.parse(boost::asio::buffer_cast<const char *>(readbuf.data()), readbuf.size()) <= 0)
|
||||
if(proxyRes.parse(std::string {boost::asio::buffers_begin(readbuf.data ()), boost::asio::buffers_begin(readbuf.data ()) + readbuf.size ()}) <= 0)
|
||||
{
|
||||
sock.close();
|
||||
LogPrint(eLogError, "Reseed: HTTP CONNECT malformed reply");
|
||||
@@ -615,62 +615,21 @@ namespace data
|
||||
{
|
||||
// assume socks if not http, is checked before this for other types
|
||||
// TODO: support username/password auth etc
|
||||
uint8_t hs_writebuf[3] = {0x05, 0x01, 0x00};
|
||||
uint8_t hs_readbuf[2];
|
||||
boost::asio::write(sock, boost::asio::buffer(hs_writebuf, 3), boost::asio::transfer_all(), ecode);
|
||||
if(ecode)
|
||||
bool success = false;
|
||||
i2p::transport::Socks5Handshake (sock, std::make_pair(url.host, url.port),
|
||||
[&success](const boost::system::error_code& ec)
|
||||
{
|
||||
if (!ec)
|
||||
success = true;
|
||||
else
|
||||
LogPrint (eLogError, "Reseed: SOCKS handshake failed: ", ec.message());
|
||||
});
|
||||
service.run (); // execute all async operations
|
||||
if (!success)
|
||||
{
|
||||
sock.close();
|
||||
LogPrint(eLogError, "Reseed: SOCKS handshake write failed: ", ecode.message());
|
||||
return "";
|
||||
}
|
||||
boost::asio::read(sock, boost::asio::buffer(hs_readbuf, 2), ecode);
|
||||
if(ecode)
|
||||
{
|
||||
sock.close();
|
||||
LogPrint(eLogError, "Reseed: SOCKS handshake read failed: ", ecode.message());
|
||||
return "";
|
||||
}
|
||||
size_t sz = 0;
|
||||
uint8_t buf[256];
|
||||
|
||||
buf[0] = 0x05;
|
||||
buf[1] = 0x01;
|
||||
buf[2] = 0x00;
|
||||
buf[3] = 0x03;
|
||||
sz += 4;
|
||||
size_t hostsz = url.host.size();
|
||||
if(1 + 2 + hostsz + sz > sizeof(buf))
|
||||
{
|
||||
sock.close();
|
||||
LogPrint(eLogError, "Reseed: SOCKS handshake failed, hostname too big: ", url.host);
|
||||
return "";
|
||||
}
|
||||
buf[4] = (uint8_t) hostsz;
|
||||
memcpy(buf+5, url.host.c_str(), hostsz);
|
||||
sz += hostsz + 1;
|
||||
htobe16buf(buf+sz, url.port);
|
||||
sz += 2;
|
||||
boost::asio::write(sock, boost::asio::buffer(buf, sz), boost::asio::transfer_all(), ecode);
|
||||
if(ecode)
|
||||
{
|
||||
sock.close();
|
||||
LogPrint(eLogError, "Reseed: SOCKS handshake failed writing: ", ecode.message());
|
||||
return "";
|
||||
}
|
||||
boost::asio::read(sock, boost::asio::buffer(buf, 10), ecode);
|
||||
if(ecode)
|
||||
{
|
||||
sock.close();
|
||||
LogPrint(eLogError, "Reseed: SOCKS handshake failed reading: ", ecode.message());
|
||||
return "";
|
||||
}
|
||||
if(buf[1] != 0x00)
|
||||
{
|
||||
sock.close();
|
||||
LogPrint(eLogError, "Reseed: SOCKS handshake bad reply code: ", std::to_string(buf[1]));
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -678,27 +637,23 @@ namespace data
|
||||
else
|
||||
{
|
||||
// direct connection
|
||||
auto it = boost::asio::ip::tcp::resolver(service).resolve (
|
||||
boost::asio::ip::tcp::resolver::query (url.host, std::to_string(url.port)), ecode);
|
||||
auto endpoints = boost::asio::ip::tcp::resolver(service).resolve (url.host, std::to_string(url.port), ecode);
|
||||
if (!ecode)
|
||||
{
|
||||
bool connected = false;
|
||||
boost::asio::ip::tcp::resolver::iterator end;
|
||||
while (it != end)
|
||||
for (const auto& it: endpoints)
|
||||
{
|
||||
boost::asio::ip::tcp::endpoint ep = *it;
|
||||
if (
|
||||
(
|
||||
!i2p::util::net::IsInReservedRange(ep.address ()) && (
|
||||
(ep.address ().is_v4 () && i2p::context.SupportsV4 ()) ||
|
||||
(ep.address ().is_v6 () && i2p::context.SupportsV6 ())
|
||||
)
|
||||
) ||
|
||||
(
|
||||
i2p::util::net::IsYggdrasilAddress (ep.address ()) &&
|
||||
i2p::context.SupportsMesh ()
|
||||
)
|
||||
)
|
||||
boost::asio::ip::tcp::endpoint ep = it;
|
||||
bool supported = false;
|
||||
if (!ep.address ().is_unspecified ())
|
||||
{
|
||||
if (ep.address ().is_v4 ())
|
||||
supported = i2p::context.SupportsV4 ();
|
||||
else if (ep.address ().is_v6 ())
|
||||
supported = i2p::util::net::IsYggdrasilAddress (ep.address ()) ?
|
||||
i2p::context.SupportsMesh () : i2p::context.SupportsV6 ();
|
||||
}
|
||||
if (supported)
|
||||
{
|
||||
s.lowest_layer().connect (ep, ecode);
|
||||
if (!ecode)
|
||||
@@ -708,7 +663,6 @@ namespace data
|
||||
break;
|
||||
}
|
||||
}
|
||||
it++;
|
||||
}
|
||||
if (!connected)
|
||||
{
|
||||
@@ -788,19 +742,16 @@ namespace data
|
||||
if (!url.port) url.port = 80;
|
||||
|
||||
boost::system::error_code ecode;
|
||||
boost::asio::io_service service;
|
||||
boost::asio::io_context service;
|
||||
boost::asio::ip::tcp::socket s(service, boost::asio::ip::tcp::v6());
|
||||
|
||||
auto it = boost::asio::ip::tcp::resolver(service).resolve (
|
||||
boost::asio::ip::tcp::resolver::query (url.host, std::to_string(url.port)), ecode);
|
||||
|
||||
auto endpoints = boost::asio::ip::tcp::resolver(service).resolve (url.host, std::to_string(url.port), ecode);
|
||||
if (!ecode)
|
||||
{
|
||||
bool connected = false;
|
||||
boost::asio::ip::tcp::resolver::iterator end;
|
||||
while (it != end)
|
||||
for (const auto& it: endpoints)
|
||||
{
|
||||
boost::asio::ip::tcp::endpoint ep = *it;
|
||||
boost::asio::ip::tcp::endpoint ep = it;
|
||||
if (
|
||||
i2p::util::net::IsYggdrasilAddress (ep.address ()) &&
|
||||
i2p::context.SupportsMesh ()
|
||||
@@ -814,7 +765,6 @@ namespace data
|
||||
break;
|
||||
}
|
||||
}
|
||||
it++;
|
||||
}
|
||||
if (!connected)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -40,7 +40,7 @@ namespace i2p
|
||||
void RouterContext::Init ()
|
||||
{
|
||||
srand (i2p::util::GetMillisecondsSinceEpoch () % 1000);
|
||||
m_StartupTime = std::chrono::steady_clock::now();
|
||||
m_StartupTime = i2p::util::GetMonotonicSeconds ();
|
||||
|
||||
if (!Load ())
|
||||
CreateNewRouter ();
|
||||
@@ -57,13 +57,12 @@ namespace i2p
|
||||
{
|
||||
m_Service.reset (new RouterService);
|
||||
m_Service->Start ();
|
||||
if (!m_IsHiddenMode)
|
||||
{
|
||||
m_PublishTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ()));
|
||||
ScheduleInitialPublish ();
|
||||
m_CongestionUpdateTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ()));
|
||||
ScheduleCongestionUpdate ();
|
||||
}
|
||||
m_PublishTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ()));
|
||||
ScheduleInitialPublish ();
|
||||
m_CongestionUpdateTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ()));
|
||||
ScheduleCongestionUpdate ();
|
||||
m_CleanupTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ()));
|
||||
ScheduleCleanupTimer ();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,9 +75,16 @@ namespace i2p
|
||||
if (m_CongestionUpdateTimer)
|
||||
m_CongestionUpdateTimer->cancel ();
|
||||
m_Service->Stop ();
|
||||
CleanUp (); // GarlicDestination
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<i2p::data::RouterInfo::Buffer> RouterContext::CopyRouterInfoBuffer () const
|
||||
{
|
||||
std::lock_guard<std::mutex> l(m_RouterInfoMutex);
|
||||
return m_RouterInfo.CopyBuffer ();
|
||||
}
|
||||
|
||||
void RouterContext::CreateNewRouter ()
|
||||
{
|
||||
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519,
|
||||
@@ -134,7 +140,7 @@ namespace i2p
|
||||
{
|
||||
boost::asio::ip::address addr;
|
||||
if (!host.empty ())
|
||||
addr = boost::asio::ip::address::from_string (host);
|
||||
addr = boost::asio::ip::make_address (host);
|
||||
if (!addr.is_v4())
|
||||
addr = boost::asio::ip::address_v4 ();
|
||||
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, addr, ntcp2Port);
|
||||
@@ -155,7 +161,7 @@ namespace i2p
|
||||
{
|
||||
boost::asio::ip::address addr;
|
||||
if (!host.empty ())
|
||||
addr = boost::asio::ip::address::from_string (host);
|
||||
addr = boost::asio::ip::make_address (host);
|
||||
if (!addr.is_v4())
|
||||
addr = boost::asio::ip::address_v4 ();
|
||||
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addr, ssu2Port);
|
||||
@@ -186,7 +192,7 @@ namespace i2p
|
||||
ntcp2Host = host;
|
||||
boost::asio::ip::address addr;
|
||||
if (!ntcp2Host.empty ())
|
||||
addr = boost::asio::ip::address::from_string (ntcp2Host);
|
||||
addr = boost::asio::ip::make_address (ntcp2Host);
|
||||
if (!addr.is_v6())
|
||||
addr = boost::asio::ip::address_v6 ();
|
||||
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, addr, ntcp2Port);
|
||||
@@ -205,7 +211,7 @@ namespace i2p
|
||||
{
|
||||
boost::asio::ip::address addr;
|
||||
if (!host.empty ())
|
||||
addr = boost::asio::ip::address::from_string (host);
|
||||
addr = boost::asio::ip::make_address (host);
|
||||
if (!addr.is_v6())
|
||||
addr = boost::asio::ip::address_v6 ();
|
||||
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addr, ssu2Port);
|
||||
@@ -247,7 +253,10 @@ namespace i2p
|
||||
|
||||
void RouterContext::UpdateRouterInfo ()
|
||||
{
|
||||
m_RouterInfo.CreateBuffer (m_Keys);
|
||||
{
|
||||
std::lock_guard<std::mutex> l(m_RouterInfoMutex);
|
||||
m_RouterInfo.CreateBuffer (m_Keys);
|
||||
}
|
||||
m_RouterInfo.SaveToFile (i2p::fs::DataDirPath (ROUTER_INFO));
|
||||
m_LastUpdateTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
}
|
||||
@@ -303,6 +312,8 @@ namespace i2p
|
||||
SetTesting (false);
|
||||
if (status != m_Status)
|
||||
{
|
||||
LogPrint(eLogInfo, "Router: network status v4 changed ",
|
||||
ROUTER_STATUS_NAMES[m_Status], " -> ", ROUTER_STATUS_NAMES[status]);
|
||||
m_Status = status;
|
||||
switch (m_Status)
|
||||
{
|
||||
@@ -312,6 +323,12 @@ namespace i2p
|
||||
case eRouterStatusFirewalled:
|
||||
SetUnreachable (true, false); // ipv4
|
||||
break;
|
||||
case eRouterStatusMesh:
|
||||
m_RouterInfo.UpdateCaps (m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eReachable);
|
||||
break;
|
||||
case eRouterStatusProxy:
|
||||
m_RouterInfo.UpdateCaps (m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eUnreachable);
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
@@ -323,6 +340,8 @@ namespace i2p
|
||||
SetTestingV6 (false);
|
||||
if (status != m_StatusV6)
|
||||
{
|
||||
LogPrint(eLogInfo, "Router: network status v6 changed ",
|
||||
ROUTER_STATUS_NAMES[m_StatusV6], " -> ", ROUTER_STATUS_NAMES[status]);
|
||||
m_StatusV6 = status;
|
||||
switch (m_StatusV6)
|
||||
{
|
||||
@@ -540,6 +559,12 @@ namespace i2p
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
void RouterContext::UpdateSSU2Introducer (const i2p::data::IdentHash& h, bool v4, uint32_t iTag, uint32_t iExp)
|
||||
{
|
||||
if (m_RouterInfo.UpdateSSU2Introducer (h, v4, iTag, iExp))
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
void RouterContext::ClearSSU2Introducers (bool v4)
|
||||
{
|
||||
auto addr = m_RouterInfo.GetSSU2Address (v4);
|
||||
@@ -554,10 +579,10 @@ namespace i2p
|
||||
{
|
||||
m_IsFloodfill = floodfill;
|
||||
if (floodfill)
|
||||
m_RouterInfo.UpdateCaps (m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eFloodfill);
|
||||
m_RouterInfo.UpdateFloodfillProperty (true);
|
||||
else
|
||||
{
|
||||
m_RouterInfo.UpdateCaps (m_RouterInfo.GetCaps () & ~i2p::data::RouterInfo::eFloodfill);
|
||||
m_RouterInfo.UpdateFloodfillProperty (false);
|
||||
// we don't publish number of routers and leaseset for non-floodfill
|
||||
m_RouterInfo.DeleteProperty (i2p::data::ROUTER_INFO_PROPERTY_LEASESETS);
|
||||
m_RouterInfo.DeleteProperty (i2p::data::ROUTER_INFO_PROPERTY_ROUTERS);
|
||||
@@ -596,9 +621,9 @@ namespace i2p
|
||||
{
|
||||
case i2p::data::CAPS_FLAG_LOW_BANDWIDTH1 : limit = 12; type = low; break;
|
||||
case i2p::data::CAPS_FLAG_LOW_BANDWIDTH2 : limit = i2p::data::LOW_BANDWIDTH_LIMIT; type = low; break; // 48
|
||||
case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH1 : limit = 64; type = high; break;
|
||||
case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH2 : limit = 128; type = high; break;
|
||||
case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH3 : limit = i2p::data::HIGH_BANDWIDTH_LIMIT; type = high; break; // 256
|
||||
case i2p::data::CAPS_FLAG_LOW_BANDWIDTH3 : limit = 64; type = low; break;
|
||||
case i2p::data::CAPS_FLAG_LOW_BANDWIDTH4 : limit = 128; type = low; break;
|
||||
case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH : limit = i2p::data::HIGH_BANDWIDTH_LIMIT; type = high; break; // 256
|
||||
case i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH1 : limit = i2p::data::EXTRA_BANDWIDTH_LIMIT; type = extra; break; // 2048
|
||||
case i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH2 : limit = 1000000; type = unlim; break; // 1Gbyte/s
|
||||
default:
|
||||
@@ -613,9 +638,7 @@ namespace i2p
|
||||
case low : /* not set */; break;
|
||||
case extra : caps |= i2p::data::RouterInfo::eExtraBandwidth; break; // 'P'
|
||||
case unlim : caps |= i2p::data::RouterInfo::eExtraBandwidth;
|
||||
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||
[[fallthrough]];
|
||||
#endif
|
||||
// no break here, extra + high means 'X'
|
||||
case high : caps |= i2p::data::RouterInfo::eHighBandwidth; break;
|
||||
}
|
||||
@@ -779,7 +802,7 @@ namespace i2p
|
||||
i2p::config::GetOption("host", ntcp2Host);
|
||||
if (!ntcp2Host.empty () && ntcp2Port)
|
||||
{
|
||||
auto addr = boost::asio::ip::address::from_string (ntcp2Host);
|
||||
auto addr = boost::asio::ip::make_address (ntcp2Host);
|
||||
if (addr.is_v6 ())
|
||||
{
|
||||
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, addr, ntcp2Port);
|
||||
@@ -808,7 +831,7 @@ namespace i2p
|
||||
std::string host; i2p::config::GetOption("host", host);
|
||||
if (!host.empty ())
|
||||
{
|
||||
auto addr = boost::asio::ip::address::from_string (host);
|
||||
auto addr = boost::asio::ip::make_address (host);
|
||||
if (addr.is_v6 ())
|
||||
{
|
||||
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addr, ssu2Port);
|
||||
@@ -877,7 +900,7 @@ namespace i2p
|
||||
std::string host; i2p::config::GetOption("host", host);
|
||||
if (!host.empty ())
|
||||
{
|
||||
auto addr = boost::asio::ip::address::from_string (host);
|
||||
auto addr = boost::asio::ip::make_address (host);
|
||||
if (addr.is_v4 ())
|
||||
{
|
||||
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, addr, ntcp2Port);
|
||||
@@ -907,7 +930,7 @@ namespace i2p
|
||||
std::string host; i2p::config::GetOption("host", host);
|
||||
if (!host.empty ())
|
||||
{
|
||||
auto addr = boost::asio::ip::address::from_string (host);
|
||||
auto addr = boost::asio::ip::make_address (host);
|
||||
if (addr.is_v4 ())
|
||||
{
|
||||
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addr, ssu2Port);
|
||||
@@ -1131,13 +1154,14 @@ namespace i2p
|
||||
return i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||
}
|
||||
|
||||
bool RouterContext::IsHighCongestion () const
|
||||
int RouterContext::GetCongestionLevel (bool longTerm) const
|
||||
{
|
||||
return i2p::tunnel::tunnels.IsTooManyTransitTunnels () ||
|
||||
i2p::transport::transports.IsBandwidthExceeded () ||
|
||||
i2p::transport::transports.IsTransitBandwidthExceeded ();
|
||||
}
|
||||
|
||||
return std::max (
|
||||
i2p::tunnel::tunnels.GetCongestionLevel (),
|
||||
i2p::transport::transports.GetCongestionLevel (longTerm)
|
||||
);
|
||||
}
|
||||
|
||||
void RouterContext::HandleI2NPMessage (const uint8_t * buf, size_t len)
|
||||
{
|
||||
i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len)));
|
||||
@@ -1145,6 +1169,13 @@ namespace i2p
|
||||
|
||||
bool RouterContext::HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len, uint32_t msgID)
|
||||
{
|
||||
if (typeID == eI2NPTunnelTest)
|
||||
{
|
||||
// try tunnel test
|
||||
auto pool = GetTunnelPool ();
|
||||
if (pool && pool->ProcessTunnelTest (bufbe32toh (payload + TUNNEL_TEST_MSGID_OFFSET), bufbe64toh (payload + TUNNEL_TEST_TIMESTAMP_OFFSET)))
|
||||
return true;
|
||||
}
|
||||
auto msg = CreateI2NPMessage (typeID, payload, len, msgID);
|
||||
if (!msg) return false;
|
||||
i2p::HandleI2NPMessage (msg);
|
||||
@@ -1154,7 +1185,7 @@ namespace i2p
|
||||
void RouterContext::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
if (m_Service)
|
||||
m_Service->GetService ().post (std::bind (&RouterContext::PostGarlicMessage, this, msg));
|
||||
boost::asio::post (m_Service->GetService (), std::bind (&RouterContext::PostGarlicMessage, this, msg));
|
||||
else
|
||||
LogPrint (eLogError, "Router: service is NULL");
|
||||
}
|
||||
@@ -1182,7 +1213,7 @@ namespace i2p
|
||||
void RouterContext::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
if (m_Service)
|
||||
m_Service->GetService ().post (std::bind (&RouterContext::PostDeliveryStatusMessage, this, msg));
|
||||
boost::asio::post (m_Service->GetService (), std::bind (&RouterContext::PostDeliveryStatusMessage, this, msg));
|
||||
else
|
||||
LogPrint (eLogError, "Router: service is NULL");
|
||||
}
|
||||
@@ -1199,21 +1230,30 @@ namespace i2p
|
||||
else
|
||||
i2p::garlic::GarlicDestination::ProcessDeliveryStatusMessage (msg);
|
||||
}
|
||||
|
||||
void RouterContext::CleanupDestination ()
|
||||
|
||||
void RouterContext::SubmitECIESx25519Key (const uint8_t * key, uint64_t tag)
|
||||
{
|
||||
if (m_Service)
|
||||
m_Service->GetService ().post ([this]()
|
||||
{
|
||||
this->i2p::garlic::GarlicDestination::CleanupExpiredTags ();
|
||||
});
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t k[32];
|
||||
uint64_t t;
|
||||
} data;
|
||||
memcpy (data.k, key, 32);
|
||||
data.t = tag;
|
||||
boost::asio::post (m_Service->GetService (), [this,data](void)
|
||||
{
|
||||
AddECIESx25519Key (data.k, data.t);
|
||||
});
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Router: service is NULL");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t RouterContext::GetUptime () const
|
||||
{
|
||||
return std::chrono::duration_cast<std::chrono::seconds> (std::chrono::steady_clock::now() - m_StartupTime).count ();
|
||||
return i2p::util::GetMonotonicSeconds () - m_StartupTime;
|
||||
}
|
||||
|
||||
bool RouterContext::Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const
|
||||
@@ -1301,9 +1341,15 @@ namespace i2p
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
if (m_RouterInfo.IsReachableBy (i2p::data::RouterInfo::eAllTransports))
|
||||
{
|
||||
UpdateCongestion ();
|
||||
HandlePublishTimer (ecode);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateTimestamp (i2p::util::GetSecondsSinceEpoch ());
|
||||
ScheduleInitialPublish ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1325,16 +1371,21 @@ namespace i2p
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
m_PublishExcluded.clear ();
|
||||
m_PublishReplyToken = 0;
|
||||
if (IsFloodfill ())
|
||||
{
|
||||
UpdateStats (); // for floodfill
|
||||
m_PublishExcluded.insert (i2p::context.GetIdentHash ()); // don't publish to ourselves
|
||||
}
|
||||
UpdateTimestamp (i2p::util::GetSecondsSinceEpoch ());
|
||||
Publish ();
|
||||
SchedulePublishResend ();
|
||||
if (!m_IsHiddenMode)
|
||||
{
|
||||
m_PublishExcluded.clear ();
|
||||
m_PublishReplyToken = 0;
|
||||
if (IsFloodfill ())
|
||||
{
|
||||
UpdateStats (); // for floodfill
|
||||
m_PublishExcluded.insert (i2p::context.GetIdentHash ()); // don't publish to ourselves
|
||||
}
|
||||
Publish ();
|
||||
SchedulePublishResend ();
|
||||
}
|
||||
else
|
||||
SchedulePublish ();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1354,10 +1405,20 @@ namespace i2p
|
||||
uint32_t replyToken;
|
||||
RAND_bytes ((uint8_t *)&replyToken, 4);
|
||||
LogPrint (eLogInfo, "Router: Publishing our RouterInfo to ", i2p::data::GetIdentHashAbbreviation(floodfill->GetIdentHash ()), ". reply token=", replyToken);
|
||||
if (floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) || // are we able to connect?
|
||||
i2p::transport::transports.IsConnected (floodfill->GetIdentHash ())) // already connected ?
|
||||
auto onDrop = [this]()
|
||||
{
|
||||
if (m_Service)
|
||||
boost::asio::post (m_Service->GetService (), [this]() { HandlePublishResendTimer (boost::system::error_code ()); });
|
||||
};
|
||||
if (i2p::transport::transports.IsConnected (floodfill->GetIdentHash ()) || // already connected
|
||||
(floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) && // are we able to connect
|
||||
!i2p::transport::transports.RoutesRestricted ())) // and routes not restricted
|
||||
{
|
||||
// send directly
|
||||
i2p::transport::transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken));
|
||||
auto msg = CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken);
|
||||
msg->onDrop = onDrop;
|
||||
i2p::transport::transports.SendMessage (floodfill->GetIdentHash (), msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise through exploratory
|
||||
@@ -1368,6 +1429,7 @@ namespace i2p
|
||||
{
|
||||
// encrypt for floodfill
|
||||
auto msg = CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken, inbound);
|
||||
msg->onDrop = onDrop;
|
||||
outbound->SendTunnelDataMsgTo (floodfill->GetIdentHash (), 0,
|
||||
i2p::garlic::WrapECIESX25519MessageForRouter (msg, floodfill->GetIdentity ()->GetEncryptionPublicKey ()));
|
||||
}
|
||||
@@ -1421,14 +1483,47 @@ namespace i2p
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
auto c = i2p::data::RouterInfo::eLowCongestion;
|
||||
if (!AcceptsTunnels ())
|
||||
c = i2p::data::RouterInfo::eRejectAll;
|
||||
else if (IsHighCongestion ())
|
||||
c = i2p::data::RouterInfo::eHighCongestion;
|
||||
if (m_RouterInfo.UpdateCongestion (c))
|
||||
UpdateRouterInfo ();
|
||||
UpdateCongestion ();
|
||||
ScheduleCongestionUpdate ();
|
||||
}
|
||||
}
|
||||
|
||||
void RouterContext::UpdateCongestion ()
|
||||
{
|
||||
auto c = i2p::data::RouterInfo::eLowCongestion;
|
||||
if (!AcceptsTunnels () || !m_ShareRatio)
|
||||
c = i2p::data::RouterInfo::eRejectAll;
|
||||
else
|
||||
{
|
||||
int congestionLevel = GetCongestionLevel (true);
|
||||
if (congestionLevel > CONGESTION_LEVEL_HIGH)
|
||||
c = i2p::data::RouterInfo::eHighCongestion;
|
||||
else if (congestionLevel > CONGESTION_LEVEL_MEDIUM)
|
||||
c = i2p::data::RouterInfo::eMediumCongestion;
|
||||
}
|
||||
if (m_RouterInfo.UpdateCongestion (c))
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
void RouterContext::ScheduleCleanupTimer ()
|
||||
{
|
||||
if (m_CleanupTimer)
|
||||
{
|
||||
m_CleanupTimer->cancel ();
|
||||
m_CleanupTimer->expires_from_now (boost::posix_time::seconds(ROUTER_INFO_CLEANUP_INTERVAL));
|
||||
m_CleanupTimer->async_wait (std::bind (&RouterContext::HandleCleanupTimer,
|
||||
this, std::placeholders::_1));
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Router: Cleanup timer is NULL");
|
||||
}
|
||||
|
||||
void RouterContext::HandleCleanupTimer (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
CleanupExpiredTags ();
|
||||
ScheduleCleanupTimer ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -12,8 +12,7 @@
|
||||
#include <inttypes.h>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <chrono>
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
#include <boost/asio.hpp>
|
||||
#include "Identity.h"
|
||||
#include "RouterInfo.h"
|
||||
@@ -38,6 +37,7 @@ namespace garlic
|
||||
const int ROUTER_INFO_CONFIRMATION_TIMEOUT = 5; // in seconds
|
||||
const int ROUTER_INFO_MAX_PUBLISH_EXCLUDED_FLOODFILLS = 15;
|
||||
const int ROUTER_INFO_CONGESTION_UPDATE_INTERVAL = 12*60; // in seconds
|
||||
const int ROUTER_INFO_CLEANUP_INTERVAL = 102; // in seconds
|
||||
|
||||
enum RouterStatus
|
||||
{
|
||||
@@ -48,6 +48,15 @@ namespace garlic
|
||||
eRouterStatusMesh = 4
|
||||
};
|
||||
|
||||
const char* const ROUTER_STATUS_NAMES[] =
|
||||
{
|
||||
"OK", // 0
|
||||
"Firewalled", // 1
|
||||
"Unknown", // 2
|
||||
"Proxy", // 3
|
||||
"Mesh" // 4
|
||||
};
|
||||
|
||||
enum RouterError
|
||||
{
|
||||
eRouterErrorNone = 0,
|
||||
@@ -81,7 +90,7 @@ namespace garlic
|
||||
public:
|
||||
|
||||
RouterService (): RunnableServiceWithWork ("Router") {};
|
||||
boost::asio::io_service& GetService () { return GetIOService (); };
|
||||
auto& GetService () { return GetIOService (); };
|
||||
void Start () { StartIOService (); };
|
||||
void Stop () { StopIOService (); };
|
||||
};
|
||||
@@ -105,7 +114,8 @@ namespace garlic
|
||||
return std::shared_ptr<i2p::garlic::GarlicDestination> (this,
|
||||
[](i2p::garlic::GarlicDestination *) {});
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::data::RouterInfo::Buffer> CopyRouterInfoBuffer () const;
|
||||
|
||||
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; };
|
||||
@@ -143,6 +153,7 @@ namespace garlic
|
||||
void PublishSSU2Address (int port, bool publish, bool v4, bool v6);
|
||||
bool AddSSU2Introducer (const i2p::data::RouterInfo::Introducer& introducer, bool v4);
|
||||
void RemoveSSU2Introducer (const i2p::data::IdentHash& h, bool v4);
|
||||
void UpdateSSU2Introducer (const i2p::data::IdentHash& h, bool v4, uint32_t iTag, uint32_t iExp);
|
||||
void ClearSSU2Introducers (bool v4);
|
||||
bool IsUnreachable () const;
|
||||
void SetUnreachable (bool v4, bool v6);
|
||||
@@ -156,7 +167,7 @@ namespace garlic
|
||||
void SetShareRatio (int percents); // 0 - 100
|
||||
bool AcceptsTunnels () const { return m_AcceptsTunnels; };
|
||||
void SetAcceptsTunnels (bool acceptsTunnels) { m_AcceptsTunnels = acceptsTunnels; };
|
||||
bool IsHighCongestion () const;
|
||||
int GetCongestionLevel (bool longTerm) const;
|
||||
bool SupportsV6 () const { return m_RouterInfo.IsV6 (); };
|
||||
bool SupportsV4 () const { return m_RouterInfo.IsV4 (); };
|
||||
bool SupportsMesh () const { return m_RouterInfo.IsMesh (); };
|
||||
@@ -166,32 +177,32 @@ namespace garlic
|
||||
void SetMTU (int mtu, bool v4);
|
||||
void SetHidden(bool hide) { m_IsHiddenMode = hide; };
|
||||
bool IsHidden() const { return m_IsHiddenMode; };
|
||||
bool IsLimitedConnectivity () const { return m_Status == eRouterStatusProxy; }; // TODO: implement other cases
|
||||
i2p::crypto::NoiseSymmetricState& GetCurrentNoiseState () { return m_CurrentNoiseState; };
|
||||
|
||||
void UpdateNTCP2V6Address (const boost::asio::ip::address& host); // called from Daemon. TODO: remove
|
||||
void UpdateStats ();
|
||||
void UpdateTimestamp (uint64_t ts); // in seconds, called from NetDb before publishing
|
||||
void CleanupDestination (); // garlic destination
|
||||
|
||||
// implements LocalDestination
|
||||
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Keys.GetPublic (); };
|
||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const;
|
||||
void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); };
|
||||
void SetLeaseSetUpdated () {};
|
||||
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const override{ return m_Keys.GetPublic (); };
|
||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const override;
|
||||
void SetLeaseSetUpdated (bool post) override {};
|
||||
|
||||
// implements GarlicDestination
|
||||
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet () { return nullptr; };
|
||||
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const;
|
||||
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet () override { return nullptr; };
|
||||
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const override;
|
||||
|
||||
// override GarlicDestination
|
||||
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg) override;
|
||||
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg) override;
|
||||
void SubmitECIESx25519Key (const uint8_t * key, uint64_t tag) override;
|
||||
|
||||
protected:
|
||||
|
||||
// implements GarlicDestination
|
||||
void HandleI2NPMessage (const uint8_t * buf, size_t len);
|
||||
bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len, uint32_t msgID);
|
||||
void HandleI2NPMessage (const uint8_t * buf, size_t len) override;
|
||||
bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len, uint32_t msgID) override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -204,6 +215,7 @@ namespace garlic
|
||||
void UpdateSSU2Keys ();
|
||||
bool Load ();
|
||||
void SaveKeys ();
|
||||
void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); };
|
||||
uint16_t SelectRandomPort () const;
|
||||
void PublishNTCP2Address (std::shared_ptr<i2p::data::RouterInfo::Address> address, int port, bool publish) const;
|
||||
|
||||
@@ -220,6 +232,9 @@ namespace garlic
|
||||
void HandlePublishResendTimer (const boost::system::error_code& ecode);
|
||||
void ScheduleCongestionUpdate ();
|
||||
void HandleCongestionUpdateTimer (const boost::system::error_code& ecode);
|
||||
void UpdateCongestion ();
|
||||
void ScheduleCleanupTimer ();
|
||||
void HandleCleanupTimer (const boost::system::error_code& ecode);
|
||||
|
||||
private:
|
||||
|
||||
@@ -229,7 +244,7 @@ namespace garlic
|
||||
std::shared_ptr<i2p::garlic::RouterIncomingRatchetSession> m_ECIESSession;
|
||||
uint64_t m_LastUpdateTime; // in seconds
|
||||
bool m_AcceptsTunnels, m_IsFloodfill;
|
||||
std::chrono::time_point<std::chrono::steady_clock> m_StartupTime;
|
||||
uint64_t m_StartupTime; // monotonic seconds
|
||||
uint64_t m_BandwidthLimit; // allowed bandwidth
|
||||
int m_ShareRatio;
|
||||
RouterStatus m_Status, m_StatusV6;
|
||||
@@ -243,10 +258,11 @@ namespace garlic
|
||||
i2p::crypto::NoiseSymmetricState m_InitialNoiseState, m_CurrentNoiseState;
|
||||
// publish
|
||||
std::unique_ptr<RouterService> m_Service;
|
||||
std::unique_ptr<boost::asio::deadline_timer> m_PublishTimer, m_CongestionUpdateTimer;
|
||||
std::set<i2p::data::IdentHash> m_PublishExcluded;
|
||||
std::unique_ptr<boost::asio::deadline_timer> m_PublishTimer, m_CongestionUpdateTimer, m_CleanupTimer;
|
||||
std::unordered_set<i2p::data::IdentHash> m_PublishExcluded;
|
||||
uint32_t m_PublishReplyToken;
|
||||
bool m_IsHiddenMode; // not publish
|
||||
mutable std::mutex m_RouterInfoMutex;
|
||||
};
|
||||
|
||||
extern RouterContext context;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -10,9 +10,10 @@
|
||||
#include <string.h>
|
||||
#include "I2PEndian.h"
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#if (BOOST_VERSION >= 105300)
|
||||
#include <boost/algorithm/string.hpp> // for boost::to_lower
|
||||
#ifndef __cpp_lib_atomic_shared_ptr
|
||||
#include <boost/atomic.hpp>
|
||||
#endif
|
||||
#include "version.h"
|
||||
@@ -21,6 +22,7 @@
|
||||
#include "Base.h"
|
||||
#include "Timestamp.h"
|
||||
#include "Log.h"
|
||||
#include "Transports.h"
|
||||
#include "NetDb.hpp"
|
||||
#include "RouterContext.h"
|
||||
#include "RouterInfo.h"
|
||||
@@ -33,33 +35,35 @@ namespace data
|
||||
{
|
||||
if (len > size ()) len = size ();
|
||||
memcpy (data (), buf, len);
|
||||
m_BufferLen = len;
|
||||
}
|
||||
|
||||
RouterInfo::RouterInfo (): m_Buffer (nullptr)
|
||||
{
|
||||
m_Addresses = boost::make_shared<Addresses>(); // create empty list
|
||||
m_Addresses = AddressesPtr(new Addresses ()); // create empty list
|
||||
}
|
||||
|
||||
RouterInfo::RouterInfo (const std::string& fullPath):
|
||||
m_FamilyID (0), m_IsUpdated (false), m_IsUnreachable (false),
|
||||
m_SupportedTransports (0),m_ReachableTransports (0),
|
||||
m_Caps (0), m_Version (0), m_Congestion (eLowCongestion)
|
||||
m_FamilyID (0), m_IsUpdated (false), m_IsUnreachable (false), m_IsFloodfill (false),
|
||||
m_IsBufferScheduledToDelete (false), m_SupportedTransports (0),
|
||||
m_ReachableTransports (0), m_PublishedTransports (0), m_Caps (0), m_Version (0),
|
||||
m_Congestion (eLowCongestion)
|
||||
{
|
||||
m_Addresses = boost::make_shared<Addresses>(); // create empty list
|
||||
m_Buffer = NewBuffer (); // always RouterInfo's
|
||||
m_Addresses = AddressesPtr(new Addresses ()); // create empty list
|
||||
m_Buffer = RouterInfo::NewBuffer (); // always RouterInfo's
|
||||
ReadFromFile (fullPath);
|
||||
}
|
||||
|
||||
RouterInfo::RouterInfo (std::shared_ptr<Buffer>&& buf, size_t len):
|
||||
m_FamilyID (0), m_IsUpdated (true), m_IsUnreachable (false),
|
||||
m_SupportedTransports (0), m_ReachableTransports (0),
|
||||
m_FamilyID (0), m_IsUpdated (true), m_IsUnreachable (false), m_IsFloodfill (false),
|
||||
m_IsBufferScheduledToDelete (false), m_SupportedTransports (0), m_ReachableTransports (0), m_PublishedTransports (0),
|
||||
m_Caps (0), m_Version (0), m_Congestion (eLowCongestion)
|
||||
{
|
||||
if (len <= MAX_RI_BUFFER_SIZE)
|
||||
{
|
||||
m_Addresses = boost::make_shared<Addresses>(); // create empty list
|
||||
m_Addresses = AddressesPtr(new Addresses ()); // create empty list
|
||||
m_Buffer = buf;
|
||||
m_BufferLen = len;
|
||||
if (m_Buffer) m_Buffer->SetBufferLen (len);
|
||||
ReadFromBuffer (true);
|
||||
}
|
||||
else
|
||||
@@ -71,7 +75,7 @@ namespace data
|
||||
}
|
||||
|
||||
RouterInfo::RouterInfo (const uint8_t * buf, size_t len):
|
||||
RouterInfo (std::make_shared<Buffer> (buf, len), len)
|
||||
RouterInfo (netdb.NewRouterInfoBuffer (buf, len), len)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -95,7 +99,8 @@ namespace data
|
||||
m_IsUnreachable = false;
|
||||
m_SupportedTransports = 0;
|
||||
m_ReachableTransports = 0;
|
||||
m_Caps = 0;
|
||||
m_PublishedTransports = 0;
|
||||
m_Caps = 0; m_IsFloodfill = false;
|
||||
// don't clean up m_Addresses, it will be replaced in ReadFromStream
|
||||
ClearProperties ();
|
||||
// skip identity
|
||||
@@ -127,16 +132,17 @@ namespace data
|
||||
if (s.is_open ())
|
||||
{
|
||||
s.seekg (0,std::ios::end);
|
||||
m_BufferLen = s.tellg ();
|
||||
if (m_BufferLen < 40 || m_BufferLen > MAX_RI_BUFFER_SIZE)
|
||||
size_t bufferLen = s.tellg ();
|
||||
if (bufferLen < 40 || bufferLen > MAX_RI_BUFFER_SIZE)
|
||||
{
|
||||
LogPrint(eLogError, "RouterInfo: File", fullPath, " is malformed");
|
||||
LogPrint(eLogError, "RouterInfo: File ", fullPath, " is malformed");
|
||||
return false;
|
||||
}
|
||||
s.seekg(0, std::ios::beg);
|
||||
if (!m_Buffer)
|
||||
m_Buffer = NewBuffer ();
|
||||
s.read((char *)m_Buffer->data (), m_BufferLen);
|
||||
s.read((char *)m_Buffer->data (), bufferLen);
|
||||
m_Buffer->SetBufferLen (bufferLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -161,11 +167,12 @@ namespace data
|
||||
m_IsUnreachable = true;
|
||||
return;
|
||||
}
|
||||
m_RouterIdentity = NewIdentity (m_Buffer->data (), m_BufferLen);
|
||||
size_t bufferLen = m_Buffer->GetBufferLen ();
|
||||
m_RouterIdentity = NewIdentity (m_Buffer->data (), bufferLen);
|
||||
size_t identityLen = m_RouterIdentity->GetFullLen ();
|
||||
if (identityLen >= m_BufferLen)
|
||||
if (identityLen >= bufferLen)
|
||||
{
|
||||
LogPrint (eLogError, "RouterInfo: Identity length ", identityLen, " exceeds buffer size ", m_BufferLen);
|
||||
LogPrint (eLogError, "RouterInfo: Identity length ", identityLen, " exceeds buffer size ", bufferLen);
|
||||
m_IsUnreachable = true;
|
||||
return;
|
||||
}
|
||||
@@ -179,7 +186,7 @@ namespace data
|
||||
return;
|
||||
}
|
||||
// verify signature
|
||||
int l = m_BufferLen - m_RouterIdentity->GetSignatureLen ();
|
||||
int l = bufferLen - m_RouterIdentity->GetSignatureLen ();
|
||||
if (l < 0 || !m_RouterIdentity->Verify ((uint8_t *)m_Buffer->data (), l, (uint8_t *)m_Buffer->data () + l))
|
||||
{
|
||||
LogPrint (eLogError, "RouterInfo: Signature verification failed");
|
||||
@@ -189,7 +196,7 @@ namespace data
|
||||
}
|
||||
// parse RI
|
||||
std::stringstream str;
|
||||
str.write ((const char *)m_Buffer->data () + identityLen, m_BufferLen - identityLen);
|
||||
str.write ((const char *)m_Buffer->data () + identityLen, bufferLen - identityLen);
|
||||
ReadFromStream (str);
|
||||
if (!str)
|
||||
{
|
||||
@@ -215,7 +222,7 @@ namespace data
|
||||
uint8_t cost; // ignore
|
||||
s.read ((char *)&cost, sizeof (cost));
|
||||
s.read ((char *)&address->date, sizeof (address->date));
|
||||
bool isHost = false, isStaticKey = false, isV2 = false;
|
||||
bool isHost = false, isStaticKey = false, isV2 = false, isIntroKey = false;
|
||||
char transportStyle[6];
|
||||
ReadString (transportStyle, 6, s);
|
||||
if (!strncmp (transportStyle, "NTCP", 4)) // NTCP or NTCP2
|
||||
@@ -250,10 +257,10 @@ namespace data
|
||||
if (!strcmp (key, "host"))
|
||||
{
|
||||
boost::system::error_code ecode;
|
||||
address->host = boost::asio::ip::address::from_string (value, ecode);
|
||||
address->host = boost::asio::ip::make_address (value, ecode);
|
||||
if (!ecode && !address->host.is_unspecified ())
|
||||
{
|
||||
if (!i2p::util::net::IsInReservedRange (address->host) ||
|
||||
if (!i2p::transport::transports.IsInReservedRange (address->host) ||
|
||||
i2p::util::net::IsYggdrasilAddress (address->host))
|
||||
isHost = true;
|
||||
else
|
||||
@@ -292,26 +299,38 @@ namespace data
|
||||
address->caps = ExtractAddressCaps (value);
|
||||
else if (!strcmp (key, "s")) // ntcp2 or ssu2 static key
|
||||
{
|
||||
Base64ToByteStream (value, strlen (value), address->s, 32);
|
||||
if (!(address->s[31] & 0x80)) // check if x25519 public key
|
||||
isStaticKey = true;
|
||||
if (Base64ToByteStream (value, strlen (value), address->s, 32) == 32 &&
|
||||
!(address->s[31] & 0x80)) // check if x25519 public key
|
||||
isStaticKey = true;
|
||||
else
|
||||
address->transportStyle = eTransportUnknown; // invalid address
|
||||
}
|
||||
else if (!strcmp (key, "i")) // ntcp2 iv or ssu2 intro
|
||||
{
|
||||
if (address->IsNTCP2 ())
|
||||
{
|
||||
Base64ToByteStream (value, strlen (value), address->i, 16);
|
||||
address->published = true; // presence of "i" means "published" NTCP2
|
||||
if (Base64ToByteStream (value, strlen (value), address->i, 16) == 16)
|
||||
address->published = true; // presence of "i" means "published" NTCP2
|
||||
else
|
||||
address->transportStyle = eTransportUnknown; // invalid address
|
||||
}
|
||||
else if (address->IsSSU2 ())
|
||||
Base64ToByteStream (value, strlen (value), address->i, 32);
|
||||
{
|
||||
if (Base64ToByteStream (value, strlen (value), address->i, 32) == 32)
|
||||
isIntroKey = true;
|
||||
else
|
||||
address->transportStyle = eTransportUnknown; // invalid address
|
||||
}
|
||||
}
|
||||
else if (!strcmp (key, "v"))
|
||||
{
|
||||
if (!strcmp (value, "2"))
|
||||
isV2 = true;
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "RouterInfo: Unexpected value ", value, " for v");
|
||||
address->transportStyle = eTransportUnknown; // invalid address
|
||||
}
|
||||
}
|
||||
else if (key[0] == 'i')
|
||||
{
|
||||
@@ -374,7 +393,7 @@ namespace data
|
||||
supportedTransports |= (i2p::util::net::IsYggdrasilAddress (address->host) ? eNTCP2V6Mesh : eNTCP2V6);
|
||||
else
|
||||
supportedTransports |= eNTCP2V4;
|
||||
m_ReachableTransports |= supportedTransports;
|
||||
m_PublishedTransports |= supportedTransports;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -389,17 +408,17 @@ namespace data
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (address->transportStyle == eTransportSSU2 && isV2 && isStaticKey)
|
||||
else if (address->transportStyle == eTransportSSU2 && isV2 && isStaticKey && isIntroKey)
|
||||
{
|
||||
if (address->IsV4 ()) supportedTransports |= eSSU2V4;
|
||||
if (address->IsV6 ()) supportedTransports |= eSSU2V6;
|
||||
if (isHost && address->port)
|
||||
{
|
||||
if (address->host.is_v4 ()) m_ReachableTransports |= eSSU2V4;
|
||||
if (address->host.is_v6 ()) m_ReachableTransports |= eSSU2V6;
|
||||
if (address->host.is_v4 ()) m_PublishedTransports |= eSSU2V4;
|
||||
if (address->host.is_v6 ()) m_PublishedTransports |= eSSU2V6;
|
||||
address->published = true;
|
||||
}
|
||||
if (address->ssu && !address->ssu->introducers.empty ())
|
||||
else if (address->ssu && !address->ssu->introducers.empty ())
|
||||
{
|
||||
// exclude invalid introducers
|
||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
@@ -419,11 +438,12 @@ namespace data
|
||||
m_SupportedTransports |= supportedTransports;
|
||||
}
|
||||
}
|
||||
m_ReachableTransports |= m_PublishedTransports;
|
||||
// update addresses
|
||||
#if (BOOST_VERSION >= 105300)
|
||||
#ifdef __cpp_lib_atomic_shared_ptr
|
||||
m_Addresses = addresses;
|
||||
#else
|
||||
boost::atomic_store (&m_Addresses, addresses);
|
||||
#else
|
||||
m_Addresses = addresses; // race condition
|
||||
#endif
|
||||
// read peers
|
||||
uint8_t numPeers;
|
||||
@@ -448,7 +468,10 @@ namespace data
|
||||
|
||||
// extract caps
|
||||
if (!strcmp (key, "caps"))
|
||||
{
|
||||
ExtractCaps (value);
|
||||
m_IsFloodfill = IsDeclaredFloodfill ();
|
||||
}
|
||||
// extract version
|
||||
else if (!strcmp (key, ROUTER_INFO_PROPERTY_VERSION))
|
||||
{
|
||||
@@ -513,14 +536,20 @@ namespace data
|
||||
case CAPS_FLAG_FLOODFILL:
|
||||
m_Caps |= Caps::eFloodfill;
|
||||
break;
|
||||
case CAPS_FLAG_HIGH_BANDWIDTH1:
|
||||
case CAPS_FLAG_HIGH_BANDWIDTH2:
|
||||
case CAPS_FLAG_HIGH_BANDWIDTH3:
|
||||
case CAPS_FLAG_LOW_BANDWIDTH1:
|
||||
case CAPS_FLAG_LOW_BANDWIDTH2:
|
||||
case CAPS_FLAG_LOW_BANDWIDTH3:
|
||||
case CAPS_FLAG_LOW_BANDWIDTH4:
|
||||
m_BandwidthCap = *cap;
|
||||
break;
|
||||
case CAPS_FLAG_HIGH_BANDWIDTH:
|
||||
m_Caps |= Caps::eHighBandwidth;
|
||||
m_BandwidthCap = *cap;
|
||||
break;
|
||||
case CAPS_FLAG_EXTRA_BANDWIDTH1:
|
||||
case CAPS_FLAG_EXTRA_BANDWIDTH2:
|
||||
m_Caps |= Caps::eExtraBandwidth | Caps::eHighBandwidth;
|
||||
m_BandwidthCap = *cap;
|
||||
break;
|
||||
case CAPS_FLAG_HIDDEN:
|
||||
m_Caps |= Caps::eHidden;
|
||||
@@ -608,6 +637,19 @@ namespace data
|
||||
return m_Buffer->data ();
|
||||
}
|
||||
|
||||
bool RouterInfo::SaveToFile (const std::string& fullPath, std::shared_ptr<Buffer> buf)
|
||||
{
|
||||
if (!buf) return false;
|
||||
std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
|
||||
if (!f.is_open ())
|
||||
{
|
||||
LogPrint (eLogError, "RouterInfo: Can't save to ", fullPath);
|
||||
return false;
|
||||
}
|
||||
f.write ((char *)buf->data (), buf->GetBufferLen ());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RouterInfo::SaveToFile (const std::string& fullPath)
|
||||
{
|
||||
if (m_IsUnreachable) return false; // don't save bad router
|
||||
@@ -616,14 +658,7 @@ namespace data
|
||||
LogPrint (eLogWarning, "RouterInfo: Can't save, m_Buffer == NULL");
|
||||
return false;
|
||||
}
|
||||
std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
|
||||
if (!f.is_open ())
|
||||
{
|
||||
LogPrint (eLogError, "RouterInfo: Can't save to ", fullPath);
|
||||
return false;
|
||||
}
|
||||
f.write ((char *)m_Buffer->data (), m_BufferLen);
|
||||
return true;
|
||||
return SaveToFile (fullPath, m_Buffer);
|
||||
}
|
||||
|
||||
size_t RouterInfo::ReadString (char * str, size_t len, std::istream& s) const
|
||||
@@ -658,12 +693,12 @@ namespace data
|
||||
if (addr->IsV4 ())
|
||||
{
|
||||
m_SupportedTransports |= eNTCP2V4;
|
||||
(*m_Addresses)[eNTCP2V4Idx] = addr;
|
||||
(*GetAddresses ())[eNTCP2V4Idx] = addr;
|
||||
}
|
||||
if (addr->IsV6 ())
|
||||
{
|
||||
m_SupportedTransports |= eNTCP2V6;
|
||||
(*m_Addresses)[eNTCP2V6Idx] = addr;
|
||||
(*GetAddresses ())[eNTCP2V6Idx] = addr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -684,11 +719,12 @@ namespace data
|
||||
if (host.is_v4 ()) addr->caps |= eV4;
|
||||
if (host.is_v6 ()) addr->caps |= eV6;
|
||||
}
|
||||
auto addresses = GetAddresses ();
|
||||
if (addr->IsV4 ())
|
||||
{
|
||||
m_SupportedTransports |= eNTCP2V4;
|
||||
m_ReachableTransports |= eNTCP2V4;
|
||||
(*m_Addresses)[eNTCP2V4Idx] = addr;
|
||||
(*addresses)[eNTCP2V4Idx] = addr;
|
||||
}
|
||||
if (addr->IsV6 ())
|
||||
{
|
||||
@@ -696,30 +732,31 @@ namespace data
|
||||
{
|
||||
m_SupportedTransports |= eNTCP2V6Mesh;
|
||||
m_ReachableTransports |= eNTCP2V6Mesh;
|
||||
(*m_Addresses)[eNTCP2V6MeshIdx] = addr;
|
||||
(*addresses)[eNTCP2V6MeshIdx] = addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_SupportedTransports |= eNTCP2V6;
|
||||
m_ReachableTransports |= eNTCP2V6;
|
||||
(*m_Addresses)[eNTCP2V6Idx] = addr;
|
||||
(*addresses)[eNTCP2V6Idx] = addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RouterInfo::RemoveNTCP2Address (bool v4)
|
||||
{
|
||||
auto addresses = GetAddresses ();
|
||||
if (v4)
|
||||
{
|
||||
if ((*m_Addresses)[eNTCP2V6Idx])
|
||||
(*m_Addresses)[eNTCP2V6Idx]->caps &= ~AddressCaps::eV4;
|
||||
(*m_Addresses)[eNTCP2V4Idx].reset ();
|
||||
if ((*addresses)[eNTCP2V6Idx])
|
||||
(*addresses)[eNTCP2V6Idx]->caps &= ~AddressCaps::eV4;
|
||||
(*addresses)[eNTCP2V4Idx].reset ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((*m_Addresses)[eNTCP2V4Idx])
|
||||
(*m_Addresses)[eNTCP2V4Idx]->caps &= ~AddressCaps::eV6;
|
||||
(*m_Addresses)[eNTCP2V6Idx].reset ();
|
||||
if ((*addresses)[eNTCP2V4Idx])
|
||||
(*addresses)[eNTCP2V4Idx]->caps &= ~AddressCaps::eV6;
|
||||
(*addresses)[eNTCP2V6Idx].reset ();
|
||||
}
|
||||
UpdateSupportedTransports ();
|
||||
}
|
||||
@@ -735,15 +772,16 @@ namespace data
|
||||
addr->ssu->mtu = 0;
|
||||
memcpy (addr->s, staticKey, 32);
|
||||
memcpy (addr->i, introKey, 32);
|
||||
auto addresses = GetAddresses ();
|
||||
if (addr->IsV4 ())
|
||||
{
|
||||
m_SupportedTransports |= eSSU2V4;
|
||||
(*m_Addresses)[eSSU2V4Idx] = addr;
|
||||
(*addresses)[eSSU2V4Idx] = addr;
|
||||
}
|
||||
if (addr->IsV6 ())
|
||||
{
|
||||
m_SupportedTransports |= eSSU2V6;
|
||||
(*m_Addresses)[eSSU2V6Idx] = addr;
|
||||
(*addresses)[eSSU2V6Idx] = addr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -768,33 +806,35 @@ namespace data
|
||||
if (host.is_v4 ()) addr->caps |= eV4;
|
||||
if (host.is_v6 ()) addr->caps |= eV6;
|
||||
}
|
||||
auto addresses = GetAddresses ();
|
||||
if (addr->IsV4 ())
|
||||
{
|
||||
m_SupportedTransports |= eSSU2V4;
|
||||
m_ReachableTransports |= eSSU2V4;
|
||||
(*m_Addresses)[eSSU2V4Idx] = addr;
|
||||
(*addresses)[eSSU2V4Idx] = addr;
|
||||
}
|
||||
if (addr->IsV6 ())
|
||||
{
|
||||
m_SupportedTransports |= eSSU2V6;
|
||||
m_ReachableTransports |= eSSU2V6;
|
||||
(*m_Addresses)[eSSU2V6Idx] = addr;
|
||||
(*addresses)[eSSU2V6Idx] = addr;
|
||||
}
|
||||
}
|
||||
|
||||
void RouterInfo::RemoveSSU2Address (bool v4)
|
||||
{
|
||||
auto addresses = GetAddresses ();
|
||||
if (v4)
|
||||
{
|
||||
if ((*m_Addresses)[eSSU2V6Idx])
|
||||
(*m_Addresses)[eSSU2V6Idx]->caps &= ~AddressCaps::eV4;
|
||||
(*m_Addresses)[eSSU2V4Idx].reset ();
|
||||
if ((*addresses)[eSSU2V6Idx])
|
||||
(*addresses)[eSSU2V6Idx]->caps &= ~AddressCaps::eV4;
|
||||
(*addresses)[eSSU2V4Idx].reset ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((*m_Addresses)[eSSU2V4Idx])
|
||||
(*m_Addresses)[eSSU2V4Idx]->caps &= ~AddressCaps::eV6;
|
||||
(*m_Addresses)[eSSU2V6Idx].reset ();
|
||||
if ((*addresses)[eSSU2V4Idx])
|
||||
(*addresses)[eSSU2V4Idx]->caps &= ~AddressCaps::eV6;
|
||||
(*addresses)[eSSU2V6Idx].reset ();
|
||||
}
|
||||
UpdateSupportedTransports ();
|
||||
}
|
||||
@@ -835,17 +875,18 @@ namespace data
|
||||
{
|
||||
if (IsV6 ())
|
||||
{
|
||||
if ((*m_Addresses)[eNTCP2V6Idx])
|
||||
auto addresses = GetAddresses ();
|
||||
if ((*addresses)[eNTCP2V6Idx])
|
||||
{
|
||||
if ((*m_Addresses)[eNTCP2V6Idx]->IsV4 () && (*m_Addresses)[eNTCP2V4Idx])
|
||||
(*m_Addresses)[eNTCP2V4Idx]->caps &= ~AddressCaps::eV6;
|
||||
(*m_Addresses)[eNTCP2V6Idx].reset ();
|
||||
if ((*addresses)[eNTCP2V6Idx]->IsV4 () && (*addresses)[eNTCP2V4Idx])
|
||||
(*addresses)[eNTCP2V4Idx]->caps &= ~AddressCaps::eV6;
|
||||
(*addresses)[eNTCP2V6Idx].reset ();
|
||||
}
|
||||
if ((*m_Addresses)[eSSU2V6Idx])
|
||||
if ((*addresses)[eSSU2V6Idx])
|
||||
{
|
||||
if ((*m_Addresses)[eSSU2V6Idx]->IsV4 () && (*m_Addresses)[eSSU2V4Idx])
|
||||
(*m_Addresses)[eSSU2V4Idx]->caps &= ~AddressCaps::eV6;
|
||||
(*m_Addresses)[eSSU2V6Idx].reset ();
|
||||
if ((*addresses)[eSSU2V6Idx]->IsV4 () && (*addresses)[eSSU2V4Idx])
|
||||
(*addresses)[eSSU2V4Idx]->caps &= ~AddressCaps::eV6;
|
||||
(*addresses)[eSSU2V6Idx].reset ();
|
||||
}
|
||||
UpdateSupportedTransports ();
|
||||
}
|
||||
@@ -855,17 +896,18 @@ namespace data
|
||||
{
|
||||
if (IsV4 ())
|
||||
{
|
||||
if ((*m_Addresses)[eNTCP2V4Idx])
|
||||
auto addresses = GetAddresses ();
|
||||
if ((*addresses)[eNTCP2V4Idx])
|
||||
{
|
||||
if ((*m_Addresses)[eNTCP2V4Idx]->IsV6 () && (*m_Addresses)[eNTCP2V6Idx])
|
||||
(*m_Addresses)[eNTCP2V6Idx]->caps &= ~AddressCaps::eV4;
|
||||
(*m_Addresses)[eNTCP2V4Idx].reset ();
|
||||
if ((*addresses)[eNTCP2V4Idx]->IsV6 () && (*addresses)[eNTCP2V6Idx])
|
||||
(*addresses)[eNTCP2V6Idx]->caps &= ~AddressCaps::eV4;
|
||||
(*addresses)[eNTCP2V4Idx].reset ();
|
||||
}
|
||||
if ((*m_Addresses)[eSSU2V4Idx])
|
||||
if ((*addresses)[eSSU2V4Idx])
|
||||
{
|
||||
if ((*m_Addresses)[eSSU2V4Idx]->IsV6 () && (*m_Addresses)[eSSU2V6Idx])
|
||||
(*m_Addresses)[eSSU2V6Idx]->caps &= ~AddressCaps::eV4;
|
||||
(*m_Addresses)[eSSU2V4Idx].reset ();
|
||||
if ((*addresses)[eSSU2V4Idx]->IsV6 () && (*addresses)[eSSU2V6Idx])
|
||||
(*addresses)[eSSU2V6Idx]->caps &= ~AddressCaps::eV4;
|
||||
(*addresses)[eSSU2V4Idx].reset ();
|
||||
}
|
||||
UpdateSupportedTransports ();
|
||||
}
|
||||
@@ -886,7 +928,7 @@ namespace data
|
||||
{
|
||||
m_SupportedTransports &= ~eNTCP2V6Mesh;
|
||||
m_ReachableTransports &= ~eNTCP2V6Mesh;
|
||||
(*m_Addresses)[eNTCP2V6MeshIdx].reset ();
|
||||
(*GetAddresses ())[eNTCP2V6MeshIdx].reset ();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -915,12 +957,12 @@ namespace data
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
boost::shared_ptr<RouterInfo::Addresses> RouterInfo::GetAddresses () const
|
||||
RouterInfo::AddressesPtr RouterInfo::GetAddresses () const
|
||||
{
|
||||
#if (BOOST_VERSION >= 105300)
|
||||
return boost::atomic_load (&m_Addresses);
|
||||
#else
|
||||
#ifdef __cpp_lib_atomic_shared_ptr
|
||||
return m_Addresses;
|
||||
#else
|
||||
return boost::atomic_load (&m_Addresses);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -928,10 +970,10 @@ namespace data
|
||||
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetAddress (Filter filter) const
|
||||
{
|
||||
// TODO: make it more generic using comparator
|
||||
#if (BOOST_VERSION >= 105300)
|
||||
#ifdef __cpp_lib_atomic_shared_ptr
|
||||
AddressesPtr addresses = m_Addresses;
|
||||
#else
|
||||
auto addresses = boost::atomic_load (&m_Addresses);
|
||||
#else
|
||||
auto addresses = m_Addresses;
|
||||
#endif
|
||||
for (const auto& address : *addresses)
|
||||
if (address && filter (address)) return address;
|
||||
@@ -988,21 +1030,28 @@ namespace data
|
||||
|
||||
bool RouterInfo::IsEligibleFloodfill () const
|
||||
{
|
||||
// floodfill must have published ipv4, >= 0.9.38 and not DSA
|
||||
return m_Version >= NETDB_MIN_FLOODFILL_VERSION && IsPublished (true) &&
|
||||
// floodfill must have published ipv4 or reachable ipv4 and published ipv6
|
||||
// >= 0.9.59 and not DSA
|
||||
return m_Version >= NETDB_MIN_FLOODFILL_VERSION && (IsPublished (true) ||
|
||||
(IsReachableBy (eNTCP2V4 | eSSU2V4) && IsPublished (false))) &&
|
||||
GetIdentity ()->GetSigningKeyType () != SIGNING_KEY_TYPE_DSA_SHA1;
|
||||
}
|
||||
|
||||
bool RouterInfo::IsPublished (bool v4) const
|
||||
{
|
||||
if (m_Caps & (eUnreachable | eHidden)) return false; // if router sets U or H we assume that all addreses are not published
|
||||
auto addr = GetAddresses ();
|
||||
if (v4)
|
||||
return ((*addr)[eNTCP2V4Idx] && ((*addr)[eNTCP2V4Idx])->published) ||
|
||||
((*addr)[eSSU2V4Idx] && ((*addr)[eSSU2V4Idx])->published);
|
||||
else
|
||||
return ((*addr)[eNTCP2V6Idx] && ((*addr)[eNTCP2V6Idx])->published) ||
|
||||
((*addr)[eSSU2V6Idx] && ((*addr)[eSSU2V6Idx])->published);
|
||||
if (m_Caps & (eUnreachable | eHidden)) return false; // if router sets U or H we assume that all addresses are not published
|
||||
return IsPublishedOn (v4 ? (eNTCP2V4 | eSSU2V4) : (eNTCP2V6 | eSSU2V6));
|
||||
}
|
||||
|
||||
bool RouterInfo::IsPublishedOn (CompatibleTransports transports) const
|
||||
{
|
||||
return m_PublishedTransports & transports;
|
||||
}
|
||||
|
||||
bool RouterInfo::IsNAT2NATOnly (const RouterInfo& other) const
|
||||
{
|
||||
return !(m_PublishedTransports & other.m_SupportedTransports) &&
|
||||
!(other.m_PublishedTransports & m_SupportedTransports);
|
||||
}
|
||||
|
||||
bool RouterInfo::IsSSU2PeerTesting (bool v4) const
|
||||
@@ -1021,7 +1070,7 @@ namespace data
|
||||
|
||||
void RouterInfo::SetUnreachableAddressesTransportCaps (uint8_t transports)
|
||||
{
|
||||
for (auto& addr: *m_Addresses)
|
||||
for (auto& addr: *GetAddresses ())
|
||||
{
|
||||
if (addr && !addr->published)
|
||||
{
|
||||
@@ -1035,7 +1084,7 @@ namespace data
|
||||
{
|
||||
m_SupportedTransports = 0;
|
||||
m_ReachableTransports = 0;
|
||||
for (const auto& addr: *m_Addresses)
|
||||
for (const auto& addr: *GetAddresses ())
|
||||
{
|
||||
if (!addr) continue;
|
||||
uint8_t transports = 0;
|
||||
@@ -1091,9 +1140,16 @@ namespace data
|
||||
m_Buffer = NewBuffer ();
|
||||
if (len > m_Buffer->size ()) len = m_Buffer->size ();
|
||||
memcpy (m_Buffer->data (), buf, len);
|
||||
m_BufferLen = len;
|
||||
m_Buffer->SetBufferLen (len);
|
||||
m_IsBufferScheduledToDelete = false;
|
||||
}
|
||||
|
||||
std::shared_ptr<RouterInfo::Buffer> RouterInfo::CopyBuffer () const
|
||||
{
|
||||
if (!m_Buffer) return nullptr;
|
||||
return netdb.NewRouterInfoBuffer (*m_Buffer);
|
||||
}
|
||||
|
||||
std::shared_ptr<RouterInfo::Buffer> RouterInfo::NewBuffer () const
|
||||
{
|
||||
return netdb.NewRouterInfoBuffer ();
|
||||
@@ -1104,7 +1160,7 @@ namespace data
|
||||
return netdb.NewRouterInfoAddress ();
|
||||
}
|
||||
|
||||
boost::shared_ptr<RouterInfo::Addresses> RouterInfo::NewAddresses () const
|
||||
RouterInfo::AddressesPtr RouterInfo::NewAddresses () const
|
||||
{
|
||||
return netdb.NewRouterInfoAddresses ();
|
||||
}
|
||||
@@ -1177,7 +1233,7 @@ namespace data
|
||||
CAPS_FLAG_EXTRA_BANDWIDTH2 : // 'X'
|
||||
CAPS_FLAG_EXTRA_BANDWIDTH1; // 'P'
|
||||
else
|
||||
caps += CAPS_FLAG_HIGH_BANDWIDTH3; // 'O'
|
||||
caps += CAPS_FLAG_HIGH_BANDWIDTH; // 'O'
|
||||
caps += CAPS_FLAG_FLOODFILL; // floodfill
|
||||
}
|
||||
else
|
||||
@@ -1185,7 +1241,7 @@ namespace data
|
||||
if (c & eExtraBandwidth)
|
||||
caps += (c & eHighBandwidth) ? CAPS_FLAG_EXTRA_BANDWIDTH2 /* 'X' */ : CAPS_FLAG_EXTRA_BANDWIDTH1; /*'P' */
|
||||
else
|
||||
caps += (c & eHighBandwidth) ? CAPS_FLAG_HIGH_BANDWIDTH3 /* 'O' */: CAPS_FLAG_LOW_BANDWIDTH2 /* 'L' */; // bandwidth
|
||||
caps += (c & eHighBandwidth) ? CAPS_FLAG_HIGH_BANDWIDTH /* 'O' */: CAPS_FLAG_LOW_BANDWIDTH2 /* 'L' */; // bandwidth
|
||||
}
|
||||
if (c & eHidden) caps += CAPS_FLAG_HIDDEN; // hidden
|
||||
if (c & eReachable) caps += CAPS_FLAG_REACHABLE; // reachable
|
||||
@@ -1425,6 +1481,20 @@ namespace data
|
||||
return "";
|
||||
}
|
||||
|
||||
void LocalRouterInfo::UpdateFloodfillProperty (bool floodfill)
|
||||
{
|
||||
if (floodfill)
|
||||
{
|
||||
UpdateCaps (GetCaps () | i2p::data::RouterInfo::eFloodfill);
|
||||
SetFloodfill ();
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateCaps (GetCaps () & ~i2p::data::RouterInfo::eFloodfill);
|
||||
ResetFloodfill ();
|
||||
}
|
||||
}
|
||||
|
||||
void LocalRouterInfo::WriteString (const std::string& str, std::ostream& s) const
|
||||
{
|
||||
uint8_t len = str.size ();
|
||||
@@ -1442,9 +1512,9 @@ namespace data
|
||||
return std::make_shared<Address> ();
|
||||
}
|
||||
|
||||
boost::shared_ptr<RouterInfo::Addresses> LocalRouterInfo::NewAddresses () const
|
||||
RouterInfo::AddressesPtr LocalRouterInfo::NewAddresses () const
|
||||
{
|
||||
return boost::make_shared<Addresses> ();
|
||||
return RouterInfo::AddressesPtr(new RouterInfo::Addresses ());
|
||||
}
|
||||
|
||||
std::shared_ptr<IdentityEx> LocalRouterInfo::NewIdentity (const uint8_t * buf, size_t len) const
|
||||
@@ -1486,5 +1556,23 @@ namespace data
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LocalRouterInfo::UpdateSSU2Introducer (const IdentHash& h, bool v4, uint32_t iTag, uint32_t iExp)
|
||||
{
|
||||
auto addresses = GetAddresses ();
|
||||
if (!addresses) return false;
|
||||
auto addr = (*addresses)[v4 ? eSSU2V4Idx : eSSU2V6Idx];
|
||||
if (addr)
|
||||
{
|
||||
for (auto& it: addr->ssu->introducers)
|
||||
if (h == it.iH)
|
||||
{
|
||||
it.iTag = iTag;
|
||||
it.iExp = iExp;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -15,8 +15,11 @@
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <boost/asio.hpp>
|
||||
#ifndef __cpp_lib_atomic_shared_ptr
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#endif
|
||||
#include "Identity.h"
|
||||
#include "Profiling.h"
|
||||
#include "Family.h"
|
||||
@@ -39,9 +42,9 @@ namespace data
|
||||
/* bandwidth flags */
|
||||
const char CAPS_FLAG_LOW_BANDWIDTH1 = 'K'; /* < 12 KBps */
|
||||
const char CAPS_FLAG_LOW_BANDWIDTH2 = 'L'; /* 12-48 KBps */
|
||||
const char CAPS_FLAG_HIGH_BANDWIDTH1 = 'M'; /* 48-64 KBps */
|
||||
const char CAPS_FLAG_HIGH_BANDWIDTH2 = 'N'; /* 64-128 KBps */
|
||||
const char CAPS_FLAG_HIGH_BANDWIDTH3 = 'O'; /* 128-256 KBps */
|
||||
const char CAPS_FLAG_LOW_BANDWIDTH3 = 'M'; /* 48-64 KBps */
|
||||
const char CAPS_FLAG_LOW_BANDWIDTH4 = 'N'; /* 64-128 KBps */
|
||||
const char CAPS_FLAG_HIGH_BANDWIDTH = 'O'; /* 128-256 KBps */
|
||||
const char CAPS_FLAG_EXTRA_BANDWIDTH1 = 'P'; /* 256-2048 KBps */
|
||||
const char CAPS_FLAG_EXTRA_BANDWIDTH2 = 'X'; /* > 2048 KBps */
|
||||
// bandwidth limits in kBps
|
||||
@@ -188,10 +191,22 @@ namespace data
|
||||
|
||||
Buffer () = default;
|
||||
Buffer (const uint8_t * buf, size_t len);
|
||||
Buffer (const Buffer& other): Buffer (other.data (), other.m_BufferLen) {};
|
||||
|
||||
size_t GetBufferLen () const { return m_BufferLen; };
|
||||
void SetBufferLen (size_t len) { m_BufferLen = len; };
|
||||
|
||||
private:
|
||||
|
||||
size_t m_BufferLen = 0;
|
||||
};
|
||||
|
||||
typedef std::array<std::shared_ptr<Address>, eNumTransports> Addresses;
|
||||
|
||||
#ifdef __cpp_lib_atomic_shared_ptr
|
||||
typedef std::shared_ptr<Addresses> AddressesPtr;
|
||||
#else
|
||||
typedef boost::shared_ptr<Addresses> AddressesPtr;
|
||||
#endif
|
||||
RouterInfo (const std::string& fullPath);
|
||||
RouterInfo (const RouterInfo& ) = default;
|
||||
RouterInfo& operator=(const RouterInfo& ) = default;
|
||||
@@ -206,7 +221,7 @@ namespace data
|
||||
int GetVersion () const { return m_Version; };
|
||||
virtual void SetProperty (const std::string& key, const std::string& value) {};
|
||||
virtual void ClearProperties () {};
|
||||
boost::shared_ptr<Addresses> GetAddresses () const; // should be called for local RI only, otherwise must return shared_ptr
|
||||
AddressesPtr GetAddresses () const; // should be called for local RI only, otherwise must return shared_ptr
|
||||
std::shared_ptr<const Address> GetNTCP2V4Address () const;
|
||||
std::shared_ptr<const Address> GetNTCP2V6Address () const;
|
||||
std::shared_ptr<const Address> GetPublishedNTCP2V4Address () const;
|
||||
@@ -227,8 +242,9 @@ namespace data
|
||||
void SetUnreachableAddressesTransportCaps (uint8_t transports); // bitmask of AddressCaps
|
||||
void UpdateSupportedTransports ();
|
||||
void UpdateIntroducers (uint64_t ts); // ts in seconds
|
||||
bool IsFloodfill () const { return m_Caps & Caps::eFloodfill; };
|
||||
void ResetFlooldFill () { m_Caps &= ~Caps::eFloodfill; };
|
||||
bool IsFloodfill () const { return m_IsFloodfill; };
|
||||
void SetFloodfill () { m_IsFloodfill = true; };
|
||||
void ResetFloodfill () { m_IsFloodfill = false; };
|
||||
bool IsECIES () const { return m_RouterIdentity->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; };
|
||||
bool IsNTCP2 (bool v4only = true) const;
|
||||
bool IsNTCP2V6 () const { return m_SupportedTransports & eNTCP2V6; };
|
||||
@@ -247,17 +263,22 @@ namespace data
|
||||
bool IsReachableFrom (const RouterInfo& other) const { return m_ReachableTransports & other.m_SupportedTransports; };
|
||||
bool IsReachableBy (CompatibleTransports transports) const { return m_ReachableTransports & transports; };
|
||||
CompatibleTransports GetCompatibleTransports (bool incoming) const { return incoming ? m_ReachableTransports : m_SupportedTransports; };
|
||||
CompatibleTransports GetPublishedTransports () const { return m_PublishedTransports; };
|
||||
bool HasValidAddresses () const { return m_SupportedTransports; };
|
||||
bool IsHidden () const { return m_Caps & eHidden; };
|
||||
bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; };
|
||||
bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; };
|
||||
bool IsEligibleFloodfill () const;
|
||||
bool IsDeclaredFloodfill () const { return m_Caps & RouterInfo::eFloodfill; };
|
||||
bool IsPublished (bool v4) const;
|
||||
bool IsPublishedOn (CompatibleTransports transports) const;
|
||||
bool IsNAT2NATOnly (const RouterInfo& other) const; // only NAT-to-NAT connection is possible
|
||||
bool IsSSU2PeerTesting (bool v4) const;
|
||||
bool IsSSU2Introducer (bool v4) const;
|
||||
bool IsHighCongestion (bool highBandwidth) const;
|
||||
|
||||
uint8_t GetCaps () const { return m_Caps; };
|
||||
char GetBandwidthCap() const { return m_BandwidthCap; };
|
||||
void SetCaps (uint8_t caps) { m_Caps = caps; };
|
||||
|
||||
Congestion GetCongestion () const { return m_Congestion; };
|
||||
@@ -268,17 +289,23 @@ namespace data
|
||||
|
||||
const uint8_t * GetBuffer () const { return m_Buffer ? m_Buffer->data () : nullptr; };
|
||||
const uint8_t * LoadBuffer (const std::string& fullPath); // load if necessary
|
||||
size_t GetBufferLen () const { return m_BufferLen; };
|
||||
size_t GetBufferLen () const { return m_Buffer ? m_Buffer->GetBufferLen () : 0; };
|
||||
void DeleteBuffer () { m_Buffer = nullptr; m_IsBufferScheduledToDelete = false; };
|
||||
std::shared_ptr<Buffer> GetSharedBuffer () const { return m_Buffer; };
|
||||
std::shared_ptr<Buffer> CopyBuffer () const;
|
||||
void ScheduleBufferToDelete () { m_IsBufferScheduledToDelete = true; };
|
||||
bool IsBufferScheduledToDelete () const { return m_IsBufferScheduledToDelete; };
|
||||
|
||||
bool IsUpdated () const { return m_IsUpdated; };
|
||||
void SetUpdated (bool updated) { m_IsUpdated = updated; };
|
||||
bool SaveToFile (const std::string& fullPath);
|
||||
|
||||
static bool SaveToFile (const std::string& fullPath, std::shared_ptr<Buffer> buf);
|
||||
|
||||
std::shared_ptr<RouterProfile> GetProfile () const;
|
||||
void DropProfile () { m_Profile = nullptr; };
|
||||
bool HasProfile () const { return (bool)m_Profile; };
|
||||
|
||||
bool Update (const uint8_t * buf, size_t len);
|
||||
void DeleteBuffer () { m_Buffer = nullptr; };
|
||||
bool IsNewer (const uint8_t * buf, size_t len) const;
|
||||
|
||||
/** return true if we are in a router family and the signature is valid */
|
||||
@@ -295,7 +322,7 @@ namespace data
|
||||
RouterInfo ();
|
||||
uint8_t * GetBufferPointer (size_t offset = 0 ) { return m_Buffer->data () + offset; };
|
||||
void UpdateBuffer (const uint8_t * buf, size_t len);
|
||||
void SetBufferLen (size_t len) { m_BufferLen = len; };
|
||||
void SetBufferLen (size_t len) { if (m_Buffer) m_Buffer->SetBufferLen (len); };
|
||||
void RefreshTimestamp ();
|
||||
CompatibleTransports GetReachableTransports () const { return m_ReachableTransports; };
|
||||
void SetReachableTransports (CompatibleTransports transports) { m_ReachableTransports = transports; };
|
||||
@@ -315,7 +342,7 @@ namespace data
|
||||
std::shared_ptr<const Address> GetAddress (Filter filter) const;
|
||||
virtual std::shared_ptr<Buffer> NewBuffer () const;
|
||||
virtual std::shared_ptr<Address> NewAddress () const;
|
||||
virtual boost::shared_ptr<Addresses> NewAddresses () const;
|
||||
virtual AddressesPtr NewAddresses () const;
|
||||
virtual std::shared_ptr<IdentityEx> NewIdentity (const uint8_t * buf, size_t len) const;
|
||||
|
||||
private:
|
||||
@@ -323,12 +350,16 @@ namespace data
|
||||
FamilyID m_FamilyID;
|
||||
std::shared_ptr<const IdentityEx> m_RouterIdentity;
|
||||
std::shared_ptr<Buffer> m_Buffer;
|
||||
size_t m_BufferLen;
|
||||
uint64_t m_Timestamp; // in milliseconds
|
||||
boost::shared_ptr<Addresses> m_Addresses; // TODO: use std::shared_ptr and std::atomic_store for gcc >= 4.9
|
||||
bool m_IsUpdated, m_IsUnreachable;
|
||||
CompatibleTransports m_SupportedTransports, m_ReachableTransports;
|
||||
#ifdef __cpp_lib_atomic_shared_ptr
|
||||
std::atomic<AddressesPtr> m_Addresses;
|
||||
#else
|
||||
AddressesPtr m_Addresses;
|
||||
#endif
|
||||
bool m_IsUpdated, m_IsUnreachable, m_IsFloodfill, m_IsBufferScheduledToDelete;
|
||||
CompatibleTransports m_SupportedTransports, m_ReachableTransports, m_PublishedTransports;
|
||||
uint8_t m_Caps;
|
||||
char m_BandwidthCap;
|
||||
int m_Version;
|
||||
Congestion m_Congestion;
|
||||
mutable std::shared_ptr<RouterProfile> m_Profile;
|
||||
@@ -347,9 +378,11 @@ namespace data
|
||||
void DeleteProperty (const std::string& key);
|
||||
std::string GetProperty (const std::string& key) const;
|
||||
void ClearProperties () override { m_Properties.clear (); };
|
||||
|
||||
void UpdateFloodfillProperty (bool floodfill);
|
||||
|
||||
bool AddSSU2Introducer (const Introducer& introducer, bool v4);
|
||||
bool RemoveSSU2Introducer (const IdentHash& h, bool v4);
|
||||
bool UpdateSSU2Introducer (const IdentHash& h, bool v4, uint32_t iTag, uint32_t iExp);
|
||||
|
||||
private:
|
||||
|
||||
@@ -358,7 +391,7 @@ namespace data
|
||||
void WriteString (const std::string& str, std::ostream& s) const;
|
||||
std::shared_ptr<Buffer> NewBuffer () const override;
|
||||
std::shared_ptr<Address> NewAddress () const override;
|
||||
boost::shared_ptr<Addresses> NewAddresses () const override;
|
||||
RouterInfo::AddressesPtr NewAddresses () const override;
|
||||
std::shared_ptr<IdentityEx> NewIdentity (const uint8_t * buf, size_t len) const override;
|
||||
|
||||
private:
|
||||
|
||||
804
libi2pd/SSU2.cpp
804
libi2pd/SSU2.cpp
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2022-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -10,28 +10,42 @@
|
||||
#define SSU2_H__
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <array>
|
||||
#include <mutex>
|
||||
#include <random>
|
||||
#include "util.h"
|
||||
#include "SSU2Session.h"
|
||||
#include "SSU2OutOfSession.h"
|
||||
#include "Socks5.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace transport
|
||||
{
|
||||
const int SSU2_TERMINATION_CHECK_TIMEOUT = 25; // in seconds
|
||||
const int SSU2_TERMINATION_CHECK_TIMEOUT = 23; // in seconds
|
||||
const int SSU2_TERMINATION_CHECK_TIMEOUT_VARIANCE = 5; // in seconds
|
||||
const int SSU2_CLEANUP_INTERVAL = 72; // in seconds
|
||||
const int SSU2_RESEND_CHECK_TIMEOUT = 400; // in milliseconds
|
||||
const int SSU2_RESEND_CHECK_TIMEOUT_VARIANCE = 100; // in milliseconds
|
||||
const int SSU2_RESEND_CHECK_MORE_TIMEOUT = 10; // in milliseconds
|
||||
const int SSU2_RESEND_CHECK_TIMEOUT = 40; // in milliseconds
|
||||
const int SSU2_RESEND_CHECK_TIMEOUT_VARIANCE = 10; // in milliseconds
|
||||
const int SSU2_RESEND_CHECK_MORE_TIMEOUT = 4; // in milliseconds
|
||||
const int SSU2_RESEND_CHECK_MORE_TIMEOUT_VARIANCE = 9; // in milliseconds
|
||||
const size_t SSU2_MAX_RESEND_PACKETS = 128; // packets to resend at the time
|
||||
const size_t SSU2_SOCKET_RECEIVE_BUFFER_SIZE = 0x1FFFF; // 128K
|
||||
const size_t SSU2_SOCKET_SEND_BUFFER_SIZE = 0x1FFFF; // 128K
|
||||
const uint64_t SSU2_SOCKET_MIN_BUFFER_SIZE = 128 * 1024;
|
||||
const uint64_t SSU2_SOCKET_MAX_BUFFER_SIZE = 4 * 1024 * 1024;
|
||||
const size_t SSU2_MAX_NUM_INTRODUCERS = 3;
|
||||
const size_t SSU2_MIN_RECEIVED_PACKET_SIZE = 40; // 16 byte short header + 8 byte minimum payload + 16 byte MAC
|
||||
const size_t SSU2_MAX_RECEIVED_QUEUE_SIZE = 2500; // in packets
|
||||
const int SSU2_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour
|
||||
const int SSU2_TO_INTRODUCER_SESSION_EXPIRATION = 4800; // 80 minutes
|
||||
const int SSU2_KEEP_ALIVE_INTERVAL = 15; // in seconds
|
||||
const int SSU2_KEEP_ALIVE_INTERVAL_VARIANCE = 4; // in seconds
|
||||
const int SSU2_PROXY_CONNECT_RETRY_TIMEOUT = 30; // in seconds
|
||||
const int SSU2_MIN_HOLE_PUNCH_EXPIRATION = 30; // in seconds
|
||||
const int SSU2_MAX_HOLE_PUNCH_EXPIRATION = 160; // in seconds
|
||||
const size_t SSU2_MAX_NUM_PACKETS_PER_BATCH = 64;
|
||||
|
||||
class SSU2Server: private i2p::util::RunnableServiceWithWork
|
||||
{
|
||||
@@ -41,13 +55,13 @@ namespace transport
|
||||
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 (); };
|
||||
auto& GetService () { return GetIOService (); };
|
||||
void Start () { StartIOService (); };
|
||||
void Stop () { StopIOService (); };
|
||||
};
|
||||
@@ -59,28 +73,40 @@ namespace transport
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
boost::asio::io_service& GetService () { return GetIOService (); };
|
||||
auto& GetService () { return GetIOService (); };
|
||||
void SetLocalAddress (const boost::asio::ip::address& localAddress);
|
||||
bool SetProxy (const std::string& address, uint16_t port);
|
||||
bool UsesProxy () const { return m_IsThroughProxy; };
|
||||
bool IsSupported (const boost::asio::ip::address& addr) const;
|
||||
uint16_t GetPort (bool v4) const;
|
||||
bool IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep, bool max = true);
|
||||
void AddConnectedRecently (const boost::asio::ip::udp::endpoint& ep, uint64_t ts);
|
||||
std::mt19937& GetRng () { return m_Rng; }
|
||||
bool IsMaxNumIntroducers (bool v4) const { return (v4 ? m_Introducers.size () : m_IntroducersV6.size ()) >= SSU2_MAX_NUM_INTRODUCERS; }
|
||||
bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; };
|
||||
void AdjustTimeOffset (int64_t offset, std::shared_ptr<const i2p::data::IdentityEx> from);
|
||||
|
||||
void AddSession (std::shared_ptr<SSU2Session> session);
|
||||
bool AddSession (std::shared_ptr<SSU2Session> session);
|
||||
void RemoveSession (uint64_t connID);
|
||||
void RequestRemoveSession (uint64_t connID);
|
||||
void AddSessionByRouterHash (std::shared_ptr<SSU2Session> session);
|
||||
bool AddPendingOutgoingSession (std::shared_ptr<SSU2Session> session);
|
||||
void RemovePendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep);
|
||||
std::shared_ptr<SSU2Session> FindSession (const i2p::data::IdentHash& ident) const;
|
||||
std::shared_ptr<SSU2Session> FindSession (const i2p::data::IdentHash& ident);
|
||||
std::shared_ptr<SSU2Session> FindPendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep) const;
|
||||
std::shared_ptr<SSU2Session> GetRandomSession (i2p::data::RouterInfo::CompatibleTransports remoteTransports,
|
||||
const i2p::data::IdentHash& excluded) const;
|
||||
std::shared_ptr<SSU2Session> GetRandomPeerTestSession (i2p::data::RouterInfo::CompatibleTransports remoteTransports,
|
||||
const i2p::data::IdentHash& excluded);
|
||||
|
||||
void AddRelay (uint32_t tag, std::shared_ptr<SSU2Session> relay);
|
||||
void RemoveRelay (uint32_t tag);
|
||||
std::shared_ptr<SSU2Session> FindRelaySession (uint32_t tag);
|
||||
|
||||
bool AddPeerTest (uint32_t nonce, std::shared_ptr<SSU2Session> aliceSession, uint64_t ts);
|
||||
std::shared_ptr<SSU2Session> GetPeerTest (uint32_t nonce);
|
||||
|
||||
bool AddRequestedPeerTest (uint32_t nonce, std::shared_ptr<SSU2PeerTestSession> session, uint64_t ts);
|
||||
std::shared_ptr<SSU2PeerTestSession> GetRequestedPeerTest (uint32_t nonce);
|
||||
|
||||
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,
|
||||
@@ -108,10 +134,12 @@ namespace transport
|
||||
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 HandleReceivedPackets (std::list<Packet *>&& packets);
|
||||
void ProcessNextPacket (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
|
||||
|
||||
void InsertToReceivedPacketsQueue (Packet * packet);
|
||||
void InsertToReceivedPacketsQueue (std::list<Packet *>& packets);
|
||||
void HandleReceivedPacketsQueue ();
|
||||
|
||||
void ScheduleTermination ();
|
||||
void HandleTerminationTimer (const boost::system::error_code& ecode);
|
||||
|
||||
@@ -121,9 +149,10 @@ namespace transport
|
||||
void ScheduleResend (bool more);
|
||||
void HandleResendTimer (const boost::system::error_code& ecode);
|
||||
|
||||
bool CheckPendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep, bool peerTest);
|
||||
void ConnectThroughIntroducer (std::shared_ptr<SSU2Session> session);
|
||||
std::list<std::shared_ptr<SSU2Session> > FindIntroducers (int maxNumIntroducers,
|
||||
bool v4, const std::set<i2p::data::IdentHash>& excluded) const;
|
||||
std::vector<std::shared_ptr<SSU2Session> > FindIntroducers (int maxNumIntroducers,
|
||||
bool v4, const std::unordered_set<i2p::data::IdentHash>& excluded);
|
||||
void UpdateIntroducers (bool v4);
|
||||
void ScheduleIntroducersUpdateTimer ();
|
||||
void HandleIntroducersUpdateTimer (const boost::system::error_code& ecode, bool v4);
|
||||
@@ -146,12 +175,14 @@ namespace transport
|
||||
boost::asio::ip::udp::socket m_SocketV4, m_SocketV6;
|
||||
boost::asio::ip::address m_AddressV4, m_AddressV6;
|
||||
std::unordered_map<uint64_t, std::shared_ptr<SSU2Session> > m_Sessions;
|
||||
std::unordered_map<i2p::data::IdentHash, std::shared_ptr<SSU2Session> > m_SessionsByRouterHash;
|
||||
std::unordered_map<i2p::data::IdentHash, std::weak_ptr<SSU2Session> > m_SessionsByRouterHash;
|
||||
mutable std::mutex m_SessionsByRouterHashMutex;
|
||||
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSU2Session> > m_PendingOutgoingSessions;
|
||||
mutable std::mutex m_PendingOutgoingSessionsMutex;
|
||||
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
|
||||
std::list<i2p::data::IdentHash> m_Introducers, m_IntroducersV6; // introducers we are connected to
|
||||
std::unordered_map<uint32_t, std::weak_ptr<SSU2Session> > m_Relays; // we are introducer, relay tag -> session
|
||||
std::unordered_map<uint32_t, std::pair <std::weak_ptr<SSU2Session>, uint64_t > > m_PeerTests; // nonce->(Alice, timestamp). We are Bob
|
||||
std::list<std::pair<i2p::data::IdentHash, uint32_t> > m_Introducers, m_IntroducersV6; // introducers we are connected to
|
||||
i2p::util::MemoryPoolMt<Packet> m_PacketsPool;
|
||||
i2p::util::MemoryPool<SSU2SentPacket> m_SentPacketsPool;
|
||||
i2p::util::MemoryPool<SSU2IncompleteMessage> m_IncompleteMessagesPool;
|
||||
@@ -161,7 +192,15 @@ namespace transport
|
||||
std::shared_ptr<SSU2Session> m_LastSession;
|
||||
bool m_IsPublished; // if we maintain introducers
|
||||
bool m_IsSyncClockFromPeers;
|
||||
|
||||
int64_t m_PendingTimeOffset; // during peer test
|
||||
std::shared_ptr<const i2p::data::IdentityEx> m_PendingTimeOffsetFrom;
|
||||
std::mt19937 m_Rng;
|
||||
std::map<boost::asio::ip::udp::endpoint, uint64_t> m_ConnectedRecently; // endpoint -> last activity time in seconds
|
||||
mutable std::mutex m_ConnectedRecentlyMutex;
|
||||
std::unordered_map<uint32_t, std::pair <std::weak_ptr<SSU2PeerTestSession>, uint64_t > > m_RequestedPeerTests; // nonce->(Alice, timestamp)
|
||||
std::list<Packet *> m_ReceivedPacketsQueue;
|
||||
mutable std::mutex m_ReceivedPacketsQueueMutex;
|
||||
|
||||
// proxy
|
||||
bool m_IsThroughProxy;
|
||||
uint8_t m_UDPRequestHeader[SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE];
|
||||
|
||||
355
libi2pd/SSU2OutOfSession.cpp
Normal file
355
libi2pd/SSU2OutOfSession.cpp
Normal file
@@ -0,0 +1,355 @@
|
||||
/*
|
||||
* Copyright (c) 2024, 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 "Log.h"
|
||||
#include "SSU2.h"
|
||||
#include "SSU2OutOfSession.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace transport
|
||||
{
|
||||
SSU2PeerTestSession::SSU2PeerTestSession (SSU2Server& server, uint64_t sourceConnID, uint64_t destConnID):
|
||||
SSU2Session (server, nullptr, nullptr, false),
|
||||
m_MsgNumReceived (0), m_NumResends (0),m_IsConnectedRecently (false), m_IsStatusChanged (false),
|
||||
m_PeerTestResendTimer (server.GetService ())
|
||||
{
|
||||
if (!sourceConnID) sourceConnID = ~destConnID;
|
||||
if (!destConnID) destConnID = ~sourceConnID;
|
||||
SetSourceConnID (sourceConnID);
|
||||
SetDestConnID (destConnID);
|
||||
SetState (eSSU2SessionStatePeerTest);
|
||||
SetTerminationTimeout (SSU2_PEER_TEST_EXPIRATION_TIMEOUT);
|
||||
}
|
||||
|
||||
bool SSU2PeerTestSession::ProcessPeerTest (uint8_t * buf, size_t len)
|
||||
{
|
||||
// we are Alice or Charlie, msgs 5,6,7
|
||||
Header header;
|
||||
memcpy (header.buf, buf, 16);
|
||||
header.ll[0] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), buf + (len - 24));
|
||||
header.ll[1] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), buf + (len - 12));
|
||||
if (header.h.type != eSSU2PeerTest)
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " instead ", (int)eSSU2PeerTest);
|
||||
return false;
|
||||
}
|
||||
if (len < 48)
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU2: PeerTest message too short ", len);
|
||||
return false;
|
||||
}
|
||||
uint8_t nonce[12] = {0};
|
||||
uint64_t headerX[2]; // sourceConnID, token
|
||||
i2p::crypto::ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX);
|
||||
SetDestConnID (headerX[0]);
|
||||
// decrypt and handle payload
|
||||
uint8_t * payload = buf + 32;
|
||||
CreateNonce (be32toh (header.h.packetNum), nonce);
|
||||
uint8_t h[32];
|
||||
memcpy (h, header.buf, 16);
|
||||
memcpy (h + 16, &headerX, 16);
|
||||
if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len - 48, h, 32,
|
||||
i2p::context.GetSSU2IntroKey (), nonce, payload, len - 48, false))
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU2: PeerTest AEAD verification failed ");
|
||||
return false;
|
||||
}
|
||||
HandlePayload (payload, len - 48);
|
||||
SetIsDataReceived (false);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SSU2PeerTestSession::HandleAddress (const uint8_t * buf, size_t len)
|
||||
{
|
||||
if (!ExtractEndpoint (buf, len, m_OurEndpoint))
|
||||
LogPrint (eLogWarning, "SSU2: Can't hanlde address block from peer test message");
|
||||
}
|
||||
|
||||
void SSU2PeerTestSession::HandlePeerTest (const uint8_t * buf, size_t len)
|
||||
{
|
||||
// msgs 5-7
|
||||
if (len < 8) return;
|
||||
uint8_t msg = buf[0];
|
||||
if (msg <= m_MsgNumReceived)
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU2: PeerTest msg num ", msg, " received after ", m_MsgNumReceived, ". Ignored");
|
||||
return;
|
||||
}
|
||||
size_t offset = 3; // points to signed data after msg + code + flag
|
||||
uint32_t nonce = bufbe32toh (buf + offset + 1); // 1 - ver
|
||||
switch (msg) // msg
|
||||
{
|
||||
case 5: // Alice from Charlie 1
|
||||
{
|
||||
if (htobe64 (((uint64_t)nonce << 32) | nonce) == GetSourceConnID ())
|
||||
{
|
||||
m_PeerTestResendTimer.cancel (); // calcel delayed msg 6 if any
|
||||
m_IsConnectedRecently = GetServer ().IsConnectedRecently (GetRemoteEndpoint ());
|
||||
if (GetAddress ())
|
||||
{
|
||||
if (!m_IsConnectedRecently)
|
||||
SetRouterStatus (eRouterStatusOK);
|
||||
else if (m_IsStatusChanged && GetRouterStatus () == eRouterStatusFirewalled)
|
||||
SetRouterStatus (eRouterStatusUnknown);
|
||||
SendPeerTest (6, buf + offset, len - offset);
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "SSU2: Peer test 5 nonce mismatch ", nonce, " connID=", GetSourceConnID ());
|
||||
break;
|
||||
}
|
||||
case 6: // Charlie from Alice
|
||||
{
|
||||
m_PeerTestResendTimer.cancel (); // no more msg 5 resends
|
||||
if (GetAddress ())
|
||||
SendPeerTest (7, buf + offset, len - offset);
|
||||
else
|
||||
LogPrint (eLogWarning, "SSU2: Unknown address for peer test 6");
|
||||
GetServer ().RequestRemoveSession (GetConnID ());
|
||||
break;
|
||||
}
|
||||
case 7: // Alice from Charlie 2
|
||||
{
|
||||
m_PeerTestResendTimer.cancel (); // no more msg 6 resends
|
||||
if (m_MsgNumReceived < 5 && m_OurEndpoint.port ()) // msg 5 was not received
|
||||
{
|
||||
if (m_OurEndpoint.address ().is_v4 ()) // ipv4
|
||||
{
|
||||
if (i2p::context.GetStatus () == eRouterStatusFirewalled)
|
||||
{
|
||||
if (m_OurEndpoint.port () != GetServer ().GetPort (true))
|
||||
i2p::context.SetError (eRouterErrorSymmetricNAT);
|
||||
else if (i2p::context.GetError () == eRouterErrorSymmetricNAT)
|
||||
i2p::context.SetError (eRouterErrorNone);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i2p::context.GetStatusV6 () == eRouterStatusFirewalled)
|
||||
{
|
||||
if (m_OurEndpoint.port () != GetServer ().GetPort (false))
|
||||
i2p::context.SetErrorV6 (eRouterErrorSymmetricNAT);
|
||||
else if (i2p::context.GetErrorV6 () == eRouterErrorSymmetricNAT)
|
||||
i2p::context.SetErrorV6 (eRouterErrorNone);
|
||||
}
|
||||
}
|
||||
}
|
||||
GetServer ().RequestRemoveSession (GetConnID ());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LogPrint (eLogWarning, "SSU2: PeerTest unexpected msg num ", msg);
|
||||
return;
|
||||
}
|
||||
m_MsgNumReceived = msg;
|
||||
}
|
||||
|
||||
void SSU2PeerTestSession::SendPeerTest (uint8_t msg)
|
||||
{
|
||||
auto addr = GetAddress ();
|
||||
if (!addr) return;
|
||||
Header header;
|
||||
uint8_t h[32], payload[SSU2_MAX_PACKET_SIZE];
|
||||
// fill packet
|
||||
header.h.connID = GetDestConnID (); // dest id
|
||||
RAND_bytes (header.buf + 8, 4); // random packet num
|
||||
header.h.type = eSSU2PeerTest;
|
||||
header.h.flags[0] = 2; // ver
|
||||
header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID
|
||||
header.h.flags[2] = 0; // flag
|
||||
memcpy (h, header.buf, 16);
|
||||
htobuf64 (h + 16, GetSourceConnID ()); // source id
|
||||
// payload
|
||||
payload[0] = eSSU2BlkDateTime;
|
||||
htobe16buf (payload + 1, 4);
|
||||
htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000);
|
||||
size_t payloadSize = 7;
|
||||
if (msg == 6 || msg == 7)
|
||||
payloadSize += CreateAddressBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize, GetRemoteEndpoint ());
|
||||
payloadSize += CreatePeerTestBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize,
|
||||
msg, eSSU2PeerTestCodeAccept, nullptr, m_SignedData.data (), m_SignedData.size ());
|
||||
payloadSize += CreatePaddingBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize);
|
||||
// encrypt
|
||||
uint8_t n[12];
|
||||
CreateNonce (be32toh (header.h.packetNum), n);
|
||||
i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, h, 32, addr->i, n, payload, payloadSize + 16, true);
|
||||
payloadSize += 16;
|
||||
header.ll[0] ^= CreateHeaderMask (addr->i, payload + (payloadSize - 24));
|
||||
header.ll[1] ^= CreateHeaderMask (addr->i, payload + (payloadSize - 12));
|
||||
memset (n, 0, 12);
|
||||
i2p::crypto::ChaCha20 (h + 16, 16, addr->i, n, h + 16);
|
||||
// send
|
||||
GetServer ().Send (header.buf, 16, h + 16, 16, payload, payloadSize, GetRemoteEndpoint ());
|
||||
UpdateNumSentBytes (payloadSize + 32);
|
||||
}
|
||||
|
||||
void SSU2PeerTestSession::SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, bool delayed)
|
||||
{
|
||||
#if __cplusplus >= 202002L // C++20
|
||||
m_SignedData.assign (signedData, signedData + signedDataLen);
|
||||
#else
|
||||
m_SignedData.resize (signedDataLen);
|
||||
memcpy (m_SignedData.data (), signedData, signedDataLen);
|
||||
#endif
|
||||
if (!delayed)
|
||||
SendPeerTest (msg);
|
||||
// schedule resend for msgs 5 or 6
|
||||
if (msg == 5 || msg == 6)
|
||||
ScheduleResend (msg);
|
||||
}
|
||||
|
||||
void SSU2PeerTestSession::SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen,
|
||||
std::shared_ptr<const i2p::data::RouterInfo::Address> addr, bool delayed)
|
||||
{
|
||||
if (!addr) return;
|
||||
SetAddress (addr);
|
||||
SendPeerTest (msg, signedData, signedDataLen, delayed);
|
||||
}
|
||||
|
||||
void SSU2PeerTestSession::Connect ()
|
||||
{
|
||||
LogPrint (eLogError, "SSU2: Can't connect peer test session");
|
||||
}
|
||||
|
||||
bool SSU2PeerTestSession::ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len)
|
||||
{
|
||||
LogPrint (eLogError, "SSU2: Can't handle incoming message in peer test session");
|
||||
return false;
|
||||
}
|
||||
|
||||
void SSU2PeerTestSession::ScheduleResend (uint8_t msg)
|
||||
{
|
||||
if (m_NumResends < SSU2_PEER_TEST_MAX_NUM_RESENDS)
|
||||
{
|
||||
m_PeerTestResendTimer.expires_from_now (boost::posix_time::milliseconds(
|
||||
SSU2_PEER_TEST_RESEND_INTERVAL + GetServer ().GetRng ()() % SSU2_PEER_TEST_RESEND_INTERVAL_VARIANCE));
|
||||
std::weak_ptr<SSU2PeerTestSession> s(std::static_pointer_cast<SSU2PeerTestSession>(shared_from_this ()));
|
||||
m_PeerTestResendTimer.async_wait ([s, msg](const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
auto s1 = s.lock ();
|
||||
if (s1)
|
||||
{
|
||||
if (msg > s1->m_MsgNumReceived)
|
||||
{
|
||||
s1->SendPeerTest (msg);
|
||||
s1->m_NumResends++;
|
||||
s1->ScheduleResend (msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
SSU2HolePunchSession::SSU2HolePunchSession (SSU2Server& server, uint32_t nonce,
|
||||
const boost::asio::ip::udp::endpoint& remoteEndpoint,
|
||||
std::shared_ptr<const i2p::data::RouterInfo::Address> addr):
|
||||
SSU2Session (server), // we create full incoming session
|
||||
m_NumResends (0), m_HolePunchResendTimer (server.GetService ())
|
||||
{
|
||||
// we are Charlie
|
||||
uint64_t destConnID = htobe64 (((uint64_t)nonce << 32) | nonce); // dest id
|
||||
uint32_t sourceConnID = ~destConnID;
|
||||
SetSourceConnID (sourceConnID);
|
||||
SetDestConnID (destConnID);
|
||||
SetState (eSSU2SessionStateHolePunch);
|
||||
SetRemoteEndpoint (remoteEndpoint);
|
||||
SetAddress (addr);
|
||||
SetTerminationTimeout (SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT);
|
||||
}
|
||||
|
||||
void SSU2HolePunchSession::SendHolePunch ()
|
||||
{
|
||||
auto addr = GetAddress ();
|
||||
if (!addr) return;
|
||||
auto& ep = GetRemoteEndpoint ();
|
||||
LogPrint (eLogDebug, "SSU2: Sending HolePunch to ", ep);
|
||||
Header header;
|
||||
uint8_t h[32], payload[SSU2_MAX_PACKET_SIZE];
|
||||
// fill packet
|
||||
header.h.connID = GetDestConnID (); // dest id
|
||||
RAND_bytes (header.buf + 8, 4); // random packet num
|
||||
header.h.type = eSSU2HolePunch;
|
||||
header.h.flags[0] = 2; // ver
|
||||
header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID
|
||||
header.h.flags[2] = 0; // flag
|
||||
memcpy (h, header.buf, 16);
|
||||
htobuf64 (h + 16, GetSourceConnID ()); // source id
|
||||
RAND_bytes (h + 24, 8); // header token, to be ignored by Alice
|
||||
// payload
|
||||
payload[0] = eSSU2BlkDateTime;
|
||||
htobe16buf (payload + 1, 4);
|
||||
htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000);
|
||||
size_t payloadSize = 7;
|
||||
payloadSize += CreateAddressBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize, ep);
|
||||
// relay response block
|
||||
if (payloadSize + m_RelayResponseBlock.size () < GetMaxPayloadSize ())
|
||||
{
|
||||
memcpy (payload + payloadSize, m_RelayResponseBlock.data (), m_RelayResponseBlock.size ());
|
||||
payloadSize += m_RelayResponseBlock.size ();
|
||||
}
|
||||
payloadSize += CreatePaddingBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize);
|
||||
// encrypt
|
||||
uint8_t n[12];
|
||||
CreateNonce (be32toh (header.h.packetNum), n);
|
||||
i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, h, 32, addr->i, n, payload, payloadSize + 16, true);
|
||||
payloadSize += 16;
|
||||
header.ll[0] ^= CreateHeaderMask (addr->i, payload + (payloadSize - 24));
|
||||
header.ll[1] ^= CreateHeaderMask (addr->i, payload + (payloadSize - 12));
|
||||
memset (n, 0, 12);
|
||||
i2p::crypto::ChaCha20 (h + 16, 16, addr->i, n, h + 16);
|
||||
// send
|
||||
GetServer ().Send (header.buf, 16, h + 16, 16, payload, payloadSize, ep);
|
||||
UpdateNumSentBytes (payloadSize + 32);
|
||||
}
|
||||
|
||||
void SSU2HolePunchSession::SendHolePunch (const uint8_t * relayResponseBlock, size_t relayResponseBlockLen)
|
||||
{
|
||||
#if __cplusplus >= 202002L // C++20
|
||||
m_RelayResponseBlock.assign (relayResponseBlock, relayResponseBlock + relayResponseBlockLen);
|
||||
#else
|
||||
m_RelayResponseBlock.resize (relayResponseBlockLen);
|
||||
memcpy (m_RelayResponseBlock.data (), relayResponseBlock, relayResponseBlockLen);
|
||||
#endif
|
||||
SendHolePunch ();
|
||||
ScheduleResend ();
|
||||
}
|
||||
|
||||
void SSU2HolePunchSession::ScheduleResend ()
|
||||
{
|
||||
if (m_NumResends < SSU2_HOLE_PUNCH_MAX_NUM_RESENDS)
|
||||
{
|
||||
m_HolePunchResendTimer.expires_from_now (boost::posix_time::milliseconds(
|
||||
SSU2_HOLE_PUNCH_RESEND_INTERVAL + GetServer ().GetRng ()() % SSU2_HOLE_PUNCH_RESEND_INTERVAL_VARIANCE));
|
||||
std::weak_ptr<SSU2HolePunchSession> s(std::static_pointer_cast<SSU2HolePunchSession>(shared_from_this ()));
|
||||
m_HolePunchResendTimer.async_wait ([s](const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
auto s1 = s.lock ();
|
||||
if (s1 && s1->GetState () == eSSU2SessionStateHolePunch)
|
||||
{
|
||||
s1->SendHolePunch ();
|
||||
s1->m_NumResends++;
|
||||
s1->ScheduleResend ();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bool SSU2HolePunchSession::ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len)
|
||||
{
|
||||
m_HolePunchResendTimer.cancel ();
|
||||
return SSU2Session::ProcessFirstIncomingMessage (connID, buf, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
86
libi2pd/SSU2OutOfSession.h
Normal file
86
libi2pd/SSU2OutOfSession.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2024, 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_OUT_OF_SESSION_H__
|
||||
#define SSU2_OUT_OF_SESSION_H__
|
||||
|
||||
#include <vector>
|
||||
#include "SSU2Session.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace transport
|
||||
{
|
||||
const int SSU2_PEER_TEST_RESEND_INTERVAL = 3000; // in milliseconds
|
||||
const int SSU2_PEER_TEST_RESEND_INTERVAL_VARIANCE = 2000; // in milliseconds
|
||||
const int SSU2_PEER_TEST_MAX_NUM_RESENDS = 3;
|
||||
|
||||
class SSU2PeerTestSession: public SSU2Session // for PeerTest msgs 5,6,7
|
||||
{
|
||||
public:
|
||||
|
||||
SSU2PeerTestSession (SSU2Server& server, uint64_t sourceConnID, uint64_t destConnID);
|
||||
|
||||
uint8_t GetMsgNumReceived () const { return m_MsgNumReceived; }
|
||||
bool IsConnectedRecently () const { return m_IsConnectedRecently; }
|
||||
void SetStatusChanged () { m_IsStatusChanged = true; }
|
||||
|
||||
void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen,
|
||||
std::shared_ptr<const i2p::data::RouterInfo::Address> addr, bool delayed = false);
|
||||
bool ProcessPeerTest (uint8_t * buf, size_t len) override;
|
||||
void Connect () override; // outgoing
|
||||
bool ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len) override; // incoming
|
||||
|
||||
private:
|
||||
|
||||
void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, bool delayed = false); // PeerTest message
|
||||
void SendPeerTest (uint8_t msg); // send or resend m_SignedData
|
||||
void HandlePeerTest (const uint8_t * buf, size_t len) override;
|
||||
void HandleAddress (const uint8_t * buf, size_t len) override;
|
||||
|
||||
void ScheduleResend (uint8_t msg);
|
||||
|
||||
private:
|
||||
|
||||
uint8_t m_MsgNumReceived, m_NumResends;
|
||||
bool m_IsConnectedRecently, m_IsStatusChanged;
|
||||
std::vector<uint8_t> m_SignedData; // for resends
|
||||
boost::asio::deadline_timer m_PeerTestResendTimer;
|
||||
boost::asio::ip::udp::endpoint m_OurEndpoint; // as seen by peer
|
||||
};
|
||||
|
||||
const int SSU2_HOLE_PUNCH_RESEND_INTERVAL = 1000; // in milliseconds
|
||||
const int SSU2_HOLE_PUNCH_RESEND_INTERVAL_VARIANCE = 500; // in milliseconds
|
||||
const int SSU2_HOLE_PUNCH_MAX_NUM_RESENDS = 3;
|
||||
|
||||
class SSU2HolePunchSession: public SSU2Session // Charlie
|
||||
{
|
||||
public:
|
||||
|
||||
SSU2HolePunchSession (SSU2Server& server, uint32_t nonce, const boost::asio::ip::udp::endpoint& remoteEndpoint,
|
||||
std::shared_ptr<const i2p::data::RouterInfo::Address> addr);
|
||||
|
||||
void SendHolePunch (const uint8_t * relayResponseBlock, size_t relayResponseBlockLen);
|
||||
|
||||
bool ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len) override; // SessionRequest
|
||||
|
||||
private:
|
||||
|
||||
void SendHolePunch ();
|
||||
void ScheduleResend ();
|
||||
|
||||
private:
|
||||
|
||||
int m_NumResends;
|
||||
std::vector<uint8_t> m_RelayResponseBlock;
|
||||
boost::asio::deadline_timer m_HolePunchResendTimer;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user