Compare commits
132 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
79b97ef2f7 | ||
![]() |
e45d68ad3a | ||
![]() |
b40f1b67b9 | ||
![]() |
4fa7e43162 | ||
![]() |
66fcbcae96 | ||
![]() |
7f0845dfd3 | ||
![]() |
f875823357 | ||
![]() |
75611866eb | ||
![]() |
c3dd7ed73a | ||
![]() |
3ae885d120 | ||
![]() |
81f53d313c | ||
![]() |
d10c86b849 | ||
![]() |
9d123fa5ad | ||
![]() |
f4d6a08d57 | ||
![]() |
e9e641afbe | ||
![]() |
8f5768f85b | ||
![]() |
3dd78a2589 | ||
![]() |
df92a85159 | ||
![]() |
ab606a1121 | ||
![]() |
457b3cf168 | ||
![]() |
c6f898b8ca | ||
![]() |
b9970e1908 | ||
![]() |
8bb9a57908 | ||
![]() |
53934a470b | ||
![]() |
a94ae7d77d | ||
![]() |
f43e860998 | ||
![]() |
3e40852999 | ||
![]() |
df073bb306 | ||
![]() |
771c4a0d02 | ||
![]() |
cb959ab14c | ||
![]() |
34b75dac02 | ||
![]() |
fbb590d9a9 | ||
![]() |
ed5c533982 | ||
![]() |
98d2ce5845 | ||
![]() |
9d9d5e3e5d | ||
![]() |
eba4626589 | ||
![]() |
ff5fa1d137 | ||
![]() |
71766ecd16 | ||
![]() |
fc63ca6982 | ||
![]() |
0e6d888ed3 | ||
![]() |
9afe3b5f39 | ||
![]() |
3bd40fc8b3 | ||
![]() |
01fe642beb | ||
![]() |
e70d57dcb4 | ||
![]() |
fd41fba069 | ||
![]() |
8a6fe0f321 | ||
![]() |
ae73e8a305 | ||
![]() |
a344c09d0d | ||
![]() |
991e37d0bf | ||
![]() |
fdeb884fe5 | ||
![]() |
4b1f5c9c9b | ||
![]() |
6b513a0f95 | ||
![]() |
b574aaf99c | ||
![]() |
bc0cdaa669 | ||
![]() |
f9106b77bb | ||
![]() |
a0419e4f34 | ||
![]() |
46a549c875 | ||
![]() |
f8a609f692 | ||
![]() |
987497bb10 | ||
![]() |
e537878b8a | ||
![]() |
617f45bc59 | ||
![]() |
fe744f8f81 | ||
![]() |
93d879b297 | ||
![]() |
dbb9295063 | ||
![]() |
09aa96e486 | ||
![]() |
4d0047ae7c | ||
![]() |
b860a4799d | ||
![]() |
6ff64352d3 | ||
![]() |
3683ec6a95 | ||
![]() |
454fa9ee9b | ||
![]() |
d33aeb4bb2 | ||
![]() |
5f9f23eb3f | ||
![]() |
5dbc7a8ca4 | ||
![]() |
33a5968eb7 | ||
![]() |
5ff34b93c0 | ||
![]() |
098fdf0596 | ||
![]() |
2eb929fe05 | ||
![]() |
ea0ed9e844 | ||
![]() |
4a3e481a83 | ||
![]() |
2197cd8620 | ||
![]() |
cf0d3b5f61 | ||
![]() |
6f7ab49346 | ||
![]() |
000e0358a7 | ||
![]() |
a3e19931f0 | ||
![]() |
9fec1a86cf | ||
![]() |
ffab29890b | ||
![]() |
206c068d8e | ||
![]() |
dc30cd1112 | ||
![]() |
412a245e88 | ||
![]() |
16290bf66f | ||
![]() |
4f8b0e6484 | ||
![]() |
5026dbc1b3 | ||
![]() |
014e4b0e1d | ||
![]() |
14a6947b02 | ||
![]() |
665a914dc3 | ||
![]() |
8feac310af | ||
![]() |
3394bb4b8d | ||
![]() |
1dd2bd0013 | ||
![]() |
5c62726992 | ||
![]() |
90981f628e | ||
![]() |
0c34189d94 | ||
![]() |
f1d3d6a7b5 | ||
![]() |
b0d962b49a | ||
![]() |
c50e453af6 | ||
![]() |
efbaf02016 | ||
![]() |
3cf809e99d | ||
![]() |
8b649aaaf8 | ||
![]() |
fdebbc4498 | ||
![]() |
3ff3417ff2 | ||
![]() |
bb6227281a | ||
![]() |
2f44d99a74 | ||
![]() |
ca4414d15a | ||
![]() |
fbb961b43c | ||
![]() |
fa9c174264 | ||
![]() |
83f43ab166 | ||
![]() |
f7e9e6a1c4 | ||
![]() |
aa21748e9a | ||
![]() |
a2f4e08b00 | ||
![]() |
66bc29d075 | ||
![]() |
e3eebe537b | ||
![]() |
3ed625f949 | ||
![]() |
a1e414c3b7 | ||
![]() |
a5a35b1fa6 | ||
![]() |
2a24584d45 | ||
![]() |
6039cdceb0 | ||
![]() |
473159be0f | ||
![]() |
0e6ad548b2 | ||
![]() |
6143515ac6 | ||
![]() |
50419f200d | ||
![]() |
455390f121 | ||
![]() |
d375299fa9 | ||
![]() |
28db337166 |
4
.github/workflows/build-freebsd.yml
vendored
4
.github/workflows/build-freebsd.yml
vendored
@@ -4,13 +4,13 @@ on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-10.15
|
||||
runs-on: macos-12
|
||||
name: with UPnP
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Test in FreeBSD
|
||||
id: test
|
||||
uses: vmactions/freebsd-vm@v0.1.5
|
||||
uses: vmactions/freebsd-vm@v0.2.0
|
||||
with:
|
||||
usesh: true
|
||||
mem: 2048
|
||||
|
30
ChangeLog
30
ChangeLog
@@ -1,6 +1,36 @@
|
||||
# for this file format description,
|
||||
# see https://github.com/olivierlacan/keep-a-changelog
|
||||
|
||||
## [2.43.0] - 2022-08-22
|
||||
### Added
|
||||
- Complete SSU2 implementation
|
||||
- Localization to Chinese
|
||||
- Send RouterInfo update for long live sessions
|
||||
- Explicit ipv6 ranges of known tunnel brokers for MTU detection
|
||||
- Always send "Connection: close" and strip out Keep-Alive for server HTTP tunnel
|
||||
- Show ports for all transports in web console
|
||||
- Translation of webconsole site title
|
||||
- Support for Windows ProgramData path when running as service
|
||||
- Ability to turn off address book
|
||||
- Handle signals TSTP and CONT to stop and resume network
|
||||
### Changed
|
||||
- Case insensitive headers for server HTTP tunnel
|
||||
- Do not show 'Address registration' line if LeaseSet is encrypted
|
||||
- SSU2 transports have higher priority than SSU
|
||||
- Disable ElGamal precalculated table if no SSU
|
||||
- Deprecate limits.ntcpsoft, limits.ntcphard and limits.ntcpthreads config options
|
||||
- SSU2 is enabled and SSU is disabled by default for new installations
|
||||
### Fixed
|
||||
- Typo with Referer header name in HTTP proxy
|
||||
- Can't handle garlic message from an exploratory tunnel
|
||||
- Incorrect encryption key for exploratory lookup reply
|
||||
- Bound checks issues in LeaseSets code
|
||||
- MTU detection on Windows
|
||||
- Crash on stop of active server tunnel
|
||||
- Send datagram to wrong destination in SAM
|
||||
- Incorrect static key in RouterInfo if the keys were regenerated
|
||||
- Duplicated sessions in BOB
|
||||
|
||||
## [2.42.1] - 2022-05-24
|
||||
### Fixed
|
||||
- Incorrect jump link in HTTP Proxy
|
||||
|
@@ -1,13 +1,13 @@
|
||||
# i2pd
|
||||
# Copyright (C) 2021 PurpleI2P team
|
||||
# Copyright (C) 2021-2022 PurpleI2P team
|
||||
# This file is distributed under the same license as the i2pd package.
|
||||
# R4SAS <r4sas@i2pmail.org>, 2021.
|
||||
# R4SAS <r4sas@i2pmail.org>, 2021-2022.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: i2pd\n"
|
||||
"Report-Msgid-Bugs-To: https://github.com/PurpleI2P/i2pd/issues\n"
|
||||
"POT-Creation-Date: 2021-08-06 17:12\n"
|
||||
"POT-Creation-Date: 2022-07-26 21:22\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
@@ -18,706 +18,712 @@ msgstr ""
|
||||
"X-Poedit-SearchPath-0: daemon/HTTPServer.cpp\n"
|
||||
"X-Poedit-SearchPath-1: libi2pd_client/HTTPProxy.cpp\n"
|
||||
|
||||
#: daemon/HTTPServer.cpp:177
|
||||
#: daemon/HTTPServer.cpp:108
|
||||
msgid "day"
|
||||
msgid_plural "days"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:181
|
||||
#: daemon/HTTPServer.cpp:112
|
||||
msgid "hour"
|
||||
msgid_plural "hours"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:185
|
||||
#: daemon/HTTPServer.cpp:116
|
||||
msgid "minute"
|
||||
msgid_plural "minutes"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:188
|
||||
#: daemon/HTTPServer.cpp:119
|
||||
msgid "second"
|
||||
msgid_plural "seconds"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#. tr: Kibibit
|
||||
#: daemon/HTTPServer.cpp:196 daemon/HTTPServer.cpp:224
|
||||
#: daemon/HTTPServer.cpp:127 daemon/HTTPServer.cpp:155
|
||||
msgid "KiB"
|
||||
msgstr ""
|
||||
|
||||
#. tr: Mebibit
|
||||
#: daemon/HTTPServer.cpp:198
|
||||
#: daemon/HTTPServer.cpp:129
|
||||
msgid "MiB"
|
||||
msgstr ""
|
||||
|
||||
#. tr: Gibibit
|
||||
#: daemon/HTTPServer.cpp:200
|
||||
#: daemon/HTTPServer.cpp:131
|
||||
msgid "GiB"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:217
|
||||
#: daemon/HTTPServer.cpp:148
|
||||
msgid "building"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:218
|
||||
#: daemon/HTTPServer.cpp:149
|
||||
msgid "failed"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:219
|
||||
#: daemon/HTTPServer.cpp:150
|
||||
msgid "expiring"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:220
|
||||
#: daemon/HTTPServer.cpp:151
|
||||
msgid "established"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:221
|
||||
#: daemon/HTTPServer.cpp:152
|
||||
msgid "unknown"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:223
|
||||
#: daemon/HTTPServer.cpp:154
|
||||
msgid "exploratory"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:259
|
||||
#. tr: Webconsole page title
|
||||
#: daemon/HTTPServer.cpp:185
|
||||
msgid "Purple I2P Webconsole"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:190
|
||||
msgid "<b>i2pd</b> webconsole"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:262
|
||||
#: daemon/HTTPServer.cpp:193
|
||||
msgid "Main page"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:263 daemon/HTTPServer.cpp:725
|
||||
#: daemon/HTTPServer.cpp:194 daemon/HTTPServer.cpp:700
|
||||
msgid "Router commands"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:264 daemon/HTTPServer.cpp:448
|
||||
#: daemon/HTTPServer.cpp:460
|
||||
#: daemon/HTTPServer.cpp:195 daemon/HTTPServer.cpp:382
|
||||
#: daemon/HTTPServer.cpp:394
|
||||
msgid "Local Destinations"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:266 daemon/HTTPServer.cpp:418
|
||||
#: daemon/HTTPServer.cpp:504 daemon/HTTPServer.cpp:510
|
||||
#: daemon/HTTPServer.cpp:641 daemon/HTTPServer.cpp:684
|
||||
#: daemon/HTTPServer.cpp:688
|
||||
#: daemon/HTTPServer.cpp:197 daemon/HTTPServer.cpp:352
|
||||
#: daemon/HTTPServer.cpp:438 daemon/HTTPServer.cpp:444
|
||||
#: daemon/HTTPServer.cpp:597 daemon/HTTPServer.cpp:640
|
||||
#: daemon/HTTPServer.cpp:644
|
||||
msgid "LeaseSets"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:268 daemon/HTTPServer.cpp:694
|
||||
#: daemon/HTTPServer.cpp:199 daemon/HTTPServer.cpp:650
|
||||
msgid "Tunnels"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:269 daemon/HTTPServer.cpp:425
|
||||
#: daemon/HTTPServer.cpp:787 daemon/HTTPServer.cpp:803
|
||||
#: daemon/HTTPServer.cpp:201 daemon/HTTPServer.cpp:359
|
||||
#: daemon/HTTPServer.cpp:770 daemon/HTTPServer.cpp:786
|
||||
msgid "Transit Tunnels"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:270 daemon/HTTPServer.cpp:852
|
||||
#: daemon/HTTPServer.cpp:203 daemon/HTTPServer.cpp:839
|
||||
msgid "Transports"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:271
|
||||
#: daemon/HTTPServer.cpp:204
|
||||
msgid "I2P tunnels"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:273 daemon/HTTPServer.cpp:914
|
||||
#: daemon/HTTPServer.cpp:924
|
||||
#: daemon/HTTPServer.cpp:206 daemon/HTTPServer.cpp:908
|
||||
#: daemon/HTTPServer.cpp:918
|
||||
msgid "SAM sessions"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:289 daemon/HTTPServer.cpp:1306
|
||||
#: daemon/HTTPServer.cpp:1309 daemon/HTTPServer.cpp:1312
|
||||
#: daemon/HTTPServer.cpp:1326 daemon/HTTPServer.cpp:1371
|
||||
#: daemon/HTTPServer.cpp:1374 daemon/HTTPServer.cpp:1377
|
||||
#: daemon/HTTPServer.cpp:222 daemon/HTTPServer.cpp:1302
|
||||
#: daemon/HTTPServer.cpp:1305 daemon/HTTPServer.cpp:1308
|
||||
#: daemon/HTTPServer.cpp:1322 daemon/HTTPServer.cpp:1367
|
||||
#: daemon/HTTPServer.cpp:1370 daemon/HTTPServer.cpp:1373
|
||||
msgid "ERROR"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:296
|
||||
#: daemon/HTTPServer.cpp:229
|
||||
msgid "OK"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:297
|
||||
#: daemon/HTTPServer.cpp:230
|
||||
msgid "Testing"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:298
|
||||
#: daemon/HTTPServer.cpp:231
|
||||
msgid "Firewalled"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:299 daemon/HTTPServer.cpp:320
|
||||
#: daemon/HTTPServer.cpp:406
|
||||
#: daemon/HTTPServer.cpp:232 daemon/HTTPServer.cpp:253
|
||||
#: daemon/HTTPServer.cpp:325
|
||||
msgid "Unknown"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:300 daemon/HTTPServer.cpp:435
|
||||
#: daemon/HTTPServer.cpp:436 daemon/HTTPServer.cpp:982
|
||||
#: daemon/HTTPServer.cpp:991
|
||||
#: daemon/HTTPServer.cpp:233 daemon/HTTPServer.cpp:369
|
||||
#: daemon/HTTPServer.cpp:370 daemon/HTTPServer.cpp:976
|
||||
#: daemon/HTTPServer.cpp:985
|
||||
msgid "Proxy"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:301
|
||||
#: daemon/HTTPServer.cpp:234
|
||||
msgid "Mesh"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:304
|
||||
#: daemon/HTTPServer.cpp:237
|
||||
msgid "Error"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:308
|
||||
#: daemon/HTTPServer.cpp:241
|
||||
msgid "Clock skew"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:311
|
||||
#: daemon/HTTPServer.cpp:244
|
||||
msgid "Offline"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:314
|
||||
#: daemon/HTTPServer.cpp:247
|
||||
msgid "Symmetric NAT"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:326
|
||||
#: daemon/HTTPServer.cpp:259
|
||||
msgid "Uptime"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:329
|
||||
#: daemon/HTTPServer.cpp:262
|
||||
msgid "Network status"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:334
|
||||
#: daemon/HTTPServer.cpp:267
|
||||
msgid "Network status v6"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:340 daemon/HTTPServer.cpp:347
|
||||
#: daemon/HTTPServer.cpp:273 daemon/HTTPServer.cpp:280
|
||||
msgid "Stopping in"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:354
|
||||
#: daemon/HTTPServer.cpp:287
|
||||
msgid "Family"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:355
|
||||
#: daemon/HTTPServer.cpp:288
|
||||
msgid "Tunnel creation success rate"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:356
|
||||
#: daemon/HTTPServer.cpp:289
|
||||
msgid "Received"
|
||||
msgstr ""
|
||||
|
||||
#. tr: Kibibit/s
|
||||
#: daemon/HTTPServer.cpp:358 daemon/HTTPServer.cpp:361
|
||||
#: daemon/HTTPServer.cpp:364
|
||||
#: daemon/HTTPServer.cpp:291 daemon/HTTPServer.cpp:294
|
||||
#: daemon/HTTPServer.cpp:297
|
||||
msgid "KiB/s"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:359
|
||||
#: daemon/HTTPServer.cpp:292
|
||||
msgid "Sent"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:362
|
||||
#: daemon/HTTPServer.cpp:295
|
||||
msgid "Transit"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:365
|
||||
#: daemon/HTTPServer.cpp:298
|
||||
msgid "Data path"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:368
|
||||
#: daemon/HTTPServer.cpp:301
|
||||
msgid "Hidden content. Press on text to see."
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:371
|
||||
#: daemon/HTTPServer.cpp:304
|
||||
msgid "Router Ident"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:373
|
||||
#: daemon/HTTPServer.cpp:306
|
||||
msgid "Router Family"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:374
|
||||
#: daemon/HTTPServer.cpp:307
|
||||
msgid "Router Caps"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:375
|
||||
#: daemon/HTTPServer.cpp:308
|
||||
msgid "Version"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:376
|
||||
#: daemon/HTTPServer.cpp:309
|
||||
msgid "Our external address"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:384
|
||||
#: daemon/HTTPServer.cpp:337
|
||||
msgid "supported"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:416
|
||||
#: daemon/HTTPServer.cpp:350
|
||||
msgid "Routers"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:417
|
||||
#: daemon/HTTPServer.cpp:351
|
||||
msgid "Floodfills"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:424 daemon/HTTPServer.cpp:968
|
||||
#: daemon/HTTPServer.cpp:358 daemon/HTTPServer.cpp:962
|
||||
msgid "Client Tunnels"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:434
|
||||
#: daemon/HTTPServer.cpp:368
|
||||
msgid "Services"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:435 daemon/HTTPServer.cpp:436
|
||||
#: daemon/HTTPServer.cpp:437 daemon/HTTPServer.cpp:438
|
||||
#: daemon/HTTPServer.cpp:439 daemon/HTTPServer.cpp:440
|
||||
#: daemon/HTTPServer.cpp:369 daemon/HTTPServer.cpp:370
|
||||
#: daemon/HTTPServer.cpp:371 daemon/HTTPServer.cpp:372
|
||||
#: daemon/HTTPServer.cpp:373 daemon/HTTPServer.cpp:374
|
||||
msgid "Enabled"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:435 daemon/HTTPServer.cpp:436
|
||||
#: daemon/HTTPServer.cpp:437 daemon/HTTPServer.cpp:438
|
||||
#: daemon/HTTPServer.cpp:439 daemon/HTTPServer.cpp:440
|
||||
#: daemon/HTTPServer.cpp:369 daemon/HTTPServer.cpp:370
|
||||
#: daemon/HTTPServer.cpp:371 daemon/HTTPServer.cpp:372
|
||||
#: daemon/HTTPServer.cpp:373 daemon/HTTPServer.cpp:374
|
||||
msgid "Disabled"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:483
|
||||
#: daemon/HTTPServer.cpp:417
|
||||
msgid "Encrypted B33 address"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:492
|
||||
#: daemon/HTTPServer.cpp:426
|
||||
msgid "Address registration line"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:497
|
||||
#: daemon/HTTPServer.cpp:431
|
||||
msgid "Domain"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:498
|
||||
#: daemon/HTTPServer.cpp:432
|
||||
msgid "Generate"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:499
|
||||
#: daemon/HTTPServer.cpp:433
|
||||
msgid ""
|
||||
"<b>Note:</b> result string can be used only for registering 2LD domains "
|
||||
"(example.i2p). For registering subdomains please use i2pd-tools."
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:505
|
||||
#: daemon/HTTPServer.cpp:439
|
||||
msgid "Address"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:505
|
||||
#: daemon/HTTPServer.cpp:439
|
||||
msgid "Type"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:505
|
||||
#: daemon/HTTPServer.cpp:439
|
||||
msgid "EncType"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:515 daemon/HTTPServer.cpp:699
|
||||
#: daemon/HTTPServer.cpp:449 daemon/HTTPServer.cpp:655
|
||||
msgid "Inbound tunnels"
|
||||
msgstr ""
|
||||
|
||||
#. tr: Milliseconds
|
||||
#: daemon/HTTPServer.cpp:520 daemon/HTTPServer.cpp:530
|
||||
#: daemon/HTTPServer.cpp:704 daemon/HTTPServer.cpp:714
|
||||
#: daemon/HTTPServer.cpp:464 daemon/HTTPServer.cpp:484
|
||||
#: daemon/HTTPServer.cpp:669 daemon/HTTPServer.cpp:689
|
||||
msgid "ms"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:525 daemon/HTTPServer.cpp:709
|
||||
#: daemon/HTTPServer.cpp:469 daemon/HTTPServer.cpp:674
|
||||
msgid "Outbound tunnels"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:537
|
||||
#: daemon/HTTPServer.cpp:491
|
||||
msgid "Tags"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:537
|
||||
#: daemon/HTTPServer.cpp:491
|
||||
msgid "Incoming"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:544 daemon/HTTPServer.cpp:547
|
||||
#: daemon/HTTPServer.cpp:498 daemon/HTTPServer.cpp:501
|
||||
msgid "Outgoing"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:545 daemon/HTTPServer.cpp:561
|
||||
#: daemon/HTTPServer.cpp:499 daemon/HTTPServer.cpp:515
|
||||
msgid "Destination"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:545
|
||||
#: daemon/HTTPServer.cpp:499
|
||||
msgid "Amount"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:552
|
||||
#: daemon/HTTPServer.cpp:506
|
||||
msgid "Incoming Tags"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:560 daemon/HTTPServer.cpp:563
|
||||
#: daemon/HTTPServer.cpp:514 daemon/HTTPServer.cpp:517
|
||||
msgid "Tags sessions"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:561
|
||||
#: daemon/HTTPServer.cpp:515
|
||||
msgid "Status"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:570 daemon/HTTPServer.cpp:626
|
||||
#: daemon/HTTPServer.cpp:524 daemon/HTTPServer.cpp:582
|
||||
msgid "Local Destination"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:580 daemon/HTTPServer.cpp:947
|
||||
#: daemon/HTTPServer.cpp:535 daemon/HTTPServer.cpp:941
|
||||
msgid "Streams"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:602
|
||||
#: daemon/HTTPServer.cpp:558
|
||||
msgid "Close stream"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:631
|
||||
#: daemon/HTTPServer.cpp:587
|
||||
msgid "I2CP session not found"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:634
|
||||
#: daemon/HTTPServer.cpp:590
|
||||
msgid "I2CP is not enabled"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:660
|
||||
#: daemon/HTTPServer.cpp:616
|
||||
msgid "Invalid"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:663
|
||||
#: daemon/HTTPServer.cpp:619
|
||||
msgid "Store type"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:664
|
||||
#: daemon/HTTPServer.cpp:620
|
||||
msgid "Expires"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:669
|
||||
#: daemon/HTTPServer.cpp:625
|
||||
msgid "Non Expired Leases"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:672
|
||||
#: daemon/HTTPServer.cpp:628
|
||||
msgid "Gateway"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:673
|
||||
#: daemon/HTTPServer.cpp:629
|
||||
msgid "TunnelID"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:674
|
||||
#: daemon/HTTPServer.cpp:630
|
||||
msgid "EndDate"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:684
|
||||
#: daemon/HTTPServer.cpp:640
|
||||
msgid "not floodfill"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:695
|
||||
#: daemon/HTTPServer.cpp:651
|
||||
msgid "Queue size"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:726
|
||||
#: daemon/HTTPServer.cpp:701
|
||||
msgid "Run peer test"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:731
|
||||
#: daemon/HTTPServer.cpp:706
|
||||
msgid "Decline transit tunnels"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:733
|
||||
#: daemon/HTTPServer.cpp:708
|
||||
msgid "Accept transit tunnels"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:737 daemon/HTTPServer.cpp:742
|
||||
#: daemon/HTTPServer.cpp:712 daemon/HTTPServer.cpp:717
|
||||
msgid "Cancel graceful shutdown"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:739 daemon/HTTPServer.cpp:744
|
||||
#: daemon/HTTPServer.cpp:714 daemon/HTTPServer.cpp:719
|
||||
msgid "Start graceful shutdown"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:747
|
||||
#: daemon/HTTPServer.cpp:722
|
||||
msgid "Force shutdown"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:748
|
||||
#: daemon/HTTPServer.cpp:723
|
||||
msgid "Reload external CSS styles"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:751
|
||||
#: daemon/HTTPServer.cpp:726
|
||||
msgid ""
|
||||
"<b>Note:</b> any action done here are not persistent and not changes your "
|
||||
"config files."
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:753
|
||||
#: daemon/HTTPServer.cpp:728
|
||||
msgid "Logging level"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:761
|
||||
#: daemon/HTTPServer.cpp:736
|
||||
msgid "Transit tunnels limit"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:766 daemon/HTTPServer.cpp:778
|
||||
#: daemon/HTTPServer.cpp:741 daemon/HTTPServer.cpp:760
|
||||
msgid "Change"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:770
|
||||
#: daemon/HTTPServer.cpp:748
|
||||
msgid "Change language"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:803
|
||||
#: daemon/HTTPServer.cpp:786
|
||||
msgid "no transit tunnels currently built"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:908 daemon/HTTPServer.cpp:931
|
||||
#: daemon/HTTPServer.cpp:902 daemon/HTTPServer.cpp:925
|
||||
msgid "SAM disabled"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:924
|
||||
#: daemon/HTTPServer.cpp:918
|
||||
msgid "no sessions currently running"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:937
|
||||
#: daemon/HTTPServer.cpp:931
|
||||
msgid "SAM session not found"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:942
|
||||
#: daemon/HTTPServer.cpp:936
|
||||
msgid "SAM Session"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:999
|
||||
#: daemon/HTTPServer.cpp:993
|
||||
msgid "Server Tunnels"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1015
|
||||
#: daemon/HTTPServer.cpp:1009
|
||||
msgid "Client Forwards"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1029
|
||||
#: daemon/HTTPServer.cpp:1023
|
||||
msgid "Server Forwards"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1227
|
||||
#: daemon/HTTPServer.cpp:1223
|
||||
msgid "Unknown page"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1246
|
||||
#: daemon/HTTPServer.cpp:1242
|
||||
msgid "Invalid token"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1304 daemon/HTTPServer.cpp:1361
|
||||
#: daemon/HTTPServer.cpp:1401
|
||||
#: daemon/HTTPServer.cpp:1300 daemon/HTTPServer.cpp:1357
|
||||
#: daemon/HTTPServer.cpp:1397
|
||||
msgid "SUCCESS"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1304
|
||||
#: daemon/HTTPServer.cpp:1300
|
||||
msgid "Stream closed"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1306
|
||||
#: daemon/HTTPServer.cpp:1302
|
||||
msgid "Stream not found or already was closed"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1309
|
||||
#: daemon/HTTPServer.cpp:1305
|
||||
msgid "Destination not found"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1312
|
||||
#: daemon/HTTPServer.cpp:1308
|
||||
msgid "StreamID can't be null"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1314 daemon/HTTPServer.cpp:1379
|
||||
#: daemon/HTTPServer.cpp:1310 daemon/HTTPServer.cpp:1375
|
||||
msgid "Return to destination page"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1315 daemon/HTTPServer.cpp:1328
|
||||
#: daemon/HTTPServer.cpp:1403
|
||||
#: daemon/HTTPServer.cpp:1311 daemon/HTTPServer.cpp:1324
|
||||
#: daemon/HTTPServer.cpp:1399
|
||||
msgid "You will be redirected in 5 seconds"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1326
|
||||
#: daemon/HTTPServer.cpp:1322
|
||||
msgid "Transit tunnels count must not exceed 65535"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1327 daemon/HTTPServer.cpp:1402
|
||||
#: daemon/HTTPServer.cpp:1323 daemon/HTTPServer.cpp:1398
|
||||
msgid "Back to commands list"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1363
|
||||
#: daemon/HTTPServer.cpp:1359
|
||||
msgid "Register at reg.i2p"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1364
|
||||
#: daemon/HTTPServer.cpp:1360
|
||||
msgid "Description"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1364
|
||||
#: daemon/HTTPServer.cpp:1360
|
||||
msgid "A bit information about service on domain"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1365
|
||||
#: daemon/HTTPServer.cpp:1361
|
||||
msgid "Submit"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1371
|
||||
#: daemon/HTTPServer.cpp:1367
|
||||
msgid "Domain can't end with .b32.i2p"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1374
|
||||
#: daemon/HTTPServer.cpp:1370
|
||||
msgid "Domain must end with .i2p"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1377
|
||||
#: daemon/HTTPServer.cpp:1373
|
||||
msgid "Such destination is not found"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1397
|
||||
#: daemon/HTTPServer.cpp:1393
|
||||
msgid "Unknown command"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1401
|
||||
#: daemon/HTTPServer.cpp:1397
|
||||
msgid "Command accepted"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:157
|
||||
#: libi2pd_client/HTTPProxy.cpp:163
|
||||
msgid "Proxy error"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:165
|
||||
#: libi2pd_client/HTTPProxy.cpp:171
|
||||
msgid "Proxy info"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:173
|
||||
#: libi2pd_client/HTTPProxy.cpp:179
|
||||
msgid "Proxy error: Host not found"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:174
|
||||
#: libi2pd_client/HTTPProxy.cpp:180
|
||||
msgid "Remote host not found in router's addressbook"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:175
|
||||
#: libi2pd_client/HTTPProxy.cpp:181
|
||||
msgid "You may try to find this host on jump services below"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:273 libi2pd_client/HTTPProxy.cpp:288
|
||||
#: libi2pd_client/HTTPProxy.cpp:322 libi2pd_client/HTTPProxy.cpp:365
|
||||
#: libi2pd_client/HTTPProxy.cpp:282 libi2pd_client/HTTPProxy.cpp:297
|
||||
#: libi2pd_client/HTTPProxy.cpp:331 libi2pd_client/HTTPProxy.cpp:372
|
||||
msgid "Invalid request"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:273
|
||||
#: libi2pd_client/HTTPProxy.cpp:282
|
||||
msgid "Proxy unable to parse your request"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:288
|
||||
#: libi2pd_client/HTTPProxy.cpp:297
|
||||
msgid "addresshelper is not supported"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:297 libi2pd_client/HTTPProxy.cpp:306
|
||||
#: libi2pd_client/HTTPProxy.cpp:385
|
||||
#: libi2pd_client/HTTPProxy.cpp:306 libi2pd_client/HTTPProxy.cpp:315
|
||||
#: libi2pd_client/HTTPProxy.cpp:392
|
||||
msgid "Host"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:297
|
||||
#: libi2pd_client/HTTPProxy.cpp:306
|
||||
msgid "added to router's addressbook from helper"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:298
|
||||
#: libi2pd_client/HTTPProxy.cpp:307
|
||||
msgid "Click here to proceed:"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:298 libi2pd_client/HTTPProxy.cpp:308
|
||||
#: libi2pd_client/HTTPProxy.cpp:307 libi2pd_client/HTTPProxy.cpp:317
|
||||
msgid "Continue"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:299 libi2pd_client/HTTPProxy.cpp:309
|
||||
#: libi2pd_client/HTTPProxy.cpp:308 libi2pd_client/HTTPProxy.cpp:318
|
||||
msgid "Addresshelper found"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:306
|
||||
#: libi2pd_client/HTTPProxy.cpp:315
|
||||
msgid "already in router's addressbook"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:307
|
||||
#. tr: The "record" means addressbook's record. That message appears when domain was already added to addressbook, but helper link is opened for it.
|
||||
#: libi2pd_client/HTTPProxy.cpp:316
|
||||
msgid "Click here to update record:"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:322
|
||||
#: libi2pd_client/HTTPProxy.cpp:331
|
||||
msgid "invalid request uri"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:365
|
||||
#: libi2pd_client/HTTPProxy.cpp:372
|
||||
msgid "Can't detect destination host from request"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:382 libi2pd_client/HTTPProxy.cpp:386
|
||||
#: libi2pd_client/HTTPProxy.cpp:389 libi2pd_client/HTTPProxy.cpp:393
|
||||
msgid "Outproxy failure"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:382
|
||||
#: libi2pd_client/HTTPProxy.cpp:389
|
||||
msgid "bad outproxy settings"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:385
|
||||
#: libi2pd_client/HTTPProxy.cpp:392
|
||||
msgid "not inside I2P network, but outproxy is not enabled"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:474
|
||||
#: libi2pd_client/HTTPProxy.cpp:482
|
||||
msgid "unknown outproxy url"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:480
|
||||
#: libi2pd_client/HTTPProxy.cpp:490
|
||||
msgid "cannot resolve upstream proxy"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:488
|
||||
#: libi2pd_client/HTTPProxy.cpp:498
|
||||
msgid "hostname too long"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:515
|
||||
#: libi2pd_client/HTTPProxy.cpp:525
|
||||
msgid "cannot connect to upstream socks proxy"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:521
|
||||
#: libi2pd_client/HTTPProxy.cpp:531
|
||||
msgid "Cannot negotiate with socks proxy"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:563
|
||||
#: libi2pd_client/HTTPProxy.cpp:573
|
||||
msgid "CONNECT error"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:563
|
||||
#: libi2pd_client/HTTPProxy.cpp:573
|
||||
msgid "Failed to Connect"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:574 libi2pd_client/HTTPProxy.cpp:600
|
||||
#: libi2pd_client/HTTPProxy.cpp:584 libi2pd_client/HTTPProxy.cpp:610
|
||||
msgid "socks proxy error"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:582
|
||||
#: libi2pd_client/HTTPProxy.cpp:592
|
||||
msgid "failed to send request to upstream"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:603
|
||||
#: libi2pd_client/HTTPProxy.cpp:613
|
||||
msgid "No Reply From socks proxy"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:610
|
||||
#: libi2pd_client/HTTPProxy.cpp:620
|
||||
msgid "cannot connect"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:610
|
||||
#: libi2pd_client/HTTPProxy.cpp:620
|
||||
msgid "http out proxy not implemented"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:611
|
||||
#: libi2pd_client/HTTPProxy.cpp:621
|
||||
msgid "cannot connect to upstream http proxy"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:644
|
||||
#: libi2pd_client/HTTPProxy.cpp:654
|
||||
msgid "Host is down"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:644
|
||||
#: libi2pd_client/HTTPProxy.cpp:654
|
||||
msgid ""
|
||||
"Can't create connection to requested host, it may be down. Please try again "
|
||||
"later."
|
||||
|
@@ -9,7 +9,7 @@ Regex for transforming gettext translations to our format:
|
||||
---
|
||||
|
||||
```
|
||||
in: msgid\ \"(.*)\"\nmsgid_plural\ \"(.*)\"\nmsgstr\[0\]\ \"(.*)\"\nmsgstr\[1\]\ \"(.*)\"\n(msgstr\[2\]\ \"(.*)\"\n)?(msgstr\[3\]\ \"(.*)\"\n)?(msgstr\[4\]\ \"(.*)\"\n)?(msgstr\[5\]\ \"(.*)\"\n)?
|
||||
in: msgid\ \"(.*)\"\nmsgid_plural\ \"(.*)\"\nmsgstr\[0\]\ \"(.*)\"\n(msgstr\[1\]\ \"(.*)\"\n)?(msgstr\[2\]\ \"(.*)\"\n)?(msgstr\[3\]\ \"(.*)\"\n)?(msgstr\[4\]\ \"(.*)\"\n)?(msgstr\[5\]\ \"(.*)\"\n)?
|
||||
out: #{"$2", {"$3", "$4", "$6", "$8", "$10"}},\n
|
||||
```
|
||||
|
||||
|
@@ -76,7 +76,7 @@ ipv4 = true
|
||||
ipv6 = false
|
||||
|
||||
## Enable SSU transport (default = true)
|
||||
# ssu = true
|
||||
ssu = false
|
||||
|
||||
## Bandwidth configuration
|
||||
## L limit bandwidth to 32KBs/sec, O - to 256KBs/sec, P - to 2048KBs/sec,
|
||||
@@ -96,6 +96,22 @@ ipv6 = false
|
||||
## Note: that mode uses much more network connections and CPU!
|
||||
# floodfill = true
|
||||
|
||||
[ntcp2]
|
||||
## Enable NTCP2 transport (default = true)
|
||||
# enabled = true
|
||||
## Publish address in RouterInfo (default = true)
|
||||
# published = true
|
||||
## Port for incoming connections (default is global port option value)
|
||||
# port = 4567
|
||||
|
||||
[ssu2]
|
||||
## Enable SSU2 transport (default = false for 2.43.0)
|
||||
enabled = true
|
||||
## Publish address in RouterInfo (default = false for 2.43.0)
|
||||
published = true
|
||||
## Port for incoming connections (default is global port option value or port + 1 if SSU is enabled)
|
||||
# port = 4567
|
||||
|
||||
[http]
|
||||
## Web Console settings
|
||||
## Uncomment and set to 'false' to disable Web Console
|
||||
@@ -110,8 +126,8 @@ port = 7070
|
||||
# user = i2pd
|
||||
# pass = changeme
|
||||
## Select webconsole language
|
||||
## Currently supported english (default), afrikaans, armenian, french, german,
|
||||
## russian, turkmen, ukrainian and uzbek languages
|
||||
## Currently supported english (default), afrikaans, armenian, chinese, french,
|
||||
## german, russian, turkmen, ukrainian and uzbek languages
|
||||
# lang = english
|
||||
|
||||
[httpproxy]
|
||||
|
@@ -1,7 +1,7 @@
|
||||
%define git_hash %(git rev-parse HEAD | cut -c -7)
|
||||
|
||||
Name: i2pd-git
|
||||
Version: 2.42.1
|
||||
Version: 2.43.0
|
||||
Release: git%{git_hash}%{?dist}
|
||||
Summary: I2P router written in C++
|
||||
Conflicts: i2pd
|
||||
@@ -62,9 +62,7 @@ pushd redhat-linux-build
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora} >= 35
|
||||
%if 0%{?fedora} < 37
|
||||
pushd redhat-linux-build
|
||||
%endif
|
||||
%else
|
||||
%if 0%{?fedora} >= 33
|
||||
pushd %{_target_platform}
|
||||
@@ -82,10 +80,8 @@ popd
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora} >= 33
|
||||
%if 0%{?fedora} < 37
|
||||
popd
|
||||
%endif
|
||||
%endif
|
||||
|
||||
%if 0%{?mageia} > 7
|
||||
popd
|
||||
@@ -99,9 +95,7 @@ pushd redhat-linux-build
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora} >= 35
|
||||
%if 0%{?fedora} < 37
|
||||
pushd redhat-linux-build
|
||||
%endif
|
||||
%else
|
||||
%if 0%{?fedora} >= 33
|
||||
pushd %{_target_platform}
|
||||
@@ -164,6 +158,9 @@ getent passwd i2pd >/dev/null || \
|
||||
|
||||
|
||||
%changelog
|
||||
* Mon Aug 22 2022 orignal <orignal@i2pmail.org> - 2.43.0
|
||||
- update to 2.43.0
|
||||
|
||||
* Tue May 24 2022 r4sas <r4sas@i2pmail.org> - 2.42.1
|
||||
- update to 2.42.1
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
Name: i2pd
|
||||
Version: 2.42.1
|
||||
Version: 2.43.0
|
||||
Release: 1%{?dist}
|
||||
Summary: I2P router written in C++
|
||||
Conflicts: i2pd-git
|
||||
@@ -59,9 +59,7 @@ pushd redhat-linux-build
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora} >= 35
|
||||
%if 0%{?fedora} < 37
|
||||
pushd redhat-linux-build
|
||||
%endif
|
||||
%else
|
||||
%if 0%{?fedora} >= 33
|
||||
pushd %{_target_platform}
|
||||
@@ -79,10 +77,8 @@ popd
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora} >= 33
|
||||
%if 0%{?fedora} < 37
|
||||
popd
|
||||
%endif
|
||||
%endif
|
||||
|
||||
%if 0%{?mageia} > 7
|
||||
popd
|
||||
@@ -96,9 +92,7 @@ pushd redhat-linux-build
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora} >= 35
|
||||
%if 0%{?fedora} < 37
|
||||
pushd redhat-linux-build
|
||||
%endif
|
||||
%else
|
||||
%if 0%{?fedora} >= 33
|
||||
pushd %{_target_platform}
|
||||
@@ -161,6 +155,9 @@ getent passwd i2pd >/dev/null || \
|
||||
|
||||
|
||||
%changelog
|
||||
* Mon Aug 22 2022 orignal <orignal@i2pmail.org> - 2.43.0
|
||||
- update to 2.43.0
|
||||
|
||||
* Tue May 24 2022 r4sas <r4sas@i2pmail.org> - 2.42.1
|
||||
- update to 2.42.1
|
||||
|
||||
|
@@ -153,6 +153,9 @@ namespace util
|
||||
bool aesni; i2p::config::GetOption("cpuext.aesni", aesni);
|
||||
bool avx; i2p::config::GetOption("cpuext.avx", avx);
|
||||
bool forceCpuExt; i2p::config::GetOption("cpuext.force", forceCpuExt);
|
||||
bool ssu; i2p::config::GetOption("ssu", ssu);
|
||||
if (!ssu && i2p::config::IsDefault ("precomputation.elgamal"))
|
||||
precomputation = false; // we don't elgamal table if no ssu, unless it's specified explicitly
|
||||
i2p::crypto::InitCrypto (precomputation, aesni, avx, forceCpuExt);
|
||||
|
||||
int netID; i2p::config::GetOption("netid", netID);
|
||||
@@ -250,17 +253,17 @@ namespace util
|
||||
if (!ipv4 && !ipv6)
|
||||
i2p::context.SetStatus (eRouterStatusMesh);
|
||||
}
|
||||
if (!ssu) i2p::context.RemoveSSUAddress (); // TODO: remove later
|
||||
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
|
||||
if (ssu2)
|
||||
{
|
||||
uint16_t ssu2port; i2p::config::GetOption("ssu2.port", ssu2port);
|
||||
if (!ssu2port) ssu2port = ssu ? (port + 1) : port;
|
||||
bool published; i2p::config::GetOption("ssu2.published", published);
|
||||
if (published)
|
||||
{
|
||||
uint16_t ssu2port; i2p::config::GetOption("ssu2.port", ssu2port);
|
||||
i2p::context.PublishSSU2Address (ssu2port, true, ipv4, ipv6); // publish
|
||||
}
|
||||
else
|
||||
i2p::context.PublishSSU2Address (0, false, ipv4, ipv6); // unpublish
|
||||
i2p::context.PublishSSU2Address (ssu2port, false, ipv4, ipv6); // unpublish
|
||||
}
|
||||
|
||||
bool transit; i2p::config::GetOption("notransit", transit);
|
||||
@@ -404,7 +407,7 @@ namespace util
|
||||
|
||||
i2p::transport::transports.SetCheckReserved(checkInReserved);
|
||||
i2p::transport::transports.Start(ntcp2, ssu, ssu2);
|
||||
if (i2p::transport::transports.IsBoundSSU() || i2p::transport::transports.IsBoundNTCP2())
|
||||
if (i2p::transport::transports.IsBoundSSU() || i2p::transport::transports.IsBoundSSU2() || i2p::transport::transports.IsBoundNTCP2())
|
||||
LogPrint(eLogInfo, "Daemon: Transports started");
|
||||
else
|
||||
{
|
||||
|
@@ -182,7 +182,7 @@ namespace http {
|
||||
" <meta charset=\"UTF-8\">\r\n"
|
||||
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n"
|
||||
" <link rel=\"shortcut icon\" href=\"" << itoopieFavicon << "\">\r\n"
|
||||
" <title>" << tr("Purple I2P Webconsole") << "</title>\r\n";
|
||||
" <title>" << tr(/* tr: Webconsole page title */ "Purple I2P Webconsole") << "</title>\r\n";
|
||||
GetStyles(s);
|
||||
s <<
|
||||
"</head>\r\n"
|
||||
@@ -222,7 +222,7 @@ namespace http {
|
||||
s << "<b>" << tr("ERROR") << ":</b> " << string << "<br>\r\n";
|
||||
}
|
||||
|
||||
static void ShowNetworkStatus (std::stringstream& s, RouterStatus status)
|
||||
static void ShowNetworkStatus (std::stringstream& s, RouterStatus status, RouterError error)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
@@ -235,7 +235,7 @@ namespace http {
|
||||
case eRouterStatusError:
|
||||
{
|
||||
s << tr("Error");
|
||||
switch (i2p::context.GetError ())
|
||||
switch (error)
|
||||
{
|
||||
case eRouterErrorClockSkew:
|
||||
s << " - " << tr("Clock skew");
|
||||
@@ -260,12 +260,12 @@ namespace http {
|
||||
ShowUptime(s, i2p::context.GetUptime ());
|
||||
s << "<br>\r\n";
|
||||
s << "<b>" << tr("Network status") << ":</b> ";
|
||||
ShowNetworkStatus (s, i2p::context.GetStatus ());
|
||||
ShowNetworkStatus (s, i2p::context.GetStatus (), i2p::context.GetError ());
|
||||
s << "<br>\r\n";
|
||||
if (i2p::context.SupportsV6 ())
|
||||
{
|
||||
s << "<b>" << tr("Network status v6") << ":</b> ";
|
||||
ShowNetworkStatus (s, i2p::context.GetStatusV6 ());
|
||||
ShowNetworkStatus (s, i2p::context.GetStatusV6 (), i2p::context.GetErrorV6 ());
|
||||
s << "<br>\r\n";
|
||||
}
|
||||
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
|
||||
@@ -531,19 +531,21 @@ namespace http {
|
||||
ShowLeaseSetDestination (s, dest, token);
|
||||
|
||||
// Print table with streams information
|
||||
s << "<table>\r\n<caption>" << tr("Streams") << "</caption>\r\n<thead>\r\n<tr>";
|
||||
s << "<th style=\"width:25px;\">StreamID</th>";
|
||||
s << "<th style=\"width:5px;\" \\>"; // Stream closing button column
|
||||
s << "<th class=\"streamdest\">Destination</th>";
|
||||
s << "<th>Sent</th>";
|
||||
s << "<th>Received</th>";
|
||||
s << "<th>Out</th>";
|
||||
s << "<th>In</th>";
|
||||
s << "<th>Buf</th>";
|
||||
s << "<th>RTT</th>";
|
||||
s << "<th>Window</th>";
|
||||
s << "<th>Status</th>";
|
||||
s << "</tr>\r\n</thead>\r\n<tbody class=\"tableitem\">\r\n";
|
||||
s << "<table>\r\n<caption>"
|
||||
<< tr("Streams")
|
||||
<< "</caption>\r\n<thead>\r\n<tr>"
|
||||
<< "<th style=\"width:25px;\">StreamID</th>"
|
||||
<< "<th style=\"width:5px;\" \\>" // Stream closing button column
|
||||
<< "<th class=\"streamdest\">Destination</th>"
|
||||
<< "<th>Sent</th>"
|
||||
<< "<th>Received</th>"
|
||||
<< "<th>Out</th>"
|
||||
<< "<th>In</th>"
|
||||
<< "<th>Buf</th>"
|
||||
<< "<th>RTT</th>"
|
||||
<< "<th>Window</th>"
|
||||
<< "<th>Status</th>"
|
||||
<< "</tr>\r\n</thead>\r\n<tbody class=\"tableitem\">\r\n";
|
||||
|
||||
for (const auto& it: dest->GetAllStreams ())
|
||||
{
|
||||
@@ -739,17 +741,25 @@ namespace http {
|
||||
s << " <button type=\"submit\">" << tr("Change") << "</button>\r\n";
|
||||
s << "</form>\r\n<br>\r\n";
|
||||
|
||||
std::string currLang = i2p::client::context.GetLanguage ()->GetLanguage(); // get current used language
|
||||
s << "<b>" << tr("Change language") << "</b><br>\r\n";
|
||||
s << "<form method=\"get\" action=\"" << webroot << "\">\r\n";
|
||||
s << " <input type=\"hidden\" name=\"cmd\" value=\"" << HTTP_COMMAND_SETLANGUAGE << "\">\r\n";
|
||||
s << " <input type=\"hidden\" name=\"token\" value=\"" << token << "\">\r\n";
|
||||
s << " <select name=\"lang\" id=\"lang\">\r\n";
|
||||
// get current used language
|
||||
std::string currLang = i2p::client::context.GetLanguage ()->GetLanguage();
|
||||
|
||||
s << "<b>"
|
||||
<< tr("Change language")
|
||||
<< "</b><br>\r\n"
|
||||
<< "<form method=\"get\" action=\"" << webroot << "\">\r\n"
|
||||
<< " <input type=\"hidden\" name=\"cmd\" value=\"" << HTTP_COMMAND_SETLANGUAGE << "\">\r\n"
|
||||
<< " <input type=\"hidden\" name=\"token\" value=\"" << token << "\">\r\n"
|
||||
<< " <select name=\"lang\" id=\"lang\">\r\n";
|
||||
|
||||
for (const auto& it: i2p::i18n::languages)
|
||||
s << " <option value=\"" << it.first << "\"" << ((it.first.compare(currLang) == 0) ? " selected" : "") << ">" << it.second.LocaleName << "</option>\r\n";
|
||||
s << " </select>\r\n";
|
||||
s << " <button type=\"submit\">" << tr("Change") << "</button>\r\n";
|
||||
s << "</form>\r\n<br>\r\n";
|
||||
|
||||
s << " </select>\r\n"
|
||||
<< " <button type=\"submit\">"
|
||||
<< tr("Change")
|
||||
<< "</button>\r\n"
|
||||
<< "</form>\r\n<br>\r\n";
|
||||
|
||||
}
|
||||
|
||||
@@ -783,12 +793,13 @@ namespace http {
|
||||
std::stringstream tmp_s, tmp_s6; uint16_t cnt = 0, cnt6 = 0;
|
||||
for (const auto& it: sessions )
|
||||
{
|
||||
if (it.second && it.second->IsEstablished () && !it.second->GetRemoteEndpoint ().address ().is_v6 ())
|
||||
auto endpoint = it.second->GetRemoteEndpoint ();
|
||||
if (it.second && it.second->IsEstablished () && endpoint.address ().is_v4 ())
|
||||
{
|
||||
tmp_s << "<div class=\"listitem\">\r\n";
|
||||
if (it.second->IsOutgoing ()) tmp_s << " ⇒ ";
|
||||
tmp_s << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": "
|
||||
<< it.second->GetRemoteEndpoint ().address ().to_string ();
|
||||
<< endpoint.address ().to_string () << ":" << endpoint.port ();
|
||||
if (!it.second->IsOutgoing ()) tmp_s << " ⇒ ";
|
||||
tmp_s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
||||
if (it.second->GetRelayTag ())
|
||||
@@ -796,12 +807,12 @@ namespace http {
|
||||
tmp_s << "</div>\r\n" << std::endl;
|
||||
cnt++;
|
||||
}
|
||||
if (it.second && it.second->IsEstablished () && it.second->GetRemoteEndpoint ().address ().is_v6 ())
|
||||
if (it.second && it.second->IsEstablished () && endpoint.address ().is_v6 ())
|
||||
{
|
||||
tmp_s6 << "<div class=\"listitem\">\r\n";
|
||||
if (it.second->IsOutgoing ()) tmp_s6 << " ⇒ ";
|
||||
tmp_s6 << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": "
|
||||
<< "[" << it.second->GetRemoteEndpoint ().address ().to_string () << "]";
|
||||
<< "[" << endpoint.address ().to_string () << "]:" << endpoint.port ();
|
||||
if (!it.second->IsOutgoing ()) tmp_s6 << " ⇒ ";
|
||||
tmp_s6 << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
||||
if (it.second->GetRelayTag ())
|
||||
|
6
debian/changelog
vendored
6
debian/changelog
vendored
@@ -1,3 +1,9 @@
|
||||
i2pd (2.43.0-1) unstable; urgency=medium
|
||||
|
||||
* updated to version 2.43.0/0.9.55
|
||||
|
||||
-- orignal <orignal@i2pmail.org> Mon, 22 Aug 2022 16:00:00 +0000
|
||||
|
||||
i2pd (2.42.1-1) unstable; urgency=medium
|
||||
|
||||
* updated to version 2.42.1/0.9.54
|
||||
|
217
i18n/Chinese.cpp
Normal file
217
i18n/Chinese.cpp
Normal file
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Copyright (c) 2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
* See full license text in LICENSE file at top of project tree
|
||||
*/
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include "I18N.h"
|
||||
|
||||
// Simplified Chinese localization file
|
||||
// This is an example translation file without strings in it.
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
namespace chinese // language namespace
|
||||
{
|
||||
// language name in lowercase
|
||||
static std::string language = "chinese";
|
||||
|
||||
// See for language plural forms here:
|
||||
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
|
||||
static int plural (int n) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static std::map<std::string, std::string> strings
|
||||
{
|
||||
{"KiB", "KiB"},
|
||||
{"MiB", "MiB"},
|
||||
{"GiB", "GiB"},
|
||||
{"building", "正在构建"},
|
||||
{"failed", "连接失败"},
|
||||
{"expiring", "即将过期"},
|
||||
{"established", "连接已建立"},
|
||||
{"unknown", "未知"},
|
||||
{"exploratory", "探测"},
|
||||
{"Purple I2P Webconsole", "Purple I2P 网页控制台"},
|
||||
{"<b>i2pd</b> webconsole", "<b>i2pd</b> 网页控制台"},
|
||||
{"Main page", "主页"},
|
||||
{"Router commands", "路由命令"},
|
||||
{"Local Destinations", "本地目标"},
|
||||
{"LeaseSets", "租契集"},
|
||||
{"Tunnels", "隧道"},
|
||||
{"Transit Tunnels", "中转隧道"},
|
||||
{"Transports", "传输"},
|
||||
{"I2P tunnels", "I2P 隧道"},
|
||||
{"SAM sessions", "SAM 会话"},
|
||||
{"ERROR", "错误"},
|
||||
{"OK", "良好"},
|
||||
{"Testing", "测试中"},
|
||||
{"Firewalled", "受到防火墙限制"},
|
||||
{"Unknown", "未知"},
|
||||
{"Proxy", "代理"},
|
||||
{"Mesh", "Mesh组网"},
|
||||
{"Error", "错误"},
|
||||
{"Clock skew", "时钟偏移"},
|
||||
{"Offline", "离线"},
|
||||
{"Symmetric NAT", "对称 NAT"},
|
||||
{"Uptime", "运行时间"},
|
||||
{"Network status", "IPv4 网络状态"},
|
||||
{"Network status v6", "IPv6 网络状态"},
|
||||
{"Stopping in", "距停止还有:"},
|
||||
{"Family", "家族"},
|
||||
{"Tunnel creation success rate", "隧道创建成功率"},
|
||||
{"Received", "已接收"},
|
||||
{"KiB/s", "KiB/s"},
|
||||
{"Sent", "已发送"},
|
||||
{"Transit", "中转"},
|
||||
{"Data path", "数据文件路径"},
|
||||
{"Hidden content. Press on text to see.", "隐藏内容 请点击此处查看。"},
|
||||
{"Router Ident", "路由身份"},
|
||||
{"Router Family", "路由器家族"},
|
||||
{"Router Caps", "路由器类型"},
|
||||
{"Version", "版本"},
|
||||
{"Our external address", "外部地址"},
|
||||
{"supported", "支持"},
|
||||
{"Routers", "路由节点"},
|
||||
{"Floodfills", "洪泛节点"},
|
||||
{"Client Tunnels", "客户端隧道"},
|
||||
{"Services", "服务"},
|
||||
{"Enabled", "启用"},
|
||||
{"Disabled", "禁用"},
|
||||
{"Encrypted B33 address", "加密的 B33 地址"},
|
||||
{"Address registration line", "地址域名注册"},
|
||||
{"Domain", "域名"},
|
||||
{"Generate", "生成"},
|
||||
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>注意:</b> 结果字符串可以用于注册次级域名(例如:example.i2p)。若需注册次级域名,请使用 i2pd-tools。"},
|
||||
{"Address", "地址"},
|
||||
{"Type", "类型"},
|
||||
{"EncType", "加密类型"},
|
||||
{"Inbound tunnels", "入站隧道"},
|
||||
{"ms", "毫秒"},
|
||||
{"Outbound tunnels", "出站隧道"},
|
||||
{"Tags", "标签"},
|
||||
{"Incoming", "传入"},
|
||||
{"Outgoing", "传出"},
|
||||
{"Destination", "目标"},
|
||||
{"Amount", "数量"},
|
||||
{"Incoming Tags", "传入标签"},
|
||||
{"Tags sessions", "标签会话"},
|
||||
{"Status", "状态"},
|
||||
{"Local Destination", "本地目标"},
|
||||
{"Streams", "流"},
|
||||
{"Close stream", "断开流"},
|
||||
{"I2CP session not found", "未找到 I2CP 会话"},
|
||||
{"I2CP is not enabled", "I2CP 未启用"},
|
||||
{"Invalid", "无效"},
|
||||
{"Store type", "存储类型"},
|
||||
{"Expires", "过期时间"},
|
||||
{"Non Expired Leases", "未到期的租约"},
|
||||
{"Gateway", "网关"},
|
||||
{"TunnelID", "隧道 ID"},
|
||||
{"EndDate", "结束日期"},
|
||||
{"not floodfill", "非洪泛"},
|
||||
{"Queue size", "队列大小"},
|
||||
{"Run peer test", "运行群体测试"},
|
||||
{"Decline transit tunnels", "拒绝中转隧道"},
|
||||
{"Accept transit tunnels", "允许中转隧道"},
|
||||
{"Cancel graceful shutdown", "取消离线"},
|
||||
{"Start graceful shutdown", "优雅地离线"},
|
||||
{"Force shutdown", "强制停止"},
|
||||
{"Reload external CSS styles", "重载外部 CSS 样式"},
|
||||
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>注意:</b> 此处完成的任何操作都不是永久的,不会更改您的配置文件。"},
|
||||
{"Logging level", "日志级别"},
|
||||
{"Transit tunnels limit", "中转隧道限制"},
|
||||
{"Change", "更换"},
|
||||
{"Change language", "更换语言"},
|
||||
{"no transit tunnels currently built", "目前未构建中转隧道"},
|
||||
{"SAM disabled", "SAM 已禁用"},
|
||||
{"no sessions currently running", "没有正在运行的会话"},
|
||||
{"SAM session not found", "未找到 SAM 会话"},
|
||||
{"SAM Session", "SAM 会话"},
|
||||
{"Server Tunnels", "服务器隧道"},
|
||||
{"Client Forwards", "客户端转发"},
|
||||
{"Server Forwards", "服务器转发"},
|
||||
{"Unknown page", "未知页面"},
|
||||
{"Invalid token", "无效凭证"},
|
||||
{"SUCCESS", "成功"},
|
||||
{"Stream closed", "流已关闭"},
|
||||
{"Stream not found or already was closed", "流未找到或已关闭"},
|
||||
{"Destination not found", "找不到目标"},
|
||||
{"StreamID can't be null", "StreamID 不能为空"},
|
||||
{"Return to destination page", "返回目标页面"},
|
||||
{"You will be redirected in 5 seconds", "您将在5秒内被重定向"},
|
||||
{"Transit tunnels count must not exceed 65535", "中转隧道数量不能超过 65535"},
|
||||
{"Back to commands list", "返回命令列表"},
|
||||
{"Register at reg.i2p", "在 reg.i2p 注册域名"},
|
||||
{"Description", "描述"},
|
||||
{"A bit information about service on domain", "在此域名上运行的服务的一些信息"},
|
||||
{"Submit", "提交"},
|
||||
{"Domain can't end with .b32.i2p", "域名不能以 .b32.i2p 结尾"},
|
||||
{"Domain must end with .i2p", "域名必须以 .i2p 结尾"},
|
||||
{"Such destination is not found", "找不到此目标"},
|
||||
{"Unknown command", "未知指令"},
|
||||
{"Command accepted", "已接受指令"},
|
||||
{"Proxy error", "代理错误"},
|
||||
{"Proxy info", "代理信息"},
|
||||
{"Proxy error: Host not found", "代理错误:找不到主机"},
|
||||
{"Remote host not found in router's addressbook", "在路由的地址簿中找不到远程主机"},
|
||||
{"You may try to find this host on jump services below", "您可以尝试在下方的跳转服务上找到这个主机"},
|
||||
{"Invalid request", "无效请求"},
|
||||
{"Proxy unable to parse your request", "代理无法解析您的请求"},
|
||||
{"addresshelper is not supported", "不支持地址助手"},
|
||||
{"Host", "主机"},
|
||||
{"added to router's addressbook from helper", "将此地址从地址助手添加到地址簿"},
|
||||
{"Click here to proceed:", "点击此处继续:"},
|
||||
{"Continue", "继续"},
|
||||
{"Addresshelper found", "找到地址助手"},
|
||||
{"already in router's addressbook", "已在路由器的地址簿中"},
|
||||
{"Click here to update record:", "点击此处更新地址簿记录"},
|
||||
{"invalid request uri", "无效的 URL 请求"},
|
||||
{"Can't detect destination host from request", "无法从请求中检测到目标主机"},
|
||||
{"Outproxy failure", "出口代理失效"},
|
||||
{"bad outproxy settings", "错误的出口代理设置"},
|
||||
{"not inside I2P network, but outproxy is not enabled", "该地址不在 I2P 网络内,但未启用出口代理"},
|
||||
{"unknown outproxy url", "未知的出口代理地址"},
|
||||
{"cannot resolve upstream proxy", "无法解析上游代理"},
|
||||
{"hostname too long", "主机名过长"},
|
||||
{"cannot connect to upstream socks proxy", "无法连接到上游 socks 代理"},
|
||||
{"Cannot negotiate with socks proxy", "无法与 socks 代理协商"},
|
||||
{"CONNECT error", "连接错误"},
|
||||
{"Failed to Connect", "连接失败"},
|
||||
{"socks proxy error", "socks 代理错误"},
|
||||
{"failed to send request to upstream", "向上游发送请求失败"},
|
||||
{"No Reply From socks proxy", "没有来自 socks 代理的回复"},
|
||||
{"cannot connect", "无法连接"},
|
||||
{"http out proxy not implemented", "http 出口代理未实现"},
|
||||
{"cannot connect to upstream http proxy", "无法连接到上游 http 代理"},
|
||||
{"Host is down", "主机已关闭"},
|
||||
{"Can't create connection to requested host, it may be down. Please try again later.", "无法创建到目标主机的连接。主机可能已下线,请稍后再试。"},
|
||||
{"", ""},
|
||||
};
|
||||
|
||||
static std::map<std::string, std::vector<std::string>> plurals
|
||||
{
|
||||
{"days", {"天"}},
|
||||
{"hours", {"时"}},
|
||||
{"minutes", {"分"}},
|
||||
{"seconds", {"秒"}},
|
||||
{"", {""}},
|
||||
};
|
||||
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale()
|
||||
{
|
||||
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
|
||||
}
|
||||
|
||||
} // language
|
||||
} // i18n
|
||||
} // i2p
|
115
i18n/French.cpp
115
i18n/French.cpp
@@ -35,24 +35,33 @@ namespace french // language namespace
|
||||
{"MiB", "Mio"},
|
||||
{"GiB", "Gio"},
|
||||
{"building", "En construction"},
|
||||
{"failed", "echoué"},
|
||||
{"failed", "échoué"},
|
||||
{"expiring", "expiré"},
|
||||
{"established", "établi"},
|
||||
{"unknown", "inconnu"},
|
||||
{"exploratory", "exploratoire"},
|
||||
{"Purple I2P Webconsole", "Console web Purple I2P"},
|
||||
{"<b>i2pd</b> webconsole", "Console web <b>i2pd</b>"},
|
||||
{"Main page", "Page principale"},
|
||||
{"Router commands", "Commandes du routeur"},
|
||||
{"Local Destinations", "Destinations locales"},
|
||||
{"LeaseSets", "Jeu de baux"},
|
||||
{"Tunnels", "Tunnels"},
|
||||
{"Transit Tunnels", "Tunnels transitoires"},
|
||||
{"Transports", "Transports"},
|
||||
{"I2P tunnels", "Tunnels I2P"},
|
||||
{"SAM sessions", "Sessions SAM"},
|
||||
{"ERROR", "ERREUR"},
|
||||
{"OK", "OK"},
|
||||
{"Testing", "Test en cours"},
|
||||
{"Firewalled", "Derrière un pare-feu"},
|
||||
{"Unknown", "Inconnu"},
|
||||
{"Proxy", "Proxy"},
|
||||
{"Mesh", "Maillé"},
|
||||
{"Error", "Erreur"},
|
||||
{"Clock skew", "Horloge décalée"},
|
||||
{"Offline", "Hors ligne"},
|
||||
{"Symmetric NAT", "NAT symétrique"},
|
||||
{"Uptime", "Temps de fonctionnement"},
|
||||
{"Network status", "État du réseau"},
|
||||
{"Network status v6", "État du réseau v6"},
|
||||
@@ -62,24 +71,124 @@ namespace french // language namespace
|
||||
{"Received", "Reçu"},
|
||||
{"KiB/s", "kio/s"},
|
||||
{"Sent", "Envoyé"},
|
||||
{"Transit", "Transit"},
|
||||
{"Hidden content. Press on text to see.", "Contenu caché. Cliquez sur le texte pour regarder."},
|
||||
{"Transit", "Transité"},
|
||||
{"Data path", "Emplacement des données"},
|
||||
{"Hidden content. Press on text to see.", "Contenu caché. Cliquez sur le texte pour afficher."},
|
||||
{"Router Ident", "Identifiant du routeur"},
|
||||
{"Router Family", "Famille du routeur"},
|
||||
{"Router Caps", "Limiteurs du routeur"},
|
||||
{"Version", "Version"},
|
||||
{"Our external address", "Notre adresse externe"},
|
||||
{"supported", "supporté"},
|
||||
{"Routers", "Routeurs"},
|
||||
{"Client Tunnels", "Tunnels clients"},
|
||||
{"Services", "Services"},
|
||||
{"Enabled", "Activé"},
|
||||
{"Disabled", "Désactivé"},
|
||||
{"Encrypted B33 address", "Adresse B33 chiffrée"},
|
||||
{"Address registration line", "Ligne d'inscription de l'adresse"},
|
||||
{"Domain", "Domaine"},
|
||||
{"Generate", "Générer"},
|
||||
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Note:</b> La chaîne résultante peut seulement être utilisée pour enregistrer les domaines 2LD (exemple.i2p). Pour enregistrer des sous-domaines, veuillez utiliser i2pd-tools."},
|
||||
{"Address", "Adresse"},
|
||||
{"Type", "Type"},
|
||||
{"Inbound tunnels", "Tunnels entrants"},
|
||||
{"ms", "ms"},
|
||||
{"Outbound tunnels", "Tunnels sortants"},
|
||||
{"Tags", "Balises"},
|
||||
{"Incoming", "Entrant"},
|
||||
{"Outgoing", "Sortant"},
|
||||
{"Destination", "Destination"},
|
||||
{"Amount", "Quantité"},
|
||||
{"Incoming Tags", "Balises entrantes"},
|
||||
{"Tags sessions", "Sessions des balises"},
|
||||
{"Status", "Statut"},
|
||||
{"Local Destination", "Destination locale"},
|
||||
{"Streams", "Flux"},
|
||||
{"Close stream", "Fermer le flux"},
|
||||
{"I2CP session not found", "Session I2CP introuvable"},
|
||||
{"I2CP is not enabled", "I2CP est désactivé"},
|
||||
{"Invalid", "Invalide"},
|
||||
{"Store type", "Type de stockage"},
|
||||
{"Expires", "Expire"},
|
||||
{"Non Expired Leases", "Baux non expirés"},
|
||||
{"Gateway", "Passerelle"},
|
||||
{"TunnelID", "ID du tunnel"},
|
||||
{"EndDate", "Date de fin"},
|
||||
{"Queue size", "Longueur de la file"},
|
||||
{"Run peer test", "Lancer test des pairs"},
|
||||
{"Decline transit tunnels", "Refuser les tunnels transitoires"},
|
||||
{"Accept transit tunnels", "Accepter les tunnels transitoires"},
|
||||
{"Cancel graceful shutdown", "Annuler l'arrêt gracieux"},
|
||||
{"Start graceful shutdown", "Démarrer l'arrêt gracieux"},
|
||||
{"Force shutdown", "Forcer l'arrêt"},
|
||||
{"Reload external CSS styles", "Rafraîchir les styles CSS externes"},
|
||||
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Note:</b> Toute action effectuée ici n'est pas permanente et ne modifie pas vos fichiers de configuration."},
|
||||
{"Logging level", "Niveau de journalisation"},
|
||||
{"Transit tunnels limit", "Limite sur les tunnels transitoires"},
|
||||
{"Change", "Changer"},
|
||||
{"Change language", "Changer la langue"},
|
||||
{"no transit tunnels currently built", "aucun tunnel transitoire présentement établi"},
|
||||
{"SAM disabled", "SAM désactivé"},
|
||||
{"no sessions currently running", "aucune session présentement en cours"},
|
||||
{"SAM session not found", "session SAM introuvable"},
|
||||
{"SAM Session", "Session SAM"},
|
||||
{"Server Tunnels", "Tunnels serveurs"},
|
||||
{"Unknown page", "Page inconnue"},
|
||||
{"Invalid token", "Jeton invalide"},
|
||||
{"SUCCESS", "SUCCÈS"},
|
||||
{"Stream closed", "Flux fermé"},
|
||||
{"Stream not found or already was closed", "Flux introuvable ou déjà fermé"},
|
||||
{"Destination not found", "Destination introuvable"},
|
||||
{"StreamID can't be null", "StreamID ne peut pas être vide"},
|
||||
{"Return to destination page", "Retourner à la page de destination"},
|
||||
{"You will be redirected in 5 seconds", "Vous allez être redirigé dans cinq secondes"},
|
||||
{"Transit tunnels count must not exceed 65535", "Le nombre de tunnels transitoires ne doit pas dépasser 65535"},
|
||||
{"Back to commands list", "Retour à la liste des commandes"},
|
||||
{"Register at reg.i2p", "Inscription à reg.i2p"},
|
||||
{"Description", "Description"},
|
||||
{"A bit information about service on domain", "Un peu d'information à propos des services disponibles dans le domaine"},
|
||||
{"Submit", "Soumettre"},
|
||||
{"Domain can't end with .b32.i2p", "Le domaine ne peut pas terminer par .b32.i2p"},
|
||||
{"Domain must end with .i2p", "Le domaine doit terminer par .i2p"},
|
||||
{"Such destination is not found", "Cette destination est introuvable"},
|
||||
{"Unknown command", "Commande inconnue"},
|
||||
{"Command accepted", "Commande acceptée"},
|
||||
{"Proxy error", "Erreur de proxy"},
|
||||
{"Proxy info", "Information sur le proxy"},
|
||||
{"Proxy error: Host not found", "Erreur de proxy: Hôte introuvable"},
|
||||
{"Remote host not found in router's addressbook", "Hôte distant introuvable dans le carnet d'adresse du routeur"},
|
||||
{"You may try to find this host on jump services below", "Vous pouvez essayer de trouver cet hôte sur des services de redirection ci-dessous"},
|
||||
{"Invalid request", "Requête invalide"},
|
||||
{"Proxy unable to parse your request", "Proxy incapable de comprendre votre requête"},
|
||||
{"addresshelper is not supported", "Assistant d'adresse non supporté"},
|
||||
{"Host", "Hôte"},
|
||||
{"added to router's addressbook from helper", "Ajouté au carnet d'adresse du routeur par l'assistant"},
|
||||
{"Click here to proceed:", "Cliquez ici pour continuer:"},
|
||||
{"Continue", "Continuer"},
|
||||
{"Addresshelper found", "Assistant d'adresse trouvé"},
|
||||
{"already in router's addressbook", "déjà dans le carnet d'adresses du routeur"},
|
||||
{"Click here to update record:", "Cliquez ici pour mettre à jour le carnet d'adresse:"},
|
||||
{"invalid request uri", "uri de la requête invalide"},
|
||||
{"Can't detect destination host from request", "Impossible de détecter l'hôte de destination à partir de la requête"},
|
||||
{"Outproxy failure", "Échec de proxy de sortie"},
|
||||
{"bad outproxy settings", "Mauvaise configuration du proxy de sortie"},
|
||||
{"not inside I2P network, but outproxy is not enabled", "pas dans le réseau I2P, mais le proxy de sortie n'est pas activé"},
|
||||
{"unknown outproxy url", "URL du proxy de sortie inconnu"},
|
||||
{"cannot resolve upstream proxy", "impossible de résoudre l'adresse du proxy en amont"},
|
||||
{"hostname too long", "nom d'hôte trop long"},
|
||||
{"cannot connect to upstream socks proxy", "impossible de se connecter au proxy socks en amont"},
|
||||
{"Cannot negotiate with socks proxy", "Impossible de négocier avec le proxy socks"},
|
||||
{"CONNECT error", "Erreur de connexion"},
|
||||
{"Failed to Connect", "Échec de connexion"},
|
||||
{"socks proxy error", "Erreur de proxy socks"},
|
||||
{"failed to send request to upstream", "Erreur lors de l'envoie de la requête en amont"},
|
||||
{"No Reply From socks proxy", "Pas de réponse du proxy socks"},
|
||||
{"cannot connect", "impossible de connecter"},
|
||||
{"http out proxy not implemented", "Proxy de sortie HTTP non implémenté"},
|
||||
{"cannot connect to upstream http proxy", "impossible de se connecter au proxy HTTP en amont"},
|
||||
{"Host is down", "Hôte hors service"},
|
||||
{"Can't create connection to requested host, it may be down. Please try again later.", "Impossible d'établir une connexion avec l'hôte, il est peut-être hors service. Veuillez réessayer plus tard."},
|
||||
{"", ""},
|
||||
};
|
||||
|
||||
|
@@ -73,6 +73,7 @@ namespace i18n
|
||||
// Add localization here with language name as namespace
|
||||
namespace afrikaans { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace armenian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace chinese { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace english { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace french { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace german { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
@@ -88,6 +89,7 @@ namespace i18n
|
||||
{
|
||||
{ "afrikaans", {"Afrikaans", "af", i2p::i18n::afrikaans::GetLocale} },
|
||||
{ "armenian", {"հայերէն", "hy", i2p::i18n::armenian::GetLocale} },
|
||||
{ "chinese", {"简体字", "zh-CN", i2p::i18n::chinese::GetLocale} },
|
||||
{ "english", {"English", "en", i2p::i18n::english::GetLocale} },
|
||||
{ "french", {"Français", "fr", i2p::i18n::french::GetLocale} },
|
||||
{ "german", {"Deutsch", "de", i2p::i18n::german::GetLocale} },
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -59,9 +59,9 @@ namespace data
|
||||
if (readIdentity || !m_Identity)
|
||||
m_Identity = std::make_shared<IdentityEx>(m_Buffer, m_BufferLen);
|
||||
size_t size = m_Identity->GetFullLen ();
|
||||
if (size > m_BufferLen)
|
||||
if (size + 256 > m_BufferLen)
|
||||
{
|
||||
LogPrint (eLogError, "LeaseSet: Identity length ", size, " exceeds buffer size ", m_BufferLen);
|
||||
LogPrint (eLogError, "LeaseSet: Identity length ", int(size), " exceeds buffer size ", int(m_BufferLen));
|
||||
m_IsValid = false;
|
||||
return;
|
||||
}
|
||||
@@ -74,7 +74,7 @@ namespace data
|
||||
size += m_Identity->GetSigningPublicKeyLen (); // unused signing key
|
||||
if (size + 1 > m_BufferLen)
|
||||
{
|
||||
LogPrint (eLogError, "LeaseSet: ", size, " exceeds buffer size ", m_BufferLen);
|
||||
LogPrint (eLogError, "LeaseSet: ", int(size), " exceeds buffer size ", int(m_BufferLen));
|
||||
m_IsValid = false;
|
||||
return;
|
||||
}
|
||||
@@ -89,7 +89,7 @@ namespace data
|
||||
}
|
||||
if (size + num*LEASE_SIZE > m_BufferLen)
|
||||
{
|
||||
LogPrint (eLogError, "LeaseSet: ", size, " exceeds buffer size ", m_BufferLen);
|
||||
LogPrint (eLogError, "LeaseSet: ", int(size), " exceeds buffer size ", int(m_BufferLen));
|
||||
m_IsValid = false;
|
||||
return;
|
||||
}
|
||||
@@ -125,7 +125,7 @@ namespace data
|
||||
auto signedSize = leases - m_Buffer;
|
||||
if (signedSize + m_Identity->GetSignatureLen () > m_BufferLen)
|
||||
{
|
||||
LogPrint (eLogError, "LeaseSet: Signature exceeds buffer size ", m_BufferLen);
|
||||
LogPrint (eLogError, "LeaseSet: Signature exceeds buffer size ", int(m_BufferLen));
|
||||
m_IsValid = false;
|
||||
}
|
||||
else if (!m_Identity->Verify (m_Buffer, signedSize, leases))
|
||||
@@ -172,7 +172,7 @@ namespace data
|
||||
m_ExpirationTime = lease.endDate;
|
||||
if (m_StoreLeases)
|
||||
{
|
||||
auto ret = m_Leases.insert (std::make_shared<Lease>(lease));
|
||||
auto ret = m_Leases.insert (i2p::data::netdb.NewLease (lease));
|
||||
if (!ret.second) (*ret.first)->endDate = lease.endDate; // update existing
|
||||
(*ret.first)->isUpdated = true;
|
||||
}
|
||||
@@ -274,7 +274,7 @@ namespace data
|
||||
{
|
||||
if (len <= m_BufferLen) m_BufferLen = len;
|
||||
else
|
||||
LogPrint (eLogError, "LeaseSet2: Actual buffer size ", len , " exceeds full buffer size ", m_BufferLen);
|
||||
LogPrint (eLogError, "LeaseSet2: Actual buffer size ", int(len) , " exceeds full buffer size ", int(m_BufferLen));
|
||||
}
|
||||
|
||||
LeaseSet2::LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases, CryptoKeyType preferredCrypto):
|
||||
@@ -320,7 +320,7 @@ namespace data
|
||||
else
|
||||
identity = GetIdentity ();
|
||||
size_t offset = identity->GetFullLen ();
|
||||
if (offset + 8 >= len) return;
|
||||
if (offset + 8 > len) return;
|
||||
m_PublishedTimestamp = bufbe32toh (buf + offset); offset += 4; // published timestamp (seconds)
|
||||
uint16_t expires = bufbe16toh (buf + offset); offset += 2; // expires (seconds)
|
||||
SetExpirationTime ((m_PublishedTimestamp + expires)*1000LL); // in milliseconds
|
||||
@@ -364,6 +364,10 @@ namespace data
|
||||
SetIsValid (verified);
|
||||
}
|
||||
offset += m_TransientVerifier ? m_TransientVerifier->GetSignatureLen () : identity->GetSignatureLen ();
|
||||
if (offset > len) {
|
||||
LogPrint (eLogWarning, "LeaseSet2: short buffer: wanted ", int(offset), "bytes, have ", int(len));
|
||||
return;
|
||||
}
|
||||
SetBufferLen (offset);
|
||||
}
|
||||
|
||||
@@ -388,17 +392,17 @@ namespace data
|
||||
// properties
|
||||
uint16_t propertiesLen = bufbe16toh (buf + offset); offset += 2;
|
||||
offset += propertiesLen; // skip for now. TODO: implement properties
|
||||
if (offset + 1 >= len) return 0;
|
||||
// key sections
|
||||
CryptoKeyType preferredKeyType = m_EncryptionType;
|
||||
bool preferredKeyFound = false;
|
||||
if (offset + 1 > len) return 0;
|
||||
int numKeySections = buf[offset]; offset++;
|
||||
for (int i = 0; i < numKeySections; i++)
|
||||
{
|
||||
if (offset + 4 > len) return 0;
|
||||
uint16_t keyType = bufbe16toh (buf + offset); offset += 2; // encryption key type
|
||||
if (offset + 2 >= len) return 0;
|
||||
uint16_t encryptionKeyLen = bufbe16toh (buf + offset); offset += 2;
|
||||
if (offset + encryptionKeyLen >= len) return 0;
|
||||
if (offset + encryptionKeyLen > len) return 0;
|
||||
if (IsStoreLeases () && !preferredKeyFound) // create encryptor with leases only
|
||||
{
|
||||
// we pick first valid key if preferred not found
|
||||
@@ -413,7 +417,7 @@ namespace data
|
||||
offset += encryptionKeyLen;
|
||||
}
|
||||
// leases
|
||||
if (offset + 1 >= len) return 0;
|
||||
if (offset + 1 > len) return 0;
|
||||
int numLeases = buf[offset]; offset++;
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
if (IsStoreLeases ())
|
||||
@@ -432,7 +436,8 @@ namespace data
|
||||
}
|
||||
else
|
||||
offset += numLeases*LEASE2_SIZE; // 40 bytes per lease
|
||||
return offset;
|
||||
|
||||
return (offset > len ? 0 : offset);
|
||||
}
|
||||
|
||||
size_t LeaseSet2::ReadMetaLS2TypeSpecificPart (const uint8_t * buf, size_t len)
|
||||
@@ -442,18 +447,18 @@ namespace data
|
||||
uint16_t propertiesLen = bufbe16toh (buf + offset); offset += 2;
|
||||
offset += propertiesLen; // skip for now. TODO: implement properties
|
||||
// entries
|
||||
if (offset + 1 >= len) return 0;
|
||||
if (offset + 1 > len) return 0;
|
||||
int numEntries = buf[offset]; offset++;
|
||||
for (int i = 0; i < numEntries; i++)
|
||||
{
|
||||
if (offset + 40 >= len) return 0;
|
||||
if (offset + LEASE2_SIZE > len) return 0;
|
||||
offset += 32; // hash
|
||||
offset += 3; // flags
|
||||
offset += 1; // cost
|
||||
offset += 4; // expires
|
||||
}
|
||||
// revocations
|
||||
if (offset + 1 >= len) return 0;
|
||||
if (offset + 1 > len) return 0;
|
||||
int numRevocations = buf[offset]; offset++;
|
||||
for (int i = 0; i < numRevocations; i++)
|
||||
{
|
||||
|
@@ -240,11 +240,10 @@ namespace data
|
||||
m_HiddenMode = hide;
|
||||
}
|
||||
|
||||
bool NetDb::AddRouterInfo (const uint8_t * buf, int len)
|
||||
std::shared_ptr<const RouterInfo> NetDb::AddRouterInfo (const uint8_t * buf, int len)
|
||||
{
|
||||
bool updated;
|
||||
AddRouterInfo (buf, len, updated);
|
||||
return updated;
|
||||
return AddRouterInfo (buf, len, updated);
|
||||
}
|
||||
|
||||
std::shared_ptr<const RouterInfo> NetDb::AddRouterInfo (const uint8_t * buf, int len, bool& updated)
|
||||
@@ -272,7 +271,10 @@ namespace data
|
||||
if (r->IsNewer (buf, len))
|
||||
{
|
||||
bool wasFloodfill = r->IsFloodfill ();
|
||||
r->Update (buf, len);
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
|
||||
r->Update (buf, len);
|
||||
}
|
||||
LogPrint (eLogInfo, "NetDb: RouterInfo updated: ", ident.ToBase64());
|
||||
if (wasFloodfill != r->IsFloodfill ()) // if floodfill status updated
|
||||
{
|
||||
@@ -436,12 +438,15 @@ namespace data
|
||||
|
||||
// try reseeding from floodfill first if specified
|
||||
std::string riPath;
|
||||
if(i2p::config::GetOption("reseed.floodfill", riPath)) {
|
||||
if(i2p::config::GetOption("reseed.floodfill", riPath))
|
||||
{
|
||||
auto ri = std::make_shared<RouterInfo>(riPath);
|
||||
if (ri->IsFloodfill()) {
|
||||
if (ri->IsFloodfill())
|
||||
{
|
||||
const uint8_t * riData = ri->GetBuffer();
|
||||
int riLen = ri->GetBufferLen();
|
||||
if(!i2p::data::netdb.AddRouterInfo(riData, riLen)) {
|
||||
if (!i2p::data::netdb.AddRouterInfo(riData, riLen))
|
||||
{
|
||||
// bad router info
|
||||
LogPrint(eLogError, "NetDb: Bad router info");
|
||||
return;
|
||||
@@ -940,9 +945,9 @@ namespace data
|
||||
}
|
||||
uint16_t numExcluded = bufbe16toh (excluded);
|
||||
excluded += 2;
|
||||
if (numExcluded > 512)
|
||||
if (numExcluded > 512 || (excluded - buf) + numExcluded*32 > (int)msg->GetPayloadLength ())
|
||||
{
|
||||
LogPrint (eLogWarning, "NetDb: Number of excluded peers", numExcluded, " exceeds 512");
|
||||
LogPrint (eLogWarning, "NetDb: Number of excluded peers", numExcluded, " is too much");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -951,10 +956,11 @@ namespace data
|
||||
{
|
||||
LogPrint (eLogInfo, "NetDb: Exploratory close to ", key, " ", numExcluded, " excluded");
|
||||
std::set<IdentHash> excludedRouters;
|
||||
const uint8_t * excluded_ident = excluded;
|
||||
for (int i = 0; i < numExcluded; i++)
|
||||
{
|
||||
excludedRouters.insert (excluded);
|
||||
excluded += 32;
|
||||
excludedRouters.insert (excluded_ident);
|
||||
excluded_ident += 32;
|
||||
}
|
||||
std::vector<IdentHash> routers;
|
||||
for (int i = 0; i < 3; i++)
|
||||
@@ -1012,7 +1018,7 @@ namespace data
|
||||
if (closestFloodfills.empty ())
|
||||
LogPrint (eLogWarning, "NetDb: Requested ", key, " not found, ", numExcluded, " peers excluded");
|
||||
replyMsg = CreateDatabaseSearchReply (ident, closestFloodfills);
|
||||
}
|
||||
}
|
||||
}
|
||||
excluded += numExcluded * 32;
|
||||
if (replyMsg)
|
||||
@@ -1231,6 +1237,16 @@ namespace data
|
||||
});
|
||||
}
|
||||
|
||||
std::shared_ptr<const RouterInfo> NetDb::GetRandomSSU2Introducer (bool v4, const std::set<IdentHash>& excluded) const
|
||||
{
|
||||
return GetRandomRouter (
|
||||
[v4, &excluded](std::shared_ptr<const RouterInfo> router)->bool
|
||||
{
|
||||
return !router->IsHidden () && router->IsSSU2Introducer (v4) &&
|
||||
!excluded.count (router->GetIdentHash ());
|
||||
});
|
||||
}
|
||||
|
||||
std::shared_ptr<const RouterInfo> NetDb::GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const
|
||||
{
|
||||
return GetRandomRouter (
|
||||
@@ -1431,6 +1447,7 @@ namespace data
|
||||
else
|
||||
++it;
|
||||
}
|
||||
m_LeasesPool.CleanUpMt ();
|
||||
}
|
||||
|
||||
void NetDb::PopulateRouterInfoBuffer (std::shared_ptr<RouterInfo> r)
|
||||
|
@@ -69,7 +69,7 @@ namespace data
|
||||
void Start ();
|
||||
void Stop ();
|
||||
|
||||
bool AddRouterInfo (const uint8_t * buf, int len);
|
||||
std::shared_ptr<const RouterInfo> AddRouterInfo (const uint8_t * buf, int len);
|
||||
bool AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len);
|
||||
bool AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len);
|
||||
bool AddLeaseSet2 (const IdentHash& ident, const uint8_t * buf, int len, uint8_t storeType);
|
||||
@@ -93,6 +93,7 @@ namespace data
|
||||
std::shared_ptr<const RouterInfo> GetRandomSSU2PeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const;
|
||||
std::shared_ptr<const RouterInfo> GetRandomSSUV6Router () const; // TODO: change to v6 peer test later
|
||||
std::shared_ptr<const RouterInfo> GetRandomIntroducer (bool v4, const std::set<IdentHash>& excluded) const;
|
||||
std::shared_ptr<const RouterInfo> GetRandomSSU2Introducer (bool v4, const std::set<IdentHash>& excluded) const;
|
||||
std::shared_ptr<const RouterInfo> GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
|
||||
std::vector<IdentHash> GetClosestFloodfills (const IdentHash& destination, size_t num,
|
||||
std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
|
||||
@@ -125,6 +126,7 @@ namespace data
|
||||
void ClearRouterInfos () { m_RouterInfos.clear (); };
|
||||
std::shared_ptr<RouterInfo::Buffer> NewRouterInfoBuffer () { return m_RouterInfoBuffersPool.AcquireSharedMt (); };
|
||||
void PopulateRouterInfoBuffer (std::shared_ptr<RouterInfo> r);
|
||||
std::shared_ptr<Lease> NewLease (const Lease& lease) { return m_LeasesPool.AcquireSharedMt (lease); };
|
||||
|
||||
uint32_t GetPublishReplyToken () const { return m_PublishReplyToken; };
|
||||
|
||||
@@ -181,6 +183,7 @@ namespace data
|
||||
uint32_t m_PublishReplyToken = 0;
|
||||
|
||||
i2p::util::MemoryPoolMt<RouterInfo::Buffer> m_RouterInfoBuffersPool;
|
||||
i2p::util::MemoryPoolMt<Lease> m_LeasesPool;
|
||||
};
|
||||
|
||||
extern NetDb netdb;
|
||||
|
@@ -29,7 +29,7 @@ namespace i2p
|
||||
RouterContext::RouterContext ():
|
||||
m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false),
|
||||
m_ShareRatio (100), m_Status (eRouterStatusUnknown), m_StatusV6 (eRouterStatusUnknown),
|
||||
m_Error (eRouterErrorNone), m_NetID (I2PD_NET_ID)
|
||||
m_Error (eRouterErrorNone), m_ErrorV6 (eRouterErrorNone), m_NetID (I2PD_NET_ID)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -60,11 +60,7 @@ namespace i2p
|
||||
i2p::data::LocalRouterInfo routerInfo;
|
||||
routerInfo.SetRouterIdentity (GetIdentity ());
|
||||
uint16_t port; i2p::config::GetOption("port", port);
|
||||
if (!port)
|
||||
{
|
||||
port = rand () % (30777 - 9111) + 9111; // I2P network ports range
|
||||
if (port == 9150) port = 9151; // Tor browser
|
||||
}
|
||||
if (!port) port = SelectRandomPort ();
|
||||
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
|
||||
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
|
||||
bool ssu; i2p::config::GetOption("ssu", ssu);
|
||||
@@ -121,7 +117,11 @@ namespace i2p
|
||||
if (ssu2)
|
||||
{
|
||||
if (ssu2Published)
|
||||
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address_v4::from_string (host), port);
|
||||
{
|
||||
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
|
||||
if (!ssu2Port) ssu2Port = ssu ? (port + 1) : port;
|
||||
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address_v4::from_string (host), ssu2Port);
|
||||
}
|
||||
else
|
||||
{
|
||||
addressCaps |= i2p::data::RouterInfo::AddressCaps::eV4;
|
||||
@@ -166,7 +166,11 @@ namespace i2p
|
||||
if (ssu2)
|
||||
{
|
||||
if (ssu2Published)
|
||||
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address_v6::from_string (host), port);
|
||||
{
|
||||
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
|
||||
if (!ssu2Port) ssu2Port = ssu ? (port + 1) : port;
|
||||
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address_v6::from_string (host), ssu2Port);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ipv4) // no other ssu2 addresses yet
|
||||
@@ -192,6 +196,13 @@ namespace i2p
|
||||
m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ());
|
||||
}
|
||||
|
||||
uint16_t RouterContext::SelectRandomPort () const
|
||||
{
|
||||
uint16_t port = rand () % (30777 - 9111) + 9111; // I2P network ports range
|
||||
if (port == 9150) port = 9151; // Tor browser
|
||||
return port;
|
||||
}
|
||||
|
||||
void RouterContext::UpdateRouterInfo ()
|
||||
{
|
||||
m_RouterInfo.CreateBuffer (m_Keys);
|
||||
@@ -225,6 +236,13 @@ namespace i2p
|
||||
fk.write ((char *)m_SSU2Keys.get (), sizeof (SSU2PrivateKeys));
|
||||
}
|
||||
|
||||
bool RouterContext::IsSSU2Only () const
|
||||
{
|
||||
auto transports = m_RouterInfo.GetCompatibleTransports (false);
|
||||
return (transports & (i2p::data::RouterInfo::eSSU2V4 | i2p::data::RouterInfo::eSSU2V6)) &&
|
||||
!(transports & (i2p::data::RouterInfo::eSSUV4 | i2p::data::RouterInfo::eSSUV6));
|
||||
}
|
||||
|
||||
void RouterContext::SetStatus (RouterStatus status)
|
||||
{
|
||||
if (status != m_Status)
|
||||
@@ -245,11 +263,18 @@ namespace i2p
|
||||
}
|
||||
}
|
||||
|
||||
void RouterContext::SetStatusSSU2 (RouterStatus status)
|
||||
{
|
||||
if (IsSSU2Only ())
|
||||
SetStatus (status);
|
||||
}
|
||||
|
||||
void RouterContext::SetStatusV6 (RouterStatus status)
|
||||
{
|
||||
if (status != m_StatusV6)
|
||||
{
|
||||
m_StatusV6 = status;
|
||||
m_ErrorV6 = eRouterErrorNone;
|
||||
switch (m_StatusV6)
|
||||
{
|
||||
case eRouterStatusOK:
|
||||
@@ -264,12 +289,18 @@ namespace i2p
|
||||
}
|
||||
}
|
||||
|
||||
void RouterContext::SetStatusV6SSU2 (RouterStatus status)
|
||||
{
|
||||
if (IsSSU2Only ())
|
||||
SetStatusV6 (status);
|
||||
}
|
||||
|
||||
void RouterContext::UpdatePort (int port)
|
||||
{
|
||||
bool updated = false;
|
||||
for (auto& address : m_RouterInfo.GetAddresses ())
|
||||
{
|
||||
if (!address->IsNTCP2 () && !address->IsSSU2 () && address->port != port)
|
||||
if (address->port != port && (address->transportStyle == i2p::data::RouterInfo::eTransportSSU || IsSSU2Only ()))
|
||||
{
|
||||
address->port = port;
|
||||
updated = true;
|
||||
@@ -297,12 +328,7 @@ namespace i2p
|
||||
}
|
||||
if (isAddr)
|
||||
{
|
||||
if (!port && !address->port)
|
||||
{
|
||||
// select random port only if address's port is not set
|
||||
port = rand () % (30777 - 9111) + 9111; // I2P network ports range
|
||||
if (port == 9150) port = 9151; // Tor browser
|
||||
}
|
||||
if (!port && !address->port) port = SelectRandomPort ();
|
||||
if (port) address->port = port;
|
||||
address->published = publish;
|
||||
memcpy (address->i, m_NTCP2Keys->iv, 16);
|
||||
@@ -318,18 +344,23 @@ namespace i2p
|
||||
{
|
||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
||||
bool found = false, updated = false;
|
||||
for (auto it = addresses.begin (); it != addresses.end (); ++it)
|
||||
for (auto it = addresses.begin (); it != addresses.end ();)
|
||||
{
|
||||
if ((*it)->IsNTCP2 ())
|
||||
{
|
||||
found = true;
|
||||
if (!enable)
|
||||
if (enable)
|
||||
{
|
||||
addresses.erase (it);
|
||||
updated= true;
|
||||
}
|
||||
break;
|
||||
(*it)->s = m_NTCP2Keys->staticPublicKey;
|
||||
memcpy ((*it)->i, m_NTCP2Keys->iv, 16);
|
||||
it++;
|
||||
}
|
||||
else
|
||||
it = addresses.erase (it);
|
||||
updated = true;
|
||||
}
|
||||
else
|
||||
it++;
|
||||
}
|
||||
if (enable && !found)
|
||||
{
|
||||
@@ -342,14 +373,26 @@ namespace i2p
|
||||
|
||||
void RouterContext::PublishSSU2Address (int port, bool publish, bool v4, bool v6)
|
||||
{
|
||||
if (!m_SSU2Keys || (publish && !port)) return;
|
||||
if (!m_SSU2Keys) return;
|
||||
int newPort = 0;
|
||||
if (!port)
|
||||
{
|
||||
for (const auto& address : m_RouterInfo.GetAddresses ())
|
||||
if (address->port)
|
||||
{
|
||||
newPort = address->port;
|
||||
break;
|
||||
}
|
||||
if (!newPort) newPort = SelectRandomPort ();
|
||||
}
|
||||
bool updated = false;
|
||||
for (auto& address : m_RouterInfo.GetAddresses ())
|
||||
{
|
||||
if (address->IsSSU2 () && (address->port != port || address->published != publish) &&
|
||||
if (address->IsSSU2 () && (!address->port || address->port != port || address->published != publish) &&
|
||||
((v4 && address->IsV4 ()) || (v6 && address->IsV6 ())))
|
||||
{
|
||||
address->port = port;
|
||||
if (port) address->port = port;
|
||||
else if (!address->port) address->port = newPort;
|
||||
address->published = publish;
|
||||
if (publish)
|
||||
address->caps |= (i2p::data::RouterInfo::eSSUIntroducer | i2p::data::RouterInfo::eSSUTesting);
|
||||
@@ -366,27 +409,41 @@ namespace i2p
|
||||
{
|
||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
||||
bool found = false, updated = false;
|
||||
for (auto it = addresses.begin (); it != addresses.end (); ++it)
|
||||
for (auto it = addresses.begin (); it != addresses.end ();)
|
||||
{
|
||||
if ((*it)->IsSSU2 ())
|
||||
{
|
||||
found = true;
|
||||
if (!enable)
|
||||
if (enable)
|
||||
{
|
||||
addresses.erase (it);
|
||||
updated= true;
|
||||
}
|
||||
break;
|
||||
(*it)->s = m_SSU2Keys->staticPublicKey;
|
||||
(*it)->i = m_SSU2Keys->intro;
|
||||
it++;
|
||||
}
|
||||
else
|
||||
it = addresses.erase (it);
|
||||
updated = true;
|
||||
}
|
||||
else
|
||||
it++;
|
||||
}
|
||||
if (enable && !found)
|
||||
{
|
||||
uint8_t addressCaps = 0;
|
||||
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
|
||||
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
|
||||
if (ipv4) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV4;
|
||||
if (ipv6) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6;
|
||||
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addressCaps);
|
||||
bool published; i2p::config::GetOption("ntcp2.published", published);
|
||||
if (published)
|
||||
{
|
||||
if (ipv4) m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::AddressCaps::eV4);
|
||||
if (ipv6) m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::AddressCaps::eV6);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t addressCaps = 0;
|
||||
if (ipv4) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV4;
|
||||
if (ipv6) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6;
|
||||
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addressCaps);
|
||||
}
|
||||
updated = true;
|
||||
}
|
||||
if (updated)
|
||||
@@ -401,23 +458,30 @@ namespace i2p
|
||||
if (address->host != host && address->IsCompatible (host) &&
|
||||
!i2p::util::net::IsYggdrasilAddress (address->host))
|
||||
{
|
||||
// update host
|
||||
address->host = host;
|
||||
if (host.is_v6 () && address->transportStyle == i2p::data::RouterInfo::eTransportSSU)
|
||||
{
|
||||
// update MTU
|
||||
auto mtu = i2p::util::net::GetMTU (host);
|
||||
if (mtu)
|
||||
{
|
||||
LogPrint (eLogDebug, "Router: Our v6 MTU=", mtu);
|
||||
if (mtu > 1472) { // TODO: magic constant
|
||||
mtu = 1472;
|
||||
LogPrint(eLogWarning, "Router: MTU dropped to upper limit of 1472 bytes");
|
||||
}
|
||||
if (address->ssu) address->ssu->mtu = mtu;
|
||||
}
|
||||
}
|
||||
updated = true;
|
||||
}
|
||||
if (host.is_v6 () && address->IsV6 () && address->ssu &&
|
||||
(!address->ssu->mtu || updated))
|
||||
{
|
||||
// update MTU
|
||||
auto mtu = i2p::util::net::GetMTU (host);
|
||||
if (mtu)
|
||||
{
|
||||
LogPrint (eLogDebug, "Router: Our v6 MTU=", mtu);
|
||||
int maxMTU = i2p::util::net::GetMaxMTU (host.to_v6 ());
|
||||
if (mtu > maxMTU)
|
||||
{
|
||||
mtu = maxMTU;
|
||||
LogPrint(eLogWarning, "Router: MTU dropped to upper limit of ", maxMTU, " bytes");
|
||||
}
|
||||
if (mtu && !address->IsSSU2 ()) // SSU1
|
||||
mtu = (mtu >> 4) << 4; // round to multiple of 16
|
||||
address->ssu->mtu = mtu;
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
if (updated || ts > m_LastUpdateTime + ROUTER_INFO_UPDATE_INTERVAL)
|
||||
@@ -438,6 +502,37 @@ namespace i2p
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
bool RouterContext::AddSSU2Introducer (const i2p::data::RouterInfo::Introducer& introducer, bool v4)
|
||||
{
|
||||
if (!IsSSU2Only ()) return false;
|
||||
bool ret = m_RouterInfo.AddSSU2Introducer (introducer, v4);
|
||||
if (ret)
|
||||
UpdateRouterInfo ();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void RouterContext::RemoveSSU2Introducer (const i2p::data::IdentHash& h, bool v4)
|
||||
{
|
||||
if (!IsSSU2Only ()) return;
|
||||
if (m_RouterInfo.RemoveSSU2Introducer (h, v4))
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
void RouterContext::ClearSSU2Introducers (bool v4)
|
||||
{
|
||||
bool updated = false;
|
||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
||||
for (auto& addr : addresses)
|
||||
if (addr->IsSSU2 () && ((v4 && addr->IsV4 ()) || (!v4 && addr->IsV6 ())) &&
|
||||
addr->ssu && !addr->ssu->introducers.empty ())
|
||||
{
|
||||
addr->ssu->introducers.clear ();
|
||||
updated = true;
|
||||
}
|
||||
if (updated)
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
void RouterContext::SetFloodfill (bool floodfill)
|
||||
{
|
||||
m_IsFloodfill = floodfill;
|
||||
@@ -538,6 +633,7 @@ namespace i2p
|
||||
|
||||
void RouterContext::RemoveNTCPAddress (bool v4only)
|
||||
{
|
||||
bool updated = false;
|
||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
||||
for (auto it = addresses.begin (); it != addresses.end ();)
|
||||
{
|
||||
@@ -545,11 +641,38 @@ namespace i2p
|
||||
(!v4only || (*it)->host.is_v4 ()))
|
||||
{
|
||||
it = addresses.erase (it);
|
||||
updated = true;
|
||||
if (v4only) break; // otherwise might be more than one address
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
if (updated)
|
||||
m_RouterInfo.UpdateSupportedTransports ();
|
||||
}
|
||||
|
||||
void RouterContext::RemoveSSUAddress ()
|
||||
{
|
||||
bool updated = false;
|
||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
||||
for (auto it = addresses.begin (); it != addresses.end ();)
|
||||
{
|
||||
if ((*it)->transportStyle == i2p::data::RouterInfo::eTransportSSU)
|
||||
{
|
||||
it = addresses.erase (it);
|
||||
updated = true;
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
if (updated)
|
||||
m_RouterInfo.UpdateSupportedTransports ();
|
||||
}
|
||||
|
||||
void RouterContext::SetUnreachableSSU2 (bool v4, bool v6)
|
||||
{
|
||||
if (IsSSU2Only ())
|
||||
SetUnreachable (v4, v6);
|
||||
}
|
||||
|
||||
void RouterContext::SetUnreachable (bool v4, bool v6)
|
||||
@@ -568,7 +691,8 @@ namespace i2p
|
||||
// delete previous introducers
|
||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
||||
for (auto& addr : addresses)
|
||||
if (addr->ssu && !addr->IsSSU2 () && ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ())))
|
||||
if (addr->ssu && (!addr->IsSSU2 () || IsSSU2Only ()) &&
|
||||
((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ())))
|
||||
{
|
||||
addr->published = false;
|
||||
addr->caps &= ~i2p::data::RouterInfo::eSSUIntroducer; // can't be introducer
|
||||
@@ -598,14 +722,19 @@ namespace i2p
|
||||
}
|
||||
uint16_t port = 0;
|
||||
// delete previous introducers
|
||||
bool isSSU2Published = IsSSU2Only (); // TODO
|
||||
if (isSSU2Published)
|
||||
i2p::config::GetOption ("ssu2.published", isSSU2Published);
|
||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
||||
for (auto& addr : addresses)
|
||||
if (addr->ssu && !addr->IsSSU2 () && ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ())))
|
||||
if (addr->ssu && (!addr->IsSSU2 () || isSSU2Published) &&
|
||||
((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ())))
|
||||
{
|
||||
addr->published = true;
|
||||
addr->caps |= i2p::data::RouterInfo::eSSUIntroducer;
|
||||
addr->ssu->introducers.clear ();
|
||||
port = addr->port;
|
||||
if (addr->port && (!addr->IsSSU2 () || IsSSU2Only ()))
|
||||
port = addr->port;
|
||||
}
|
||||
// publish NTCP2
|
||||
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
||||
@@ -652,16 +781,17 @@ namespace i2p
|
||||
}
|
||||
port = addr->port;
|
||||
}
|
||||
if (!port) i2p::config::GetOption("port", port);
|
||||
if (!port)
|
||||
{
|
||||
i2p::config::GetOption("port", port);
|
||||
if (!port) port = SelectRandomPort ();
|
||||
}
|
||||
// SSU
|
||||
if (!foundSSU)
|
||||
bool ssu; i2p::config::GetOption("ssu", ssu);
|
||||
if (!foundSSU && ssu)
|
||||
{
|
||||
bool ssu; i2p::config::GetOption("ssu", ssu);
|
||||
if (ssu)
|
||||
{
|
||||
std::string host = "::1"; // TODO: read host
|
||||
m_RouterInfo.AddSSUAddress (host.c_str (), port, nullptr);
|
||||
}
|
||||
std::string host = "::1"; // TODO: read host
|
||||
m_RouterInfo.AddSSUAddress (host.c_str (), port, nullptr);
|
||||
}
|
||||
// NTCP2
|
||||
if (!foundNTCP2)
|
||||
@@ -695,6 +825,7 @@ namespace i2p
|
||||
if (ssu2Published)
|
||||
{
|
||||
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
|
||||
if (!ssu2Port) ssu2Port = ssu ? (port + 1) : port;
|
||||
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address::from_string ("::1"), ssu2Port);
|
||||
}
|
||||
else
|
||||
@@ -740,14 +871,16 @@ namespace i2p
|
||||
}
|
||||
if (addr->port) port = addr->port;
|
||||
}
|
||||
if (!port) i2p::config::GetOption("port", port);
|
||||
if (!port)
|
||||
{
|
||||
i2p::config::GetOption("port", port);
|
||||
if (!port) port = SelectRandomPort ();
|
||||
}
|
||||
// SSU
|
||||
if (!foundSSU)
|
||||
{
|
||||
bool ssu; i2p::config::GetOption("ssu", ssu);
|
||||
if (ssu)
|
||||
m_RouterInfo.AddSSUAddress (host.c_str (), port, nullptr);
|
||||
}
|
||||
bool ssu; i2p::config::GetOption("ssu", ssu);
|
||||
if (!foundSSU && ssu)
|
||||
m_RouterInfo.AddSSUAddress (host.c_str (), port, nullptr);
|
||||
|
||||
// NTCP2
|
||||
if (!foundNTCP2)
|
||||
{
|
||||
@@ -775,10 +908,11 @@ namespace i2p
|
||||
if (ssu2Published)
|
||||
{
|
||||
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
|
||||
if (!ssu2Port) ssu2Port = ssu ? (port + 1) : port;
|
||||
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address::from_string ("127.0.0.1"), ssu2Port);
|
||||
}
|
||||
else
|
||||
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::eV6);
|
||||
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::eV4);
|
||||
}
|
||||
}
|
||||
m_RouterInfo.EnableV4 ();
|
||||
@@ -815,6 +949,43 @@ namespace i2p
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
void RouterContext::SetMTU (int mtu, bool v4)
|
||||
{
|
||||
if (mtu < 1280 || mtu > 1500) return;
|
||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
||||
for (auto& addr: addresses)
|
||||
{
|
||||
if (addr->ssu && ((v4 && addr->IsV4 ()) || (!v4 && addr->IsV6 ())))
|
||||
{
|
||||
if (!addr->IsSSU2 ()) // SSU1
|
||||
{
|
||||
// round to multiple of 16
|
||||
if (v4)
|
||||
{
|
||||
if (mtu > 1484) mtu = 1484;
|
||||
else
|
||||
{
|
||||
mtu -= 12;
|
||||
mtu = (mtu >> 4) << 4;
|
||||
mtu += 12;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mtu > 1488) mtu = 1488;
|
||||
else
|
||||
mtu = (mtu >> 4) << 4;
|
||||
}
|
||||
}
|
||||
if (mtu)
|
||||
{
|
||||
addr->ssu->mtu = mtu;
|
||||
LogPrint (eLogDebug, "Router: MTU for ", v4 ? "ipv4" : "ipv6", " address ", addr->host.to_string(), " is set to ", mtu);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RouterContext::UpdateNTCP2V6Address (const boost::asio::ip::address& host)
|
||||
{
|
||||
bool isYgg = i2p::util::net::IsYggdrasilAddress (host);
|
||||
|
@@ -103,10 +103,14 @@ namespace garlic
|
||||
uint64_t GetTransitBandwidthLimit () const { return (m_BandwidthLimit*m_ShareRatio)/100LL; };
|
||||
RouterStatus GetStatus () const { return m_Status; };
|
||||
void SetStatus (RouterStatus status);
|
||||
void SetStatusSSU2 (RouterStatus status);
|
||||
RouterError GetError () const { return m_Error; };
|
||||
void SetError (RouterError error) { m_Status = eRouterStatusError; m_Error = error; };
|
||||
RouterStatus GetStatusV6 () const { return m_StatusV6; };
|
||||
void SetStatusV6 (RouterStatus status);
|
||||
void SetStatusV6SSU2 (RouterStatus status);
|
||||
RouterError GetErrorV6 () const { return m_ErrorV6; };
|
||||
void SetErrorV6 (RouterError error) { m_StatusV6 = eRouterStatusError; m_ErrorV6 = error; };
|
||||
int GetNetID () const { return m_NetID; };
|
||||
void SetNetID (int netID) { m_NetID = netID; };
|
||||
bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data);
|
||||
@@ -119,10 +123,15 @@ namespace garlic
|
||||
void PublishSSU2Address (int port, bool publish, bool v4, bool v6);
|
||||
void UpdateSSU2Address (bool enable);
|
||||
void RemoveNTCPAddress (bool v4only = true); // delete NTCP address for older routers. TODO: remove later
|
||||
void RemoveSSUAddress (); // delete SSU address for older routers
|
||||
bool AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer);
|
||||
void RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
|
||||
bool AddSSU2Introducer (const i2p::data::RouterInfo::Introducer& introducer, bool v4);
|
||||
void RemoveSSU2Introducer (const i2p::data::IdentHash& h, bool v4);
|
||||
void ClearSSU2Introducers (bool v4);
|
||||
bool IsUnreachable () const;
|
||||
void SetUnreachable (bool v4, bool v6);
|
||||
void SetUnreachableSSU2 (bool v4, bool v6);
|
||||
void SetReachable (bool v4, bool v6);
|
||||
bool IsFloodfill () const { return m_IsFloodfill; };
|
||||
void SetFloodfill (bool floodfill);
|
||||
@@ -139,6 +148,7 @@ namespace garlic
|
||||
void SetSupportsV6 (bool supportsV6);
|
||||
void SetSupportsV4 (bool supportsV4);
|
||||
void SetSupportsMesh (bool supportsmesh, const boost::asio::ip::address_v6& host);
|
||||
void SetMTU (int mtu, bool v4);
|
||||
i2p::crypto::NoiseSymmetricState& GetCurrentNoiseState () { return m_CurrentNoiseState; };
|
||||
|
||||
void UpdateNTCP2V6Address (const boost::asio::ip::address& host); // called from Daemon. TODO: remove
|
||||
@@ -173,8 +183,10 @@ namespace garlic
|
||||
void UpdateRouterInfo ();
|
||||
void NewNTCP2Keys ();
|
||||
void NewSSU2Keys ();
|
||||
bool IsSSU2Only () const; // SSU2 and no SSU
|
||||
bool Load ();
|
||||
void SaveKeys ();
|
||||
uint16_t SelectRandomPort () const;
|
||||
|
||||
bool DecryptECIESTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, size_t clearTextSize);
|
||||
|
||||
@@ -190,7 +202,7 @@ namespace garlic
|
||||
uint64_t m_BandwidthLimit; // allowed bandwidth
|
||||
int m_ShareRatio;
|
||||
RouterStatus m_Status, m_StatusV6;
|
||||
RouterError m_Error;
|
||||
RouterError m_Error, m_ErrorV6;
|
||||
int m_NetID;
|
||||
std::mutex m_GarlicMutex;
|
||||
std::unique_ptr<NTCP2PrivateKeys> m_NTCP2Keys;
|
||||
|
@@ -708,6 +708,7 @@ namespace data
|
||||
{
|
||||
auto addr = std::make_shared<Address>();
|
||||
addr->transportStyle = eTransportSSU2;
|
||||
addr->port = 0;
|
||||
addr->caps = caps;
|
||||
addr->date = 0;
|
||||
addr->ssu.reset (new SSUExt ());
|
||||
@@ -727,7 +728,7 @@ namespace data
|
||||
addr->host = host;
|
||||
addr->port = port;
|
||||
addr->published = true;
|
||||
addr->caps = 0;
|
||||
addr->caps = i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer; // BC;
|
||||
addr->date = 0;
|
||||
addr->ssu.reset (new SSUExt ());
|
||||
addr->ssu->mtu = 0;
|
||||
@@ -979,7 +980,8 @@ namespace data
|
||||
return GetAddress (
|
||||
[key, isV6](std::shared_ptr<const RouterInfo::Address> address)->bool
|
||||
{
|
||||
return address->IsSSU2 () && !memcmp (address->s, key, 32) && address->IsV6 () == isV6;
|
||||
return address->IsSSU2 () && !memcmp (address->s, key, 32) &&
|
||||
((isV6 && address->IsV6 ()) || (!isV6 && address->IsV4 ()));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1065,6 +1067,17 @@ namespace data
|
||||
});
|
||||
}
|
||||
|
||||
bool RouterInfo::IsSSU2Introducer (bool v4) const
|
||||
{
|
||||
if (!(m_SupportedTransports & (v4 ? eSSU2V4 : eSSU2V6))) return false;
|
||||
return (bool)GetAddress (
|
||||
[v4](std::shared_ptr<const RouterInfo::Address> address)->bool
|
||||
{
|
||||
return (address->IsSSU2 ()) && address->IsIntroducer () &&
|
||||
((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())) && !address->host.is_unspecified ();
|
||||
});
|
||||
}
|
||||
|
||||
void RouterInfo::SetUnreachableAddressesTransportCaps (uint8_t transports)
|
||||
{
|
||||
for (auto& addr: *m_Addresses)
|
||||
@@ -1296,7 +1309,7 @@ namespace data
|
||||
else
|
||||
WriteString ("", s);
|
||||
|
||||
if (isPublished)
|
||||
if (isPublished && !address.host.is_unspecified ())
|
||||
{
|
||||
WriteString ("host", properties);
|
||||
properties << '=';
|
||||
@@ -1399,7 +1412,7 @@ namespace data
|
||||
properties << ';';
|
||||
}
|
||||
}
|
||||
if (isPublished || (address.ssu && !address.IsSSU2 ()))
|
||||
if ((isPublished || (address.ssu && !address.IsSSU2 ())) && address.port)
|
||||
{
|
||||
WriteString ("port", properties);
|
||||
properties << '=';
|
||||
@@ -1467,5 +1480,40 @@ namespace data
|
||||
{
|
||||
return std::make_shared<Buffer> ();
|
||||
}
|
||||
|
||||
bool LocalRouterInfo::AddSSU2Introducer (const Introducer& introducer, bool v4)
|
||||
{
|
||||
for (auto& addr : GetAddresses ())
|
||||
{
|
||||
if (addr->IsSSU2 () && ((v4 && addr->IsV4 ()) || (!v4 && addr->IsV6 ())))
|
||||
{
|
||||
for (auto& intro: addr->ssu->introducers)
|
||||
if (intro.iTag == introducer.iTag) return false; // already presented
|
||||
addr->ssu->introducers.push_back (introducer);
|
||||
SetReachableTransports (GetReachableTransports () | ((addr->IsV4 () ? eSSU2V4 : eSSU2V6)));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LocalRouterInfo::RemoveSSU2Introducer (const IdentHash& h, bool v4)
|
||||
{
|
||||
for (auto& addr: GetAddresses ())
|
||||
{
|
||||
if (addr->IsSSU2 () && ((v4 && addr->IsV4 ()) || (!v4 && addr->IsV6 ())))
|
||||
{
|
||||
for (auto it = addr->ssu->introducers.begin (); it != addr->ssu->introducers.end (); ++it)
|
||||
if (h == it->iKey)
|
||||
{
|
||||
addr->ssu->introducers.erase (it);
|
||||
if (addr->ssu->introducers.empty ())
|
||||
SetReachableTransports (GetReachableTransports () & ~(addr->IsV4 () ? eSSU2V4 : eSSU2V6));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -235,6 +235,7 @@ namespace data
|
||||
bool IsPeerTesting (bool v4) const;
|
||||
bool IsSSU2PeerTesting (bool v4) const;
|
||||
bool IsIntroducer (bool v4) const;
|
||||
bool IsSSU2Introducer (bool v4) const;
|
||||
|
||||
uint8_t GetCaps () const { return m_Caps; };
|
||||
void SetCaps (uint8_t caps) { m_Caps = caps; };
|
||||
@@ -274,6 +275,8 @@ namespace data
|
||||
void SetBufferLen (size_t len) { m_BufferLen = len; };
|
||||
void RefreshTimestamp ();
|
||||
const Addresses& GetAddresses () const { return *m_Addresses; };
|
||||
CompatibleTransports GetReachableTransports () const { return m_ReachableTransports; };
|
||||
void SetReachableTransports (CompatibleTransports transports) { m_ReachableTransports = transports; };
|
||||
|
||||
private:
|
||||
|
||||
@@ -316,6 +319,9 @@ namespace data
|
||||
std::string GetProperty (const std::string& key) const;
|
||||
void ClearProperties () override { m_Properties.clear (); };
|
||||
|
||||
bool AddSSU2Introducer (const Introducer& introducer, bool v4);
|
||||
bool RemoveSSU2Introducer (const IdentHash& h, bool v4);
|
||||
|
||||
private:
|
||||
|
||||
void WriteToStream (std::ostream& s) const;
|
||||
|
420
libi2pd/SSU2.cpp
420
libi2pd/SSU2.cpp
@@ -6,6 +6,7 @@
|
||||
* See full license text in LICENSE file at top of project tree
|
||||
*/
|
||||
|
||||
#include <random>
|
||||
#include "Log.h"
|
||||
#include "RouterContext.h"
|
||||
#include "Transports.h"
|
||||
@@ -21,7 +22,9 @@ namespace transport
|
||||
RunnableServiceWithWork ("SSU2"), m_ReceiveService ("SSU2r"),
|
||||
m_SocketV4 (m_ReceiveService.GetService ()), m_SocketV6 (m_ReceiveService.GetService ()),
|
||||
m_AddressV4 (boost::asio::ip::address_v4()), m_AddressV6 (boost::asio::ip::address_v6()),
|
||||
m_TerminationTimer (GetService ()), m_ResendTimer (GetService ())
|
||||
m_TerminationTimer (GetService ()), m_ResendTimer (GetService ()),
|
||||
m_IntroducersUpdateTimer (GetService ()), m_IntroducersUpdateTimerV6 (GetService ()),
|
||||
m_IsPublished (true), m_IsSyncClockFromPeers (true)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -30,6 +33,8 @@ namespace transport
|
||||
if (!IsRunning ())
|
||||
{
|
||||
StartIOService ();
|
||||
i2p::config::GetOption ("ssu2.published", m_IsPublished);
|
||||
i2p::config::GetOption("nettime.frompeers", m_IsSyncClockFromPeers);
|
||||
bool found = false;
|
||||
auto& addresses = i2p::context.GetRouterInfo ().GetAddresses ();
|
||||
for (const auto& address: addresses)
|
||||
@@ -44,8 +49,9 @@ namespace transport
|
||||
if (ssu2Port) port = ssu2Port;
|
||||
else
|
||||
{
|
||||
bool ssu; i2p::config::GetOption("ssu", ssu);
|
||||
uint16_t p; i2p::config::GetOption ("port", p);
|
||||
if (p) port = p;
|
||||
if (p) port = ssu ? (p + 1) : p;
|
||||
}
|
||||
}
|
||||
if (port)
|
||||
@@ -59,6 +65,7 @@ namespace transport
|
||||
{
|
||||
Receive (m_SocketV4);
|
||||
});
|
||||
ScheduleIntroducersUpdateTimer (); // wait for 30 seconds and decide if we need introducers
|
||||
}
|
||||
if (address->IsV6 ())
|
||||
{
|
||||
@@ -69,6 +76,7 @@ namespace transport
|
||||
{
|
||||
Receive (m_SocketV6);
|
||||
});
|
||||
ScheduleIntroducersUpdateTimerV6 (); // wait for 30 seconds and decide if we need introducers
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -83,30 +91,56 @@ namespace transport
|
||||
|
||||
void SSU2Server::Stop ()
|
||||
{
|
||||
for (auto& it: m_Sessions)
|
||||
if (IsRunning ())
|
||||
{
|
||||
m_TerminationTimer.cancel ();
|
||||
m_ResendTimer.cancel ();
|
||||
m_IntroducersUpdateTimer.cancel ();
|
||||
m_IntroducersUpdateTimerV6.cancel ();
|
||||
}
|
||||
|
||||
auto sessions = m_Sessions;
|
||||
for (auto& it: sessions)
|
||||
{
|
||||
it.second->RequestTermination (eSSU2TerminationReasonRouterShutdown);
|
||||
it.second->Done ();
|
||||
}
|
||||
|
||||
if (context.SupportsV4 () || context.SupportsV6 ())
|
||||
m_ReceiveService.Stop ();
|
||||
m_SocketV4.close ();
|
||||
m_SocketV6.close ();
|
||||
|
||||
StopIOService ();
|
||||
|
||||
m_Sessions.clear ();
|
||||
m_SessionsByRouterHash.clear ();
|
||||
m_PendingOutgoingSessions.clear ();
|
||||
|
||||
if (context.SupportsV4 () || context.SupportsV6 ())
|
||||
m_ReceiveService.Stop ();
|
||||
|
||||
m_SocketV4.close ();
|
||||
m_SocketV6.close ();
|
||||
if (IsRunning ())
|
||||
m_TerminationTimer.cancel ();
|
||||
|
||||
StopIOService ();
|
||||
m_Relays.clear ();
|
||||
m_Introducers.clear ();
|
||||
m_IntroducersV6.clear ();
|
||||
}
|
||||
|
||||
void SSU2Server::SetLocalAddress (const boost::asio::ip::address& localAddress)
|
||||
{
|
||||
if (localAddress.is_unspecified ()) return;
|
||||
if (localAddress.is_v4 ())
|
||||
{
|
||||
m_AddressV4 = localAddress;
|
||||
int mtu = i2p::util::net::GetMTU (localAddress);
|
||||
if (mtu < (int)SSU2_MIN_PACKET_SIZE) mtu = SSU2_MIN_PACKET_SIZE;
|
||||
if (mtu > (int)SSU2_MAX_PACKET_SIZE) mtu = SSU2_MAX_PACKET_SIZE;
|
||||
i2p::context.SetMTU (mtu, true);
|
||||
}
|
||||
else if (localAddress.is_v6 ())
|
||||
{
|
||||
m_AddressV6 = localAddress;
|
||||
int maxMTU = i2p::util::net::GetMaxMTU (localAddress.to_v6 ());
|
||||
int mtu = i2p::util::net::GetMTU (localAddress);
|
||||
if (mtu > maxMTU) mtu = maxMTU;
|
||||
if (mtu < (int)SSU2_MIN_PACKET_SIZE) mtu = SSU2_MIN_PACKET_SIZE;
|
||||
i2p::context.SetMTU (mtu, false);
|
||||
}
|
||||
}
|
||||
|
||||
bool SSU2Server::IsSupported (const boost::asio::ip::address& addr) const
|
||||
@@ -123,6 +157,14 @@ namespace transport
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t SSU2Server::GetPort (bool v4) const
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
boost::asio::ip::udp::endpoint ep = v4 ? m_SocketV4.local_endpoint (ec) : m_SocketV6.local_endpoint (ec);
|
||||
if (ec) return 0;
|
||||
return ep.port ();
|
||||
}
|
||||
|
||||
boost::asio::ip::udp::socket& SSU2Server::OpenSocket (const boost::asio::ip::udp::endpoint& localEndpoint)
|
||||
{
|
||||
@@ -148,7 +190,7 @@ namespace transport
|
||||
void SSU2Server::Receive (boost::asio::ip::udp::socket& socket)
|
||||
{
|
||||
Packet * packet = m_PacketsPool.AcquireMt ();
|
||||
socket.async_receive_from (boost::asio::buffer (packet->buf, SSU2_MTU), packet->from,
|
||||
socket.async_receive_from (boost::asio::buffer (packet->buf, SSU2_MAX_PACKET_SIZE), packet->from,
|
||||
std::bind (&SSU2Server::HandleReceivedFrom, this, std::placeholders::_1, std::placeholders::_2, packet, std::ref (socket)));
|
||||
}
|
||||
|
||||
@@ -169,7 +211,7 @@ namespace transport
|
||||
while (moreBytes && packets.size () < 32)
|
||||
{
|
||||
packet = m_PacketsPool.AcquireMt ();
|
||||
packet->len = socket.receive_from (boost::asio::buffer (packet->buf, SSU2_MTU), packet->from, 0, ec);
|
||||
packet->len = socket.receive_from (boost::asio::buffer (packet->buf, SSU2_MAX_PACKET_SIZE), packet->from, 0, ec);
|
||||
if (!ec)
|
||||
{
|
||||
i2p::transport::transports.UpdateReceivedBytes (packet->len);
|
||||
@@ -210,7 +252,8 @@ namespace transport
|
||||
{
|
||||
ProcessNextPacket (packet->buf, packet->len, packet->from);
|
||||
m_PacketsPool.ReleaseMt (packet);
|
||||
if (m_LastSession) m_LastSession->FlushData ();
|
||||
if (m_LastSession && m_LastSession->GetState () != eSSU2SessionStateTerminated)
|
||||
m_LastSession->FlushData ();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,7 +262,8 @@ namespace transport
|
||||
for (auto& packet: packets)
|
||||
ProcessNextPacket (packet->buf, packet->len, packet->from);
|
||||
m_PacketsPool.ReleaseMt (packets);
|
||||
if (m_LastSession) m_LastSession->FlushData ();
|
||||
if (m_LastSession && m_LastSession->GetState () != eSSU2SessionStateTerminated)
|
||||
m_LastSession->FlushData ();
|
||||
}
|
||||
|
||||
void SSU2Server::AddSession (std::shared_ptr<SSU2Session> session)
|
||||
@@ -239,6 +283,8 @@ namespace transport
|
||||
auto ident = it->second->GetRemoteIdentity ();
|
||||
if (ident)
|
||||
m_SessionsByRouterHash.erase (ident->GetIdentHash ());
|
||||
if (m_LastSession == it->second)
|
||||
m_LastSession = nullptr;
|
||||
m_Sessions.erase (it);
|
||||
}
|
||||
}
|
||||
@@ -254,9 +300,9 @@ namespace transport
|
||||
if (!ret.second)
|
||||
{
|
||||
// session already exists
|
||||
LogPrint (eLogWarning, "SSU2: Session to ", ident->GetIdentHash ().ToBase64 (), " aready exists");
|
||||
LogPrint (eLogWarning, "SSU2: Session to ", ident->GetIdentHash ().ToBase64 (), " already exists");
|
||||
// terminate existing
|
||||
GetService ().post (std::bind (&SSU2Session::Terminate, ret.first->second));
|
||||
GetService ().post (std::bind (&SSU2Session::RequestTermination, ret.first->second, eSSU2TerminationReasonReplacedByNewSession));
|
||||
// update session
|
||||
ret.first->second = session;
|
||||
}
|
||||
@@ -366,7 +412,11 @@ namespace transport
|
||||
m_LastSession->ProcessData (buf, len);
|
||||
break;
|
||||
case eSSU2SessionStateSessionCreatedSent:
|
||||
m_LastSession->ProcessSessionConfirmed (buf, len);
|
||||
if (!m_LastSession->ProcessSessionConfirmed (buf, len))
|
||||
{
|
||||
m_LastSession->Done ();
|
||||
m_LastSession = nullptr;
|
||||
}
|
||||
break;
|
||||
case eSSU2SessionStateIntroduced:
|
||||
if (m_LastSession->GetRemoteEndpoint ().address ().is_unspecified ())
|
||||
@@ -377,7 +427,7 @@ namespace transport
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU2: HolePunch endpoint ", senderEndpoint,
|
||||
" doesn't match RelayResponse ", m_LastSession->GetRemoteEndpoint ());
|
||||
m_LastSession->Terminate ();
|
||||
m_LastSession->Done ();
|
||||
m_LastSession = nullptr;
|
||||
}
|
||||
break;
|
||||
@@ -385,6 +435,11 @@ namespace transport
|
||||
m_LastSession->SetRemoteEndpoint (senderEndpoint);
|
||||
m_LastSession->ProcessPeerTest (buf, len);
|
||||
break;
|
||||
case eSSU2SessionStateClosing:
|
||||
m_LastSession->ProcessData (buf, len); // we might receive termintaion block
|
||||
if (m_LastSession && m_LastSession->GetState () != eSSU2SessionStateTerminated)
|
||||
m_LastSession->RequestTermination (eSSU2TerminationReasonIdleTimeout); // send termination again
|
||||
break;
|
||||
case eSSU2SessionStateTerminated:
|
||||
m_LastSession = nullptr;
|
||||
break;
|
||||
@@ -459,10 +514,23 @@ namespace transport
|
||||
{
|
||||
if (router && address)
|
||||
{
|
||||
// check is no peding session
|
||||
// check if no session
|
||||
auto it = m_SessionsByRouterHash.find (router->GetIdentHash ());
|
||||
if (it != m_SessionsByRouterHash.end ())
|
||||
{
|
||||
// session with router found, trying to send peer test if requested
|
||||
if (peerTest && it->second->IsEstablished ())
|
||||
{
|
||||
auto session = it->second;
|
||||
GetService ().post ([session]() { session->SendPeerTest (); });
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// check is no pending session
|
||||
bool isValidEndpoint = !address->host.is_unspecified () && address->port;
|
||||
if (isValidEndpoint)
|
||||
{
|
||||
if (i2p::util::net::IsInReservedRange(address->host)) return false;
|
||||
auto s = FindPendingOutgoingSession (boost::asio::ip::udp::endpoint (address->host, address->port));
|
||||
if (s)
|
||||
{
|
||||
@@ -519,18 +587,27 @@ namespace transport
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
std::shared_ptr<i2p::data::RouterInfo> r;
|
||||
uint32_t relayTag = 0;
|
||||
for (auto& it: address->ssu->introducers)
|
||||
{
|
||||
if (it.iTag && ts < it.iExp)
|
||||
{
|
||||
r = i2p::data::netdb.FindRouter (it.iKey);
|
||||
if (r && r->IsReachableFrom (i2p::context.GetRouterInfo ()))
|
||||
{
|
||||
relayTag = it.iTag;
|
||||
if (relayTag) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!address->ssu->introducers.empty ())
|
||||
{
|
||||
std::vector<int> indicies;
|
||||
for (int i = 0; i < (int)address->ssu->introducers.size (); i++) indicies.push_back(i);
|
||||
if (indicies.size () > 1)
|
||||
std::shuffle (indicies.begin(), indicies.end(), std::mt19937(std::random_device()()));
|
||||
|
||||
for (auto i: indicies)
|
||||
{
|
||||
const auto& introducer = address->ssu->introducers[indicies[i]];
|
||||
if (introducer.iTag && ts < introducer.iExp)
|
||||
{
|
||||
r = i2p::data::netdb.FindRouter (introducer.iKey);
|
||||
if (r && r->IsReachableFrom (i2p::context.GetRouterInfo ()))
|
||||
{
|
||||
relayTag = introducer.iTag;
|
||||
if (relayTag) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (r)
|
||||
{
|
||||
if (relayTag)
|
||||
@@ -539,7 +616,8 @@ namespace transport
|
||||
auto addr = address->IsV6 () ? r->GetSSU2V6Address () : r->GetSSU2V4Address ();
|
||||
if (addr)
|
||||
{
|
||||
bool isValidEndpoint = !addr->host.is_unspecified () && addr->port;
|
||||
bool isValidEndpoint = !addr->host.is_unspecified () && addr->port &&
|
||||
!i2p::util::net::IsInReservedRange(addr->host);
|
||||
if (isValidEndpoint)
|
||||
{
|
||||
auto s = FindPendingOutgoingSession (boost::asio::ip::udp::endpoint (addr->host, addr->port));
|
||||
@@ -588,8 +666,9 @@ namespace transport
|
||||
else
|
||||
s->SetOnEstablished ([s]() { s->SendPeerTest (); });
|
||||
return true;
|
||||
}
|
||||
CreateSession (router, addr, true);
|
||||
}
|
||||
else
|
||||
CreateSession (router, addr, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -616,24 +695,38 @@ namespace transport
|
||||
it++;
|
||||
}
|
||||
|
||||
for (auto it = m_Sessions.begin (); it != m_Sessions.end ();)
|
||||
for (auto it: m_Sessions)
|
||||
{
|
||||
if (it->second->GetState () == eSSU2SessionStateTerminated ||
|
||||
it->second->IsTerminationTimeoutExpired (ts))
|
||||
auto state = it.second->GetState ();
|
||||
if (state == eSSU2SessionStateTerminated || state == eSSU2SessionStateClosing)
|
||||
it.second->Done ();
|
||||
else if (it.second->IsTerminationTimeoutExpired (ts))
|
||||
{
|
||||
if (it->second->IsEstablished ())
|
||||
it->second->TerminateByTimeout ();
|
||||
if (it->second == m_LastSession)
|
||||
m_LastSession = nullptr;
|
||||
it = m_Sessions.erase (it);
|
||||
if (it.second->IsEstablished ())
|
||||
it.second->RequestTermination (eSSU2TerminationReasonIdleTimeout);
|
||||
else
|
||||
it.second->Done ();
|
||||
}
|
||||
else
|
||||
{
|
||||
it->second->CleanUp (ts);
|
||||
it++;
|
||||
}
|
||||
it.second->CleanUp (ts);
|
||||
}
|
||||
|
||||
for (auto it = m_SessionsByRouterHash.begin (); it != m_SessionsByRouterHash.begin ();)
|
||||
{
|
||||
if (it->second && it->second->GetState () == eSSU2SessionStateTerminated)
|
||||
it = m_SessionsByRouterHash.erase (it);
|
||||
else
|
||||
it++;
|
||||
}
|
||||
|
||||
for (auto it = m_Relays.begin (); it != m_Relays.begin ();)
|
||||
{
|
||||
if (it->second && it->second->GetState () == eSSU2SessionStateTerminated)
|
||||
it = m_Relays.erase (it);
|
||||
else
|
||||
it++;
|
||||
}
|
||||
|
||||
for (auto it = m_IncomingTokens.begin (); it != m_IncomingTokens.end (); )
|
||||
{
|
||||
if (ts > it->second.second)
|
||||
@@ -649,14 +742,16 @@ namespace transport
|
||||
else
|
||||
it++;
|
||||
}
|
||||
|
||||
|
||||
m_PacketsPool.CleanUpMt ();
|
||||
m_SentPacketsPool.CleanUp ();
|
||||
ScheduleTermination ();
|
||||
}
|
||||
}
|
||||
|
||||
void SSU2Server::ScheduleResend ()
|
||||
{
|
||||
m_ResendTimer.expires_from_now (boost::posix_time::seconds(SSU2_RESEND_INTERVAL));
|
||||
m_ResendTimer.expires_from_now (boost::posix_time::milliseconds(SSU2_RESEND_CHECK_TIMEOUT));
|
||||
m_ResendTimer.async_wait (std::bind (&SSU2Server::HandleResendTimer,
|
||||
this, std::placeholders::_1));
|
||||
}
|
||||
@@ -665,7 +760,7 @@ namespace transport
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
for (auto it: m_Sessions)
|
||||
it.second->Resend (ts);
|
||||
for (auto it: m_PendingOutgoingSessions)
|
||||
@@ -711,5 +806,226 @@ namespace transport
|
||||
m_IncomingTokens.emplace (ep, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::list<std::shared_ptr<SSU2Session> > SSU2Server::FindIntroducers (int maxNumIntroducers,
|
||||
bool v4, const std::set<i2p::data::IdentHash>& excluded) const
|
||||
{
|
||||
std::list<std::shared_ptr<SSU2Session> > ret;
|
||||
for (const auto& s : m_Sessions)
|
||||
{
|
||||
if (s.second->IsEstablished () && (s.second->GetRelayTag () && s.second->IsOutgoing ()) &&
|
||||
!excluded.count (s.second->GetRemoteIdentity ()->GetIdentHash ()) &&
|
||||
((v4 && (s.second->GetRemoteTransports () & i2p::data::RouterInfo::eSSU2V4)) ||
|
||||
(!v4 && (s.second->GetRemoteTransports () & i2p::data::RouterInfo::eSSU2V6))))
|
||||
ret.push_back (s.second);
|
||||
}
|
||||
if ((int)ret.size () > maxNumIntroducers)
|
||||
{
|
||||
// shink ret randomly
|
||||
int sz = ret.size () - maxNumIntroducers;
|
||||
for (int i = 0; i < sz; i++)
|
||||
{
|
||||
auto ind = rand () % ret.size ();
|
||||
auto it = ret.begin ();
|
||||
std::advance (it, ind);
|
||||
ret.erase (it);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SSU2Server::UpdateIntroducers (bool v4)
|
||||
{
|
||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
std::list<i2p::data::IdentHash> newList;
|
||||
auto& introducers = v4 ? m_Introducers : m_IntroducersV6;
|
||||
std::set<i2p::data::IdentHash> excluded;
|
||||
for (const auto& it : introducers)
|
||||
{
|
||||
std::shared_ptr<SSU2Session> session;
|
||||
auto it1 = m_SessionsByRouterHash.find (it);
|
||||
if (it1 != m_SessionsByRouterHash.end ())
|
||||
{
|
||||
session = it1->second;
|
||||
excluded.insert (it);
|
||||
}
|
||||
if (session && session->IsEstablished ())
|
||||
{
|
||||
if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION)
|
||||
session->SendKeepAlive ();
|
||||
if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION)
|
||||
newList.push_back (it);
|
||||
else
|
||||
session = nullptr;
|
||||
}
|
||||
if (!session)
|
||||
i2p::context.RemoveSSU2Introducer (it, v4);
|
||||
}
|
||||
if (newList.size () < SSU2_MAX_NUM_INTRODUCERS)
|
||||
{
|
||||
auto sessions = FindIntroducers (SSU2_MAX_NUM_INTRODUCERS - newList.size (), v4, excluded);
|
||||
if (sessions.empty () && !introducers.empty ())
|
||||
{
|
||||
// bump creation time for previous introducers if no new sessions found
|
||||
LogPrint (eLogDebug, "SSU2: No new introducers found. Trying to reuse existing");
|
||||
for (auto& it : introducers)
|
||||
{
|
||||
auto it1 = m_SessionsByRouterHash.find (it);
|
||||
if (it1 != m_SessionsByRouterHash.end ())
|
||||
{
|
||||
auto session = it1->second;
|
||||
if (session->IsEstablished ())
|
||||
{
|
||||
session->SetCreationTime (session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION);
|
||||
if (std::find (newList.begin (), newList.end (), it) == newList.end ())
|
||||
{
|
||||
newList.push_back (it);
|
||||
sessions.push_back (session);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& it : sessions)
|
||||
{
|
||||
i2p::data::RouterInfo::Introducer introducer;
|
||||
introducer.iTag = it->GetRelayTag ();
|
||||
introducer.iKey = it->GetRemoteIdentity ()->GetIdentHash ();
|
||||
introducer.iExp = it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION;
|
||||
excluded.insert (it->GetRemoteIdentity ()->GetIdentHash ());
|
||||
if (i2p::context.AddSSU2Introducer (introducer, v4))
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU2: Introducer added ", it->GetRelayTag (), " at ",
|
||||
i2p::data::GetIdentHashAbbreviation (it->GetRemoteIdentity ()->GetIdentHash ()));
|
||||
newList.push_back (it->GetRemoteIdentity ()->GetIdentHash ());
|
||||
if (newList.size () >= SSU2_MAX_NUM_INTRODUCERS) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
introducers = newList;
|
||||
|
||||
if (introducers.size () < SSU2_MAX_NUM_INTRODUCERS)
|
||||
{
|
||||
for (auto i = introducers.size (); i < SSU2_MAX_NUM_INTRODUCERS; i++)
|
||||
{
|
||||
auto introducer = i2p::data::netdb.GetRandomSSU2Introducer (v4, excluded);
|
||||
if (introducer)
|
||||
{
|
||||
auto address = v4 ? introducer->GetSSU2V4Address () : introducer->GetSSU2V6Address ();
|
||||
if (address)
|
||||
{
|
||||
CreateSession (introducer, address);
|
||||
excluded.insert (introducer->GetIdentHash ());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU2: Can't find more introducers");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSU2Server::ScheduleIntroducersUpdateTimer ()
|
||||
{
|
||||
if (m_IsPublished)
|
||||
{
|
||||
m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU2_KEEP_ALIVE_INTERVAL));
|
||||
m_IntroducersUpdateTimer.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
|
||||
this, std::placeholders::_1, true));
|
||||
}
|
||||
}
|
||||
|
||||
void SSU2Server::RescheduleIntroducersUpdateTimer ()
|
||||
{
|
||||
if (m_IsPublished)
|
||||
{
|
||||
m_IntroducersUpdateTimer.cancel ();
|
||||
i2p::context.ClearSSU2Introducers (true);
|
||||
m_Introducers.clear ();
|
||||
m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU2_KEEP_ALIVE_INTERVAL/2));
|
||||
m_IntroducersUpdateTimer.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
|
||||
this, std::placeholders::_1, true));
|
||||
}
|
||||
}
|
||||
|
||||
void SSU2Server::ScheduleIntroducersUpdateTimerV6 ()
|
||||
{
|
||||
if (m_IsPublished)
|
||||
{
|
||||
m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(SSU2_KEEP_ALIVE_INTERVAL));
|
||||
m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
|
||||
this, std::placeholders::_1, false));
|
||||
}
|
||||
}
|
||||
|
||||
void SSU2Server::RescheduleIntroducersUpdateTimerV6 ()
|
||||
{
|
||||
if (m_IsPublished)
|
||||
{
|
||||
m_IntroducersUpdateTimerV6.cancel ();
|
||||
i2p::context.ClearSSU2Introducers (false);
|
||||
m_IntroducersV6.clear ();
|
||||
m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(SSU2_KEEP_ALIVE_INTERVAL/2));
|
||||
m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
|
||||
this, std::placeholders::_1, false));
|
||||
}
|
||||
}
|
||||
|
||||
void SSU2Server::HandleIntroducersUpdateTimer (const boost::system::error_code& ecode, bool v4)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
// timeout expired
|
||||
if (v4)
|
||||
{
|
||||
if (i2p::context.GetStatus () == eRouterStatusTesting)
|
||||
{
|
||||
// we still don't know if we need introducers
|
||||
ScheduleIntroducersUpdateTimer ();
|
||||
return;
|
||||
}
|
||||
if (i2p::context.GetStatus () != eRouterStatusFirewalled)
|
||||
{
|
||||
// we don't need introducers
|
||||
i2p::context.ClearSSU2Introducers (true);
|
||||
m_Introducers.clear ();
|
||||
return;
|
||||
}
|
||||
// we are firewalled
|
||||
auto addr = i2p::context.GetRouterInfo ().GetSSU2V4Address ();
|
||||
if (addr && addr->ssu && addr->ssu->introducers.empty ())
|
||||
i2p::context.SetUnreachableSSU2 (true, false); // v4
|
||||
|
||||
UpdateIntroducers (true);
|
||||
ScheduleIntroducersUpdateTimer ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i2p::context.GetStatusV6 () == eRouterStatusTesting)
|
||||
{
|
||||
// we still don't know if we need introducers
|
||||
ScheduleIntroducersUpdateTimerV6 ();
|
||||
return;
|
||||
}
|
||||
if (i2p::context.GetStatusV6 () != eRouterStatusFirewalled)
|
||||
{
|
||||
// we don't need introducers
|
||||
i2p::context.ClearSSU2Introducers (false);
|
||||
m_IntroducersV6.clear ();
|
||||
return;
|
||||
}
|
||||
// we are firewalled
|
||||
auto addr = i2p::context.GetRouterInfo ().GetSSU2V6Address ();
|
||||
if (addr && addr->ssu && addr->ssu->introducers.empty ())
|
||||
i2p::context.SetUnreachableSSU2 (false, true); // v6
|
||||
|
||||
UpdateIntroducers (false);
|
||||
ScheduleIntroducersUpdateTimerV6 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -17,15 +17,20 @@ namespace i2p
|
||||
{
|
||||
namespace transport
|
||||
{
|
||||
const int SSU2_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds
|
||||
const int SSU2_TERMINATION_CHECK_TIMEOUT = 30; // in seconds
|
||||
const int SSU2_RESEND_CHECK_TIMEOUT = 500; // in milliseconds
|
||||
const size_t SSU2_SOCKET_RECEIVE_BUFFER_SIZE = 0x1FFFF; // 128K
|
||||
const size_t SSU2_SOCKET_SEND_BUFFER_SIZE = 0x1FFFF; // 128K
|
||||
const size_t SSU2_MAX_NUM_INTRODUCERS = 3;
|
||||
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 = 30; // 30 seconds
|
||||
|
||||
class SSU2Server: private i2p::util::RunnableServiceWithWork
|
||||
{
|
||||
struct Packet
|
||||
{
|
||||
uint8_t buf[SSU2_MTU];
|
||||
uint8_t buf[SSU2_MAX_PACKET_SIZE];
|
||||
size_t len;
|
||||
boost::asio::ip::udp::endpoint from;
|
||||
};
|
||||
@@ -50,6 +55,8 @@ namespace transport
|
||||
boost::asio::io_service& GetService () { return GetIOService (); };
|
||||
void SetLocalAddress (const boost::asio::ip::address& localAddress);
|
||||
bool IsSupported (const boost::asio::ip::address& addr) const;
|
||||
uint16_t GetPort (bool v4) const;
|
||||
bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; };
|
||||
|
||||
void AddSession (std::shared_ptr<SSU2Session> session);
|
||||
void RemoveSession (uint64_t connID);
|
||||
@@ -79,7 +86,11 @@ namespace transport
|
||||
uint64_t GetIncomingToken (const boost::asio::ip::udp::endpoint& ep);
|
||||
std::pair<uint64_t, uint32_t> NewIncomingToken (const boost::asio::ip::udp::endpoint& ep);
|
||||
|
||||
void RescheduleIntroducersUpdateTimer ();
|
||||
void RescheduleIntroducersUpdateTimerV6 ();
|
||||
|
||||
i2p::util::MemoryPool<SSU2SentPacket>& GetSentPacketsPool () { return m_SentPacketsPool; };
|
||||
|
||||
private:
|
||||
|
||||
boost::asio::ip::udp::socket& OpenSocket (const boost::asio::ip::udp::endpoint& localEndpoint);
|
||||
@@ -97,21 +108,32 @@ namespace transport
|
||||
void HandleResendTimer (const boost::system::error_code& ecode);
|
||||
|
||||
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;
|
||||
void UpdateIntroducers (bool v4);
|
||||
void ScheduleIntroducersUpdateTimer ();
|
||||
void HandleIntroducersUpdateTimer (const boost::system::error_code& ecode, bool v4);
|
||||
void ScheduleIntroducersUpdateTimerV6 ();
|
||||
|
||||
private:
|
||||
|
||||
ReceiveService m_ReceiveService;
|
||||
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::map<i2p::data::IdentHash, std::shared_ptr<SSU2Session> > m_SessionsByRouterHash;
|
||||
std::unordered_map<i2p::data::IdentHash, std::shared_ptr<SSU2Session> > m_SessionsByRouterHash;
|
||||
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSU2Session> > m_PendingOutgoingSessions;
|
||||
std::map<boost::asio::ip::udp::endpoint, std::pair<uint64_t, uint32_t> > m_IncomingTokens, m_OutgoingTokens; // remote endpoint -> (token, expires in seconds)
|
||||
std::map<uint32_t, std::shared_ptr<SSU2Session> > m_Relays; // we are introducer, relay tag -> session
|
||||
std::list<i2p::data::IdentHash> m_Introducers, m_IntroducersV6; // introducers we are connected to
|
||||
i2p::util::MemoryPoolMt<Packet> m_PacketsPool;
|
||||
boost::asio::deadline_timer m_TerminationTimer, m_ResendTimer;
|
||||
i2p::util::MemoryPool<SSU2SentPacket> m_SentPacketsPool;
|
||||
boost::asio::deadline_timer m_TerminationTimer, m_ResendTimer,
|
||||
m_IntroducersUpdateTimer, m_IntroducersUpdateTimerV6;
|
||||
std::shared_ptr<SSU2Session> m_LastSession;
|
||||
|
||||
bool m_IsPublished; // if we maintain introducers
|
||||
bool m_IsSyncClockFromPeers;
|
||||
|
||||
public:
|
||||
|
||||
// for HTTP/I2PControl
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,7 @@
|
||||
#include <boost/asio.hpp>
|
||||
#include "Crypto.h"
|
||||
#include "RouterInfo.h"
|
||||
#include "RouterContext.h"
|
||||
#include "TransportSession.h"
|
||||
|
||||
namespace i2p
|
||||
@@ -25,19 +26,27 @@ namespace transport
|
||||
{
|
||||
const int SSU2_CONNECT_TIMEOUT = 5; // 5 seconds
|
||||
const int SSU2_TERMINATION_TIMEOUT = 330; // 5.5 minutes
|
||||
const int SSU2_CLOCK_SKEW = 60; // in seconds
|
||||
const int SSU2_CLOCK_THRESHOLD = 15; // in seconds, if more we should adjust
|
||||
const int SSU2_TOKEN_EXPIRATION_TIMEOUT = 9; // for Retry message, in seconds
|
||||
const int SSU2_NEXT_TOKEN_EXPIRATION_TIMEOUT = 52*60; // for next token block, in seconds
|
||||
const int SSU2_TOKEN_EXPIRATION_THRESHOLD = 2; // in seconds
|
||||
const int SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT = 10; // in seconds
|
||||
const int SSU2_PEER_TEST_EXPIRATION_TIMEOUT = 60; // 60 seconds
|
||||
const size_t SSU2_MTU = 1440; // TODO: should be 1456 for ipv4
|
||||
const size_t SSU2_MAX_PAYLOAD_SIZE = SSU2_MTU - 32;
|
||||
const int SSU2_HANDSHAKE_RESEND_INTERVAL = 1; // in seconds
|
||||
const int SSU2_RESEND_INTERVAL = 3; // in seconds
|
||||
const size_t SSU2_MAX_PACKET_SIZE = 1500;
|
||||
const size_t SSU2_MIN_PACKET_SIZE = 1280;
|
||||
const int SSU2_HANDSHAKE_RESEND_INTERVAL = 1000; // in millseconds
|
||||
const int SSU2_RESEND_INTERVAL = 300; // in milliseconds
|
||||
const int SSU2_MAX_NUM_RESENDS = 5;
|
||||
const int SSU2_INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds
|
||||
const size_t SSU2_MAX_WINDOW_SIZE = 128; // in packets
|
||||
const size_t SSU2_MIN_WINDOW_SIZE = 16; // in packets
|
||||
const size_t SSU2_MAX_WINDOW_SIZE = 256; // in packets
|
||||
const size_t SSU2_MIN_RTO = 100; // in milliseconds
|
||||
const size_t SSU2_MAX_RTO = 2500; // in milliseconds
|
||||
const float SSU2_kAPPA = 1.8;
|
||||
const size_t SSU2_MAX_OUTGOING_QUEUE_SIZE = 500; // in messages
|
||||
const int SSU2_MAX_NUM_ACK_RANGES = 32; // to send
|
||||
const uint8_t SSU2_MAX_NUM_FRAGMENTS = 64;
|
||||
|
||||
enum SSU2MessageType
|
||||
{
|
||||
@@ -82,9 +91,12 @@ namespace transport
|
||||
eSSU2SessionStateUnknown,
|
||||
eSSU2SessionStateTokenReceived,
|
||||
eSSU2SessionStateSessionRequestSent,
|
||||
eSSU2SessionStateSessionRequestReceived,
|
||||
eSSU2SessionStateSessionCreatedSent,
|
||||
eSSU2SessionStateSessionCreatedReceived,
|
||||
eSSU2SessionStateSessionConfirmedSent,
|
||||
eSSU2SessionStateEstablished,
|
||||
eSSU2SessionStateClosing,
|
||||
eSSU2SessionStateTerminated,
|
||||
eSSU2SessionStateFailed,
|
||||
eSSU2SessionStateIntroduced,
|
||||
@@ -117,12 +129,39 @@ namespace transport
|
||||
eSSU2RelayResponseCodeCharlieSignatureFailure = 67,
|
||||
eSSU2RelayResponseCodeCharlieAliceIsUnknown = 70
|
||||
};
|
||||
|
||||
enum SSU2TerminationReason
|
||||
{
|
||||
eSSU2TerminationReasonNormalClose = 0,
|
||||
eSSU2TerminationReasonTerminationReceived = 1,
|
||||
eSSU2TerminationReasonIdleTimeout = 2,
|
||||
eSSU2TerminationReasonRouterShutdown = 3,
|
||||
eSSU2TerminationReasonDataPhaseAEADFailure= 4,
|
||||
eSSU2TerminationReasonIncompatibleOptions = 5,
|
||||
eSSU2TerminationReasonTncompatibleSignatureType = 6,
|
||||
eSSU2TerminationReasonClockSkew = 7,
|
||||
eSSU2TerminationPaddingViolation = 8,
|
||||
eSSU2TerminationReasonAEADFramingError = 9,
|
||||
eSSU2TerminationReasonPayloadFormatError = 10,
|
||||
eSSU2TerminationReasonSessionRequestError = 11,
|
||||
eSSU2TerminationReasonSessionCreatedError = 12,
|
||||
eSSU2TerminationReasonSessionConfirmedError = 13,
|
||||
eSSU2TerminationReasonTimeout = 14,
|
||||
eSSU2TerminationReasonRouterInfoSignatureVerificationFail = 15,
|
||||
eSSU2TerminationReasonInvalidS = 16,
|
||||
eSSU2TerminationReasonBanned = 17,
|
||||
eSSU2TerminationReasonBadToken = 18,
|
||||
eSSU2TerminationReasonConnectionLimits = 19,
|
||||
eSSU2TerminationReasonIncompatibleVersion = 20,
|
||||
eSSU2TerminationReasonWrongNetID = 21,
|
||||
eSSU2TerminationReasonReplacedByNewSession = 22
|
||||
};
|
||||
|
||||
struct SSU2IncompleteMessage
|
||||
{
|
||||
struct Fragment
|
||||
{
|
||||
uint8_t buf[SSU2_MTU];
|
||||
uint8_t buf[SSU2_MAX_PACKET_SIZE];
|
||||
size_t len;
|
||||
bool isLast;
|
||||
};
|
||||
@@ -131,8 +170,18 @@ namespace transport
|
||||
int nextFragmentNum;
|
||||
uint32_t lastFragmentInsertTime; // in seconds
|
||||
std::map<int, std::shared_ptr<Fragment> > outOfSequenceFragments;
|
||||
|
||||
void AttachNextFragment (const uint8_t * fragment, size_t fragmentSize);
|
||||
};
|
||||
|
||||
struct SSU2SentPacket
|
||||
{
|
||||
uint8_t payload[SSU2_MAX_PACKET_SIZE];
|
||||
size_t payloadSize = 0;
|
||||
uint64_t sendTime; // in milliseconds
|
||||
int numResends = 0;
|
||||
};
|
||||
|
||||
// RouterInfo flags
|
||||
const uint8_t SSU2_ROUTER_INFO_FLAG_REQUEST_FLOOD = 0x01;
|
||||
const uint8_t SSU2_ROUTER_INFO_FLAG_GZIP = 0x02;
|
||||
@@ -153,18 +202,14 @@ namespace transport
|
||||
} h;
|
||||
};
|
||||
|
||||
struct SentPacket
|
||||
{
|
||||
uint8_t payload[SSU2_MAX_PAYLOAD_SIZE];
|
||||
size_t payloadSize = 0;
|
||||
uint32_t nextResendTime; // in seconds
|
||||
int numResends = 0;
|
||||
};
|
||||
|
||||
struct HandshakePacket: public SentPacket
|
||||
struct HandshakePacket
|
||||
{
|
||||
Header header;
|
||||
uint8_t headerX[48]; // part1 for SessionConfirmed
|
||||
uint8_t payload[SSU2_MAX_PACKET_SIZE*2];
|
||||
size_t payloadSize = 0;
|
||||
uint64_t sendTime = 0; // in milliseconds
|
||||
bool isSecondFragment = false; // for SessionConfirmed
|
||||
};
|
||||
|
||||
typedef std::function<void ()> OnEstablished;
|
||||
@@ -186,8 +231,8 @@ namespace transport
|
||||
bool Introduce (std::shared_ptr<SSU2Session> session, uint32_t relayTag);
|
||||
void WaitForIntroduction ();
|
||||
void SendPeerTest (); // Alice, Data message
|
||||
void Terminate ();
|
||||
void TerminateByTimeout ();
|
||||
void SendKeepAlive ();
|
||||
void RequestTermination (SSU2TerminationReason reason);
|
||||
void CleanUp (uint64_t ts);
|
||||
void FlushData ();
|
||||
void Done () override;
|
||||
@@ -210,13 +255,16 @@ namespace transport
|
||||
|
||||
private:
|
||||
|
||||
void Terminate ();
|
||||
void Established ();
|
||||
void ScheduleConnectTimer ();
|
||||
void HandleConnectTimer (const boost::system::error_code& ecode);
|
||||
void PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs);
|
||||
bool SendQueue ();
|
||||
void SendFragmentedMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
bool SendQueue (); // returns true if ack block was sent
|
||||
bool SendFragmentedMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
void ResendHandshakePacket ();
|
||||
void ConnectAfterIntroduction ();
|
||||
|
||||
void ProcessSessionRequest (Header& header, uint8_t * buf, size_t len);
|
||||
void ProcessTokenRequest (Header& header, uint8_t * buf, size_t len);
|
||||
|
||||
@@ -229,15 +277,21 @@ namespace transport
|
||||
uint32_t SendData (const uint8_t * buf, size_t len); // returns packet num
|
||||
void SendQuickAck ();
|
||||
void SendTermination ();
|
||||
void SendHolePunch (uint32_t nonce, const boost::asio::ip::udp::endpoint& ep, const uint8_t * introKey);
|
||||
void SendHolePunch (uint32_t nonce, const boost::asio::ip::udp::endpoint& ep, const uint8_t * introKey, uint64_t token);
|
||||
void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, const uint8_t * introKey); // PeerTest message
|
||||
void SendPathResponse (const uint8_t * data, size_t len);
|
||||
|
||||
void HandlePayload (const uint8_t * buf, size_t len);
|
||||
void HandleDateTime (const uint8_t * buf, size_t len);
|
||||
void HandleAck (const uint8_t * buf, size_t len);
|
||||
void HandleAckRange (uint32_t firstPacketNum, uint32_t lastPacketNum);
|
||||
void HandleAckRange (uint32_t firstPacketNum, uint32_t lastPacketNum, uint64_t ts);
|
||||
void HandleAddress (const uint8_t * buf, size_t len);
|
||||
bool ExtractEndpoint (const uint8_t * buf, size_t size, boost::asio::ip::udp::endpoint& ep);
|
||||
size_t CreateEndpoint (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep);
|
||||
std::shared_ptr<const i2p::data::RouterInfo::Address> FindLocalAddress () const;
|
||||
void AdjustMaxPayloadSize ();
|
||||
RouterStatus GetRouterStatus () const;
|
||||
void SetRouterStatus (RouterStatus status) const;
|
||||
std::shared_ptr<const i2p::data::RouterInfo> ExtractRouterInfo (const uint8_t * buf, size_t size);
|
||||
void CreateNonce (uint64_t seqn, uint8_t * nonce);
|
||||
bool UpdateReceivePacketNum (uint32_t packetNum); // for Ack, returns false if duplicate
|
||||
@@ -257,17 +311,18 @@ namespace transport
|
||||
size_t CreateFirstFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage> msg);
|
||||
size_t CreateFollowOnFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage> msg, uint8_t& fragmentNum, uint32_t msgID);
|
||||
size_t CreateRelayIntroBlock (uint8_t * buf, size_t len, const uint8_t * introData, size_t introDataLen);
|
||||
size_t CreateRelayResponseBlock (uint8_t * buf, size_t len, SSU2RelayResponseCode code, uint32_t nonce, bool endpoint); // add endpoint for Chralie and no endpoint for Bob
|
||||
size_t CreateRelayResponseBlock (uint8_t * buf, size_t len, SSU2RelayResponseCode code, uint32_t nonce, uint64_t token, bool v4);
|
||||
size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint8_t msg, SSU2PeerTestCode code, const uint8_t * routerHash, const uint8_t * signedData, size_t signedDataLen);
|
||||
size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint32_t nonce); // Alice
|
||||
size_t CreateTerminationBlock (uint8_t * buf, size_t len);
|
||||
|
||||
private:
|
||||
|
||||
SSU2Server& m_Server;
|
||||
std::shared_ptr<i2p::crypto::X25519Keys> m_EphemeralKeys;
|
||||
std::unique_ptr<i2p::crypto::NoiseSymmetricState> m_NoiseState;
|
||||
std::unique_ptr<HandshakePacket> m_SessionConfirmedFragment1; // for Bob if applicable
|
||||
std::unique_ptr<HandshakePacket> m_SentHandshakePacket; // SessionRequest or SessionCreated
|
||||
std::unique_ptr<HandshakePacket> m_SessionConfirmedFragment; // for Bob if applicable or second fragment for Alice
|
||||
std::unique_ptr<HandshakePacket> m_SentHandshakePacket; // SessionRequest, SessionCreated or SessionConfirmed
|
||||
std::shared_ptr<const i2p::data::RouterInfo::Address> m_Address;
|
||||
boost::asio::ip::udp::endpoint m_RemoteEndpoint;
|
||||
i2p::data::RouterInfo::CompatibleTransports m_RemoteTransports; // for peer tests
|
||||
@@ -276,17 +331,19 @@ namespace transport
|
||||
uint8_t m_KeyDataSend[64], m_KeyDataReceive[64];
|
||||
uint32_t m_SendPacketNum, m_ReceivePacketNum;
|
||||
std::set<uint32_t> m_OutOfSequencePackets; // packet nums > receive packet num
|
||||
std::map<uint32_t, std::shared_ptr<SentPacket> > m_SentPackets; // packetNum -> packet
|
||||
std::map<uint32_t, std::shared_ptr<SSU2SentPacket> > m_SentPackets; // packetNum -> packet
|
||||
std::map<uint32_t, std::shared_ptr<SSU2IncompleteMessage> > m_IncompleteMessages; // I2NP
|
||||
std::map<uint32_t, std::pair <std::shared_ptr<SSU2Session>, uint64_t > > m_RelaySessions; // nonce->(Alice, timestamp) for Bob or nonce->(Charlie, timestamp) for Alice
|
||||
std::map<uint32_t, std::pair <std::shared_ptr<SSU2Session>, uint64_t > > m_PeerTests; // same as for relay sessions
|
||||
std::list<std::shared_ptr<I2NPMessage> > m_SendQueue;
|
||||
i2p::I2NPMessagesHandler m_Handler;
|
||||
bool m_IsDataReceived;
|
||||
size_t m_WindowSize;
|
||||
size_t m_WindowSize, m_RTT, m_RTO;
|
||||
uint32_t m_RelayTag; // between Bob and Charlie
|
||||
OnEstablished m_OnEstablished; // callback from Established
|
||||
boost::asio::deadline_timer m_ConnectTimer;
|
||||
SSU2TerminationReason m_TerminationReason;
|
||||
size_t m_MaxPayloadSize;
|
||||
};
|
||||
|
||||
inline uint64_t CreateHeaderMask (const uint8_t * kh, const uint8_t * nonce)
|
||||
|
@@ -19,17 +19,14 @@
|
||||
#include "I2NPProtocol.h"
|
||||
#include "Identity.h"
|
||||
#include "RouterInfo.h"
|
||||
#include "TransportSession.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace transport
|
||||
{
|
||||
|
||||
const size_t SSU_MTU_V4 = 1484;
|
||||
const size_t SSU_MTU_V6 = 1488;
|
||||
const size_t IPV4_HEADER_SIZE = 20;
|
||||
const size_t IPV6_HEADER_SIZE = 40;
|
||||
const size_t UDP_HEADER_SIZE = 8;
|
||||
const size_t SSU_V4_MAX_PACKET_SIZE = SSU_MTU_V4 - IPV4_HEADER_SIZE - UDP_HEADER_SIZE; // 1456
|
||||
const size_t SSU_V6_MAX_PACKET_SIZE = SSU_MTU_V6 - IPV6_HEADER_SIZE - UDP_HEADER_SIZE; // 1440
|
||||
const int RESEND_INTERVAL = 3; // in seconds
|
||||
|
@@ -41,7 +41,6 @@ namespace transport
|
||||
i2p::context.GetRouterInfo ().GetSSUAddress (true);
|
||||
if (address) m_IntroKey = address->i;
|
||||
}
|
||||
m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
}
|
||||
|
||||
SSUSession::~SSUSession ()
|
||||
|
@@ -103,8 +103,6 @@ namespace transport
|
||||
void SendKeepAlive ();
|
||||
uint32_t GetRelayTag () const { return m_RelayTag; };
|
||||
const i2p::data::RouterInfo::IntroKey& GetIntroKey () const { return m_IntroKey; };
|
||||
uint32_t GetCreationTime () const { return m_CreationTime; };
|
||||
void SetCreationTime (uint32_t ts) { m_CreationTime = ts; }; // for introducers
|
||||
|
||||
void FlushData ();
|
||||
void CleanUp (uint64_t ts);
|
||||
@@ -167,7 +165,6 @@ namespace transport
|
||||
i2p::crypto::AESKey m_SessionKey;
|
||||
i2p::crypto::MACKey m_MacKey;
|
||||
i2p::data::RouterInfo::IntroKey m_IntroKey;
|
||||
uint32_t m_CreationTime; // seconds since epoch
|
||||
SSUData m_Data;
|
||||
bool m_IsDataReceived;
|
||||
std::unique_ptr<SignedData> m_SignedData; // we need it for SessionConfirmed only
|
||||
|
@@ -24,6 +24,10 @@ namespace i2p
|
||||
{
|
||||
namespace transport
|
||||
{
|
||||
const size_t IPV4_HEADER_SIZE = 20;
|
||||
const size_t IPV6_HEADER_SIZE = 40;
|
||||
const size_t UDP_HEADER_SIZE = 8;
|
||||
|
||||
class SignedData
|
||||
{
|
||||
public:
|
||||
@@ -64,7 +68,7 @@ namespace transport
|
||||
|
||||
std::stringstream m_Stream;
|
||||
};
|
||||
|
||||
|
||||
class TransportSession
|
||||
{
|
||||
public:
|
||||
@@ -75,6 +79,7 @@ namespace transport
|
||||
{
|
||||
if (router)
|
||||
m_RemoteIdentity = router->GetRouterIdentity ();
|
||||
m_CreationTime = m_LastActivityTimestamp;
|
||||
}
|
||||
|
||||
virtual ~TransportSession () {};
|
||||
@@ -102,6 +107,9 @@ namespace transport
|
||||
bool IsTerminationTimeoutExpired (uint64_t ts) const
|
||||
{ return ts >= m_LastActivityTimestamp + GetTerminationTimeout (); };
|
||||
|
||||
uint32_t GetCreationTime () const { return m_CreationTime; };
|
||||
void SetCreationTime (uint32_t ts) { m_CreationTime = ts; }; // for introducers
|
||||
|
||||
virtual uint32_t GetRelayTag () const { return 0; };
|
||||
virtual void SendLocalRouterInfo (bool update = false) { SendI2NPMessages ({ CreateDatabaseStoreMsg () }); };
|
||||
virtual void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) = 0;
|
||||
@@ -114,6 +122,7 @@ namespace transport
|
||||
bool m_IsOutgoing;
|
||||
int m_TerminationTimeout;
|
||||
uint64_t m_LastActivityTimestamp;
|
||||
uint32_t m_CreationTime; // seconds since epoch
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@@ -285,8 +285,8 @@ namespace transport
|
||||
delete m_SSUServer;
|
||||
m_SSUServer = nullptr;
|
||||
}
|
||||
if (m_SSUServer) DetectExternalIP ();
|
||||
}
|
||||
if (m_SSUServer || m_SSU2Server) DetectExternalIP ();
|
||||
|
||||
m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT));
|
||||
m_PeerCleanupTimer->async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1));
|
||||
@@ -453,7 +453,7 @@ namespace transport
|
||||
peer.router = netdb.FindRouter (ident); // try to get new one from netdb
|
||||
if (peer.router) // we have RI already
|
||||
{
|
||||
if (peer.numAttempts < 2) // NTCP2, 0 - ipv6, 1- ipv4
|
||||
if (peer.numAttempts < 2) // NTCP2, 0 - ipv6, 1 - ipv4
|
||||
{
|
||||
if (m_NTCP2Server) // we support NTCP2
|
||||
{
|
||||
@@ -491,60 +491,12 @@ namespace transport
|
||||
else
|
||||
peer.numAttempts = 2; // switch to SSU
|
||||
}
|
||||
if (peer.numAttempts == 2 || peer.numAttempts == 3) // SSU
|
||||
{
|
||||
if (m_SSUServer)
|
||||
{
|
||||
std::shared_ptr<const RouterInfo::Address> address;
|
||||
if (peer.numAttempts == 2) // SSU ipv6
|
||||
{
|
||||
if (context.GetRouterInfo ().IsSSUV6 () && peer.router->IsReachableBy (RouterInfo::eSSUV6))
|
||||
{
|
||||
address = peer.router->GetSSUV6Address ();
|
||||
if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host))
|
||||
address = nullptr;
|
||||
}
|
||||
peer.numAttempts++;
|
||||
}
|
||||
if (!address && peer.numAttempts == 3) // SSU ipv4
|
||||
{
|
||||
if (context.GetRouterInfo ().IsSSU (true) && peer.router->IsReachableBy (RouterInfo::eSSUV4))
|
||||
{
|
||||
address = peer.router->GetSSUAddress (true);
|
||||
if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host))
|
||||
address = nullptr;
|
||||
}
|
||||
peer.numAttempts++;
|
||||
}
|
||||
if (address && address->IsReachableSSU ())
|
||||
{
|
||||
if (m_SSUServer->CreateSession (peer.router, address))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
peer.numAttempts += 2; // switch to Mesh
|
||||
}
|
||||
if (peer.numAttempts == 4) // Mesh
|
||||
{
|
||||
peer.numAttempts++;
|
||||
if (m_NTCP2Server && context.GetRouterInfo ().IsMesh () && peer.router->IsMesh ())
|
||||
{
|
||||
auto address = peer.router->GetYggdrasilAddress ();
|
||||
if (address)
|
||||
{
|
||||
auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router, address);
|
||||
m_NTCP2Server->Connect (s);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (peer.numAttempts == 5 || peer.numAttempts == 6) // SSU2
|
||||
if (peer.numAttempts == 2 || peer.numAttempts == 3) // SSU2, 2 - ipv6, 3 - ipv4
|
||||
{
|
||||
if (m_SSU2Server)
|
||||
{
|
||||
std::shared_ptr<const RouterInfo::Address> address;
|
||||
if (peer.numAttempts == 5) // SSU2 ipv6
|
||||
if (peer.numAttempts == 2) // SSU2 ipv6
|
||||
{
|
||||
if (context.GetRouterInfo ().IsSSU2V6 () && peer.router->IsReachableBy (RouterInfo::eSSU2V6))
|
||||
{
|
||||
@@ -554,7 +506,7 @@ namespace transport
|
||||
}
|
||||
peer.numAttempts++;
|
||||
}
|
||||
if (!address && peer.numAttempts == 6) // SSU2 ipv4
|
||||
if (!address && peer.numAttempts == 3) // SSU2 ipv4
|
||||
{
|
||||
if (context.GetRouterInfo ().IsSSU2V4 () && peer.router->IsReachableBy (RouterInfo::eSSU2V4))
|
||||
{
|
||||
@@ -571,7 +523,55 @@ namespace transport
|
||||
}
|
||||
}
|
||||
else
|
||||
peer.numAttempts += 2;
|
||||
peer.numAttempts += 2; // switch to mesh
|
||||
}
|
||||
if (peer.numAttempts == 4) // Mesh
|
||||
{
|
||||
peer.numAttempts++;
|
||||
if (m_NTCP2Server && context.GetRouterInfo ().IsMesh () && peer.router->IsMesh ())
|
||||
{
|
||||
auto address = peer.router->GetYggdrasilAddress ();
|
||||
if (address)
|
||||
{
|
||||
auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router, address);
|
||||
m_NTCP2Server->Connect (s);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (peer.numAttempts == 5 || peer.numAttempts == 6) // SSU, 5 - ipv6, 6 - ipv4
|
||||
{
|
||||
if (m_SSUServer)
|
||||
{
|
||||
std::shared_ptr<const RouterInfo::Address> address;
|
||||
if (peer.numAttempts == 5) // SSU ipv6
|
||||
{
|
||||
if (context.GetRouterInfo ().IsSSUV6 () && peer.router->IsReachableBy (RouterInfo::eSSUV6))
|
||||
{
|
||||
address = peer.router->GetSSUV6Address ();
|
||||
if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host))
|
||||
address = nullptr;
|
||||
}
|
||||
peer.numAttempts++;
|
||||
}
|
||||
if (!address && peer.numAttempts == 6) // SSU ipv4
|
||||
{
|
||||
if (context.GetRouterInfo ().IsSSU (true) && peer.router->IsReachableBy (RouterInfo::eSSUV4))
|
||||
{
|
||||
address = peer.router->GetSSUAddress (true);
|
||||
if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host))
|
||||
address = nullptr;
|
||||
}
|
||||
peer.numAttempts++;
|
||||
}
|
||||
if (address && address->IsReachableSSU ())
|
||||
{
|
||||
if (m_SSUServer->CreateSession (peer.router, address))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
peer.numAttempts += 2;
|
||||
}
|
||||
LogPrint (eLogInfo, "Transports: No compatble NTCP2 or SSU addresses available");
|
||||
i2p::data::netdb.SetUnreachable (ident, true); // we are here because all connection attempts failed
|
||||
@@ -622,88 +622,109 @@ namespace transport
|
||||
i2p::context.SetStatus (eRouterStatusOK);
|
||||
return;
|
||||
}
|
||||
if (m_SSUServer)
|
||||
if (m_SSUServer || m_SSU2Server)
|
||||
PeerTest ();
|
||||
else
|
||||
LogPrint (eLogError, "Transports: Can't detect external IP. SSU is not available");
|
||||
LogPrint (eLogWarning, "Transports: Can't detect external IP. SSU or SSU2 is not available");
|
||||
}
|
||||
|
||||
void Transports::PeerTest (bool ipv4, bool ipv6)
|
||||
{
|
||||
if (RoutesRestricted() || !m_SSUServer) return;
|
||||
if (RoutesRestricted() || (!m_SSUServer && !m_SSU2Server)) return;
|
||||
if (ipv4 && i2p::context.SupportsV4 ())
|
||||
{
|
||||
LogPrint (eLogInfo, "Transports: Started peer test IPv4");
|
||||
std::set<i2p::data::IdentHash> excluded;
|
||||
excluded.insert (i2p::context.GetIdentHash ()); // don't pick own router
|
||||
bool statusChanged = false;
|
||||
for (int i = 0; i < 5; i++)
|
||||
if (m_SSUServer)
|
||||
{
|
||||
auto router = i2p::data::netdb.GetRandomPeerTestRouter (true, excluded); // v4
|
||||
if (router)
|
||||
bool statusChanged = false;
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
auto addr = router->GetSSUAddress (true); // ipv4
|
||||
if (addr && !i2p::util::net::IsInReservedRange(addr->host))
|
||||
auto router = i2p::data::netdb.GetRandomPeerTestRouter (true, excluded); // v4
|
||||
if (router)
|
||||
{
|
||||
if (!statusChanged)
|
||||
auto addr = router->GetSSUAddress (true); // ipv4
|
||||
if (addr && !i2p::util::net::IsInReservedRange(addr->host))
|
||||
{
|
||||
statusChanged = true;
|
||||
i2p::context.SetStatus (eRouterStatusTesting); // first time only
|
||||
if (!statusChanged)
|
||||
{
|
||||
statusChanged = true;
|
||||
i2p::context.SetStatus (eRouterStatusTesting); // first time only
|
||||
}
|
||||
m_SSUServer->CreateSession (router, addr, true); // peer test v4
|
||||
}
|
||||
m_SSUServer->CreateSession (router, addr, true); // peer test v4
|
||||
excluded.insert (router->GetIdentHash ());
|
||||
}
|
||||
excluded.insert (router->GetIdentHash ());
|
||||
}
|
||||
if (!statusChanged)
|
||||
LogPrint (eLogWarning, "Transports: Can't find routers for peer test IPv4");
|
||||
}
|
||||
if (!statusChanged)
|
||||
LogPrint (eLogWarning, "Transports: Can't find routers for peer test IPv4");
|
||||
|
||||
// SSU2
|
||||
if (m_SSU2Server)
|
||||
{
|
||||
excluded.clear ();
|
||||
excluded.insert (i2p::context.GetIdentHash ());
|
||||
auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (true, excluded); // v4
|
||||
if (router)
|
||||
m_SSU2Server->StartPeerTest (router, true);
|
||||
}
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (true, excluded); // v4
|
||||
if (router)
|
||||
{
|
||||
if (i2p::context.GetStatus () != eRouterStatusTesting)
|
||||
i2p::context.SetStatusSSU2 (eRouterStatusTesting);
|
||||
m_SSU2Server->StartPeerTest (router, true);
|
||||
excluded.insert (router->GetIdentHash ());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ipv6 && i2p::context.SupportsV6 ())
|
||||
{
|
||||
LogPrint (eLogInfo, "Transports: Started peer test IPv6");
|
||||
std::set<i2p::data::IdentHash> excluded;
|
||||
excluded.insert (i2p::context.GetIdentHash ()); // don't pick own router
|
||||
bool statusChanged = false;
|
||||
for (int i = 0; i < 5; i++)
|
||||
if (m_SSUServer)
|
||||
{
|
||||
auto router = i2p::data::netdb.GetRandomPeerTestRouter (false, excluded); // v6
|
||||
if (router)
|
||||
bool statusChanged = false;
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
auto addr = router->GetSSUV6Address ();
|
||||
if (addr && !i2p::util::net::IsInReservedRange(addr->host))
|
||||
auto router = i2p::data::netdb.GetRandomPeerTestRouter (false, excluded); // v6
|
||||
if (router)
|
||||
{
|
||||
if (!statusChanged)
|
||||
auto addr = router->GetSSUV6Address ();
|
||||
if (addr && !i2p::util::net::IsInReservedRange(addr->host))
|
||||
{
|
||||
statusChanged = true;
|
||||
i2p::context.SetStatusV6 (eRouterStatusTesting); // first time only
|
||||
if (!statusChanged)
|
||||
{
|
||||
statusChanged = true;
|
||||
i2p::context.SetStatusV6 (eRouterStatusTesting); // first time only
|
||||
}
|
||||
m_SSUServer->CreateSession (router, addr, true); // peer test v6
|
||||
}
|
||||
m_SSUServer->CreateSession (router, addr, true); // peer test v6
|
||||
excluded.insert (router->GetIdentHash ());
|
||||
}
|
||||
excluded.insert (router->GetIdentHash ());
|
||||
}
|
||||
if (!statusChanged)
|
||||
LogPrint (eLogWarning, "Transports: Can't find routers for peer test IPv6");
|
||||
}
|
||||
if (!statusChanged)
|
||||
LogPrint (eLogWarning, "Transports: Can't find routers for peer test IPv6");
|
||||
|
||||
// SSU2
|
||||
if (m_SSU2Server)
|
||||
{
|
||||
excluded.clear ();
|
||||
excluded.insert (i2p::context.GetIdentHash ());
|
||||
auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (false, excluded); // v6
|
||||
if (router)
|
||||
m_SSU2Server->StartPeerTest (router, false);
|
||||
}
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (false, excluded); // v6
|
||||
if (router)
|
||||
{
|
||||
if (i2p::context.GetStatusV6 () != eRouterStatusTesting)
|
||||
i2p::context.SetStatusV6SSU2 (eRouterStatusTesting);
|
||||
m_SSU2Server->StartPeerTest (router, false);
|
||||
excluded.insert (router->GetIdentHash ());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -826,9 +847,9 @@ namespace transport
|
||||
session->SendLocalRouterInfo (true);
|
||||
it->second.nextRouterInfoUpdateTime = ts + PEER_ROUTER_INFO_UPDATE_INTERVAL +
|
||||
rand () % PEER_ROUTER_INFO_UPDATE_INTERVAL_VARIANCE;
|
||||
}
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
UpdateBandwidth (); // TODO: use separate timer(s) for it
|
||||
bool ipv4Testing = i2p::context.GetStatus () == eRouterStatusTesting;
|
||||
|
@@ -93,6 +93,7 @@ namespace transport
|
||||
void Stop ();
|
||||
|
||||
bool IsBoundSSU() const { return m_SSUServer != nullptr; }
|
||||
bool IsBoundSSU2() const { return m_SSU2Server != nullptr; }
|
||||
bool IsBoundNTCP2() const { return m_NTCP2Server != nullptr; }
|
||||
|
||||
bool IsOnline() const { return m_IsOnline; };
|
||||
|
111
libi2pd/util.cpp
111
libi2pd/util.cpp
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "util.h"
|
||||
#include "Log.h"
|
||||
#include "I2PEndian.h"
|
||||
|
||||
#if not defined (__FreeBSD__)
|
||||
#include <pthread.h>
|
||||
@@ -35,7 +36,7 @@
|
||||
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
|
||||
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
|
||||
|
||||
// inet_pton exists Windows since Vista, but XP doesn't have that function!
|
||||
// inet_pton and inet_ntop have been in Windows since Vista, but XP doesn't have these functions!
|
||||
// This function was written by Petar Korponai?. See http://stackoverflow.com/questions/15660203/inet-pton-identifier-not-found
|
||||
int inet_pton_xp (int af, const char *src, void *dst)
|
||||
{
|
||||
@@ -61,6 +62,29 @@ int inet_pton_xp (int af, const char *src, void *dst)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *inet_ntop_xp(int af, const void *src, char *dst, socklen_t size)
|
||||
{
|
||||
struct sockaddr_storage ss;
|
||||
unsigned long s = size;
|
||||
|
||||
ZeroMemory(&ss, sizeof(ss));
|
||||
ss.ss_family = af;
|
||||
|
||||
switch(af) {
|
||||
case AF_INET:
|
||||
((struct sockaddr_in *)&ss)->sin_addr = *(struct in_addr *)src;
|
||||
break;
|
||||
case AF_INET6:
|
||||
((struct sockaddr_in6 *)&ss)->sin6_addr = *(struct in6_addr *)src;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
/* cannot direclty use &size because of strict aliasing rules */
|
||||
return (WSAAddressToString((struct sockaddr *)&ss, sizeof(ss), NULL, dst, &s) == 0)? dst : NULL;
|
||||
}
|
||||
|
||||
#else /* !_WIN32 => UNIX */
|
||||
#include <sys/types.h>
|
||||
#ifdef ANDROID
|
||||
@@ -133,27 +157,12 @@ namespace util
|
||||
namespace net
|
||||
{
|
||||
#ifdef _WIN32
|
||||
bool IsWindowsXPorLater ()
|
||||
{
|
||||
static bool isRequested = false;
|
||||
static bool isXP = false;
|
||||
if (!isRequested)
|
||||
{
|
||||
// request
|
||||
OSVERSIONINFO osvi;
|
||||
|
||||
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
|
||||
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
||||
GetVersionEx(&osvi);
|
||||
|
||||
isXP = osvi.dwMajorVersion <= 5;
|
||||
isRequested = true;
|
||||
}
|
||||
return isXP;
|
||||
}
|
||||
|
||||
int GetMTUWindowsIpv4 (sockaddr_in inputAddress, int fallback)
|
||||
{
|
||||
typedef const char *(* IPN)(int af, const void *src, char *dst, socklen_t size);
|
||||
IPN inetntop = (IPN)GetProcAddress (GetModuleHandle ("ws2_32.dll"), "InetNtop");
|
||||
if (!inetntop) inetntop = inet_ntop_xp; // use own implementation if not found
|
||||
|
||||
ULONG outBufLen = 0;
|
||||
PIP_ADAPTER_ADDRESSES pAddresses = nullptr;
|
||||
PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr;
|
||||
@@ -172,7 +181,7 @@ namespace net
|
||||
|
||||
if(dwRetVal != NO_ERROR)
|
||||
{
|
||||
LogPrint(eLogError, "NetIface: GetMTU(): Enclosed GetAdaptersAddresses() call has failed");
|
||||
LogPrint(eLogError, "NetIface: GetMTU: Enclosed GetAdaptersAddresses() call has failed");
|
||||
FREE(pAddresses);
|
||||
return fallback;
|
||||
}
|
||||
@@ -184,7 +193,7 @@ namespace net
|
||||
|
||||
pUnicast = pCurrAddresses->FirstUnicastAddress;
|
||||
if(pUnicast == nullptr)
|
||||
LogPrint(eLogError, "NetIface: GetMTU(): Not a unicast IPv4 address, this is not supported");
|
||||
LogPrint(eLogError, "NetIface: GetMTU: Not a unicast IPv4 address, this is not supported");
|
||||
|
||||
for(int i = 0; pUnicast != nullptr; ++i)
|
||||
{
|
||||
@@ -192,8 +201,13 @@ namespace net
|
||||
sockaddr_in* localInterfaceAddress = (sockaddr_in*) lpAddr;
|
||||
if(localInterfaceAddress->sin_addr.S_un.S_addr == inputAddress.sin_addr.S_un.S_addr)
|
||||
{
|
||||
auto result = pAddresses->Mtu;
|
||||
char addr[INET_ADDRSTRLEN];
|
||||
inetntop(AF_INET, &(((struct sockaddr_in *)localInterfaceAddress)->sin_addr), addr, INET_ADDRSTRLEN);
|
||||
|
||||
auto result = pCurrAddresses->Mtu;
|
||||
FREE(pAddresses);
|
||||
pAddresses = nullptr;
|
||||
LogPrint(eLogInfo, "NetIface: GetMTU: Using ", result, " bytes for IPv4 address ", addr);
|
||||
return result;
|
||||
}
|
||||
pUnicast = pUnicast->Next;
|
||||
@@ -201,19 +215,23 @@ namespace net
|
||||
pCurrAddresses = pCurrAddresses->Next;
|
||||
}
|
||||
|
||||
LogPrint(eLogError, "NetIface: GetMTU(): No usable unicast IPv4 addresses found");
|
||||
LogPrint(eLogError, "NetIface: GetMTU: No usable unicast IPv4 addresses found");
|
||||
FREE(pAddresses);
|
||||
return fallback;
|
||||
}
|
||||
|
||||
int GetMTUWindowsIpv6 (sockaddr_in6 inputAddress, int fallback)
|
||||
{
|
||||
typedef const char *(* IPN)(int af, const void *src, char *dst, socklen_t size);
|
||||
IPN inetntop = (IPN)GetProcAddress (GetModuleHandle ("ws2_32.dll"), "InetNtop");
|
||||
if (!inetntop) inetntop = inet_ntop_xp; // use own implementation if not found
|
||||
|
||||
ULONG outBufLen = 0;
|
||||
PIP_ADAPTER_ADDRESSES pAddresses = nullptr;
|
||||
PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr;
|
||||
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr;
|
||||
|
||||
if(GetAdaptersAddresses(AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen)
|
||||
if (GetAdaptersAddresses(AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen)
|
||||
== ERROR_BUFFER_OVERFLOW)
|
||||
{
|
||||
FREE(pAddresses);
|
||||
@@ -224,23 +242,23 @@ namespace net
|
||||
AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen
|
||||
);
|
||||
|
||||
if(dwRetVal != NO_ERROR)
|
||||
if (dwRetVal != NO_ERROR)
|
||||
{
|
||||
LogPrint(eLogError, "NetIface: GetMTU(): Enclosed GetAdaptersAddresses() call has failed");
|
||||
LogPrint(eLogError, "NetIface: GetMTU: Enclosed GetAdaptersAddresses() call has failed");
|
||||
FREE(pAddresses);
|
||||
return fallback;
|
||||
}
|
||||
|
||||
bool found_address = false;
|
||||
pCurrAddresses = pAddresses;
|
||||
while(pCurrAddresses)
|
||||
while (pCurrAddresses)
|
||||
{
|
||||
PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress;
|
||||
pUnicast = pCurrAddresses->FirstUnicastAddress;
|
||||
if(pUnicast == nullptr)
|
||||
LogPrint(eLogError, "NetIface: GetMTU(): Not a unicast IPv6 address, this is not supported");
|
||||
if (pUnicast == nullptr)
|
||||
LogPrint(eLogError, "NetIface: GetMTU: Not a unicast IPv6 address, this is not supported");
|
||||
|
||||
for(int i = 0; pUnicast != nullptr; ++i)
|
||||
for (int i = 0; pUnicast != nullptr; ++i)
|
||||
{
|
||||
LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr;
|
||||
sockaddr_in6 *localInterfaceAddress = (sockaddr_in6*) lpAddr;
|
||||
@@ -255,9 +273,13 @@ namespace net
|
||||
|
||||
if (found_address)
|
||||
{
|
||||
auto result = pAddresses->Mtu;
|
||||
char addr[INET6_ADDRSTRLEN];
|
||||
inetntop(AF_INET6, &(((struct sockaddr_in6 *)localInterfaceAddress)->sin6_addr), addr, INET6_ADDRSTRLEN);
|
||||
|
||||
auto result = pCurrAddresses->Mtu;
|
||||
FREE(pAddresses);
|
||||
pAddresses = nullptr;
|
||||
LogPrint(eLogInfo, "NetIface: GetMTU: Using ", result, " bytes for IPv6 address ", addr);
|
||||
return result;
|
||||
}
|
||||
pUnicast = pUnicast->Next;
|
||||
@@ -266,7 +288,7 @@ namespace net
|
||||
pCurrAddresses = pCurrAddresses->Next;
|
||||
}
|
||||
|
||||
LogPrint(eLogError, "NetIface: GetMTU(): No usable unicast IPv6 addresses found");
|
||||
LogPrint(eLogError, "NetIface: GetMTU: No usable unicast IPv6 addresses found");
|
||||
FREE(pAddresses);
|
||||
return fallback;
|
||||
}
|
||||
@@ -298,7 +320,7 @@ namespace net
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint(eLogError, "NetIface: GetMTU(): Address family is not supported");
|
||||
LogPrint(eLogError, "NetIface: GetMTU: Address family is not supported");
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
@@ -423,6 +445,27 @@ namespace net
|
||||
#endif
|
||||
}
|
||||
|
||||
int GetMaxMTU (const boost::asio::ip::address_v6& localAddress)
|
||||
{
|
||||
uint32_t prefix = bufbe32toh (localAddress.to_bytes ().data ());
|
||||
switch (prefix)
|
||||
{
|
||||
case 0x20010470:
|
||||
case 0x260070ff:
|
||||
// Hurricane Electric
|
||||
return 1480;
|
||||
break;
|
||||
case 0x2a06a003:
|
||||
case 0x2a06a004:
|
||||
case 0x2a06a005:
|
||||
// route48
|
||||
return 1420;
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
return 1500;
|
||||
}
|
||||
|
||||
static bool IsYggdrasilAddress (const uint8_t addr[16])
|
||||
{
|
||||
return addr[0] == 0x02 || addr[0] == 0x03;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -218,6 +218,7 @@ namespace util
|
||||
namespace net
|
||||
{
|
||||
int GetMTU (const boost::asio::ip::address& localAddress);
|
||||
int GetMaxMTU (const boost::asio::ip::address_v6& localAddress); // check tunnel broker for ipv6 address
|
||||
const boost::asio::ip::address GetInterfaceAddress (const std::string & ifname, bool ipv6=false);
|
||||
boost::asio::ip::address_v6 GetYggdrasilAddress ();
|
||||
bool IsLocalAddress (const boost::asio::ip::address& addr);
|
||||
|
@@ -16,8 +16,8 @@
|
||||
#define MAKE_VERSION_NUMBER(a,b,c) ((a*100+b)*100+c)
|
||||
|
||||
#define I2PD_VERSION_MAJOR 2
|
||||
#define I2PD_VERSION_MINOR 42
|
||||
#define I2PD_VERSION_MICRO 1
|
||||
#define I2PD_VERSION_MINOR 43
|
||||
#define I2PD_VERSION_MICRO 0
|
||||
#define I2PD_VERSION_PATCH 0
|
||||
#ifdef GITVER
|
||||
#define I2PD_VERSION GITVER
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
#define I2P_VERSION_MAJOR 0
|
||||
#define I2P_VERSION_MINOR 9
|
||||
#define I2P_VERSION_MICRO 54
|
||||
#define I2P_VERSION_MICRO 55
|
||||
#define I2P_VERSION_PATCH 0
|
||||
#define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
|
||||
#define I2P_VERSION_NUMBER MAKE_VERSION_NUMBER(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
|
||||
|
@@ -313,7 +313,7 @@ namespace proxy {
|
||||
std::string full_url = m_RequestURL.to_string();
|
||||
std::stringstream ss;
|
||||
ss << tr("Host") << " " << m_RequestURL.host << " <font color=red>" << tr("already in router's addressbook") << "</font>. ";
|
||||
ss << tr("Click here to update record:") << " <a href=\"" << full_url << (full_url.find('?') != std::string::npos ? "&i2paddresshelper=" : "?i2paddresshelper=");
|
||||
ss << tr(/* tr: The "record" means addressbook's record. That message appears when domain was already added to addressbook, but helper link is opened for it. */ "Click here to update record:" ) << " <a href=\"" << full_url << (full_url.find('?') != std::string::npos ? "&i2paddresshelper=" : "?i2paddresshelper=");
|
||||
ss << jump << "&update=true\">" << tr("Continue") << "</a>.";
|
||||
GenericProxyInfo(tr("Addresshelper found"), ss.str());
|
||||
return true; /* request processed */
|
||||
@@ -422,8 +422,8 @@ namespace proxy {
|
||||
void HTTPReqHandler::ForwardToUpstreamProxy()
|
||||
{
|
||||
LogPrint(eLogDebug, "HTTPProxy: Forwarded to upstream");
|
||||
// build http request
|
||||
|
||||
/* build http request */
|
||||
m_ClientRequestURL = m_RequestURL;
|
||||
LogPrint(eLogDebug, "HTTPProxy: ", m_ClientRequestURL.host);
|
||||
m_ClientRequestURL.schema = "";
|
||||
@@ -431,17 +431,17 @@ namespace proxy {
|
||||
std::string origURI = m_ClientRequest.uri; // TODO: what do we need to change uri for?
|
||||
m_ClientRequest.uri = m_ClientRequestURL.to_string();
|
||||
|
||||
// update User-Agent to ESR version of Firefox, same as Tor Browser below version 8, for non-HTTPS connections
|
||||
/* update User-Agent to ESR version of Firefox, same as Tor Browser below version 8, for non-HTTPS connections */
|
||||
if(m_ClientRequest.method != "CONNECT")
|
||||
m_ClientRequest.UpdateHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; rv:60.0) Gecko/20100101 Firefox/60.0");
|
||||
|
||||
m_ClientRequest.write(m_ClientRequestBuffer);
|
||||
m_ClientRequestBuffer << m_recv_buf.substr(m_req_len);
|
||||
|
||||
// assume http if empty schema
|
||||
/* assume http if empty schema */
|
||||
if (m_ProxyURL.schema == "" || m_ProxyURL.schema == "http")
|
||||
{
|
||||
// handle upstream http proxy
|
||||
/* handle upstream http proxy */
|
||||
if (!m_ProxyURL.port) m_ProxyURL.port = 80;
|
||||
if (m_ProxyURL.is_i2p())
|
||||
{
|
||||
@@ -449,9 +449,9 @@ namespace proxy {
|
||||
auto auth = i2p::http::CreateBasicAuthorizationString (m_ProxyURL.user, m_ProxyURL.pass);
|
||||
if (!auth.empty ())
|
||||
{
|
||||
// remove existing authorization if any
|
||||
/* remove existing authorization if any */
|
||||
m_ClientRequest.RemoveHeader("Proxy-");
|
||||
// add own http proxy authorization
|
||||
/* add own http proxy authorization */
|
||||
m_ClientRequest.AddHeader("Proxy-Authorization", auth);
|
||||
}
|
||||
m_send_buf = m_ClientRequest.to_string();
|
||||
@@ -470,7 +470,7 @@ namespace proxy {
|
||||
}
|
||||
else if (m_ProxyURL.schema == "socks")
|
||||
{
|
||||
// handle upstream socks proxy
|
||||
/* handle upstream socks proxy */
|
||||
if (!m_ProxyURL.port) m_ProxyURL.port = 9050; // default to tor default if not specified
|
||||
boost::asio::ip::tcp::resolver::query q(m_ProxyURL.host, std::to_string(m_ProxyURL.port));
|
||||
m_proxy_resolver.async_resolve(q, std::bind(&HTTPReqHandler::HandleUpstreamProxyResolved, this, std::placeholders::_1, std::placeholders::_2, [&](boost::asio::ip::tcp::endpoint ep) {
|
||||
@@ -479,7 +479,7 @@ namespace proxy {
|
||||
}
|
||||
else
|
||||
{
|
||||
// unknown type, complain
|
||||
/* unknown type, complain */
|
||||
GenericProxyError(tr("unknown outproxy url"), m_ProxyURL.to_string());
|
||||
}
|
||||
}
|
||||
|
@@ -660,6 +660,12 @@ namespace client
|
||||
|
||||
void I2PServerTunnel::Stop ()
|
||||
{
|
||||
if (m_PortDestination)
|
||||
m_PortDestination->ResetAcceptor ();
|
||||
auto localDestination = GetLocalDestination ();
|
||||
if (localDestination)
|
||||
localDestination->StopAcceptingStreams ();
|
||||
|
||||
ClearHandlers ();
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -1478,14 +1478,21 @@ namespace client
|
||||
auto session = FindSession (sessionID);
|
||||
if (session)
|
||||
{
|
||||
i2p::data::IdentityEx dest;
|
||||
dest.FromBase64 (destination);
|
||||
if (session->Type == eSAMSessionTypeDatagram)
|
||||
session->GetLocalDestination ()->GetDatagramDestination ()->
|
||||
SendDatagramTo ((uint8_t *)eol, payloadLen, dest.GetIdentHash ());
|
||||
else // raw
|
||||
session->GetLocalDestination ()->GetDatagramDestination ()->
|
||||
SendRawDatagramTo ((uint8_t *)eol, payloadLen, dest.GetIdentHash ());
|
||||
auto localDest = session->GetLocalDestination ();
|
||||
auto datagramDest = localDest ? localDest->GetDatagramDestination () : nullptr;
|
||||
if (datagramDest)
|
||||
{
|
||||
i2p::data::IdentityEx dest;
|
||||
dest.FromBase64 (destination);
|
||||
if (session->Type == eSAMSessionTypeDatagram)
|
||||
datagramDest->SendDatagramTo ((uint8_t *)eol, payloadLen, dest.GetIdentHash ());
|
||||
else if (session->Type == eSAMSessionTypeRaw)
|
||||
datagramDest->SendRawDatagramTo ((uint8_t *)eol, payloadLen, dest.GetIdentHash ());
|
||||
else
|
||||
LogPrint (eLogError, "SAM: Unexpected session type ", (int)session->Type, "for session ", sessionID);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "SAM: Datagram destination is not set for session ", sessionID);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "SAM: Session ", sessionID, " not found");
|
||||
|
Reference in New Issue
Block a user