mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-03-07 06:09:42 +00:00
Compare commits
399 Commits
moduled
...
i2pcontrol
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58e351f5d9 | ||
|
|
2a01ad953c | ||
|
|
3458665df8 | ||
|
|
8320987124 | ||
|
|
648b09d45f | ||
|
|
857df5c734 | ||
|
|
737603e81b | ||
|
|
53ca5dc67a | ||
|
|
8ad5696e50 | ||
|
|
ef9d27e424 | ||
|
|
2bb5ff7184 | ||
|
|
753c7efde8 | ||
|
|
d0d0cd8445 | ||
|
|
410d2c2fa9 | ||
|
|
6a743f66e8 | ||
|
|
709c451400 | ||
|
|
cb73c7c72e | ||
|
|
50abeea82a | ||
|
|
8db352b4d0 | ||
|
|
6589bdf6b5 | ||
|
|
1ac171152a | ||
|
|
629c718527 | ||
|
|
519c0fe81d | ||
|
|
eb0ef80a17 | ||
|
|
9763499dbe | ||
|
|
949c38f5f0 | ||
|
|
2a6f906177 | ||
|
|
b4c226f4b3 | ||
|
|
64c3282aae | ||
|
|
f5d511ae0f | ||
|
|
aa9a9ef18d | ||
|
|
73b9c0302b | ||
|
|
aead9db971 | ||
|
|
d8230644b2 | ||
|
|
97ef908b0c | ||
|
|
fb8be32c28 | ||
|
|
a298588943 | ||
|
|
ccfeca728e | ||
|
|
7705423c42 | ||
|
|
379075c594 | ||
|
|
6a23153c0b | ||
|
|
9e02c99db5 | ||
|
|
ba3cee1cf1 | ||
|
|
9f59ff2df4 | ||
|
|
8df4082d6f | ||
|
|
cf005821d7 | ||
|
|
39b3996596 | ||
|
|
78357baca4 | ||
|
|
85b78dfb9b | ||
|
|
9fd60b52f1 | ||
|
|
851be41d0d | ||
|
|
c6a6a4e0e8 | ||
|
|
28aeebd4c7 | ||
|
|
c88638afe4 | ||
|
|
7f98a8b972 | ||
|
|
e1e4924592 | ||
|
|
8299f80ea5 | ||
|
|
b8ce0b0838 | ||
|
|
e13f151474 | ||
|
|
4ed4e8708e | ||
|
|
1738d118f7 | ||
|
|
f1f66d7b8f | ||
|
|
4ed5e44de7 | ||
|
|
3e3f92c616 | ||
|
|
5fb1247b87 | ||
|
|
016222463d | ||
|
|
0e477bf938 | ||
|
|
eb75eb0e55 | ||
|
|
2a703e0844 | ||
|
|
2b6d9eaa8b | ||
|
|
f9b0bb0383 | ||
|
|
c6e8873d57 | ||
|
|
b2767304e9 | ||
|
|
3d4d3ce80d | ||
|
|
01ea1854bc | ||
|
|
f3aada9e1a | ||
|
|
08fd32b3bf | ||
|
|
39a86ce5c9 | ||
|
|
fe25260ee2 | ||
|
|
63fd05c7d3 | ||
|
|
6c2aec8854 | ||
|
|
e5553f7528 | ||
|
|
6e3cec653d | ||
|
|
55976fd9dc | ||
|
|
bcbd5201e9 | ||
|
|
c2f91ea63b | ||
|
|
1d9d89b115 | ||
|
|
798dd8b27b | ||
|
|
3544f77e90 | ||
|
|
96c4463d39 | ||
|
|
650b7abef6 | ||
|
|
714b3856a2 | ||
|
|
6b939eba59 | ||
|
|
e82662b389 | ||
|
|
8f9dae8556 | ||
|
|
69ca3bc75d | ||
|
|
3945f34e96 | ||
|
|
549dcbee32 | ||
|
|
0a0c2350f2 | ||
|
|
cef2263a7f | ||
|
|
e338ce7da9 | ||
|
|
638c376e5b | ||
|
|
8eade86624 | ||
|
|
24ae8d5443 | ||
|
|
030af11d86 | ||
|
|
857a2bc399 | ||
|
|
09e6e2940f | ||
|
|
23e18a34d4 | ||
|
|
3bdef5f58d | ||
|
|
cf27581c76 | ||
|
|
cf41df82e2 | ||
|
|
4634bff9f0 | ||
|
|
1a9c658836 | ||
|
|
1a32c55ca3 | ||
|
|
f4e230f1ad | ||
|
|
9abc4cf359 | ||
|
|
c54fc7ee44 | ||
|
|
9df757a3fd | ||
|
|
9b5a885b3b | ||
|
|
f32b288785 | ||
|
|
f378119889 | ||
|
|
8fd466c5a9 | ||
|
|
36eddd48c3 | ||
|
|
2470ba76f0 | ||
|
|
d32475440a | ||
|
|
b4d73683d1 | ||
|
|
95f19a5fb2 | ||
|
|
f98780b1d7 | ||
|
|
150c89e48a | ||
|
|
c85bf82749 | ||
|
|
63227ab2f1 | ||
|
|
5b19237a85 | ||
|
|
150b8f8cbd | ||
|
|
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 | ||
|
|
6ca9a599ff | ||
|
|
83bd3b6f0b | ||
|
|
a68765e021 | ||
|
|
f5ed9129cd | ||
|
|
5e3115a614 | ||
|
|
624c46f925 | ||
|
|
52d1ee161f | ||
|
|
d3bc9eb110 | ||
|
|
72b61a29c2 | ||
|
|
a99fcfe54f | ||
|
|
b5d139f7b2 | ||
|
|
463ed12ce8 | ||
|
|
baf74cb582 | ||
|
|
63d7cffefe | ||
|
|
d7d74666b2 | ||
|
|
078d76c6f3 | ||
|
|
3539ee9be6 | ||
|
|
437282b148 | ||
|
|
5394b747a1 | ||
|
|
dd1dd3b7cf | ||
|
|
ae77d4ad22 | ||
|
|
821987fed7 | ||
|
|
18ddba4332 | ||
|
|
aaad6dece6 | ||
|
|
ed04747b9d | ||
|
|
827a88d772 | ||
|
|
24e325db62 | ||
|
|
38e43bc9c8 | ||
|
|
c3c5c7ae63 | ||
|
|
578a15bbe5 | ||
|
|
6b3d7372ae | ||
|
|
55f7529167 | ||
|
|
bceae244c1 | ||
|
|
5de224d6bf | ||
|
|
694b936f30 | ||
|
|
dda25d431c | ||
|
|
22f9abc2f1 | ||
|
|
c6c3de9164 | ||
|
|
58186f0283 | ||
|
|
0253e2d3f6 | ||
|
|
ee20d5b804 | ||
|
|
3a5295dbb9 | ||
|
|
39f14fd952 | ||
|
|
4d59df9f59 | ||
|
|
b8bc114502 | ||
|
|
74d29770e1 | ||
|
|
e4d5788cdc | ||
|
|
2a5cf3e4a8 | ||
|
|
c348736058 | ||
|
|
5bb20cb039 | ||
|
|
dd602a27b5 | ||
|
|
2067de162a | ||
|
|
2cc106b43e | ||
|
|
b15bfd99b3 | ||
|
|
67252b90b3 | ||
|
|
079f7e515c | ||
|
|
e8c58270c4 | ||
|
|
0c64f278d7 | ||
|
|
03518ec94f | ||
|
|
93b5dc2dff | ||
|
|
3bef6383d9 | ||
|
|
605ccf3e02 | ||
|
|
17892238a9 | ||
|
|
b678c989e2 | ||
|
|
b72d1237d2 | ||
|
|
f7b6db5dad | ||
|
|
b744a0cc38 | ||
|
|
b918499f14 | ||
|
|
2cfd054f2c | ||
|
|
dddc7ab039 | ||
|
|
2e4d8cdc8b | ||
|
|
0640bec026 | ||
|
|
cbcee5fb45 | ||
|
|
47460d86b2 | ||
|
|
3cd74f0d4f | ||
|
|
690c9f7c6f | ||
|
|
e2718e5a12 | ||
|
|
d9fefe757e | ||
|
|
55e4bf6b65 | ||
|
|
0176e5cf18 | ||
|
|
4670b12d49 | ||
|
|
321ec8ae4d | ||
|
|
1ccbb8d10b | ||
|
|
86c0accdce | ||
|
|
38d6c29ce9 | ||
|
|
0cf9478cd4 | ||
|
|
a04abd304a | ||
|
|
84aec9fe31 | ||
|
|
593b9bb6c5 | ||
|
|
d3a9cc8fde | ||
|
|
87a434c377 | ||
|
|
56022c9442 | ||
|
|
593d6bf466 | ||
|
|
29a4366dcf | ||
|
|
0a42f414bf | ||
|
|
9b2ac4349e | ||
|
|
2d4c7729ad | ||
|
|
6ecab66b0e | ||
|
|
1dded57a1c | ||
|
|
1d6104ecf3 | ||
|
|
14da941ff4 | ||
|
|
06b87311ea | ||
|
|
3b31773117 | ||
|
|
9c87fe79ea | ||
|
|
bd00112562 | ||
|
|
1c9160c37d | ||
|
|
e2ef88229f | ||
|
|
fd7b889a0f | ||
|
|
a7aa056ec1 | ||
|
|
4f74acb2d3 | ||
|
|
22ef1be82b | ||
|
|
9ddbf255ba | ||
|
|
dfb171d32a | ||
|
|
6b4ffcff5a | ||
|
|
d31cd2e5d6 | ||
|
|
396c74e6c6 | ||
|
|
609c658a9b | ||
|
|
ee6bb40736 | ||
|
|
f8c5ea2b42 | ||
|
|
923eb9fdb3 | ||
|
|
2cd3ebbdb3 | ||
|
|
5e25e30330 | ||
|
|
5aa2a8f60f | ||
|
|
0a1e302e8a | ||
|
|
bb705a77cf | ||
|
|
cb6155b946 | ||
|
|
714d1cc993 | ||
|
|
bc8e4494c4 | ||
|
|
c3a064f980 | ||
|
|
eb3feb7dbd | ||
|
|
da3f3ccac9 | ||
|
|
1a1871e8cd | ||
|
|
c22ab7e1fc | ||
|
|
436992b069 |
32
.github/workflows/build-deb.yml
vendored
Normal file
32
.github/workflows/build-deb.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
name: Build Debian packages
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: ${{ matrix.dist }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
dist: ['buster', 'bullseye', 'bookworm']
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: change debian changelog
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install devscripts
|
||||||
|
debchange -v "`git describe --tags`-${{ matrix.dist }}" -b -M --distribution ${{ matrix.dist }} "trunk build"
|
||||||
|
- uses: jtdor/build-deb-action@v1
|
||||||
|
with:
|
||||||
|
docker-image: debian:${{ matrix.dist }}-slim
|
||||||
|
buildpackage-opts: --build=binary --no-sign
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: i2pd_${{ matrix.dist }}
|
||||||
|
path: debian/artifacts/i2pd_*.deb
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: i2pd-dbgsym_${{ matrix.dist }}
|
||||||
|
path: debian/artifacts/i2pd-dbgsym_*.deb
|
||||||
11
.github/workflows/build-freebsd.yml
vendored
11
.github/workflows/build-freebsd.yml
vendored
@@ -4,18 +4,25 @@ on: [push, pull_request]
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: macos-10.15
|
runs-on: macos-12
|
||||||
name: with UPnP
|
name: with UPnP
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Test in FreeBSD
|
- name: Test in FreeBSD
|
||||||
id: test
|
id: test
|
||||||
uses: vmactions/freebsd-vm@v0.1.5
|
uses: vmactions/freebsd-vm@v0.3.0
|
||||||
with:
|
with:
|
||||||
usesh: true
|
usesh: true
|
||||||
mem: 2048
|
mem: 2048
|
||||||
|
sync: rsync
|
||||||
|
copyback: true
|
||||||
prepare: pkg install -y devel/cmake devel/gmake devel/boost-libs security/openssl net/miniupnpc
|
prepare: pkg install -y devel/cmake devel/gmake devel/boost-libs security/openssl net/miniupnpc
|
||||||
run: |
|
run: |
|
||||||
cd build
|
cd build
|
||||||
cmake -DWITH_UPNP=ON -DCMAKE_BUILD_TYPE=Release .
|
cmake -DWITH_UPNP=ON -DCMAKE_BUILD_TYPE=Release .
|
||||||
gmake -j2
|
gmake -j2
|
||||||
|
- name: Upload artifacts
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: i2pd-freebsd
|
||||||
|
path: build/i2pd
|
||||||
48
.github/workflows/build.yml
vendored
48
.github/workflows/build.yml
vendored
@@ -38,51 +38,3 @@ jobs:
|
|||||||
cd build
|
cd build
|
||||||
cmake -DWITH_UPNP=${{ matrix.with_upnp }} .
|
cmake -DWITH_UPNP=${{ matrix.with_upnp }} .
|
||||||
make -j3
|
make -j3
|
||||||
build-deb-stretch:
|
|
||||||
name: Build package for stretch
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: change debian changelog
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install devscripts
|
|
||||||
debchange -v "`git describe --tags`-stretch" -b -M --distribution stretch "trunk build"
|
|
||||||
- uses: singingwolfboy/build-dpkg-stretch@v1
|
|
||||||
id: build
|
|
||||||
with:
|
|
||||||
args: --unsigned-source --unsigned-changes -b
|
|
||||||
- uses: actions/upload-artifact@v1
|
|
||||||
with:
|
|
||||||
name: ${{ steps.build.outputs.filename }}
|
|
||||||
path: ${{ steps.build.outputs.filename }}
|
|
||||||
- uses: actions/upload-artifact@v1
|
|
||||||
with:
|
|
||||||
name: ${{ steps.build.outputs.filename-dbgsym }}
|
|
||||||
path: ${{ steps.build.outputs.filename-dbgsym }}
|
|
||||||
build-deb-buster:
|
|
||||||
name: Build package for buster
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: change debian changelog
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install devscripts
|
|
||||||
debchange -v "`git describe --tags`-buster" -b -M --distribution buster "trunk build"
|
|
||||||
- uses: singingwolfboy/build-dpkg-buster@v1
|
|
||||||
id: build
|
|
||||||
with:
|
|
||||||
args: --unsigned-source --unsigned-changes -b
|
|
||||||
- uses: actions/upload-artifact@v1
|
|
||||||
with:
|
|
||||||
name: ${{ steps.build.outputs.filename }}
|
|
||||||
path: ${{ steps.build.outputs.filename }}
|
|
||||||
- uses: actions/upload-artifact@v1
|
|
||||||
with:
|
|
||||||
name: ${{ steps.build.outputs.filename-dbgsym }}
|
|
||||||
path: ${{ steps.build.outputs.filename-dbgsym }}
|
|
||||||
|
|||||||
123
.github/workflows/docker.yml
vendored
123
.github/workflows/docker.yml
vendored
@@ -1,63 +1,140 @@
|
|||||||
name: Build containers
|
name: Build containers
|
||||||
|
|
||||||
on: [push]
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- openssl
|
||||||
|
- docker
|
||||||
|
tags:
|
||||||
|
- '*'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
docker:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
packages: write
|
packages: write
|
||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include: [
|
||||||
|
{ platform: 'linux/amd64', archname: 'amd64' },
|
||||||
|
{ platform: 'linux/386', archname: 'i386' },
|
||||||
|
{ platform: 'linux/arm64', archname: 'arm64' },
|
||||||
|
{ platform: 'linux/arm/v7', archname: 'armv7' },
|
||||||
|
]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v1
|
uses: docker/setup-qemu-action@v2
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v1
|
uses: docker/setup-buildx-action@v2
|
||||||
|
|
||||||
- name: Login to DockerHub
|
- name: Login to DockerHub
|
||||||
uses: docker/login-action@v1
|
uses: docker/login-action@v2
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Login to GitHub Container registry
|
- name: Login to GitHub Container registry
|
||||||
uses: docker/login-action@v1
|
uses: docker/login-action@v2
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Build and push trunk container
|
- name: Build container for ${{ matrix.archname }}
|
||||||
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
uses: docker/build-push-action@v3
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
with:
|
||||||
context: ./contrib/docker
|
context: ./contrib/docker
|
||||||
file: ./contrib/docker/Dockerfile
|
file: ./contrib/docker/Dockerfile
|
||||||
platforms: linux/amd64,linux/386,linux/arm64,linux/arm/v7
|
platforms: ${{ matrix.platform }}
|
||||||
push: true
|
push: true
|
||||||
tags: |
|
tags: |
|
||||||
purplei2p/i2pd:latest
|
purplei2p/i2pd:latest-${{ matrix.archname }}
|
||||||
ghcr.io/purplei2p/i2pd:latest
|
ghcr.io/purplei2p/i2pd:latest-${{ matrix.archname }}
|
||||||
|
|
||||||
- name: Set env
|
push:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
packages: write
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
needs: build
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v2
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
|
||||||
|
- name: Login to DockerHub
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Login to GitHub Container registry
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Create and push latest manifest image to Docker Hub
|
||||||
|
uses: Noelware/docker-manifest-action@master
|
||||||
|
with:
|
||||||
|
base-image: purplei2p/i2pd:latest
|
||||||
|
extra-images: purplei2p/i2pd:latest-amd64,purplei2p/i2pd:latest-i386,purplei2p/i2pd:latest-arm64,purplei2p/i2pd:latest-armv7
|
||||||
|
push: true
|
||||||
|
|
||||||
|
- name: Create and push latest manifest image to GHCR
|
||||||
|
uses: Noelware/docker-manifest-action@master
|
||||||
|
with:
|
||||||
|
base-image: ghcr.io/purplei2p/i2pd:latest
|
||||||
|
extra-images: ghcr.io/purplei2p/i2pd:latest-amd64,ghcr.io/purplei2p/i2pd:latest-i386,ghcr.io/purplei2p/i2pd:latest-arm64,ghcr.io/purplei2p/i2pd:latest-armv7
|
||||||
|
push: true
|
||||||
|
|
||||||
|
- name: Store release version to env
|
||||||
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||||
run: echo "RELEASE_VERSION=${GITHUB_REF:10}" >> $GITHUB_ENV
|
run: echo "RELEASE_VERSION=${GITHUB_REF:10}" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Build and push release container
|
- name: Create and push release manifest image to Docker Hub
|
||||||
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||||
uses: docker/build-push-action@v2
|
uses: Noelware/docker-manifest-action@master
|
||||||
with:
|
with:
|
||||||
context: ./contrib/docker
|
base-image: purplei2p/i2pd:latest-release
|
||||||
file: ./contrib/docker/Dockerfile
|
extra-images: purplei2p/i2pd:latest-amd64,purplei2p/i2pd:latest-i386,purplei2p/i2pd:latest-arm64,purplei2p/i2pd:latest-armv7
|
||||||
platforms: linux/amd64,linux/386,linux/arm64,linux/arm/v7
|
push: true
|
||||||
|
|
||||||
|
- name: Create and push release manifest image to GHCR
|
||||||
|
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||||
|
uses: Noelware/docker-manifest-action@master
|
||||||
|
with:
|
||||||
|
base-image: ghcr.io/purplei2p/i2pd:latest-release
|
||||||
|
extra-images: ghcr.io/purplei2p/i2pd:latest-amd64,ghcr.io/purplei2p/i2pd:latest-i386,ghcr.io/purplei2p/i2pd:latest-arm64,ghcr.io/purplei2p/i2pd:latest-armv7
|
||||||
|
push: true
|
||||||
|
|
||||||
|
- name: Create and push versioned manifest image to Docker Hub
|
||||||
|
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||||
|
uses: Noelware/docker-manifest-action@master
|
||||||
|
with:
|
||||||
|
base-image: purplei2p/i2pd:release-${{ env.RELEASE_VERSION }}
|
||||||
|
extra-images: purplei2p/i2pd:latest-amd64,purplei2p/i2pd:latest-i386,purplei2p/i2pd:latest-arm64,purplei2p/i2pd:latest-armv7
|
||||||
|
push: true
|
||||||
|
|
||||||
|
- name: Create and push versioned manifest image to GHCR
|
||||||
|
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||||
|
uses: Noelware/docker-manifest-action@master
|
||||||
|
with:
|
||||||
|
base-image: ghcr.io/purplei2p/i2pd:release-${{ env.RELEASE_VERSION }}
|
||||||
|
extra-images: ghcr.io/purplei2p/i2pd:latest-amd64,ghcr.io/purplei2p/i2pd:latest-i386,ghcr.io/purplei2p/i2pd:latest-arm64,ghcr.io/purplei2p/i2pd:latest-armv7
|
||||||
push: true
|
push: true
|
||||||
tags: |
|
|
||||||
purplei2p/i2pd:latest
|
|
||||||
purplei2p/i2pd:release-${{ env.RELEASE_VERSION }}
|
|
||||||
ghcr.io/purplei2p/i2pd:latest
|
|
||||||
ghcr.io/purplei2p/i2pd:release-${{ env.RELEASE_VERSION }}
|
|
||||||
|
|||||||
94
ChangeLog
94
ChangeLog
@@ -1,6 +1,100 @@
|
|||||||
# for this file format description,
|
# for this file format description,
|
||||||
# see https://github.com/olivierlacan/keep-a-changelog
|
# see https://github.com/olivierlacan/keep-a-changelog
|
||||||
|
|
||||||
|
## [2.44.0] - 2022-11-20
|
||||||
|
### Added
|
||||||
|
- SSL connection for server I2P tunnels
|
||||||
|
- Localization to Italian and Spanish
|
||||||
|
- SSU2 through SOCKS5 UDP proxy
|
||||||
|
- Reload tunnels through web console
|
||||||
|
- SSU2 send immediate ack request flag
|
||||||
|
- SSU2 send and verify path challenge
|
||||||
|
- Configurable ssu2.mtu4 and ssu2.mtu6
|
||||||
|
### Changed
|
||||||
|
- SSU2 is enbaled and SSU is disabled by default
|
||||||
|
- Separate network status and error
|
||||||
|
- Random selection between NTCP2 and SSU2 priority
|
||||||
|
- Added notbob.i2p to jump services
|
||||||
|
- Remove DoNotTrack flag from HTTP Request header
|
||||||
|
- Skip addresshelper page if destination was not changed
|
||||||
|
- SSU2 allow different ports from RelayReponse and HolePunch
|
||||||
|
- SSU2 resend PeerTest msg 1 and msg 2
|
||||||
|
- SSU2 Send Retry instead SessionCreated if clock skew detected
|
||||||
|
### Fixed
|
||||||
|
- Long HTTP headers for HTTP proxy and HTTP server tunnel
|
||||||
|
- SSU2 resends and resend limits
|
||||||
|
- Crash at startup if addressbook is disabled
|
||||||
|
- NTCP2 ipv6 connection through SOCKS5 proxy
|
||||||
|
- SSU2 SessionRequest with zero token
|
||||||
|
- SSU2 MTU less than 1280
|
||||||
|
- SSU2 port=1
|
||||||
|
- Incorrect addresses from network interfaces
|
||||||
|
- Definitions for Darwin PPC; do not use pthread_setname_np
|
||||||
|
|
||||||
|
## [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
|
||||||
|
|
||||||
|
## [2.42.0] - 2022-05-22
|
||||||
|
### Added
|
||||||
|
- Preliminary SSU2 implementation
|
||||||
|
- Tunnel length variance
|
||||||
|
- Localization to French
|
||||||
|
- Daily cleanup of obsolete peer profiles
|
||||||
|
- Ordered jump services list in HTTP proxy
|
||||||
|
- Win32 service
|
||||||
|
- Show port for local non-published SSU addresses in web console
|
||||||
|
### Changed
|
||||||
|
- Maximum RouterInfo length increased to 3K
|
||||||
|
- Skip unknown addresses in RouterInfo
|
||||||
|
- Don't pick own router for peer test
|
||||||
|
- Reseeds list
|
||||||
|
- Internal numeric id for families
|
||||||
|
- Use ipv6 preference only when netinet headers not used
|
||||||
|
- Close stream if delete requested
|
||||||
|
- Remove version from title in web console
|
||||||
|
- Drop MESHNET build option
|
||||||
|
- Set data path before initialization
|
||||||
|
- Don't show registration block in web console if token is not provided
|
||||||
|
### Fixed
|
||||||
|
- Encrypted LeaseSet for EdDSA signature
|
||||||
|
- Clients tunnels are not built if clock is not synced on start
|
||||||
|
- Incorrect processing of i2cp.dontPublishLeaseSet param
|
||||||
|
- UDP tunnels reload
|
||||||
|
- Build for LibreSSL 3.5.2
|
||||||
|
- Race condition in short tunnel build message
|
||||||
|
- Race condition in local RouterInfo buffer allocation
|
||||||
|
|
||||||
## [2.41.0] - 2022-02-20
|
## [2.41.0] - 2022-02-20
|
||||||
### Added
|
### Added
|
||||||
- Clock syncronization through SSU
|
- Clock syncronization through SSU
|
||||||
|
|||||||
29
Makefile
29
Makefile
@@ -4,7 +4,7 @@ SYS := $(shell $(CXX) -dumpmachine)
|
|||||||
|
|
||||||
ifneq (, $(findstring darwin, $(SYS)))
|
ifneq (, $(findstring darwin, $(SYS)))
|
||||||
SHARED_SUFFIX = dylib
|
SHARED_SUFFIX = dylib
|
||||||
else ifneq (, $(findstring mingw, $(SYS))$(findstring cygwin, $(SYS)))
|
else ifneq (, $(findstring mingw, $(SYS))$(findstring windows-gnu, $(SYS))$(findstring cygwin, $(SYS)))
|
||||||
SHARED_SUFFIX = dll
|
SHARED_SUFFIX = dll
|
||||||
else
|
else
|
||||||
SHARED_SUFFIX = so
|
SHARED_SUFFIX = so
|
||||||
@@ -40,12 +40,6 @@ USE_GIT_VERSION := $(or $(USE_GIT_VERSION),no)
|
|||||||
# for MacOS only, waiting for "1", not "yes"
|
# for MacOS only, waiting for "1", not "yes"
|
||||||
HOMEBREW := $(or $(HOMEBREW),0)
|
HOMEBREW := $(or $(HOMEBREW),0)
|
||||||
|
|
||||||
# Client protocols
|
|
||||||
USE_I2PC := $(or $(USE_I2PC),yes)
|
|
||||||
USE_I2CP := $(or $(USE_I2CP),yes)
|
|
||||||
USE_SAM := $(or $(USE_SAM),yes)
|
|
||||||
USE_BOB := $(or $(USE_BOB),yes)
|
|
||||||
|
|
||||||
ifeq ($(DEBUG),yes)
|
ifeq ($(DEBUG),yes)
|
||||||
CXX_DEBUG = -g
|
CXX_DEBUG = -g
|
||||||
else
|
else
|
||||||
@@ -53,19 +47,6 @@ else
|
|||||||
LD_DEBUG = -s
|
LD_DEBUG = -s
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(USE_I2PC),yes)
|
|
||||||
NEEDED_CXXFLAGS += -DWITH_I2PC
|
|
||||||
endif
|
|
||||||
ifeq ($(USE_I2CP),yes)
|
|
||||||
NEEDED_CXXFLAGS += -DWITH_I2CP
|
|
||||||
endif
|
|
||||||
ifeq ($(USE_SAM),yes)
|
|
||||||
NEEDED_CXXFLAGS += -DWITH_SAM
|
|
||||||
endif
|
|
||||||
ifeq ($(USE_BOB),yes)
|
|
||||||
NEEDED_CXXFLAGS += -DWITH_BOB
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifneq (, $(findstring darwin, $(SYS)))
|
ifneq (, $(findstring darwin, $(SYS)))
|
||||||
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
|
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
|
||||||
ifeq ($(HOMEBREW),1)
|
ifeq ($(HOMEBREW),1)
|
||||||
@@ -73,15 +54,15 @@ ifneq (, $(findstring darwin, $(SYS)))
|
|||||||
else
|
else
|
||||||
include Makefile.osx
|
include Makefile.osx
|
||||||
endif
|
endif
|
||||||
|
else ifneq (, $(findstring mingw, $(SYS))$(findstring windows-gnu, $(SYS))$(findstring cygwin, $(SYS)))
|
||||||
|
DAEMON_SRC += Win32/DaemonWin32.cpp Win32/Win32App.cpp Win32/Win32Service.cpp Win32/Win32NetState.cpp
|
||||||
|
include Makefile.mingw
|
||||||
else ifneq (, $(findstring linux, $(SYS))$(findstring gnu, $(SYS)))
|
else ifneq (, $(findstring linux, $(SYS))$(findstring gnu, $(SYS)))
|
||||||
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
|
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
|
||||||
include Makefile.linux
|
include Makefile.linux
|
||||||
else ifneq (, $(findstring freebsd, $(SYS))$(findstring openbsd, $(SYS)))
|
else ifneq (, $(findstring freebsd, $(SYS))$(findstring openbsd, $(SYS)))
|
||||||
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
|
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
|
||||||
include Makefile.bsd
|
include Makefile.bsd
|
||||||
else ifneq (, $(findstring mingw, $(SYS))$(findstring cygwin, $(SYS)))
|
|
||||||
DAEMON_SRC += Win32/DaemonWin32.cpp Win32/Win32App.cpp Win32/Win32Service.cpp Win32/Win32NetState.cpp
|
|
||||||
include Makefile.mingw
|
|
||||||
else # not supported
|
else # not supported
|
||||||
$(error Not supported platform)
|
$(error Not supported platform)
|
||||||
endif
|
endif
|
||||||
@@ -91,7 +72,7 @@ ifeq ($(USE_GIT_VERSION),yes)
|
|||||||
NEEDED_CXXFLAGS += -DGITVER=\"$(GIT_VERSION)\"
|
NEEDED_CXXFLAGS += -DGITVER=\"$(GIT_VERSION)\"
|
||||||
endif
|
endif
|
||||||
|
|
||||||
NEEDED_CXXFLAGS += -MMD -MP -I$(LIB_SRC_DIR) -I$(LIB_CLIENT_SRC_DIR) -I$(LANG_SRC_DIR)
|
NEEDED_CXXFLAGS += -MMD -MP -I$(LIB_SRC_DIR) -I$(LIB_CLIENT_SRC_DIR) -I$(LANG_SRC_DIR) -DOPENSSL_SUPPRESS_DEPRECATED
|
||||||
|
|
||||||
LIB_OBJS += $(patsubst %.cpp,obj/%.o,$(LIB_SRC))
|
LIB_OBJS += $(patsubst %.cpp,obj/%.o,$(LIB_SRC))
|
||||||
LIB_CLIENT_OBJS += $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC))
|
LIB_CLIENT_OBJS += $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC))
|
||||||
|
|||||||
@@ -39,13 +39,18 @@ ifeq ($(USE_AESNI),yes)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
install: all
|
install: all
|
||||||
install -d ${PREFIX}/bin ${PREFIX}/etc/i2pd ${PREFIX}/etc/i2pd/tunnels.conf.d ${PREFIX}/share/doc/i2pd ${PREFIX}/share/i2pd ${PREFIX}/share/man/man1 ${PREFIX}/var/lib/i2pd
|
install -d ${PREFIX}/bin
|
||||||
install -m 755 ${I2PD} ${PREFIX}/bin/
|
install -m 755 ${I2PD} ${PREFIX}/bin
|
||||||
|
install -d ${PREFIX}/etc ${PREFIX}/etc/i2pd ${PREFIX}/etc/i2pd/tunnels.conf.d
|
||||||
install -m 644 contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/etc/i2pd
|
install -m 644 contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/etc/i2pd
|
||||||
@cp -R contrib/certificates ${PREFIX}/share/i2pd/
|
install -d ${PREFIX}/share ${PREFIX}/share/doc ${PREFIX}/share/doc/i2pd
|
||||||
install -m 644 ChangeLog LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/share/doc/i2pd
|
install -m 644 ChangeLog LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/share/doc/i2pd
|
||||||
|
install -d ${PREFIX}/share/i2pd
|
||||||
|
@cp -R contrib/certificates ${PREFIX}/share/i2pd/
|
||||||
|
install -d ${PREFIX}/share/man ${PREFIX}/share/man/man1
|
||||||
@gzip -kf debian/i2pd.1 && install debian/i2pd.1.gz ${PREFIX}/share/man/man1
|
@gzip -kf debian/i2pd.1 && install debian/i2pd.1.gz ${PREFIX}/share/man/man1
|
||||||
@ln -sf ${PREFIX}/share/i2pd/certificates ${PREFIX}/var/lib/i2pd/
|
install -d ${PREFIX}/var ${PREFIX}/var/lib ${PREFIX}/var/lib/i2pd
|
||||||
|
@ln -sf ${PREFIX}/share/i2pd/certificates ${PREFIX}/var/lib/i2pd/certificates
|
||||||
@ln -sf ${PREFIX}/etc/i2pd/tunnels.conf.d ${PREFIX}/var/lib/i2pd/tunnels.d
|
@ln -sf ${PREFIX}/etc/i2pd/tunnels.conf.d ${PREFIX}/var/lib/i2pd/tunnels.d
|
||||||
@ln -sf ${PREFIX}/etc/i2pd/i2pd.conf ${PREFIX}/var/lib/i2pd/i2pd.conf
|
@ln -sf ${PREFIX}/etc/i2pd/i2pd.conf ${PREFIX}/var/lib/i2pd/i2pd.conf
|
||||||
@ln -sf ${PREFIX}/etc/i2pd/subscriptions.txt ${PREFIX}/var/lib/i2pd/subscriptions.txt
|
@ln -sf ${PREFIX}/etc/i2pd/subscriptions.txt ${PREFIX}/var/lib/i2pd/subscriptions.txt
|
||||||
|
|||||||
@@ -64,13 +64,18 @@ endif
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
install: all
|
install: all
|
||||||
install -d ${PREFIX}/bin ${PREFIX}/etc ${PREFIX}/etc/i2pd ${PREFIX}/etc/i2pd/tunnels.conf.d ${PREFIX}/usr ${PREFIX}/usr/share ${PREFIX}/usr/share/doc/i2pd ${PREFIX}/usr/share/i2pd ${PREFIX}/usr/share/man ${PREFIX}/usr/share/man/man1 ${PREFIX}/var/lib ${PREFIX}/var/lib/i2pd
|
install -d ${PREFIX}/bin
|
||||||
install -m 755 ${I2PD} ${PREFIX}/bin/
|
install -m 755 ${I2PD} ${PREFIX}/bin
|
||||||
|
install -d ${PREFIX}/etc ${PREFIX}/etc/i2pd ${PREFIX}/etc/i2pd/tunnels.conf.d
|
||||||
install -m 644 contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/etc/i2pd
|
install -m 644 contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/etc/i2pd
|
||||||
@cp -R contrib/certificates ${PREFIX}/usr/share/i2pd/
|
install -d ${PREFIX}/share ${PREFIX}/share/doc ${PREFIX}/share/doc/i2pd
|
||||||
install -m 644 ChangeLog LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/usr/share/doc/i2pd
|
install -m 644 ChangeLog LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/share/doc/i2pd
|
||||||
@gzip -kf debian/i2pd.1 && install debian/i2pd.1.gz ${PREFIX}/usr/share/man/man1
|
install -d ${PREFIX}/share/i2pd
|
||||||
@ln -sf ${PREFIX}/usr/share/i2pd/certificates ${PREFIX}/var/lib/i2pd/
|
@cp -R contrib/certificates ${PREFIX}/share/i2pd/
|
||||||
|
install -d ${PREFIX}/share/man ${PREFIX}/share/man/man1
|
||||||
|
@gzip -kf debian/i2pd.1 && install debian/i2pd.1.gz ${PREFIX}/share/man/man1
|
||||||
|
install -d ${PREFIX}/var ${PREFIX}/var/lib ${PREFIX}/var/lib/i2pd
|
||||||
|
@ln -sf ${PREFIX}/share/i2pd/certificates ${PREFIX}/var/lib/i2pd/certificates
|
||||||
@ln -sf ${PREFIX}/etc/i2pd/tunnels.conf.d ${PREFIX}/var/lib/i2pd/tunnels.d
|
@ln -sf ${PREFIX}/etc/i2pd/tunnels.conf.d ${PREFIX}/var/lib/i2pd/tunnels.d
|
||||||
@ln -sf ${PREFIX}/etc/i2pd/i2pd.conf ${PREFIX}/var/lib/i2pd/i2pd.conf
|
@ln -sf ${PREFIX}/etc/i2pd/i2pd.conf ${PREFIX}/var/lib/i2pd/i2pd.conf
|
||||||
@ln -sf ${PREFIX}/etc/i2pd/subscriptions.txt ${PREFIX}/var/lib/i2pd/subscriptions.txt
|
@ln -sf ${PREFIX}/etc/i2pd/subscriptions.txt ${PREFIX}/var/lib/i2pd/subscriptions.txt
|
||||||
|
|||||||
@@ -3,19 +3,11 @@ USE_WIN32_APP := yes
|
|||||||
|
|
||||||
WINDRES = windres
|
WINDRES = windres
|
||||||
|
|
||||||
CXXFLAGS := $(CXX_DEBUG) -DWIN32_LEAN_AND_MEAN -fPIC -msse
|
CXXFLAGS := $(CXX_DEBUG) -fPIC -msse
|
||||||
INCFLAGS = -I$(DAEMON_SRC_DIR) -IWin32
|
INCFLAGS = -I$(DAEMON_SRC_DIR) -IWin32
|
||||||
LDFLAGS := ${LD_DEBUG} -static
|
LDFLAGS := ${LD_DEBUG} -static
|
||||||
|
|
||||||
# detect proper flag for c++11 support by compilers
|
NEEDED_CXXFLAGS += -std=c++17 -DWIN32_LEAN_AND_MEAN
|
||||||
CXXVER := $(shell $(CXX) -dumpversion)
|
|
||||||
ifeq ($(shell expr match ${CXXVER} "[4]\.[7-9]\|4\.1[0-9]\|[5-6]"),4) # gcc 4.7 - 6
|
|
||||||
NEEDED_CXXFLAGS += -std=c++11
|
|
||||||
else ifeq ($(shell expr match ${CXXVER} "[1,7-9]"),1) # gcc >= 7
|
|
||||||
NEEDED_CXXFLAGS += -std=c++17
|
|
||||||
else # not supported
|
|
||||||
$(error Compiler too old)
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Boost libraries suffix
|
# Boost libraries suffix
|
||||||
BOOST_SUFFIX = -mt
|
BOOST_SUFFIX = -mt
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@@ -154,9 +154,10 @@ namespace win32
|
|||||||
case eRouterStatusUnknown: s << "Unk"; break;
|
case eRouterStatusUnknown: s << "Unk"; break;
|
||||||
case eRouterStatusProxy: s << "Proxy"; break;
|
case eRouterStatusProxy: s << "Proxy"; break;
|
||||||
case eRouterStatusMesh: s << "Mesh"; break;
|
case eRouterStatusMesh: s << "Mesh"; break;
|
||||||
case eRouterStatusError:
|
default: s << "Unk";
|
||||||
|
};
|
||||||
|
if (i2p::context.GetError () != eRouterErrorNone)
|
||||||
{
|
{
|
||||||
s << "Err";
|
|
||||||
switch (i2p::context.GetError ())
|
switch (i2p::context.GetError ())
|
||||||
{
|
{
|
||||||
case eRouterErrorClockSkew:
|
case eRouterErrorClockSkew:
|
||||||
@@ -170,9 +171,6 @@ namespace win32
|
|||||||
break;
|
break;
|
||||||
default: ;
|
default: ;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: s << "Unk";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,12 +17,13 @@ option(WITH_LIBRARY "Build library" ON)
|
|||||||
option(WITH_BINARY "Build binary" ON)
|
option(WITH_BINARY "Build binary" ON)
|
||||||
option(WITH_STATIC "Static build" OFF)
|
option(WITH_STATIC "Static build" OFF)
|
||||||
option(WITH_UPNP "Include support for UPnP client" OFF)
|
option(WITH_UPNP "Include support for UPnP client" OFF)
|
||||||
|
option(WITH_GIT_VERSION "Use git commit info as version" OFF)
|
||||||
option(WITH_ADDRSANITIZER "Build with address sanitizer unix only" OFF)
|
option(WITH_ADDRSANITIZER "Build with address sanitizer unix only" OFF)
|
||||||
option(WITH_THREADSANITIZER "Build with thread sanitizer unix only" OFF)
|
option(WITH_THREADSANITIZER "Build with thread sanitizer unix only" OFF)
|
||||||
|
|
||||||
# paths
|
# paths
|
||||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules")
|
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules")
|
||||||
set(CMAKE_SOURCE_DIR "..")
|
set(CMAKE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/..")
|
||||||
|
|
||||||
#Handle paths nicely
|
#Handle paths nicely
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
@@ -84,6 +85,7 @@ set(DAEMON_SRC
|
|||||||
"${DAEMON_SRC_DIR}/Daemon.cpp"
|
"${DAEMON_SRC_DIR}/Daemon.cpp"
|
||||||
"${DAEMON_SRC_DIR}/HTTPServer.cpp"
|
"${DAEMON_SRC_DIR}/HTTPServer.cpp"
|
||||||
"${DAEMON_SRC_DIR}/I2PControl.cpp"
|
"${DAEMON_SRC_DIR}/I2PControl.cpp"
|
||||||
|
"${DAEMON_SRC_DIR}/I2PControlHandlers.cpp"
|
||||||
"${DAEMON_SRC_DIR}/i2pd.cpp"
|
"${DAEMON_SRC_DIR}/i2pd.cpp"
|
||||||
"${DAEMON_SRC_DIR}/UPnP.cpp"
|
"${DAEMON_SRC_DIR}/UPnP.cpp"
|
||||||
)
|
)
|
||||||
@@ -92,6 +94,12 @@ if(WITH_UPNP)
|
|||||||
add_definitions(-DUSE_UPNP)
|
add_definitions(-DUSE_UPNP)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(WITH_GIT_VERSION)
|
||||||
|
include(GetGitRevisionDescription)
|
||||||
|
git_describe(GIT_VERSION)
|
||||||
|
add_definitions(-DGITVER="${GIT_VERSION}")
|
||||||
|
endif()
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
add_definitions(-DMAC_OSX)
|
add_definitions(-DMAC_OSX)
|
||||||
endif()
|
endif()
|
||||||
@@ -164,25 +172,21 @@ if(WITH_THREADSANITIZER)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
# Enable usage of STD's Atomic instead of Boost's on PowerPC
|
||||||
|
# For more information refer to https://github.com/PurpleI2P/i2pd/issues/1726#issuecomment-1306335111
|
||||||
|
if(ARCHITECTURE MATCHES "ppc")
|
||||||
|
add_definitions(-DBOOST_SP_USE_STD_ATOMIC)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
# libraries
|
# libraries
|
||||||
# TODO: once CMake 3.1+ becomes mainstream, see e.g. http://stackoverflow.com/a/29871891/673826
|
|
||||||
# use imported Threads::Threads instead
|
|
||||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||||
if(IOS)
|
|
||||||
set(CMAKE_THREAD_LIBS_INIT "-lpthread")
|
|
||||||
set(CMAKE_HAVE_THREADS_LIBRARY 1)
|
|
||||||
set(CMAKE_USE_WIN32_THREADS_INIT 0)
|
|
||||||
set(CMAKE_USE_PTHREADS_INIT 1)
|
|
||||||
else()
|
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
endif()
|
|
||||||
if(THREADS_HAVE_PTHREAD_ARG) # compile time flag
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WITH_STATIC)
|
if(WITH_STATIC)
|
||||||
set(Boost_USE_STATIC_LIBS ON)
|
set(Boost_USE_STATIC_LIBS ON)
|
||||||
set(Boost_USE_STATIC_RUNTIME ON)
|
set(Boost_USE_STATIC_RUNTIME ON)
|
||||||
|
set(OPENSSL_USE_STATIC_LIBS ON)
|
||||||
set(BUILD_SHARED_LIBS OFF)
|
set(BUILD_SHARED_LIBS OFF)
|
||||||
if(${CMAKE_CXX_COMPILER} MATCHES ".*-openwrt-.*")
|
if(${CMAKE_CXX_COMPILER} MATCHES ".*-openwrt-.*")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
|
||||||
@@ -197,8 +201,6 @@ else()
|
|||||||
add_definitions(-DBOOST_SYSTEM_DYN_LINK -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_PROGRAM_OPTIONS_DYN_LINK -DBOOST_DATE_TIME_DYN_LINK -DBOOST_REGEX_DYN_LINK)
|
add_definitions(-DBOOST_SYSTEM_DYN_LINK -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_PROGRAM_OPTIONS_DYN_LINK -DBOOST_DATE_TIME_DYN_LINK -DBOOST_REGEX_DYN_LINK)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries(libi2pdclient libi2pd libi2pdlang)
|
|
||||||
|
|
||||||
find_package(Boost COMPONENTS system filesystem program_options date_time REQUIRED)
|
find_package(Boost COMPONENTS system filesystem program_options date_time REQUIRED)
|
||||||
if(NOT DEFINED Boost_INCLUDE_DIRS)
|
if(NOT DEFINED Boost_INCLUDE_DIRS)
|
||||||
message(SEND_ERROR "Boost is not found, or your boost version was below 1.46. Please download Boost!")
|
message(SEND_ERROR "Boost is not found, or your boost version was below 1.46. Please download Boost!")
|
||||||
@@ -210,7 +212,7 @@ if(NOT DEFINED OPENSSL_INCLUDE_DIR)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(OPENSSL_VERSION VERSION_GREATER_EQUAL "3.0.0")
|
if(OPENSSL_VERSION VERSION_GREATER_EQUAL "3.0.0")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations")
|
add_definitions(-DOPENSSL_SUPPRESS_DEPRECATED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WITH_UPNP)
|
if(WITH_UPNP)
|
||||||
@@ -247,6 +249,7 @@ message(STATUS " LIBRARY : ${WITH_LIBRARY}")
|
|||||||
message(STATUS " BINARY : ${WITH_BINARY}")
|
message(STATUS " BINARY : ${WITH_BINARY}")
|
||||||
message(STATUS " STATIC BUILD : ${WITH_STATIC}")
|
message(STATUS " STATIC BUILD : ${WITH_STATIC}")
|
||||||
message(STATUS " UPnP : ${WITH_UPNP}")
|
message(STATUS " UPnP : ${WITH_UPNP}")
|
||||||
|
message(STATUS " GIT VERSION : ${WITH_GIT_VERSION}")
|
||||||
message(STATUS " ADDRSANITIZER : ${WITH_ADDRSANITIZER}")
|
message(STATUS " ADDRSANITIZER : ${WITH_ADDRSANITIZER}")
|
||||||
message(STATUS " THREADSANITIZER : ${WITH_THREADSANITIZER}")
|
message(STATUS " THREADSANITIZER : ${WITH_THREADSANITIZER}")
|
||||||
message(STATUS "---------------------------------------")
|
message(STATUS "---------------------------------------")
|
||||||
@@ -262,23 +265,17 @@ if(WITH_BINARY)
|
|||||||
set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-z relro -z now")
|
set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-z relro -z now")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WITH_UPNP)
|
|
||||||
set(UPNP_LIB ${MINIUPNPC_LIBRARY})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# FindBoost pulls pthread for thread which is broken for static linking at least on Ubuntu 15.04
|
# FindBoost pulls pthread for thread which is broken for static linking at least on Ubuntu 15.04
|
||||||
list(GET Boost_LIBRARIES -1 LAST_Boost_LIBRARIES)
|
list(GET Boost_LIBRARIES -1 LAST_Boost_LIBRARIES)
|
||||||
if(${LAST_Boost_LIBRARIES} MATCHES ".*pthread.*")
|
if(${LAST_Boost_LIBRARIES} MATCHES ".*pthread.*")
|
||||||
list(REMOVE_AT Boost_LIBRARIES -1)
|
list(REMOVE_AT Boost_LIBRARIES -1)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
if(WITH_STATIC)
|
if(WITH_STATIC)
|
||||||
set(DL_LIB ${CMAKE_DL_LIBS})
|
set(DL_LIB ${CMAKE_DL_LIBS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries(libi2pd ${Boost_LIBRARIES} ${ZLIB_LIBRARY})
|
target_link_libraries("${PROJECT_NAME}" libi2pd libi2pdclient libi2pdlang ${DL_LIB} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto ${MINIUPNPC_LIBRARY} ZLIB::ZLIB Threads::Threads ${DL_LIB} ${CMAKE_REQUIRED_LIBRARIES})
|
||||||
target_link_libraries("${PROJECT_NAME}" libi2pd libi2pdclient libi2pdlang ${DL_LIB} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${UPNP_LIB} ${ZLIB_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${DL_LIB} ${CMAKE_REQUIRED_LIBRARIES})
|
|
||||||
|
|
||||||
install(TARGETS "${PROJECT_NAME}" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime)
|
install(TARGETS "${PROJECT_NAME}" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime)
|
||||||
set(APPS "\${CMAKE_INSTALL_PREFIX}/bin/${PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX}")
|
set(APPS "\${CMAKE_INSTALL_PREFIX}/bin/${PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX}")
|
||||||
|
|||||||
@@ -52,9 +52,8 @@ REM converting configuration files to DOS format (make usable in Windows Notepad
|
|||||||
%xSH% "unix2dos contrib/i2pd.conf contrib/tunnels.conf contrib/tunnels.d/* contrib/webconsole/style.css" >> build\build.log 2>&1
|
%xSH% "unix2dos contrib/i2pd.conf contrib/tunnels.conf contrib/tunnels.d/* contrib/webconsole/style.css" >> build\build.log 2>&1
|
||||||
|
|
||||||
REM Prepare binary signing command if signing key and password provided
|
REM Prepare binary signing command if signing key and password provided
|
||||||
if defined SIGNKEY (
|
if defined SIGN (
|
||||||
if defined SIGNPASS (
|
echo Signing enabled
|
||||||
echo Signing options found
|
|
||||||
|
|
||||||
for %%X in (signtool.exe) do (set xSIGNTOOL=%%~$PATH:X)
|
for %%X in (signtool.exe) do (set xSIGNTOOL=%%~$PATH:X)
|
||||||
if not defined xSIGNTOOL (
|
if not defined xSIGNTOOL (
|
||||||
@@ -66,8 +65,15 @@ if defined SIGNKEY (
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
set "xSIGNOPTS=sign /tr http://timestamp.digicert.com /td sha256 /fd sha256 /f ^"%SIGNKEY%^" /p ^"%SIGNPASS%^""
|
if defined SIGNKEY (
|
||||||
|
set "xSIGNKEYOPTS=/f ^"%SIGNKEY%^""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if defined SIGNPASS (
|
||||||
|
set "xSIGNPASSOPTS=/p ^"%SIGNPASS%^""
|
||||||
|
)
|
||||||
|
|
||||||
|
set "xSIGNOPTS=sign /tr http://timestamp.digicert.com /td sha256 /fd sha256 %xSIGNKEYOPTS% %xSIGNPASSOPTS%"
|
||||||
)
|
)
|
||||||
|
|
||||||
REM starting building
|
REM starting building
|
||||||
|
|||||||
284
build/cmake_modules/GetGitRevisionDescription.cmake
Normal file
284
build/cmake_modules/GetGitRevisionDescription.cmake
Normal file
@@ -0,0 +1,284 @@
|
|||||||
|
# - Returns a version string from Git
|
||||||
|
#
|
||||||
|
# These functions force a re-configure on each git commit so that you can
|
||||||
|
# trust the values of the variables in your build system.
|
||||||
|
#
|
||||||
|
# get_git_head_revision(<refspecvar> <hashvar> [ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR])
|
||||||
|
#
|
||||||
|
# Returns the refspec and sha hash of the current head revision
|
||||||
|
#
|
||||||
|
# git_describe(<var> [<additional arguments to git describe> ...])
|
||||||
|
#
|
||||||
|
# Returns the results of git describe on the source tree, and adjusting
|
||||||
|
# the output so that it tests false if an error occurs.
|
||||||
|
#
|
||||||
|
# git_describe_working_tree(<var> [<additional arguments to git describe> ...])
|
||||||
|
#
|
||||||
|
# Returns the results of git describe on the working tree (--dirty option),
|
||||||
|
# and adjusting the output so that it tests false if an error occurs.
|
||||||
|
#
|
||||||
|
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
|
||||||
|
#
|
||||||
|
# Returns the results of git describe --exact-match on the source tree,
|
||||||
|
# and adjusting the output so that it tests false if there was no exact
|
||||||
|
# matching tag.
|
||||||
|
#
|
||||||
|
# git_local_changes(<var>)
|
||||||
|
#
|
||||||
|
# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes.
|
||||||
|
# Uses the return code of "git diff-index --quiet HEAD --".
|
||||||
|
# Does not regard untracked files.
|
||||||
|
#
|
||||||
|
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||||
|
#
|
||||||
|
# Original Author:
|
||||||
|
# 2009-2020 Ryan Pavlik <ryan.pavlik@gmail.com> <abiryan@ryand.net>
|
||||||
|
# http://academic.cleardefinition.com
|
||||||
|
#
|
||||||
|
# Copyright 2009-2013, Iowa State University.
|
||||||
|
# Copyright 2013-2020, Ryan Pavlik
|
||||||
|
# Copyright 2013-2020, Contributors
|
||||||
|
# SPDX-License-Identifier: BSL-1.0
|
||||||
|
# Distributed under the Boost Software License, Version 1.0.
|
||||||
|
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
# http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
if(__get_git_revision_description)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(__get_git_revision_description YES)
|
||||||
|
|
||||||
|
# We must run the following at "include" time, not at function call time,
|
||||||
|
# to find the path to this module rather than the path to a calling list file
|
||||||
|
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
|
||||||
|
|
||||||
|
# Function _git_find_closest_git_dir finds the next closest .git directory
|
||||||
|
# that is part of any directory in the path defined by _start_dir.
|
||||||
|
# The result is returned in the parent scope variable whose name is passed
|
||||||
|
# as variable _git_dir_var. If no .git directory can be found, the
|
||||||
|
# function returns an empty string via _git_dir_var.
|
||||||
|
#
|
||||||
|
# Example: Given a path C:/bla/foo/bar and assuming C:/bla/.git exists and
|
||||||
|
# neither foo nor bar contain a file/directory .git. This wil return
|
||||||
|
# C:/bla/.git
|
||||||
|
#
|
||||||
|
function(_git_find_closest_git_dir _start_dir _git_dir_var)
|
||||||
|
set(cur_dir "${_start_dir}")
|
||||||
|
set(git_dir "${_start_dir}/.git")
|
||||||
|
while(NOT EXISTS "${git_dir}")
|
||||||
|
# .git dir not found, search parent directories
|
||||||
|
set(git_previous_parent "${cur_dir}")
|
||||||
|
get_filename_component(cur_dir "${cur_dir}" DIRECTORY)
|
||||||
|
if(cur_dir STREQUAL git_previous_parent)
|
||||||
|
# We have reached the root directory, we are not in git
|
||||||
|
set(${_git_dir_var}
|
||||||
|
""
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(git_dir "${cur_dir}/.git")
|
||||||
|
endwhile()
|
||||||
|
set(${_git_dir_var}
|
||||||
|
"${git_dir}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(get_git_head_revision _refspecvar _hashvar)
|
||||||
|
_git_find_closest_git_dir("${CMAKE_CURRENT_SOURCE_DIR}" GIT_DIR)
|
||||||
|
|
||||||
|
if("${ARGN}" STREQUAL "ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR")
|
||||||
|
set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR TRUE)
|
||||||
|
else()
|
||||||
|
set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR FALSE)
|
||||||
|
endif()
|
||||||
|
if(NOT "${GIT_DIR}" STREQUAL "")
|
||||||
|
file(RELATIVE_PATH _relative_to_source_dir "${CMAKE_SOURCE_DIR}"
|
||||||
|
"${GIT_DIR}")
|
||||||
|
if("${_relative_to_source_dir}" MATCHES "[.][.]" AND NOT ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR)
|
||||||
|
# We've gone above the CMake root dir.
|
||||||
|
set(GIT_DIR "")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
if("${GIT_DIR}" STREQUAL "")
|
||||||
|
set(${_refspecvar}
|
||||||
|
"GITDIR-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
set(${_hashvar}
|
||||||
|
"GITDIR-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Check if the current source dir is a git submodule or a worktree.
|
||||||
|
# In both cases .git is a file instead of a directory.
|
||||||
|
#
|
||||||
|
if(NOT IS_DIRECTORY ${GIT_DIR})
|
||||||
|
# The following git command will return a non empty string that
|
||||||
|
# points to the super project working tree if the current
|
||||||
|
# source dir is inside a git submodule.
|
||||||
|
# Otherwise the command will return an empty string.
|
||||||
|
#
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${GIT_EXECUTABLE}" rev-parse
|
||||||
|
--show-superproject-working-tree
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
OUTPUT_VARIABLE out
|
||||||
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if(NOT "${out}" STREQUAL "")
|
||||||
|
# If out is empty, GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a submodule
|
||||||
|
file(READ ${GIT_DIR} submodule)
|
||||||
|
string(REGEX REPLACE "gitdir: (.*)$" "\\1" GIT_DIR_RELATIVE
|
||||||
|
${submodule})
|
||||||
|
string(STRIP ${GIT_DIR_RELATIVE} GIT_DIR_RELATIVE)
|
||||||
|
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
|
||||||
|
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE}
|
||||||
|
ABSOLUTE)
|
||||||
|
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
|
||||||
|
else()
|
||||||
|
# GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a worktree
|
||||||
|
file(READ ${GIT_DIR} worktree_ref)
|
||||||
|
# The .git directory contains a path to the worktree information directory
|
||||||
|
# inside the parent git repo of the worktree.
|
||||||
|
#
|
||||||
|
string(REGEX REPLACE "gitdir: (.*)$" "\\1" git_worktree_dir
|
||||||
|
${worktree_ref})
|
||||||
|
string(STRIP ${git_worktree_dir} git_worktree_dir)
|
||||||
|
_git_find_closest_git_dir("${git_worktree_dir}" GIT_DIR)
|
||||||
|
set(HEAD_SOURCE_FILE "${git_worktree_dir}/HEAD")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
|
||||||
|
endif()
|
||||||
|
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
|
||||||
|
if(NOT EXISTS "${GIT_DATA}")
|
||||||
|
file(MAKE_DIRECTORY "${GIT_DATA}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT EXISTS "${HEAD_SOURCE_FILE}")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(HEAD_FILE "${GIT_DATA}/HEAD")
|
||||||
|
configure_file("${HEAD_SOURCE_FILE}" "${HEAD_FILE}" COPYONLY)
|
||||||
|
|
||||||
|
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
|
||||||
|
"${GIT_DATA}/grabRef.cmake" @ONLY)
|
||||||
|
include("${GIT_DATA}/grabRef.cmake")
|
||||||
|
|
||||||
|
set(${_refspecvar}
|
||||||
|
"${HEAD_REF}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
set(${_hashvar}
|
||||||
|
"${HEAD_HASH}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_describe _var)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
find_package(Git QUIET)
|
||||||
|
endif()
|
||||||
|
get_git_head_revision(refspec hash)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
set(${_var}
|
||||||
|
"GIT-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
if(NOT hash)
|
||||||
|
set(${_var}
|
||||||
|
"HEAD-HASH-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# TODO sanitize
|
||||||
|
#if((${ARGN}" MATCHES "&&") OR
|
||||||
|
# (ARGN MATCHES "||") OR
|
||||||
|
# (ARGN MATCHES "\\;"))
|
||||||
|
# message("Please report the following error to the project!")
|
||||||
|
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
|
||||||
|
#endif()
|
||||||
|
|
||||||
|
#message(STATUS "Arguments to execute_process: ${ARGN}")
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${GIT_EXECUTABLE}" describe --tags --always ${hash} ${ARGN}
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
RESULT_VARIABLE res
|
||||||
|
OUTPUT_VARIABLE out
|
||||||
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if(NOT res EQUAL 0)
|
||||||
|
set(out "${out}-${res}-NOTFOUND")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(${_var}
|
||||||
|
"${out}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_describe_working_tree _var)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
find_package(Git QUIET)
|
||||||
|
endif()
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
set(${_var}
|
||||||
|
"GIT-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${GIT_EXECUTABLE}" describe --dirty ${ARGN}
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
RESULT_VARIABLE res
|
||||||
|
OUTPUT_VARIABLE out
|
||||||
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if(NOT res EQUAL 0)
|
||||||
|
set(out "${out}-${res}-NOTFOUND")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(${_var}
|
||||||
|
"${out}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_get_exact_tag _var)
|
||||||
|
git_describe(out --exact-match ${ARGN})
|
||||||
|
set(${_var}
|
||||||
|
"${out}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_local_changes _var)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
find_package(Git QUIET)
|
||||||
|
endif()
|
||||||
|
get_git_head_revision(refspec hash)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
set(${_var}
|
||||||
|
"GIT-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
if(NOT hash)
|
||||||
|
set(${_var}
|
||||||
|
"HEAD-HASH-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${GIT_EXECUTABLE}" diff-index --quiet HEAD --
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
RESULT_VARIABLE res
|
||||||
|
OUTPUT_VARIABLE out
|
||||||
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if(res EQUAL 0)
|
||||||
|
set(${_var}
|
||||||
|
"CLEAN"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
else()
|
||||||
|
set(${_var}
|
||||||
|
"DIRTY"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
43
build/cmake_modules/GetGitRevisionDescription.cmake.in
Normal file
43
build/cmake_modules/GetGitRevisionDescription.cmake.in
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#
|
||||||
|
# Internal file for GetGitRevisionDescription.cmake
|
||||||
|
#
|
||||||
|
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||||
|
#
|
||||||
|
# Original Author:
|
||||||
|
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||||
|
# http://academic.cleardefinition.com
|
||||||
|
# Iowa State University HCI Graduate Program/VRAC
|
||||||
|
#
|
||||||
|
# Copyright 2009-2012, Iowa State University
|
||||||
|
# Copyright 2011-2015, Contributors
|
||||||
|
# Distributed under the Boost Software License, Version 1.0.
|
||||||
|
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
# http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
# SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
set(HEAD_HASH)
|
||||||
|
|
||||||
|
file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
|
||||||
|
|
||||||
|
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
|
||||||
|
if(HEAD_CONTENTS MATCHES "ref")
|
||||||
|
# named branch
|
||||||
|
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
|
||||||
|
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
|
||||||
|
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
|
||||||
|
else()
|
||||||
|
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
|
||||||
|
file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
|
||||||
|
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
|
||||||
|
set(HEAD_HASH "${CMAKE_MATCH_1}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
# detached HEAD
|
||||||
|
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT HEAD_HASH)
|
||||||
|
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
|
||||||
|
string(STRIP "${HEAD_HASH}" HEAD_HASH)
|
||||||
|
endif()
|
||||||
@@ -61,7 +61,7 @@ set(archdetect_c_code "
|
|||||||
#else
|
#else
|
||||||
#error cmake_ARCH mips
|
#error cmake_ARCH mips
|
||||||
#endif
|
#endif
|
||||||
#elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) \\
|
#elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) || defined(__POWERPC__) \\
|
||||||
|| defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) \\
|
|| defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) \\
|
||||||
|| defined(_M_MPPC) || defined(_M_PPC)
|
|| defined(_M_MPPC) || defined(_M_PPC)
|
||||||
#if defined(__ppc64__) || defined(__powerpc64__) || defined(__64BIT__)
|
#if defined(__ppc64__) || defined(__powerpc64__) || defined(__64BIT__)
|
||||||
|
|||||||
@@ -1,5 +1,18 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2017-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
|
||||||
|
#
|
||||||
|
|
||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
LABEL authors "Mikal Villa <mikal@sigterm.no>, Darknet Villain <supervillain@riseup.net>"
|
LABEL authors="Mikal Villa <mikal@sigterm.no>, Darknet Villain <supervillain@riseup.net>"
|
||||||
|
LABEL maintainer="R4SAS <r4sas@i2pmail.org>"
|
||||||
|
|
||||||
|
LABEL org.opencontainers.image.source=https://github.com/PurpleI2P/i2pd
|
||||||
|
LABEL org.opencontainers.image.documentation=https://i2pd.readthedocs.io/en/latest/
|
||||||
|
LABEL org.opencontainers.image.licenses=BSD3
|
||||||
|
|
||||||
# Expose git branch, tag and URL variables as arguments
|
# Expose git branch, tag and URL variables as arguments
|
||||||
ARG GIT_BRANCH="openssl"
|
ARG GIT_BRANCH="openssl"
|
||||||
@@ -11,27 +24,28 @@ ENV REPO_URL=${REPO_URL}
|
|||||||
|
|
||||||
ENV I2PD_HOME="/home/i2pd"
|
ENV I2PD_HOME="/home/i2pd"
|
||||||
ENV DATA_DIR="${I2PD_HOME}/data"
|
ENV DATA_DIR="${I2PD_HOME}/data"
|
||||||
ENV DEFAULT_ARGS=" --datadir=$DATA_DIR --reseed.verify=true --upnp.enabled=false --http.enabled=true --http.address=0.0.0.0 --httpproxy.enabled=true --httpproxy.address=0.0.0.0 --socksproxy.enabled=true --socksproxy.address=0.0.0.0 --sam.enabled=true --sam.address=0.0.0.0"
|
ENV DEFAULT_ARGS=" --datadir=$DATA_DIR"
|
||||||
|
|
||||||
RUN mkdir -p "$I2PD_HOME" "$DATA_DIR" \
|
RUN mkdir -p "$I2PD_HOME" "$DATA_DIR" \
|
||||||
&& adduser -S -h "$I2PD_HOME" i2pd \
|
&& adduser -S -h "$I2PD_HOME" i2pd \
|
||||||
&& chown -R i2pd:nobody "$I2PD_HOME"
|
&& chown -R i2pd:nobody "$I2PD_HOME"
|
||||||
|
|
||||||
#
|
|
||||||
|
# 1. Building binary
|
||||||
# Each RUN is a layer, adding the dependencies and building i2pd in one layer takes around 8-900Mb, so to keep the
|
# Each RUN is a layer, adding the dependencies and building i2pd in one layer takes around 8-900Mb, so to keep the
|
||||||
# image under 20mb we need to remove all the build dependencies in the same "RUN" / layer.
|
# image under 20mb we need to remove all the build dependencies in the same "RUN" / layer.
|
||||||
#
|
#
|
||||||
|
|
||||||
# 1. install deps, clone and build.
|
# 1. install deps, clone and build.
|
||||||
# 2. strip binaries.
|
# 2. strip binaries.
|
||||||
# 3. Purge all dependencies and other unrelated packages, including build directory.
|
# 3. Purge all dependencies and other unrelated packages, including build directory.
|
||||||
|
|
||||||
RUN apk update \
|
RUN apk update \
|
||||||
&& apk --no-cache --virtual build-dependendencies add make gcc g++ libtool zlib-dev boost-dev build-base openssl-dev openssl miniupnpc-dev git \
|
&& apk --no-cache --virtual build-dependendencies add make gcc g++ libtool zlib-dev boost-dev build-base openssl-dev openssl miniupnpc-dev git \
|
||||||
&& mkdir -p /tmp/build \
|
&& mkdir -p /tmp/build \
|
||||||
&& cd /tmp/build && git clone -b ${GIT_BRANCH} ${REPO_URL} \
|
&& cd /tmp/build && git clone -b ${GIT_BRANCH} ${REPO_URL} \
|
||||||
&& cd i2pd \
|
&& cd i2pd \
|
||||||
&& if [ -n "${GIT_TAG}" ]; then git checkout tags/${GIT_TAG}; fi \
|
&& if [ -n "${GIT_TAG}" ]; then git checkout tags/${GIT_TAG}; fi \
|
||||||
&& make USE_UPNP=yes \
|
&& make -j$(nproc) USE_UPNP=yes \
|
||||||
&& cp -R contrib/certificates /i2pd_certificates \
|
&& cp -R contrib/certificates /i2pd_certificates \
|
||||||
&& mkdir -p /usr/local/bin \
|
&& mkdir -p /usr/local/bin \
|
||||||
&& mv i2pd /usr/local/bin \
|
&& mv i2pd /usr/local/bin \
|
||||||
@@ -45,6 +59,9 @@ RUN apk update \
|
|||||||
# 2. Adding required libraries to run i2pd to ensure it will run.
|
# 2. Adding required libraries to run i2pd to ensure it will run.
|
||||||
RUN apk --no-cache add boost-filesystem boost-system boost-program_options boost-date_time boost-thread boost-iostreams openssl miniupnpc musl-utils libstdc++
|
RUN apk --no-cache add boost-filesystem boost-system boost-program_options boost-date_time boost-thread boost-iostreams openssl miniupnpc musl-utils libstdc++
|
||||||
|
|
||||||
|
# 3. Copy preconfigured config file and entrypoint
|
||||||
|
COPY i2pd-docker.conf "$I2PD_HOME/i2pd.conf"
|
||||||
|
RUN chown i2pd:nobody "$I2PD_HOME/i2pd.conf"
|
||||||
COPY entrypoint.sh /entrypoint.sh
|
COPY entrypoint.sh /entrypoint.sh
|
||||||
RUN chmod a+x /entrypoint.sh
|
RUN chmod a+x /entrypoint.sh
|
||||||
|
|
||||||
|
|||||||
52
contrib/docker/i2pd-docker.conf
Normal file
52
contrib/docker/i2pd-docker.conf
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
## Preconfigured i2pd configuration file for a Docker container
|
||||||
|
## See https://i2pd.readthedocs.io/en/latest/user-guide/configuration/
|
||||||
|
## for more options you can use in this file.
|
||||||
|
|
||||||
|
## Note that for exposing ports outside of container you need to bind all services to 0.0.0.0
|
||||||
|
|
||||||
|
log = file
|
||||||
|
loglevel = none
|
||||||
|
|
||||||
|
ipv4 = true
|
||||||
|
ipv6 = false
|
||||||
|
|
||||||
|
# bandwidth = L
|
||||||
|
# notransit = false
|
||||||
|
# floodfill = false
|
||||||
|
|
||||||
|
[ntcp2]
|
||||||
|
enabled = true
|
||||||
|
published = true
|
||||||
|
|
||||||
|
[ssu2]
|
||||||
|
enabled = true
|
||||||
|
published = true
|
||||||
|
|
||||||
|
[http]
|
||||||
|
enabled = true
|
||||||
|
address = 0.0.0.0
|
||||||
|
port = 7070
|
||||||
|
|
||||||
|
[httpproxy]
|
||||||
|
enabled = true
|
||||||
|
address = 0.0.0.0
|
||||||
|
port = 4444
|
||||||
|
|
||||||
|
[socksproxy]
|
||||||
|
enabled = true
|
||||||
|
address = 0.0.0.0
|
||||||
|
port = 4447
|
||||||
|
|
||||||
|
[sam]
|
||||||
|
enabled = true
|
||||||
|
address = 0.0.0.0
|
||||||
|
port = 7656
|
||||||
|
|
||||||
|
[upnp]
|
||||||
|
enabled = false
|
||||||
|
|
||||||
|
[reseed]
|
||||||
|
verify = true
|
||||||
|
|
||||||
|
[limits]
|
||||||
|
# transittunnels = 2500
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
# i2pd
|
# i2pd
|
||||||
# Copyright (C) 2021 PurpleI2P team
|
# Copyright (C) 2021-2022 PurpleI2P team
|
||||||
# This file is distributed under the same license as the i2pd package.
|
# This file is distributed under the same license as the i2pd package.
|
||||||
# R4SAS <r4sas@i2pmail.org>, 2021.
|
# R4SAS <r4sas@i2pmail.org>, 2021-2022.
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: i2pd\n"
|
"Project-Id-Version: i2pd\n"
|
||||||
"Report-Msgid-Bugs-To: https://github.com/PurpleI2P/i2pd/issues\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"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
@@ -18,706 +18,712 @@ msgstr ""
|
|||||||
"X-Poedit-SearchPath-0: daemon/HTTPServer.cpp\n"
|
"X-Poedit-SearchPath-0: daemon/HTTPServer.cpp\n"
|
||||||
"X-Poedit-SearchPath-1: libi2pd_client/HTTPProxy.cpp\n"
|
"X-Poedit-SearchPath-1: libi2pd_client/HTTPProxy.cpp\n"
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:177
|
#: daemon/HTTPServer.cpp:108
|
||||||
msgid "day"
|
msgid "day"
|
||||||
msgid_plural "days"
|
msgid_plural "days"
|
||||||
msgstr[0] ""
|
msgstr[0] ""
|
||||||
msgstr[1] ""
|
msgstr[1] ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:181
|
#: daemon/HTTPServer.cpp:112
|
||||||
msgid "hour"
|
msgid "hour"
|
||||||
msgid_plural "hours"
|
msgid_plural "hours"
|
||||||
msgstr[0] ""
|
msgstr[0] ""
|
||||||
msgstr[1] ""
|
msgstr[1] ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:185
|
#: daemon/HTTPServer.cpp:116
|
||||||
msgid "minute"
|
msgid "minute"
|
||||||
msgid_plural "minutes"
|
msgid_plural "minutes"
|
||||||
msgstr[0] ""
|
msgstr[0] ""
|
||||||
msgstr[1] ""
|
msgstr[1] ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:188
|
#: daemon/HTTPServer.cpp:119
|
||||||
msgid "second"
|
msgid "second"
|
||||||
msgid_plural "seconds"
|
msgid_plural "seconds"
|
||||||
msgstr[0] ""
|
msgstr[0] ""
|
||||||
msgstr[1] ""
|
msgstr[1] ""
|
||||||
|
|
||||||
#. tr: Kibibit
|
#. tr: Kibibit
|
||||||
#: daemon/HTTPServer.cpp:196 daemon/HTTPServer.cpp:224
|
#: daemon/HTTPServer.cpp:127 daemon/HTTPServer.cpp:155
|
||||||
msgid "KiB"
|
msgid "KiB"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. tr: Mebibit
|
#. tr: Mebibit
|
||||||
#: daemon/HTTPServer.cpp:198
|
#: daemon/HTTPServer.cpp:129
|
||||||
msgid "MiB"
|
msgid "MiB"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. tr: Gibibit
|
#. tr: Gibibit
|
||||||
#: daemon/HTTPServer.cpp:200
|
#: daemon/HTTPServer.cpp:131
|
||||||
msgid "GiB"
|
msgid "GiB"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:217
|
#: daemon/HTTPServer.cpp:148
|
||||||
msgid "building"
|
msgid "building"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:218
|
#: daemon/HTTPServer.cpp:149
|
||||||
msgid "failed"
|
msgid "failed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:219
|
#: daemon/HTTPServer.cpp:150
|
||||||
msgid "expiring"
|
msgid "expiring"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:220
|
#: daemon/HTTPServer.cpp:151
|
||||||
msgid "established"
|
msgid "established"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:221
|
#: daemon/HTTPServer.cpp:152
|
||||||
msgid "unknown"
|
msgid "unknown"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:223
|
#: daemon/HTTPServer.cpp:154
|
||||||
msgid "exploratory"
|
msgid "exploratory"
|
||||||
msgstr ""
|
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"
|
msgid "<b>i2pd</b> webconsole"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:262
|
#: daemon/HTTPServer.cpp:193
|
||||||
msgid "Main page"
|
msgid "Main page"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:263 daemon/HTTPServer.cpp:725
|
#: daemon/HTTPServer.cpp:194 daemon/HTTPServer.cpp:700
|
||||||
msgid "Router commands"
|
msgid "Router commands"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:264 daemon/HTTPServer.cpp:448
|
#: daemon/HTTPServer.cpp:195 daemon/HTTPServer.cpp:382
|
||||||
#: daemon/HTTPServer.cpp:460
|
#: daemon/HTTPServer.cpp:394
|
||||||
msgid "Local Destinations"
|
msgid "Local Destinations"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:266 daemon/HTTPServer.cpp:418
|
#: daemon/HTTPServer.cpp:197 daemon/HTTPServer.cpp:352
|
||||||
#: daemon/HTTPServer.cpp:504 daemon/HTTPServer.cpp:510
|
#: daemon/HTTPServer.cpp:438 daemon/HTTPServer.cpp:444
|
||||||
#: daemon/HTTPServer.cpp:641 daemon/HTTPServer.cpp:684
|
#: daemon/HTTPServer.cpp:597 daemon/HTTPServer.cpp:640
|
||||||
#: daemon/HTTPServer.cpp:688
|
#: daemon/HTTPServer.cpp:644
|
||||||
msgid "LeaseSets"
|
msgid "LeaseSets"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:268 daemon/HTTPServer.cpp:694
|
#: daemon/HTTPServer.cpp:199 daemon/HTTPServer.cpp:650
|
||||||
msgid "Tunnels"
|
msgid "Tunnels"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:269 daemon/HTTPServer.cpp:425
|
#: daemon/HTTPServer.cpp:201 daemon/HTTPServer.cpp:359
|
||||||
#: daemon/HTTPServer.cpp:787 daemon/HTTPServer.cpp:803
|
#: daemon/HTTPServer.cpp:770 daemon/HTTPServer.cpp:786
|
||||||
msgid "Transit Tunnels"
|
msgid "Transit Tunnels"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:270 daemon/HTTPServer.cpp:852
|
#: daemon/HTTPServer.cpp:203 daemon/HTTPServer.cpp:839
|
||||||
msgid "Transports"
|
msgid "Transports"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:271
|
#: daemon/HTTPServer.cpp:204
|
||||||
msgid "I2P tunnels"
|
msgid "I2P tunnels"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:273 daemon/HTTPServer.cpp:914
|
#: daemon/HTTPServer.cpp:206 daemon/HTTPServer.cpp:908
|
||||||
#: daemon/HTTPServer.cpp:924
|
#: daemon/HTTPServer.cpp:918
|
||||||
msgid "SAM sessions"
|
msgid "SAM sessions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:289 daemon/HTTPServer.cpp:1306
|
#: daemon/HTTPServer.cpp:222 daemon/HTTPServer.cpp:1302
|
||||||
#: daemon/HTTPServer.cpp:1309 daemon/HTTPServer.cpp:1312
|
#: daemon/HTTPServer.cpp:1305 daemon/HTTPServer.cpp:1308
|
||||||
#: daemon/HTTPServer.cpp:1326 daemon/HTTPServer.cpp:1371
|
#: daemon/HTTPServer.cpp:1322 daemon/HTTPServer.cpp:1367
|
||||||
#: daemon/HTTPServer.cpp:1374 daemon/HTTPServer.cpp:1377
|
#: daemon/HTTPServer.cpp:1370 daemon/HTTPServer.cpp:1373
|
||||||
msgid "ERROR"
|
msgid "ERROR"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:296
|
#: daemon/HTTPServer.cpp:229
|
||||||
msgid "OK"
|
msgid "OK"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:297
|
#: daemon/HTTPServer.cpp:230
|
||||||
msgid "Testing"
|
msgid "Testing"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:298
|
#: daemon/HTTPServer.cpp:231
|
||||||
msgid "Firewalled"
|
msgid "Firewalled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:299 daemon/HTTPServer.cpp:320
|
#: daemon/HTTPServer.cpp:232 daemon/HTTPServer.cpp:253
|
||||||
#: daemon/HTTPServer.cpp:406
|
#: daemon/HTTPServer.cpp:325
|
||||||
msgid "Unknown"
|
msgid "Unknown"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:300 daemon/HTTPServer.cpp:435
|
#: daemon/HTTPServer.cpp:233 daemon/HTTPServer.cpp:369
|
||||||
#: daemon/HTTPServer.cpp:436 daemon/HTTPServer.cpp:982
|
#: daemon/HTTPServer.cpp:370 daemon/HTTPServer.cpp:976
|
||||||
#: daemon/HTTPServer.cpp:991
|
#: daemon/HTTPServer.cpp:985
|
||||||
msgid "Proxy"
|
msgid "Proxy"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:301
|
#: daemon/HTTPServer.cpp:234
|
||||||
msgid "Mesh"
|
msgid "Mesh"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:304
|
#: daemon/HTTPServer.cpp:237
|
||||||
msgid "Error"
|
msgid "Error"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:308
|
#: daemon/HTTPServer.cpp:241
|
||||||
msgid "Clock skew"
|
msgid "Clock skew"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:311
|
#: daemon/HTTPServer.cpp:244
|
||||||
msgid "Offline"
|
msgid "Offline"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:314
|
#: daemon/HTTPServer.cpp:247
|
||||||
msgid "Symmetric NAT"
|
msgid "Symmetric NAT"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:326
|
#: daemon/HTTPServer.cpp:259
|
||||||
msgid "Uptime"
|
msgid "Uptime"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:329
|
#: daemon/HTTPServer.cpp:262
|
||||||
msgid "Network status"
|
msgid "Network status"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:334
|
#: daemon/HTTPServer.cpp:267
|
||||||
msgid "Network status v6"
|
msgid "Network status v6"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:340 daemon/HTTPServer.cpp:347
|
#: daemon/HTTPServer.cpp:273 daemon/HTTPServer.cpp:280
|
||||||
msgid "Stopping in"
|
msgid "Stopping in"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:354
|
#: daemon/HTTPServer.cpp:287
|
||||||
msgid "Family"
|
msgid "Family"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:355
|
#: daemon/HTTPServer.cpp:288
|
||||||
msgid "Tunnel creation success rate"
|
msgid "Tunnel creation success rate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:356
|
#: daemon/HTTPServer.cpp:289
|
||||||
msgid "Received"
|
msgid "Received"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. tr: Kibibit/s
|
#. tr: Kibibit/s
|
||||||
#: daemon/HTTPServer.cpp:358 daemon/HTTPServer.cpp:361
|
#: daemon/HTTPServer.cpp:291 daemon/HTTPServer.cpp:294
|
||||||
#: daemon/HTTPServer.cpp:364
|
#: daemon/HTTPServer.cpp:297
|
||||||
msgid "KiB/s"
|
msgid "KiB/s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:359
|
#: daemon/HTTPServer.cpp:292
|
||||||
msgid "Sent"
|
msgid "Sent"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:362
|
#: daemon/HTTPServer.cpp:295
|
||||||
msgid "Transit"
|
msgid "Transit"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:365
|
#: daemon/HTTPServer.cpp:298
|
||||||
msgid "Data path"
|
msgid "Data path"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:368
|
#: daemon/HTTPServer.cpp:301
|
||||||
msgid "Hidden content. Press on text to see."
|
msgid "Hidden content. Press on text to see."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:371
|
#: daemon/HTTPServer.cpp:304
|
||||||
msgid "Router Ident"
|
msgid "Router Ident"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:373
|
#: daemon/HTTPServer.cpp:306
|
||||||
msgid "Router Family"
|
msgid "Router Family"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:374
|
#: daemon/HTTPServer.cpp:307
|
||||||
msgid "Router Caps"
|
msgid "Router Caps"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:375
|
#: daemon/HTTPServer.cpp:308
|
||||||
msgid "Version"
|
msgid "Version"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:376
|
#: daemon/HTTPServer.cpp:309
|
||||||
msgid "Our external address"
|
msgid "Our external address"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:384
|
#: daemon/HTTPServer.cpp:337
|
||||||
msgid "supported"
|
msgid "supported"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:416
|
#: daemon/HTTPServer.cpp:350
|
||||||
msgid "Routers"
|
msgid "Routers"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:417
|
#: daemon/HTTPServer.cpp:351
|
||||||
msgid "Floodfills"
|
msgid "Floodfills"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:424 daemon/HTTPServer.cpp:968
|
#: daemon/HTTPServer.cpp:358 daemon/HTTPServer.cpp:962
|
||||||
msgid "Client Tunnels"
|
msgid "Client Tunnels"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:434
|
#: daemon/HTTPServer.cpp:368
|
||||||
msgid "Services"
|
msgid "Services"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:435 daemon/HTTPServer.cpp:436
|
#: daemon/HTTPServer.cpp:369 daemon/HTTPServer.cpp:370
|
||||||
#: daemon/HTTPServer.cpp:437 daemon/HTTPServer.cpp:438
|
#: daemon/HTTPServer.cpp:371 daemon/HTTPServer.cpp:372
|
||||||
#: daemon/HTTPServer.cpp:439 daemon/HTTPServer.cpp:440
|
#: daemon/HTTPServer.cpp:373 daemon/HTTPServer.cpp:374
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:435 daemon/HTTPServer.cpp:436
|
#: daemon/HTTPServer.cpp:369 daemon/HTTPServer.cpp:370
|
||||||
#: daemon/HTTPServer.cpp:437 daemon/HTTPServer.cpp:438
|
#: daemon/HTTPServer.cpp:371 daemon/HTTPServer.cpp:372
|
||||||
#: daemon/HTTPServer.cpp:439 daemon/HTTPServer.cpp:440
|
#: daemon/HTTPServer.cpp:373 daemon/HTTPServer.cpp:374
|
||||||
msgid "Disabled"
|
msgid "Disabled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:483
|
#: daemon/HTTPServer.cpp:417
|
||||||
msgid "Encrypted B33 address"
|
msgid "Encrypted B33 address"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:492
|
#: daemon/HTTPServer.cpp:426
|
||||||
msgid "Address registration line"
|
msgid "Address registration line"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:497
|
#: daemon/HTTPServer.cpp:431
|
||||||
msgid "Domain"
|
msgid "Domain"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:498
|
#: daemon/HTTPServer.cpp:432
|
||||||
msgid "Generate"
|
msgid "Generate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:499
|
#: daemon/HTTPServer.cpp:433
|
||||||
msgid ""
|
msgid ""
|
||||||
"<b>Note:</b> result string can be used only for registering 2LD domains "
|
"<b>Note:</b> result string can be used only for registering 2LD domains "
|
||||||
"(example.i2p). For registering subdomains please use i2pd-tools."
|
"(example.i2p). For registering subdomains please use i2pd-tools."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:505
|
#: daemon/HTTPServer.cpp:439
|
||||||
msgid "Address"
|
msgid "Address"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:505
|
#: daemon/HTTPServer.cpp:439
|
||||||
msgid "Type"
|
msgid "Type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:505
|
#: daemon/HTTPServer.cpp:439
|
||||||
msgid "EncType"
|
msgid "EncType"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:515 daemon/HTTPServer.cpp:699
|
#: daemon/HTTPServer.cpp:449 daemon/HTTPServer.cpp:655
|
||||||
msgid "Inbound tunnels"
|
msgid "Inbound tunnels"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. tr: Milliseconds
|
#. tr: Milliseconds
|
||||||
#: daemon/HTTPServer.cpp:520 daemon/HTTPServer.cpp:530
|
#: daemon/HTTPServer.cpp:464 daemon/HTTPServer.cpp:484
|
||||||
#: daemon/HTTPServer.cpp:704 daemon/HTTPServer.cpp:714
|
#: daemon/HTTPServer.cpp:669 daemon/HTTPServer.cpp:689
|
||||||
msgid "ms"
|
msgid "ms"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:525 daemon/HTTPServer.cpp:709
|
#: daemon/HTTPServer.cpp:469 daemon/HTTPServer.cpp:674
|
||||||
msgid "Outbound tunnels"
|
msgid "Outbound tunnels"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:537
|
#: daemon/HTTPServer.cpp:491
|
||||||
msgid "Tags"
|
msgid "Tags"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:537
|
#: daemon/HTTPServer.cpp:491
|
||||||
msgid "Incoming"
|
msgid "Incoming"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:544 daemon/HTTPServer.cpp:547
|
#: daemon/HTTPServer.cpp:498 daemon/HTTPServer.cpp:501
|
||||||
msgid "Outgoing"
|
msgid "Outgoing"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:545 daemon/HTTPServer.cpp:561
|
#: daemon/HTTPServer.cpp:499 daemon/HTTPServer.cpp:515
|
||||||
msgid "Destination"
|
msgid "Destination"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:545
|
#: daemon/HTTPServer.cpp:499
|
||||||
msgid "Amount"
|
msgid "Amount"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:552
|
#: daemon/HTTPServer.cpp:506
|
||||||
msgid "Incoming Tags"
|
msgid "Incoming Tags"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:560 daemon/HTTPServer.cpp:563
|
#: daemon/HTTPServer.cpp:514 daemon/HTTPServer.cpp:517
|
||||||
msgid "Tags sessions"
|
msgid "Tags sessions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:561
|
#: daemon/HTTPServer.cpp:515
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:570 daemon/HTTPServer.cpp:626
|
#: daemon/HTTPServer.cpp:524 daemon/HTTPServer.cpp:582
|
||||||
msgid "Local Destination"
|
msgid "Local Destination"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:580 daemon/HTTPServer.cpp:947
|
#: daemon/HTTPServer.cpp:535 daemon/HTTPServer.cpp:941
|
||||||
msgid "Streams"
|
msgid "Streams"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:602
|
#: daemon/HTTPServer.cpp:558
|
||||||
msgid "Close stream"
|
msgid "Close stream"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:631
|
#: daemon/HTTPServer.cpp:587
|
||||||
msgid "I2CP session not found"
|
msgid "I2CP session not found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:634
|
#: daemon/HTTPServer.cpp:590
|
||||||
msgid "I2CP is not enabled"
|
msgid "I2CP is not enabled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:660
|
#: daemon/HTTPServer.cpp:616
|
||||||
msgid "Invalid"
|
msgid "Invalid"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:663
|
#: daemon/HTTPServer.cpp:619
|
||||||
msgid "Store type"
|
msgid "Store type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:664
|
#: daemon/HTTPServer.cpp:620
|
||||||
msgid "Expires"
|
msgid "Expires"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:669
|
#: daemon/HTTPServer.cpp:625
|
||||||
msgid "Non Expired Leases"
|
msgid "Non Expired Leases"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:672
|
#: daemon/HTTPServer.cpp:628
|
||||||
msgid "Gateway"
|
msgid "Gateway"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:673
|
#: daemon/HTTPServer.cpp:629
|
||||||
msgid "TunnelID"
|
msgid "TunnelID"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:674
|
#: daemon/HTTPServer.cpp:630
|
||||||
msgid "EndDate"
|
msgid "EndDate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:684
|
#: daemon/HTTPServer.cpp:640
|
||||||
msgid "not floodfill"
|
msgid "not floodfill"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:695
|
#: daemon/HTTPServer.cpp:651
|
||||||
msgid "Queue size"
|
msgid "Queue size"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:726
|
#: daemon/HTTPServer.cpp:701
|
||||||
msgid "Run peer test"
|
msgid "Run peer test"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:731
|
#: daemon/HTTPServer.cpp:706
|
||||||
msgid "Decline transit tunnels"
|
msgid "Decline transit tunnels"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:733
|
#: daemon/HTTPServer.cpp:708
|
||||||
msgid "Accept transit tunnels"
|
msgid "Accept transit tunnels"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:737 daemon/HTTPServer.cpp:742
|
#: daemon/HTTPServer.cpp:712 daemon/HTTPServer.cpp:717
|
||||||
msgid "Cancel graceful shutdown"
|
msgid "Cancel graceful shutdown"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:739 daemon/HTTPServer.cpp:744
|
#: daemon/HTTPServer.cpp:714 daemon/HTTPServer.cpp:719
|
||||||
msgid "Start graceful shutdown"
|
msgid "Start graceful shutdown"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:747
|
#: daemon/HTTPServer.cpp:722
|
||||||
msgid "Force shutdown"
|
msgid "Force shutdown"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:748
|
#: daemon/HTTPServer.cpp:723
|
||||||
msgid "Reload external CSS styles"
|
msgid "Reload external CSS styles"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:751
|
#: daemon/HTTPServer.cpp:726
|
||||||
msgid ""
|
msgid ""
|
||||||
"<b>Note:</b> any action done here are not persistent and not changes your "
|
"<b>Note:</b> any action done here are not persistent and not changes your "
|
||||||
"config files."
|
"config files."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:753
|
#: daemon/HTTPServer.cpp:728
|
||||||
msgid "Logging level"
|
msgid "Logging level"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:761
|
#: daemon/HTTPServer.cpp:736
|
||||||
msgid "Transit tunnels limit"
|
msgid "Transit tunnels limit"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:766 daemon/HTTPServer.cpp:778
|
#: daemon/HTTPServer.cpp:741 daemon/HTTPServer.cpp:760
|
||||||
msgid "Change"
|
msgid "Change"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:770
|
#: daemon/HTTPServer.cpp:748
|
||||||
msgid "Change language"
|
msgid "Change language"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:803
|
#: daemon/HTTPServer.cpp:786
|
||||||
msgid "no transit tunnels currently built"
|
msgid "no transit tunnels currently built"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:908 daemon/HTTPServer.cpp:931
|
#: daemon/HTTPServer.cpp:902 daemon/HTTPServer.cpp:925
|
||||||
msgid "SAM disabled"
|
msgid "SAM disabled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:924
|
#: daemon/HTTPServer.cpp:918
|
||||||
msgid "no sessions currently running"
|
msgid "no sessions currently running"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:937
|
#: daemon/HTTPServer.cpp:931
|
||||||
msgid "SAM session not found"
|
msgid "SAM session not found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:942
|
#: daemon/HTTPServer.cpp:936
|
||||||
msgid "SAM Session"
|
msgid "SAM Session"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:999
|
#: daemon/HTTPServer.cpp:993
|
||||||
msgid "Server Tunnels"
|
msgid "Server Tunnels"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:1015
|
#: daemon/HTTPServer.cpp:1009
|
||||||
msgid "Client Forwards"
|
msgid "Client Forwards"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:1029
|
#: daemon/HTTPServer.cpp:1023
|
||||||
msgid "Server Forwards"
|
msgid "Server Forwards"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:1227
|
#: daemon/HTTPServer.cpp:1223
|
||||||
msgid "Unknown page"
|
msgid "Unknown page"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:1246
|
#: daemon/HTTPServer.cpp:1242
|
||||||
msgid "Invalid token"
|
msgid "Invalid token"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:1304 daemon/HTTPServer.cpp:1361
|
#: daemon/HTTPServer.cpp:1300 daemon/HTTPServer.cpp:1357
|
||||||
#: daemon/HTTPServer.cpp:1401
|
#: daemon/HTTPServer.cpp:1397
|
||||||
msgid "SUCCESS"
|
msgid "SUCCESS"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:1304
|
#: daemon/HTTPServer.cpp:1300
|
||||||
msgid "Stream closed"
|
msgid "Stream closed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:1306
|
#: daemon/HTTPServer.cpp:1302
|
||||||
msgid "Stream not found or already was closed"
|
msgid "Stream not found or already was closed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:1309
|
#: daemon/HTTPServer.cpp:1305
|
||||||
msgid "Destination not found"
|
msgid "Destination not found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:1312
|
#: daemon/HTTPServer.cpp:1308
|
||||||
msgid "StreamID can't be null"
|
msgid "StreamID can't be null"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:1314 daemon/HTTPServer.cpp:1379
|
#: daemon/HTTPServer.cpp:1310 daemon/HTTPServer.cpp:1375
|
||||||
msgid "Return to destination page"
|
msgid "Return to destination page"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:1315 daemon/HTTPServer.cpp:1328
|
#: daemon/HTTPServer.cpp:1311 daemon/HTTPServer.cpp:1324
|
||||||
#: daemon/HTTPServer.cpp:1403
|
#: daemon/HTTPServer.cpp:1399
|
||||||
msgid "You will be redirected in 5 seconds"
|
msgid "You will be redirected in 5 seconds"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:1326
|
#: daemon/HTTPServer.cpp:1322
|
||||||
msgid "Transit tunnels count must not exceed 65535"
|
msgid "Transit tunnels count must not exceed 65535"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:1327 daemon/HTTPServer.cpp:1402
|
#: daemon/HTTPServer.cpp:1323 daemon/HTTPServer.cpp:1398
|
||||||
msgid "Back to commands list"
|
msgid "Back to commands list"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:1363
|
#: daemon/HTTPServer.cpp:1359
|
||||||
msgid "Register at reg.i2p"
|
msgid "Register at reg.i2p"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:1364
|
#: daemon/HTTPServer.cpp:1360
|
||||||
msgid "Description"
|
msgid "Description"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:1364
|
#: daemon/HTTPServer.cpp:1360
|
||||||
msgid "A bit information about service on domain"
|
msgid "A bit information about service on domain"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:1365
|
#: daemon/HTTPServer.cpp:1361
|
||||||
msgid "Submit"
|
msgid "Submit"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:1371
|
#: daemon/HTTPServer.cpp:1367
|
||||||
msgid "Domain can't end with .b32.i2p"
|
msgid "Domain can't end with .b32.i2p"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:1374
|
#: daemon/HTTPServer.cpp:1370
|
||||||
msgid "Domain must end with .i2p"
|
msgid "Domain must end with .i2p"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:1377
|
#: daemon/HTTPServer.cpp:1373
|
||||||
msgid "Such destination is not found"
|
msgid "Such destination is not found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:1397
|
#: daemon/HTTPServer.cpp:1393
|
||||||
msgid "Unknown command"
|
msgid "Unknown command"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: daemon/HTTPServer.cpp:1401
|
#: daemon/HTTPServer.cpp:1397
|
||||||
msgid "Command accepted"
|
msgid "Command accepted"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:157
|
#: libi2pd_client/HTTPProxy.cpp:163
|
||||||
msgid "Proxy error"
|
msgid "Proxy error"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:165
|
#: libi2pd_client/HTTPProxy.cpp:171
|
||||||
msgid "Proxy info"
|
msgid "Proxy info"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:173
|
#: libi2pd_client/HTTPProxy.cpp:179
|
||||||
msgid "Proxy error: Host not found"
|
msgid "Proxy error: Host not found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:174
|
#: libi2pd_client/HTTPProxy.cpp:180
|
||||||
msgid "Remote host not found in router's addressbook"
|
msgid "Remote host not found in router's addressbook"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:175
|
#: libi2pd_client/HTTPProxy.cpp:181
|
||||||
msgid "You may try to find this host on jump services below"
|
msgid "You may try to find this host on jump services below"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:273 libi2pd_client/HTTPProxy.cpp:288
|
#: libi2pd_client/HTTPProxy.cpp:282 libi2pd_client/HTTPProxy.cpp:297
|
||||||
#: libi2pd_client/HTTPProxy.cpp:322 libi2pd_client/HTTPProxy.cpp:365
|
#: libi2pd_client/HTTPProxy.cpp:331 libi2pd_client/HTTPProxy.cpp:372
|
||||||
msgid "Invalid request"
|
msgid "Invalid request"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:273
|
#: libi2pd_client/HTTPProxy.cpp:282
|
||||||
msgid "Proxy unable to parse your request"
|
msgid "Proxy unable to parse your request"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:288
|
#: libi2pd_client/HTTPProxy.cpp:297
|
||||||
msgid "addresshelper is not supported"
|
msgid "addresshelper is not supported"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:297 libi2pd_client/HTTPProxy.cpp:306
|
#: libi2pd_client/HTTPProxy.cpp:306 libi2pd_client/HTTPProxy.cpp:315
|
||||||
#: libi2pd_client/HTTPProxy.cpp:385
|
#: libi2pd_client/HTTPProxy.cpp:392
|
||||||
msgid "Host"
|
msgid "Host"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:297
|
#: libi2pd_client/HTTPProxy.cpp:306
|
||||||
msgid "added to router's addressbook from helper"
|
msgid "added to router's addressbook from helper"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:298
|
#: libi2pd_client/HTTPProxy.cpp:307
|
||||||
msgid "Click here to proceed:"
|
msgid "Click here to proceed:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:298 libi2pd_client/HTTPProxy.cpp:308
|
#: libi2pd_client/HTTPProxy.cpp:307 libi2pd_client/HTTPProxy.cpp:317
|
||||||
msgid "Continue"
|
msgid "Continue"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:299 libi2pd_client/HTTPProxy.cpp:309
|
#: libi2pd_client/HTTPProxy.cpp:308 libi2pd_client/HTTPProxy.cpp:318
|
||||||
msgid "Addresshelper found"
|
msgid "Addresshelper found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:306
|
#: libi2pd_client/HTTPProxy.cpp:315
|
||||||
msgid "already in router's addressbook"
|
msgid "already in router's addressbook"
|
||||||
msgstr ""
|
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:"
|
msgid "Click here to update record:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:322
|
#: libi2pd_client/HTTPProxy.cpp:331
|
||||||
msgid "invalid request uri"
|
msgid "invalid request uri"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:365
|
#: libi2pd_client/HTTPProxy.cpp:372
|
||||||
msgid "Can't detect destination host from request"
|
msgid "Can't detect destination host from request"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:382 libi2pd_client/HTTPProxy.cpp:386
|
#: libi2pd_client/HTTPProxy.cpp:389 libi2pd_client/HTTPProxy.cpp:393
|
||||||
msgid "Outproxy failure"
|
msgid "Outproxy failure"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:382
|
#: libi2pd_client/HTTPProxy.cpp:389
|
||||||
msgid "bad outproxy settings"
|
msgid "bad outproxy settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:385
|
#: libi2pd_client/HTTPProxy.cpp:392
|
||||||
msgid "not inside I2P network, but outproxy is not enabled"
|
msgid "not inside I2P network, but outproxy is not enabled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:474
|
#: libi2pd_client/HTTPProxy.cpp:482
|
||||||
msgid "unknown outproxy url"
|
msgid "unknown outproxy url"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:480
|
#: libi2pd_client/HTTPProxy.cpp:490
|
||||||
msgid "cannot resolve upstream proxy"
|
msgid "cannot resolve upstream proxy"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:488
|
#: libi2pd_client/HTTPProxy.cpp:498
|
||||||
msgid "hostname too long"
|
msgid "hostname too long"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:515
|
#: libi2pd_client/HTTPProxy.cpp:525
|
||||||
msgid "cannot connect to upstream socks proxy"
|
msgid "cannot connect to upstream socks proxy"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:521
|
#: libi2pd_client/HTTPProxy.cpp:531
|
||||||
msgid "Cannot negotiate with socks proxy"
|
msgid "Cannot negotiate with socks proxy"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:563
|
#: libi2pd_client/HTTPProxy.cpp:573
|
||||||
msgid "CONNECT error"
|
msgid "CONNECT error"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:563
|
#: libi2pd_client/HTTPProxy.cpp:573
|
||||||
msgid "Failed to Connect"
|
msgid "Failed to Connect"
|
||||||
msgstr ""
|
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"
|
msgid "socks proxy error"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:582
|
#: libi2pd_client/HTTPProxy.cpp:592
|
||||||
msgid "failed to send request to upstream"
|
msgid "failed to send request to upstream"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:603
|
#: libi2pd_client/HTTPProxy.cpp:613
|
||||||
msgid "No Reply From socks proxy"
|
msgid "No Reply From socks proxy"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:610
|
#: libi2pd_client/HTTPProxy.cpp:620
|
||||||
msgid "cannot connect"
|
msgid "cannot connect"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:610
|
#: libi2pd_client/HTTPProxy.cpp:620
|
||||||
msgid "http out proxy not implemented"
|
msgid "http out proxy not implemented"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:611
|
#: libi2pd_client/HTTPProxy.cpp:621
|
||||||
msgid "cannot connect to upstream http proxy"
|
msgid "cannot connect to upstream http proxy"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:644
|
#: libi2pd_client/HTTPProxy.cpp:654
|
||||||
msgid "Host is down"
|
msgid "Host is down"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: libi2pd_client/HTTPProxy.cpp:644
|
#: libi2pd_client/HTTPProxy.cpp:654
|
||||||
msgid ""
|
msgid ""
|
||||||
"Can't create connection to requested host, it may be down. Please try again "
|
"Can't create connection to requested host, it may be down. Please try again "
|
||||||
"later."
|
"later."
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ 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
|
out: #{"$2", {"$3", "$5", "$7", "$9", "$11"}},\n
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -75,8 +75,8 @@ ipv4 = true
|
|||||||
## Enable communication through ipv6
|
## Enable communication through ipv6
|
||||||
ipv6 = false
|
ipv6 = false
|
||||||
|
|
||||||
## Enable SSU transport (default = true)
|
## Enable SSU transport
|
||||||
# ssu = true
|
ssu = false
|
||||||
|
|
||||||
## Bandwidth configuration
|
## Bandwidth configuration
|
||||||
## L limit bandwidth to 32KBs/sec, O - to 256KBs/sec, P - to 2048KBs/sec,
|
## 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!
|
## Note: that mode uses much more network connections and CPU!
|
||||||
# floodfill = true
|
# 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
|
||||||
|
# enabled = true
|
||||||
|
## Publish address in RouterInfo
|
||||||
|
# published = true
|
||||||
|
## Port for incoming connections (default is global port option value or port + 1 if SSU is enabled)
|
||||||
|
# port = 4567
|
||||||
|
|
||||||
[http]
|
[http]
|
||||||
## Web Console settings
|
## Web Console settings
|
||||||
## Uncomment and set to 'false' to disable Web Console
|
## Uncomment and set to 'false' to disable Web Console
|
||||||
@@ -110,8 +126,8 @@ port = 7070
|
|||||||
# user = i2pd
|
# user = i2pd
|
||||||
# pass = changeme
|
# pass = changeme
|
||||||
## Select webconsole language
|
## Select webconsole language
|
||||||
## Currently supported english (default), afrikaans, armenian, german, russian,
|
## Currently supported english (default), afrikaans, armenian, chinese, french,
|
||||||
## turkmen, ukrainian and uzbek languages
|
## german, italian, russian, spanish, turkmen, ukrainian and uzbek languages
|
||||||
# lang = english
|
# lang = english
|
||||||
|
|
||||||
[httpproxy]
|
[httpproxy]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
%define git_hash %(git rev-parse HEAD | cut -c -7)
|
%define git_hash %(git rev-parse HEAD | cut -c -7)
|
||||||
|
|
||||||
Name: i2pd-git
|
Name: i2pd-git
|
||||||
Version: 2.41.0
|
Version: 2.44.0
|
||||||
Release: git%{git_hash}%{?dist}
|
Release: git%{git_hash}%{?dist}
|
||||||
Summary: I2P router written in C++
|
Summary: I2P router written in C++
|
||||||
Conflicts: i2pd
|
Conflicts: i2pd
|
||||||
@@ -62,9 +62,7 @@ pushd redhat-linux-build
|
|||||||
%endif
|
%endif
|
||||||
|
|
||||||
%if 0%{?fedora} >= 35
|
%if 0%{?fedora} >= 35
|
||||||
%if 0%{?fedora} < 37
|
|
||||||
pushd redhat-linux-build
|
pushd redhat-linux-build
|
||||||
%endif
|
|
||||||
%else
|
%else
|
||||||
%if 0%{?fedora} >= 33
|
%if 0%{?fedora} >= 33
|
||||||
pushd %{_target_platform}
|
pushd %{_target_platform}
|
||||||
@@ -82,10 +80,8 @@ popd
|
|||||||
%endif
|
%endif
|
||||||
|
|
||||||
%if 0%{?fedora} >= 33
|
%if 0%{?fedora} >= 33
|
||||||
%if 0%{?fedora} < 37
|
|
||||||
popd
|
popd
|
||||||
%endif
|
%endif
|
||||||
%endif
|
|
||||||
|
|
||||||
%if 0%{?mageia} > 7
|
%if 0%{?mageia} > 7
|
||||||
popd
|
popd
|
||||||
@@ -99,9 +95,7 @@ pushd redhat-linux-build
|
|||||||
%endif
|
%endif
|
||||||
|
|
||||||
%if 0%{?fedora} >= 35
|
%if 0%{?fedora} >= 35
|
||||||
%if 0%{?fedora} < 37
|
|
||||||
pushd redhat-linux-build
|
pushd redhat-linux-build
|
||||||
%endif
|
|
||||||
%else
|
%else
|
||||||
%if 0%{?fedora} >= 33
|
%if 0%{?fedora} >= 33
|
||||||
pushd %{_target_platform}
|
pushd %{_target_platform}
|
||||||
@@ -164,6 +158,18 @@ getent passwd i2pd >/dev/null || \
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Sun Nov 20 2022 orignal <orignal@i2pmail.org> - 2.44.0
|
||||||
|
- update to 2.44.0
|
||||||
|
|
||||||
|
* 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
|
||||||
|
|
||||||
|
* Sun May 22 2022 orignal <orignal@i2pmail.org> - 2.42.0
|
||||||
|
- update to 2.42.0
|
||||||
|
|
||||||
* Sun Feb 20 2022 r4sas <r4sas@i2pmail.org> - 2.41.0
|
* Sun Feb 20 2022 r4sas <r4sas@i2pmail.org> - 2.41.0
|
||||||
- update to 2.41.0
|
- update to 2.41.0
|
||||||
- fixed build on Fedora Copr over openssl trunk code
|
- fixed build on Fedora Copr over openssl trunk code
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
Name: i2pd
|
Name: i2pd
|
||||||
Version: 2.41.0
|
Version: 2.44.0
|
||||||
Release: 1%{?dist}
|
Release: 1%{?dist}
|
||||||
Summary: I2P router written in C++
|
Summary: I2P router written in C++
|
||||||
Conflicts: i2pd-git
|
Conflicts: i2pd-git
|
||||||
@@ -59,9 +59,7 @@ pushd redhat-linux-build
|
|||||||
%endif
|
%endif
|
||||||
|
|
||||||
%if 0%{?fedora} >= 35
|
%if 0%{?fedora} >= 35
|
||||||
%if 0%{?fedora} < 37
|
|
||||||
pushd redhat-linux-build
|
pushd redhat-linux-build
|
||||||
%endif
|
|
||||||
%else
|
%else
|
||||||
%if 0%{?fedora} >= 33
|
%if 0%{?fedora} >= 33
|
||||||
pushd %{_target_platform}
|
pushd %{_target_platform}
|
||||||
@@ -79,10 +77,8 @@ popd
|
|||||||
%endif
|
%endif
|
||||||
|
|
||||||
%if 0%{?fedora} >= 33
|
%if 0%{?fedora} >= 33
|
||||||
%if 0%{?fedora} < 37
|
|
||||||
popd
|
popd
|
||||||
%endif
|
%endif
|
||||||
%endif
|
|
||||||
|
|
||||||
%if 0%{?mageia} > 7
|
%if 0%{?mageia} > 7
|
||||||
popd
|
popd
|
||||||
@@ -96,9 +92,7 @@ pushd redhat-linux-build
|
|||||||
%endif
|
%endif
|
||||||
|
|
||||||
%if 0%{?fedora} >= 35
|
%if 0%{?fedora} >= 35
|
||||||
%if 0%{?fedora} < 37
|
|
||||||
pushd redhat-linux-build
|
pushd redhat-linux-build
|
||||||
%endif
|
|
||||||
%else
|
%else
|
||||||
%if 0%{?fedora} >= 33
|
%if 0%{?fedora} >= 33
|
||||||
pushd %{_target_platform}
|
pushd %{_target_platform}
|
||||||
@@ -161,6 +155,18 @@ getent passwd i2pd >/dev/null || \
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Sun Nov 20 2022 orignal <orignal@i2pmail.org> - 2.44.0
|
||||||
|
- update to 2.44.0
|
||||||
|
|
||||||
|
* 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
|
||||||
|
|
||||||
|
* Sun May 22 2022 orignal <orignal@i2pmail.org> - 2.42.0
|
||||||
|
- update to 2.42.0
|
||||||
|
|
||||||
* Sun Feb 20 2022 r4sas <r4sas@i2pmail.org> - 2.41.0
|
* Sun Feb 20 2022 r4sas <r4sas@i2pmail.org> - 2.41.0
|
||||||
- update to 2.41.0
|
- update to 2.41.0
|
||||||
|
|
||||||
|
|||||||
@@ -26,14 +26,11 @@
|
|||||||
#include "Streaming.h"
|
#include "Streaming.h"
|
||||||
#include "Destination.h"
|
#include "Destination.h"
|
||||||
#include "HTTPServer.h"
|
#include "HTTPServer.h"
|
||||||
#ifdef WITH_I2PC
|
|
||||||
#include "I2PControl.h"
|
#include "I2PControl.h"
|
||||||
#endif
|
|
||||||
#include "ClientContext.h"
|
#include "ClientContext.h"
|
||||||
#include "Crypto.h"
|
#include "Crypto.h"
|
||||||
#include "UPnP.h"
|
#include "UPnP.h"
|
||||||
#include "Timestamp.h"
|
#include "Timestamp.h"
|
||||||
#include "util.h"
|
|
||||||
#include "I18N.h"
|
#include "I18N.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
@@ -47,9 +44,7 @@ namespace util
|
|||||||
~Daemon_Singleton_Private() {};
|
~Daemon_Singleton_Private() {};
|
||||||
|
|
||||||
std::unique_ptr<i2p::http::HTTPServer> httpServer;
|
std::unique_ptr<i2p::http::HTTPServer> httpServer;
|
||||||
#ifdef WITH_I2PC
|
|
||||||
std::unique_ptr<i2p::client::I2PControlService> m_I2PControlService;
|
std::unique_ptr<i2p::client::I2PControlService> m_I2PControlService;
|
||||||
#endif
|
|
||||||
std::unique_ptr<i2p::transport::UPnP> UPnP;
|
std::unique_ptr<i2p::transport::UPnP> UPnP;
|
||||||
std::unique_ptr<i2p::util::NTPTimeSync> m_NTPSync;
|
std::unique_ptr<i2p::util::NTPTimeSync> m_NTPSync;
|
||||||
};
|
};
|
||||||
@@ -62,9 +57,7 @@ namespace util
|
|||||||
bool Daemon_Singleton::IsService () const
|
bool Daemon_Singleton::IsService () const
|
||||||
{
|
{
|
||||||
bool service = false;
|
bool service = false;
|
||||||
#ifndef _WIN32
|
|
||||||
i2p::config::GetOption("service", service);
|
i2p::config::GetOption("service", service);
|
||||||
#endif
|
|
||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,115 +152,18 @@ namespace util
|
|||||||
bool aesni; i2p::config::GetOption("cpuext.aesni", aesni);
|
bool aesni; i2p::config::GetOption("cpuext.aesni", aesni);
|
||||||
bool avx; i2p::config::GetOption("cpuext.avx", avx);
|
bool avx; i2p::config::GetOption("cpuext.avx", avx);
|
||||||
bool forceCpuExt; i2p::config::GetOption("cpuext.force", forceCpuExt);
|
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);
|
i2p::crypto::InitCrypto (precomputation, aesni, avx, forceCpuExt);
|
||||||
|
|
||||||
|
i2p::transport::InitAddressFromIface (); // get address4/6 from interfaces
|
||||||
|
|
||||||
int netID; i2p::config::GetOption("netid", netID);
|
int netID; i2p::config::GetOption("netid", netID);
|
||||||
i2p::context.SetNetID (netID);
|
i2p::context.SetNetID (netID);
|
||||||
i2p::context.Init ();
|
i2p::context.Init ();
|
||||||
|
|
||||||
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
|
i2p::transport::InitTransports ();
|
||||||
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
|
|
||||||
|
|
||||||
// ifname -> address
|
|
||||||
std::string ifname; i2p::config::GetOption("ifname", ifname);
|
|
||||||
if (ipv4 && i2p::config::IsDefault ("address4"))
|
|
||||||
{
|
|
||||||
std::string ifname4; i2p::config::GetOption("ifname4", ifname4);
|
|
||||||
if (!ifname4.empty ())
|
|
||||||
i2p::config::SetOption ("address4", i2p::util::net::GetInterfaceAddress(ifname4, false).to_string ()); // v4
|
|
||||||
else if (!ifname.empty ())
|
|
||||||
i2p::config::SetOption ("address4", i2p::util::net::GetInterfaceAddress(ifname, false).to_string ()); // v4
|
|
||||||
}
|
|
||||||
if (ipv6 && i2p::config::IsDefault ("address6"))
|
|
||||||
{
|
|
||||||
std::string ifname6; i2p::config::GetOption("ifname6", ifname6);
|
|
||||||
if (!ifname6.empty ())
|
|
||||||
i2p::config::SetOption ("address6", i2p::util::net::GetInterfaceAddress(ifname6, true).to_string ()); // v6
|
|
||||||
else if (!ifname.empty ())
|
|
||||||
i2p::config::SetOption ("address6", i2p::util::net::GetInterfaceAddress(ifname, true).to_string ()); // v6
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg);
|
|
||||||
boost::asio::ip::address_v6 yggaddr;
|
|
||||||
if (ygg)
|
|
||||||
{
|
|
||||||
std::string yggaddress; i2p::config::GetOption ("meshnets.yggaddress", yggaddress);
|
|
||||||
if (!yggaddress.empty ())
|
|
||||||
{
|
|
||||||
yggaddr = boost::asio::ip::address_v6::from_string (yggaddress);
|
|
||||||
if (yggaddr.is_unspecified () || !i2p::util::net::IsYggdrasilAddress (yggaddr) ||
|
|
||||||
!i2p::util::net::IsLocalAddress (yggaddr))
|
|
||||||
{
|
|
||||||
LogPrint(eLogWarning, "Daemon: Can't find Yggdrasil address ", yggaddress);
|
|
||||||
ygg = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
yggaddr = i2p::util::net::GetYggdrasilAddress ();
|
|
||||||
if (yggaddr.is_unspecified ())
|
|
||||||
{
|
|
||||||
LogPrint(eLogWarning, "Daemon: Yggdrasil is not running. Disabled");
|
|
||||||
ygg = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t port; i2p::config::GetOption("port", port);
|
|
||||||
if (!i2p::config::IsDefault("port"))
|
|
||||||
{
|
|
||||||
LogPrint(eLogInfo, "Daemon: Accepting incoming connections at port ", port);
|
|
||||||
i2p::context.UpdatePort (port);
|
|
||||||
}
|
|
||||||
i2p::context.SetSupportsV6 (ipv6);
|
|
||||||
i2p::context.SetSupportsV4 (ipv4);
|
|
||||||
i2p::context.SetSupportsMesh (ygg, yggaddr);
|
|
||||||
|
|
||||||
i2p::context.RemoveNTCPAddress (!ipv6); // TODO: remove later
|
|
||||||
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
|
||||||
if (ntcp2)
|
|
||||||
{
|
|
||||||
bool published; i2p::config::GetOption("ntcp2.published", published);
|
|
||||||
if (published)
|
|
||||||
{
|
|
||||||
std::string ntcp2proxy; i2p::config::GetOption("ntcp2.proxy", ntcp2proxy);
|
|
||||||
if (!ntcp2proxy.empty ()) published = false;
|
|
||||||
}
|
|
||||||
if (published)
|
|
||||||
{
|
|
||||||
uint16_t ntcp2port; i2p::config::GetOption("ntcp2.port", ntcp2port);
|
|
||||||
if (!ntcp2port) ntcp2port = port; // use standard port
|
|
||||||
i2p::context.PublishNTCP2Address (ntcp2port, true, ipv4, ipv6, false); // publish
|
|
||||||
if (ipv6)
|
|
||||||
{
|
|
||||||
std::string ipv6Addr; i2p::config::GetOption("ntcp2.addressv6", ipv6Addr);
|
|
||||||
auto addr = boost::asio::ip::address_v6::from_string (ipv6Addr);
|
|
||||||
if (!addr.is_unspecified () && addr != boost::asio::ip::address_v6::any ())
|
|
||||||
i2p::context.UpdateNTCP2V6Address (addr); // set ipv6 address if configured
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
i2p::context.PublishNTCP2Address (port, false, ipv4, ipv6, false); // unpublish
|
|
||||||
}
|
|
||||||
if (ygg)
|
|
||||||
{
|
|
||||||
i2p::context.PublishNTCP2Address (port, true, false, false, true);
|
|
||||||
i2p::context.UpdateNTCP2V6Address (yggaddr);
|
|
||||||
if (!ipv4 && !ipv6)
|
|
||||||
i2p::context.SetStatus (eRouterStatusMesh);
|
|
||||||
}
|
|
||||||
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
|
|
||||||
if (ssu2)
|
|
||||||
{
|
|
||||||
bool published; i2p::config::GetOption("ssu2.published", published);
|
|
||||||
if (published)
|
|
||||||
{
|
|
||||||
uint16_t ssu2port; i2p::config::GetOption("ssu2.port", ssu2port);
|
|
||||||
i2p::context.PublishSSU2Address (ssu2port, true, ipv4, ipv6); // publish
|
|
||||||
}
|
|
||||||
else
|
|
||||||
i2p::context.PublishSSU2Address (0, false, ipv4, ipv6); // unpublish
|
|
||||||
}
|
|
||||||
|
|
||||||
bool transit; i2p::config::GetOption("notransit", transit);
|
bool transit; i2p::config::GetOption("notransit", transit);
|
||||||
i2p::context.SetAcceptsTunnels (!transit);
|
i2p::context.SetAcceptsTunnels (!transit);
|
||||||
@@ -402,15 +298,14 @@ namespace util
|
|||||||
|
|
||||||
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
||||||
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
|
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
|
||||||
bool ssu; i2p::config::GetOption("ssu", ssu);
|
|
||||||
bool checkInReserved; i2p::config::GetOption("reservedrange", checkInReserved);
|
bool checkInReserved; i2p::config::GetOption("reservedrange", checkInReserved);
|
||||||
LogPrint(eLogInfo, "Daemon: Starting Transports");
|
LogPrint(eLogInfo, "Daemon: Starting Transports");
|
||||||
if(!ssu) LogPrint(eLogInfo, "Daemon: SSU disabled");
|
if(!ssu2) LogPrint(eLogInfo, "Daemon: SSU2 disabled");
|
||||||
if(!ntcp2) LogPrint(eLogInfo, "Daemon: NTCP2 disabled");
|
if(!ntcp2) LogPrint(eLogInfo, "Daemon: NTCP2 disabled");
|
||||||
|
|
||||||
i2p::transport::transports.SetCheckReserved(checkInReserved);
|
i2p::transport::transports.SetCheckReserved(checkInReserved);
|
||||||
i2p::transport::transports.Start(ntcp2, ssu, ssu2);
|
i2p::transport::transports.Start(ntcp2, ssu2);
|
||||||
if (i2p::transport::transports.IsBoundSSU() || i2p::transport::transports.IsBoundNTCP2())
|
if (i2p::transport::transports.IsBoundSSU2() || i2p::transport::transports.IsBoundNTCP2())
|
||||||
LogPrint(eLogInfo, "Daemon: Transports started");
|
LogPrint(eLogInfo, "Daemon: Transports started");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -445,7 +340,6 @@ namespace util
|
|||||||
LogPrint(eLogInfo, "Daemon: Starting Client");
|
LogPrint(eLogInfo, "Daemon: Starting Client");
|
||||||
i2p::client::context.Start ();
|
i2p::client::context.Start ();
|
||||||
|
|
||||||
#ifdef WITH_I2PC
|
|
||||||
// I2P Control Protocol
|
// I2P Control Protocol
|
||||||
bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol);
|
bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol);
|
||||||
if (i2pcontrol) {
|
if (i2pcontrol) {
|
||||||
@@ -463,7 +357,6 @@ namespace util
|
|||||||
ThrowFatal ("Unable to start I2PControl service at ", i2pcpAddr, ":", i2pcpPort, ": ", ex.what ());
|
ThrowFatal ("Unable to start I2PControl service at ", i2pcpAddr, ":", i2pcpPort, ": ", ex.what ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -496,14 +389,12 @@ namespace util
|
|||||||
d.httpServer->Stop();
|
d.httpServer->Stop();
|
||||||
d.httpServer = nullptr;
|
d.httpServer = nullptr;
|
||||||
}
|
}
|
||||||
#ifdef WITH_I2PC
|
|
||||||
if (d.m_I2PControlService)
|
if (d.m_I2PControlService)
|
||||||
{
|
{
|
||||||
LogPrint(eLogInfo, "Daemon: Stopping I2PControl");
|
LogPrint(eLogInfo, "Daemon: Stopping I2PControl");
|
||||||
d.m_I2PControlService->Stop ();
|
d.m_I2PControlService->Stop ();
|
||||||
d.m_I2PControlService = nullptr;
|
d.m_I2PControlService = nullptr;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
i2p::crypto::TerminateCrypto ();
|
i2p::crypto::TerminateCrypto ();
|
||||||
i2p::log::Logger().Stop();
|
i2p::log::Logger().Stop();
|
||||||
|
|
||||||
|
|||||||
@@ -68,13 +68,9 @@ namespace http {
|
|||||||
const char HTTP_PAGE_TRANSPORTS[] = "transports";
|
const char HTTP_PAGE_TRANSPORTS[] = "transports";
|
||||||
const char HTTP_PAGE_LOCAL_DESTINATIONS[] = "local_destinations";
|
const char HTTP_PAGE_LOCAL_DESTINATIONS[] = "local_destinations";
|
||||||
const char HTTP_PAGE_LOCAL_DESTINATION[] = "local_destination";
|
const char HTTP_PAGE_LOCAL_DESTINATION[] = "local_destination";
|
||||||
#ifdef WITH_I2CP
|
|
||||||
const char HTTP_PAGE_I2CP_LOCAL_DESTINATION[] = "i2cp_local_destination";
|
const char HTTP_PAGE_I2CP_LOCAL_DESTINATION[] = "i2cp_local_destination";
|
||||||
#endif
|
|
||||||
#ifdef WITH_SAM
|
|
||||||
const char HTTP_PAGE_SAM_SESSIONS[] = "sam_sessions";
|
const char HTTP_PAGE_SAM_SESSIONS[] = "sam_sessions";
|
||||||
const char HTTP_PAGE_SAM_SESSION[] = "sam_session";
|
const char HTTP_PAGE_SAM_SESSION[] = "sam_session";
|
||||||
#endif
|
|
||||||
const char HTTP_PAGE_I2P_TUNNELS[] = "i2p_tunnels";
|
const char HTTP_PAGE_I2P_TUNNELS[] = "i2p_tunnels";
|
||||||
const char HTTP_PAGE_COMMANDS[] = "commands";
|
const char HTTP_PAGE_COMMANDS[] = "commands";
|
||||||
const char HTTP_PAGE_LEASESETS[] = "leasesets";
|
const char HTTP_PAGE_LEASESETS[] = "leasesets";
|
||||||
@@ -84,16 +80,14 @@ namespace http {
|
|||||||
const char HTTP_COMMAND_SHUTDOWN_CANCEL[] = "shutdown_cancel";
|
const char HTTP_COMMAND_SHUTDOWN_CANCEL[] = "shutdown_cancel";
|
||||||
const char HTTP_COMMAND_SHUTDOWN_NOW[] = "terminate";
|
const char HTTP_COMMAND_SHUTDOWN_NOW[] = "terminate";
|
||||||
const char HTTP_COMMAND_RUN_PEER_TEST[] = "run_peer_test";
|
const char HTTP_COMMAND_RUN_PEER_TEST[] = "run_peer_test";
|
||||||
const char HTTP_COMMAND_RELOAD_CONFIG[] = "reload_config";
|
const char HTTP_COMMAND_RELOAD_TUNNELS_CONFIG[] = "reload_tunnels_config";
|
||||||
const char HTTP_COMMAND_LOGLEVEL[] = "set_loglevel";
|
const char HTTP_COMMAND_LOGLEVEL[] = "set_loglevel";
|
||||||
const char HTTP_COMMAND_KILLSTREAM[] = "closestream";
|
const char HTTP_COMMAND_KILLSTREAM[] = "closestream";
|
||||||
const char HTTP_COMMAND_LIMITTRANSIT[] = "limittransit";
|
const char HTTP_COMMAND_LIMITTRANSIT[] = "limittransit";
|
||||||
const char HTTP_COMMAND_GET_REG_STRING[] = "get_reg_string";
|
const char HTTP_COMMAND_GET_REG_STRING[] = "get_reg_string";
|
||||||
const char HTTP_COMMAND_SETLANGUAGE[] = "setlanguage";
|
const char HTTP_COMMAND_SETLANGUAGE[] = "setlanguage";
|
||||||
const char HTTP_COMMAND_RELOAD_CSS[] = "reload_css";
|
const char HTTP_COMMAND_RELOAD_CSS[] = "reload_css";
|
||||||
#ifdef WITH_SAM
|
|
||||||
const char HTTP_PARAM_SAM_SESSION_ID[] = "id";
|
const char HTTP_PARAM_SAM_SESSION_ID[] = "id";
|
||||||
#endif
|
|
||||||
const char HTTP_PARAM_ADDRESS[] = "address";
|
const char HTTP_PARAM_ADDRESS[] = "address";
|
||||||
|
|
||||||
static std::string ConvertTime (uint64_t time)
|
static std::string ConvertTime (uint64_t time)
|
||||||
@@ -188,7 +182,7 @@ namespace http {
|
|||||||
" <meta charset=\"UTF-8\">\r\n"
|
" <meta charset=\"UTF-8\">\r\n"
|
||||||
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n"
|
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n"
|
||||||
" <link rel=\"shortcut icon\" href=\"" << itoopieFavicon << "\">\r\n"
|
" <link rel=\"shortcut icon\" href=\"" << itoopieFavicon << "\">\r\n"
|
||||||
" <title>Purple I2P Webconsole</title>\r\n";
|
" <title>" << tr(/* tr: Webconsole page title */ "Purple I2P Webconsole") << "</title>\r\n";
|
||||||
GetStyles(s);
|
GetStyles(s);
|
||||||
s <<
|
s <<
|
||||||
"</head>\r\n"
|
"</head>\r\n"
|
||||||
@@ -208,10 +202,8 @@ namespace http {
|
|||||||
s <<
|
s <<
|
||||||
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSPORTS << "\">" << tr ("Transports") << "</a><br>\r\n"
|
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSPORTS << "\">" << tr ("Transports") << "</a><br>\r\n"
|
||||||
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_I2P_TUNNELS << "\">" << tr("I2P tunnels") << "</a><br>\r\n";
|
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_I2P_TUNNELS << "\">" << tr("I2P tunnels") << "</a><br>\r\n";
|
||||||
#ifdef WITH_SAM
|
|
||||||
if (i2p::client::context.GetSAMBridge ())
|
if (i2p::client::context.GetSAMBridge ())
|
||||||
s << " <a href=\"" << webroot << "?page=" << HTTP_PAGE_SAM_SESSIONS << "\">" << tr("SAM sessions") << "</a><br>\r\n";
|
s << " <a href=\"" << webroot << "?page=" << HTTP_PAGE_SAM_SESSIONS << "\">" << tr("SAM sessions") << "</a><br>\r\n";
|
||||||
#endif
|
|
||||||
s <<
|
s <<
|
||||||
"</div>\r\n"
|
"</div>\r\n"
|
||||||
"<div class=\"content\">";
|
"<div class=\"content\">";
|
||||||
@@ -230,7 +222,7 @@ namespace http {
|
|||||||
s << "<b>" << tr("ERROR") << ":</b> " << string << "<br>\r\n";
|
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)
|
switch (status)
|
||||||
{
|
{
|
||||||
@@ -240,10 +232,12 @@ namespace http {
|
|||||||
case eRouterStatusUnknown: s << tr("Unknown"); break;
|
case eRouterStatusUnknown: s << tr("Unknown"); break;
|
||||||
case eRouterStatusProxy: s << tr("Proxy"); break;
|
case eRouterStatusProxy: s << tr("Proxy"); break;
|
||||||
case eRouterStatusMesh: s << tr("Mesh"); break;
|
case eRouterStatusMesh: s << tr("Mesh"); break;
|
||||||
case eRouterStatusError:
|
default: s << tr("Unknown");
|
||||||
|
}
|
||||||
|
if (error != eRouterErrorNone)
|
||||||
{
|
{
|
||||||
s << tr("Error");
|
s << "<br>";
|
||||||
switch (i2p::context.GetError ())
|
switch (error)
|
||||||
{
|
{
|
||||||
case eRouterErrorClockSkew:
|
case eRouterErrorClockSkew:
|
||||||
s << " - " << tr("Clock skew");
|
s << " - " << tr("Clock skew");
|
||||||
@@ -254,11 +248,11 @@ namespace http {
|
|||||||
case eRouterErrorSymmetricNAT:
|
case eRouterErrorSymmetricNAT:
|
||||||
s << " - " << tr("Symmetric NAT");
|
s << " - " << tr("Symmetric NAT");
|
||||||
break;
|
break;
|
||||||
|
case eRouterErrorNoDescriptors:
|
||||||
|
s << " - " << tr("No Descriptors");
|
||||||
|
break;
|
||||||
default: ;
|
default: ;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: s << tr("Unknown");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,12 +262,12 @@ namespace http {
|
|||||||
ShowUptime(s, i2p::context.GetUptime ());
|
ShowUptime(s, i2p::context.GetUptime ());
|
||||||
s << "<br>\r\n";
|
s << "<br>\r\n";
|
||||||
s << "<b>" << tr("Network status") << ":</b> ";
|
s << "<b>" << tr("Network status") << ":</b> ";
|
||||||
ShowNetworkStatus (s, i2p::context.GetStatus ());
|
ShowNetworkStatus (s, i2p::context.GetStatus (), i2p::context.GetError ());
|
||||||
s << "<br>\r\n";
|
s << "<br>\r\n";
|
||||||
if (i2p::context.SupportsV6 ())
|
if (i2p::context.SupportsV6 ())
|
||||||
{
|
{
|
||||||
s << "<b>" << tr("Network status v6") << ":</b> ";
|
s << "<b>" << tr("Network status v6") << ":</b> ";
|
||||||
ShowNetworkStatus (s, i2p::context.GetStatusV6 ());
|
ShowNetworkStatus (s, i2p::context.GetStatusV6 (), i2p::context.GetErrorV6 ());
|
||||||
s << "<br>\r\n";
|
s << "<br>\r\n";
|
||||||
}
|
}
|
||||||
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
|
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
|
||||||
@@ -296,36 +290,37 @@ namespace http {
|
|||||||
s << "<b>" << tr("Tunnel creation success rate") << ":</b> " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate () << "%<br>\r\n";
|
s << "<b>" << tr("Tunnel creation success rate") << ":</b> " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate () << "%<br>\r\n";
|
||||||
s << "<b>" << tr("Received") << ":</b> ";
|
s << "<b>" << tr("Received") << ":</b> ";
|
||||||
ShowTraffic (s, i2p::transport::transports.GetTotalReceivedBytes ());
|
ShowTraffic (s, i2p::transport::transports.GetTotalReceivedBytes ());
|
||||||
s << " (" << (double) i2p::transport::transports.GetInBandwidth () / 1024 << " " << tr(/* tr: Kibibit/s */ "KiB/s") << ")<br>\r\n";
|
s << " (" << (double) i2p::transport::transports.GetInBandwidth15s () / 1024 << " " << tr(/* tr: Kibibit/s */ "KiB/s") << ")<br>\r\n";
|
||||||
s << "<b>" << tr("Sent") << ":</b> ";
|
s << "<b>" << tr("Sent") << ":</b> ";
|
||||||
ShowTraffic (s, i2p::transport::transports.GetTotalSentBytes ());
|
ShowTraffic (s, i2p::transport::transports.GetTotalSentBytes ());
|
||||||
s << " (" << (double) i2p::transport::transports.GetOutBandwidth () / 1024 << " " << tr(/* tr: Kibibit/s */ "KiB/s") << ")<br>\r\n";
|
s << " (" << (double) i2p::transport::transports.GetOutBandwidth15s () / 1024 << " " << tr(/* tr: Kibibit/s */ "KiB/s") << ")<br>\r\n";
|
||||||
s << "<b>" << tr("Transit") << ":</b> ";
|
s << "<b>" << tr("Transit") << ":</b> ";
|
||||||
ShowTraffic (s, i2p::transport::transports.GetTotalTransitTransmittedBytes ());
|
ShowTraffic (s, i2p::transport::transports.GetTotalTransitTransmittedBytes ());
|
||||||
s << " (" << (double) i2p::transport::transports.GetTransitBandwidth () / 1024 << " " << tr(/* tr: Kibibit/s */ "KiB/s") << ")<br>\r\n";
|
s << " (" << (double) i2p::transport::transports.GetTransitBandwidth15s () / 1024 << " " << tr(/* tr: Kibibit/s */ "KiB/s") << ")<br>\r\n";
|
||||||
s << "<b>" << tr("Data path") << ":</b> " << i2p::fs::GetUTF8DataDir() << "<br>\r\n";
|
s << "<b>" << tr("Data path") << ":</b> " << i2p::fs::GetUTF8DataDir() << "<br>\r\n";
|
||||||
s << "<div class='slide'>";
|
s << "<div class='slide'>";
|
||||||
if ((outputFormat == OutputFormatEnum::forWebConsole) || !includeHiddenContent) {
|
if ((outputFormat == OutputFormatEnum::forWebConsole) || !includeHiddenContent) {
|
||||||
s << "<label for=\"slide-info\">" << tr("Hidden content. Press on text to see.") << "</label>\r\n<input type=\"checkbox\" id=\"slide-info\" />\r\n<div class=\"slidecontent\">\r\n";
|
s << "<label for=\"slide-info\">" << tr("Hidden content. Press on text to see.") << "</label>\r\n<input type=\"checkbox\" id=\"slide-info\" />\r\n<div class=\"slidecontent\">\r\n";
|
||||||
}
|
}
|
||||||
if (includeHiddenContent) {
|
if (includeHiddenContent)
|
||||||
|
{
|
||||||
s << "<b>" << tr("Router Ident") << ":</b> " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "<br>\r\n";
|
s << "<b>" << tr("Router Ident") << ":</b> " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "<br>\r\n";
|
||||||
if (!i2p::context.GetRouterInfo().GetProperty("family").empty())
|
if (!i2p::context.GetRouterInfo().GetProperty("family").empty())
|
||||||
s << "<b>" << tr("Router Family") << ":</b> " << i2p::context.GetRouterInfo().GetProperty("family") << "<br>\r\n";
|
s << "<b>" << tr("Router Family") << ":</b> " << i2p::context.GetRouterInfo().GetProperty("family") << "<br>\r\n";
|
||||||
s << "<b>" << tr("Router Caps") << ":</b> " << i2p::context.GetRouterInfo().GetProperty("caps") << "<br>\r\n";
|
s << "<b>" << tr("Router Caps") << ":</b> " << i2p::context.GetRouterInfo().GetProperty("caps") << "<br>\r\n";
|
||||||
s << "<b>" << tr("Version") << ":</b> " VERSION "<br>\r\n";
|
s << "<b>" << tr("Version") << ":</b> " VERSION "<br>\r\n";
|
||||||
s << "<b>"<< tr("Our external address") << ":</b>" << "<br>\r\n<table class=\"extaddr\"><tbody>\r\n";
|
s << "<b>"<< tr("Our external address") << ":</b>" << "<br>\r\n<table class=\"extaddr\"><tbody>\r\n";
|
||||||
for (const auto& address : i2p::context.GetRouterInfo().GetAddresses())
|
auto addresses = i2p::context.GetRouterInfo().GetAddresses ();
|
||||||
|
if (addresses)
|
||||||
|
{
|
||||||
|
for (const auto& address : *addresses)
|
||||||
{
|
{
|
||||||
s << "<tr>\r\n<td>";
|
s << "<tr>\r\n<td>";
|
||||||
switch (address->transportStyle)
|
switch (address->transportStyle)
|
||||||
{
|
{
|
||||||
case i2p::data::RouterInfo::eTransportNTCP:
|
case i2p::data::RouterInfo::eTransportNTCP2:
|
||||||
s << "NTCP2";
|
s << "NTCP2";
|
||||||
break;
|
break;
|
||||||
case i2p::data::RouterInfo::eTransportSSU:
|
|
||||||
s << "SSU";
|
|
||||||
break;
|
|
||||||
case i2p::data::RouterInfo::eTransportSSU2:
|
case i2p::data::RouterInfo::eTransportSSU2:
|
||||||
s << "SSU2";
|
s << "SSU2";
|
||||||
break;
|
break;
|
||||||
@@ -349,6 +344,7 @@ namespace http {
|
|||||||
}
|
}
|
||||||
s << "</tr>\r\n";
|
s << "</tr>\r\n";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
s << "</tbody></table>\r\n";
|
s << "</tbody></table>\r\n";
|
||||||
}
|
}
|
||||||
s << "</div>\r\n</div>\r\n";
|
s << "</div>\r\n</div>\r\n";
|
||||||
@@ -369,25 +365,17 @@ namespace http {
|
|||||||
if (outputFormat==OutputFormatEnum::forWebConsole) {
|
if (outputFormat==OutputFormatEnum::forWebConsole) {
|
||||||
bool httpproxy = i2p::client::context.GetHttpProxy () ? true : false;
|
bool httpproxy = i2p::client::context.GetHttpProxy () ? true : false;
|
||||||
bool socksproxy = i2p::client::context.GetSocksProxy () ? true : false;
|
bool socksproxy = i2p::client::context.GetSocksProxy () ? true : false;
|
||||||
|
bool bob = i2p::client::context.GetBOBCommandChannel () ? true : false;
|
||||||
|
bool sam = i2p::client::context.GetSAMBridge () ? true : false;
|
||||||
|
bool i2cp = i2p::client::context.GetI2CPServer () ? true : false;
|
||||||
|
bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol);
|
||||||
s << "<table class=\"services\"><caption>" << tr("Services") << "</caption><tbody>\r\n";
|
s << "<table class=\"services\"><caption>" << tr("Services") << "</caption><tbody>\r\n";
|
||||||
s << "<tr><td>" << "HTTP " << tr("Proxy") << "</td><td class='" << (httpproxy ? "enabled" : "disabled") << "'>" << (httpproxy ? tr("Enabled") : tr("Disabled")) << "</td></tr>\r\n";
|
s << "<tr><td>" << "HTTP " << tr("Proxy") << "</td><td class='" << (httpproxy ? "enabled" : "disabled") << "'>" << (httpproxy ? tr("Enabled") : tr("Disabled")) << "</td></tr>\r\n";
|
||||||
s << "<tr><td>" << "SOCKS " << tr("Proxy") << "</td><td class='" << (socksproxy ? "enabled" : "disabled") << "'>" << (socksproxy ? tr("Enabled") : tr("Disabled")) << "</td></tr>\r\n";
|
s << "<tr><td>" << "SOCKS " << tr("Proxy") << "</td><td class='" << (socksproxy ? "enabled" : "disabled") << "'>" << (socksproxy ? tr("Enabled") : tr("Disabled")) << "</td></tr>\r\n";
|
||||||
#ifdef WITH_BOB
|
|
||||||
bool bob = i2p::client::context.GetBOBCommandChannel () ? true : false;
|
|
||||||
s << "<tr><td>" << "BOB" << "</td><td class='" << (bob ? "enabled" : "disabled") << "'>" << (bob ? tr("Enabled") : tr("Disabled")) << "</td></tr>\r\n";
|
s << "<tr><td>" << "BOB" << "</td><td class='" << (bob ? "enabled" : "disabled") << "'>" << (bob ? tr("Enabled") : tr("Disabled")) << "</td></tr>\r\n";
|
||||||
#endif
|
|
||||||
#ifdef WITH_SAM
|
|
||||||
bool sam = i2p::client::context.GetSAMBridge () ? true : false;
|
|
||||||
s << "<tr><td>" << "SAM" << "</td><td class='" << (sam ? "enabled" : "disabled") << "'>" << (sam ? tr("Enabled") : tr("Disabled")) << "</td></tr>\r\n";
|
s << "<tr><td>" << "SAM" << "</td><td class='" << (sam ? "enabled" : "disabled") << "'>" << (sam ? tr("Enabled") : tr("Disabled")) << "</td></tr>\r\n";
|
||||||
#endif
|
|
||||||
#ifdef WITH_I2CP
|
|
||||||
bool i2cp = i2p::client::context.GetI2CPServer () ? true : false;
|
|
||||||
s << "<tr><td>" << "I2CP" << "</td><td class='" << (i2cp ? "enabled" : "disabled") << "'>" << (i2cp ? tr("Enabled") : tr("Disabled")) << "</td></tr>\r\n";
|
s << "<tr><td>" << "I2CP" << "</td><td class='" << (i2cp ? "enabled" : "disabled") << "'>" << (i2cp ? tr("Enabled") : tr("Disabled")) << "</td></tr>\r\n";
|
||||||
#endif
|
|
||||||
#ifdef WITH_I2PC
|
|
||||||
bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol);
|
|
||||||
s << "<tr><td>" << "I2PControl" << "</td><td class='" << (i2pcontrol ? "enabled" : "disabled") << "'>" << (i2pcontrol ? tr("Enabled") : tr("Disabled")) << "</td></tr>\r\n";
|
s << "<tr><td>" << "I2PControl" << "</td><td class='" << (i2pcontrol ? "enabled" : "disabled") << "'>" << (i2pcontrol ? tr("Enabled") : tr("Disabled")) << "</td></tr>\r\n";
|
||||||
#endif
|
|
||||||
s << "</tbody></table>\r\n";
|
s << "</tbody></table>\r\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -404,7 +392,6 @@ namespace http {
|
|||||||
}
|
}
|
||||||
s << "</div>\r\n";
|
s << "</div>\r\n";
|
||||||
|
|
||||||
#ifdef WITH_I2CP
|
|
||||||
auto i2cpServer = i2p::client::context.GetI2CPServer ();
|
auto i2cpServer = i2p::client::context.GetI2CPServer ();
|
||||||
if (i2cpServer && !(i2cpServer->GetSessions ().empty ()))
|
if (i2cpServer && !(i2cpServer->GetSessions ().empty ()))
|
||||||
{
|
{
|
||||||
@@ -422,7 +409,6 @@ namespace http {
|
|||||||
}
|
}
|
||||||
s << "</div>\r\n";
|
s << "</div>\r\n";
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ShowLeaseSetDestination (std::stringstream& s, std::shared_ptr<const i2p::client::LeaseSetDestination> dest, uint32_t token)
|
static void ShowLeaseSetDestination (std::stringstream& s, std::shared_ptr<const i2p::client::LeaseSetDestination> dest, uint32_t token)
|
||||||
@@ -437,7 +423,7 @@ namespace http {
|
|||||||
s << "</div>\r\n</div>\r\n";
|
s << "</div>\r\n</div>\r\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dest->IsPublic() && token)
|
if (dest->IsPublic() && token && !dest->IsEncryptedLeaseSet ())
|
||||||
{
|
{
|
||||||
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
|
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
|
||||||
auto base32 = dest->GetIdentHash ().ToBase32 ();
|
auto base32 = dest->GetIdentHash ().ToBase32 ();
|
||||||
@@ -549,19 +535,21 @@ namespace http {
|
|||||||
ShowLeaseSetDestination (s, dest, token);
|
ShowLeaseSetDestination (s, dest, token);
|
||||||
|
|
||||||
// Print table with streams information
|
// Print table with streams information
|
||||||
s << "<table>\r\n<caption>" << tr("Streams") << "</caption>\r\n<thead>\r\n<tr>";
|
s << "<table>\r\n<caption>"
|
||||||
s << "<th style=\"width:25px;\">StreamID</th>";
|
<< tr("Streams")
|
||||||
s << "<th style=\"width:5px;\" \\>"; // Stream closing button column
|
<< "</caption>\r\n<thead>\r\n<tr>"
|
||||||
s << "<th class=\"streamdest\">Destination</th>";
|
<< "<th style=\"width:25px;\">StreamID</th>"
|
||||||
s << "<th>Sent</th>";
|
<< "<th style=\"width:5px;\" \\>" // Stream closing button column
|
||||||
s << "<th>Received</th>";
|
<< "<th class=\"streamdest\">Destination</th>"
|
||||||
s << "<th>Out</th>";
|
<< "<th>Sent</th>"
|
||||||
s << "<th>In</th>";
|
<< "<th>Received</th>"
|
||||||
s << "<th>Buf</th>";
|
<< "<th>Out</th>"
|
||||||
s << "<th>RTT</th>";
|
<< "<th>In</th>"
|
||||||
s << "<th>Window</th>";
|
<< "<th>Buf</th>"
|
||||||
s << "<th>Status</th>";
|
<< "<th>RTT</th>"
|
||||||
s << "</tr>\r\n</thead>\r\n<tbody class=\"tableitem\">\r\n";
|
<< "<th>Window</th>"
|
||||||
|
<< "<th>Status</th>"
|
||||||
|
<< "</tr>\r\n</thead>\r\n<tbody class=\"tableitem\">\r\n";
|
||||||
|
|
||||||
for (const auto& it: dest->GetAllStreams ())
|
for (const auto& it: dest->GetAllStreams ())
|
||||||
{
|
{
|
||||||
@@ -590,7 +578,6 @@ namespace http {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_I2CP
|
|
||||||
void ShowI2CPLocalDestination (std::stringstream& s, const std::string& id)
|
void ShowI2CPLocalDestination (std::stringstream& s, const std::string& id)
|
||||||
{
|
{
|
||||||
auto i2cpServer = i2p::client::context.GetI2CPServer ();
|
auto i2cpServer = i2p::client::context.GetI2CPServer ();
|
||||||
@@ -606,7 +593,6 @@ namespace http {
|
|||||||
else
|
else
|
||||||
ShowError(s, tr("I2CP is not enabled"));
|
ShowError(s, tr("I2CP is not enabled"));
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
void ShowLeasesSets(std::stringstream& s)
|
void ShowLeasesSets(std::stringstream& s)
|
||||||
{
|
{
|
||||||
@@ -717,8 +703,7 @@ namespace http {
|
|||||||
|
|
||||||
s << "<b>" << tr("Router commands") << "</b><br>\r\n<br>\r\n<div class=\"commands\">\r\n";
|
s << "<b>" << tr("Router commands") << "</b><br>\r\n<br>\r\n<div class=\"commands\">\r\n";
|
||||||
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_RUN_PEER_TEST << "&token=" << token << "\">" << tr("Run peer test") << "</a><br>\r\n";
|
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_RUN_PEER_TEST << "&token=" << token << "\">" << tr("Run peer test") << "</a><br>\r\n";
|
||||||
|
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_RELOAD_TUNNELS_CONFIG << "&token=" << token << "\">" << tr("Reload tunnels configuration") << "</a><br>\r\n";
|
||||||
// s << " <a href=\"/?cmd=" << HTTP_COMMAND_RELOAD_CONFIG << "\">Reload config</a><br>\r\n";
|
|
||||||
|
|
||||||
if (i2p::context.AcceptsTunnels ())
|
if (i2p::context.AcceptsTunnels ())
|
||||||
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_DISABLE_TRANSIT << "&token=" << token << "\">" << tr("Decline transit tunnels") << "</a><br>\r\n";
|
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_DISABLE_TRANSIT << "&token=" << token << "\">" << tr("Decline transit tunnels") << "</a><br>\r\n";
|
||||||
@@ -759,17 +744,25 @@ namespace http {
|
|||||||
s << " <button type=\"submit\">" << tr("Change") << "</button>\r\n";
|
s << " <button type=\"submit\">" << tr("Change") << "</button>\r\n";
|
||||||
s << "</form>\r\n<br>\r\n";
|
s << "</form>\r\n<br>\r\n";
|
||||||
|
|
||||||
std::string currLang = i2p::client::context.GetLanguage ()->GetLanguage(); // get current used language
|
// get current used language
|
||||||
s << "<b>" << tr("Change language") << "</b><br>\r\n";
|
std::string currLang = i2p::client::context.GetLanguage ()->GetLanguage();
|
||||||
s << "<form method=\"get\" action=\"" << webroot << "\">\r\n";
|
|
||||||
s << " <input type=\"hidden\" name=\"cmd\" value=\"" << HTTP_COMMAND_SETLANGUAGE << "\">\r\n";
|
s << "<b>"
|
||||||
s << " <input type=\"hidden\" name=\"token\" value=\"" << token << "\">\r\n";
|
<< tr("Change language")
|
||||||
s << " <select name=\"lang\" id=\"lang\">\r\n";
|
<< "</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)
|
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 << " <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 << " </select>\r\n"
|
||||||
s << "</form>\r\n<br>\r\n";
|
<< " <button type=\"submit\">"
|
||||||
|
<< tr("Change")
|
||||||
|
<< "</button>\r\n"
|
||||||
|
<< "</form>\r\n<br>\r\n";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -803,25 +796,30 @@ namespace http {
|
|||||||
std::stringstream tmp_s, tmp_s6; uint16_t cnt = 0, cnt6 = 0;
|
std::stringstream tmp_s, tmp_s6; uint16_t cnt = 0, cnt6 = 0;
|
||||||
for (const auto& it: sessions )
|
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";
|
tmp_s << "<div class=\"listitem\">\r\n";
|
||||||
if (it.second->IsOutgoing ()) tmp_s << " ⇒ ";
|
if (it.second->IsOutgoing ()) tmp_s << " ⇒ ";
|
||||||
tmp_s << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": "
|
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 << " ⇒ ";
|
if (!it.second->IsOutgoing ()) tmp_s << " ⇒ ";
|
||||||
tmp_s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
tmp_s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
||||||
|
if (it.second->GetRelayTag ())
|
||||||
|
tmp_s << " [itag:" << it.second->GetRelayTag () << "]";
|
||||||
tmp_s << "</div>\r\n" << std::endl;
|
tmp_s << "</div>\r\n" << std::endl;
|
||||||
cnt++;
|
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";
|
tmp_s6 << "<div class=\"listitem\">\r\n";
|
||||||
if (it.second->IsOutgoing ()) tmp_s6 << " ⇒ ";
|
if (it.second->IsOutgoing ()) tmp_s6 << " ⇒ ";
|
||||||
tmp_s6 << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": "
|
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 << " ⇒ ";
|
if (!it.second->IsOutgoing ()) tmp_s6 << " ⇒ ";
|
||||||
tmp_s6 << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
tmp_s6 << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
||||||
|
if (it.second->GetRelayTag ())
|
||||||
|
tmp_s6 << " [itag:" << it.second->GetRelayTag () << "]";
|
||||||
tmp_s6 << "</div>\r\n" << std::endl;
|
tmp_s6 << "</div>\r\n" << std::endl;
|
||||||
cnt6++;
|
cnt6++;
|
||||||
}
|
}
|
||||||
@@ -850,46 +848,6 @@ namespace http {
|
|||||||
if (!sessions.empty ())
|
if (!sessions.empty ())
|
||||||
ShowTransportSessions (s, sessions, "NTCP2");
|
ShowTransportSessions (s, sessions, "NTCP2");
|
||||||
}
|
}
|
||||||
auto ssuServer = i2p::transport::transports.GetSSUServer ();
|
|
||||||
if (ssuServer)
|
|
||||||
{
|
|
||||||
auto sessions = ssuServer->GetSessions ();
|
|
||||||
if (!sessions.empty ())
|
|
||||||
{
|
|
||||||
s << "<div class='slide'><label for='slide_ssu'><b>SSU</b> ( " << (int) sessions.size() << " )</label>\r\n<input type=\"checkbox\" id=\"slide_ssu\" />\r\n<div class=\"slidecontent list\">";
|
|
||||||
for (const auto& it: sessions)
|
|
||||||
{
|
|
||||||
s << "<div class=\"listitem\">\r\n";
|
|
||||||
auto endpoint = it.second->GetRemoteEndpoint ();
|
|
||||||
if (it.second->IsOutgoing ()) s << " ⇒ ";
|
|
||||||
s << endpoint.address ().to_string () << ":" << endpoint.port ();
|
|
||||||
if (!it.second->IsOutgoing ()) s << " ⇒ ";
|
|
||||||
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
|
||||||
if (it.second->GetRelayTag ())
|
|
||||||
s << " [itag:" << it.second->GetRelayTag () << "]";
|
|
||||||
s << "</div>\r\n" << std::endl;
|
|
||||||
}
|
|
||||||
s << "</div>\r\n</div>\r\n";
|
|
||||||
}
|
|
||||||
auto sessions6 = ssuServer->GetSessionsV6 ();
|
|
||||||
if (!sessions6.empty ())
|
|
||||||
{
|
|
||||||
s << "<div class='slide'><label for='slide_ssuv6'><b>SSUv6</b> ( " << (int) sessions6.size() << " )</label>\r\n<input type=\"checkbox\" id=\"slide_ssuv6\" />\r\n<div class=\"slidecontent list\">";
|
|
||||||
for (const auto& it: sessions6)
|
|
||||||
{
|
|
||||||
s << "<div class=\"listitem\">\r\n";
|
|
||||||
auto endpoint = it.second->GetRemoteEndpoint ();
|
|
||||||
if (it.second->IsOutgoing ()) s << " ⇒ ";
|
|
||||||
s << "[" << endpoint.address ().to_string () << "]:" << endpoint.port ();
|
|
||||||
if (!it.second->IsOutgoing ()) s << " ⇒ ";
|
|
||||||
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
|
||||||
if (it.second->GetRelayTag ())
|
|
||||||
s << " [itag:" << it.second->GetRelayTag () << "]";
|
|
||||||
s << "</div>\r\n" << std::endl;
|
|
||||||
}
|
|
||||||
s << "</div>\r\n</div>\r\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
auto ssu2Server = i2p::transport::transports.GetSSU2Server ();
|
auto ssu2Server = i2p::transport::transports.GetSSU2Server ();
|
||||||
if (ssu2Server)
|
if (ssu2Server)
|
||||||
{
|
{
|
||||||
@@ -899,7 +857,6 @@ namespace http {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_SAM
|
|
||||||
void ShowSAMSessions (std::stringstream& s)
|
void ShowSAMSessions (std::stringstream& s)
|
||||||
{
|
{
|
||||||
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
|
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
|
||||||
@@ -962,7 +919,6 @@ namespace http {
|
|||||||
}
|
}
|
||||||
s << "</div>\r\n";
|
s << "</div>\r\n";
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
void ShowI2PTunnels (std::stringstream& s)
|
void ShowI2PTunnels (std::stringstream& s)
|
||||||
{
|
{
|
||||||
@@ -1216,16 +1172,12 @@ namespace http {
|
|||||||
uint32_t token = CreateToken ();
|
uint32_t token = CreateToken ();
|
||||||
ShowLocalDestination (s, params["b32"], token);
|
ShowLocalDestination (s, params["b32"], token);
|
||||||
}
|
}
|
||||||
#ifdef WITH_I2CP
|
|
||||||
else if (page == HTTP_PAGE_I2CP_LOCAL_DESTINATION)
|
else if (page == HTTP_PAGE_I2CP_LOCAL_DESTINATION)
|
||||||
ShowI2CPLocalDestination (s, params["i2cp_id"]);
|
ShowI2CPLocalDestination (s, params["i2cp_id"]);
|
||||||
#endif
|
|
||||||
#ifdef WITH_SAM
|
|
||||||
else if (page == HTTP_PAGE_SAM_SESSIONS)
|
else if (page == HTTP_PAGE_SAM_SESSIONS)
|
||||||
ShowSAMSessions (s);
|
ShowSAMSessions (s);
|
||||||
else if (page == HTTP_PAGE_SAM_SESSION)
|
else if (page == HTTP_PAGE_SAM_SESSION)
|
||||||
ShowSAMSession (s, params["sam_id"]);
|
ShowSAMSession (s, params["sam_id"]);
|
||||||
#endif
|
|
||||||
else if (page == HTTP_PAGE_I2P_TUNNELS)
|
else if (page == HTTP_PAGE_I2P_TUNNELS)
|
||||||
ShowI2PTunnels (s);
|
ShowI2PTunnels (s);
|
||||||
else if (page == HTTP_PAGE_LEASESETS)
|
else if (page == HTTP_PAGE_LEASESETS)
|
||||||
@@ -1258,7 +1210,7 @@ namespace http {
|
|||||||
std::string cmd = params["cmd"];
|
std::string cmd = params["cmd"];
|
||||||
if (cmd == HTTP_COMMAND_RUN_PEER_TEST)
|
if (cmd == HTTP_COMMAND_RUN_PEER_TEST)
|
||||||
i2p::transport::transports.PeerTest ();
|
i2p::transport::transports.PeerTest ();
|
||||||
else if (cmd == HTTP_COMMAND_RELOAD_CONFIG)
|
else if (cmd == HTTP_COMMAND_RELOAD_TUNNELS_CONFIG)
|
||||||
i2p::client::context.ReloadConfig ();
|
i2p::client::context.ReloadConfig ();
|
||||||
else if (cmd == HTTP_COMMAND_ENABLE_TRANSIT)
|
else if (cmd == HTTP_COMMAND_ENABLE_TRANSIT)
|
||||||
i2p::context.SetAcceptsTunnels (true);
|
i2p::context.SetAcceptsTunnels (true);
|
||||||
|
|||||||
@@ -95,15 +95,11 @@ namespace http
|
|||||||
void ShowTunnels (std::stringstream& s);
|
void ShowTunnels (std::stringstream& s);
|
||||||
void ShowTransitTunnels (std::stringstream& s);
|
void ShowTransitTunnels (std::stringstream& s);
|
||||||
void ShowTransports (std::stringstream& s);
|
void ShowTransports (std::stringstream& s);
|
||||||
|
void ShowSAMSessions (std::stringstream& s);
|
||||||
void ShowI2PTunnels (std::stringstream& s);
|
void ShowI2PTunnels (std::stringstream& s);
|
||||||
void ShowLocalDestination (std::stringstream& s, const std::string& b32, uint32_t token);
|
void ShowLocalDestination (std::stringstream& s, const std::string& b32, uint32_t token);
|
||||||
#ifdef WITH_SAM
|
|
||||||
void ShowSAMSessions (std::stringstream& s);
|
|
||||||
void ShowSAMSession (std::stringstream& s, const std::string& id);
|
void ShowSAMSession (std::stringstream& s, const std::string& id);
|
||||||
#endif
|
|
||||||
#ifdef WITH_I2CP
|
|
||||||
void ShowI2CPLocalDestination (std::stringstream& s, const std::string& id);
|
void ShowI2CPLocalDestination (std::stringstream& s, const std::string& id);
|
||||||
#endif
|
|
||||||
} // http
|
} // http
|
||||||
} // i2p
|
} // i2p
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,6 @@
|
|||||||
* See full license text in LICENSE file at top of project tree
|
* See full license text in LICENSE file at top of project tree
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef WITH_I2PC
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <openssl/x509.h>
|
#include <openssl/x509.h>
|
||||||
@@ -16,25 +14,17 @@
|
|||||||
// Use global placeholders from boost introduced when local_time.hpp is loaded
|
// Use global placeholders from boost introduced when local_time.hpp is loaded
|
||||||
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
|
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
|
||||||
|
|
||||||
#include <boost/lexical_cast.hpp>
|
|
||||||
#include <boost/date_time/local_time/local_time.hpp>
|
#include <boost/date_time/local_time/local_time.hpp>
|
||||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||||
#include <boost/property_tree/ini_parser.hpp>
|
|
||||||
#include <boost/property_tree/json_parser.hpp>
|
#include <boost/property_tree/json_parser.hpp>
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
|
|
||||||
#include "Crypto.h"
|
|
||||||
#include "FS.h"
|
#include "FS.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "NetDb.hpp"
|
#include "NetDb.hpp"
|
||||||
#include "RouterContext.h"
|
|
||||||
#include "Daemon.h"
|
|
||||||
#include "Tunnel.h"
|
#include "Tunnel.h"
|
||||||
#include "Timestamp.h"
|
#include "Daemon.h"
|
||||||
#include "Transports.h"
|
|
||||||
#include "version.h"
|
|
||||||
#include "util.h"
|
|
||||||
#include "ClientContext.h"
|
|
||||||
#include "I2PControl.h"
|
#include "I2PControl.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
@@ -71,50 +61,18 @@ namespace client
|
|||||||
m_MethodHandlers["Authenticate"] = &I2PControlService::AuthenticateHandler;
|
m_MethodHandlers["Authenticate"] = &I2PControlService::AuthenticateHandler;
|
||||||
m_MethodHandlers["Echo"] = &I2PControlService::EchoHandler;
|
m_MethodHandlers["Echo"] = &I2PControlService::EchoHandler;
|
||||||
m_MethodHandlers["I2PControl"] = &I2PControlService::I2PControlHandler;
|
m_MethodHandlers["I2PControl"] = &I2PControlService::I2PControlHandler;
|
||||||
m_MethodHandlers["RouterInfo"] = &I2PControlService::RouterInfoHandler;
|
m_MethodHandlers["RouterInfo"] = &I2PControlHandlers::RouterInfoHandler;
|
||||||
m_MethodHandlers["RouterManager"] = &I2PControlService::RouterManagerHandler;
|
m_MethodHandlers["RouterManager"] = &I2PControlService::RouterManagerHandler;
|
||||||
m_MethodHandlers["NetworkSetting"] = &I2PControlService::NetworkSettingHandler;
|
m_MethodHandlers["NetworkSetting"] = &I2PControlHandlers::NetworkSettingHandler;
|
||||||
m_MethodHandlers["ClientServicesInfo"] = &I2PControlService::ClientServicesInfoHandler;
|
m_MethodHandlers["ClientServicesInfo"] = &I2PControlHandlers::ClientServicesInfoHandler;
|
||||||
|
|
||||||
// I2PControl
|
// I2PControl
|
||||||
m_I2PControlHandlers["i2pcontrol.password"] = &I2PControlService::PasswordHandler;
|
m_I2PControlHandlers["i2pcontrol.password"] = &I2PControlService::PasswordHandler;
|
||||||
|
|
||||||
// RouterInfo
|
|
||||||
m_RouterInfoHandlers["i2p.router.uptime"] = &I2PControlService::UptimeHandler;
|
|
||||||
m_RouterInfoHandlers["i2p.router.version"] = &I2PControlService::VersionHandler;
|
|
||||||
m_RouterInfoHandlers["i2p.router.status"] = &I2PControlService::StatusHandler;
|
|
||||||
m_RouterInfoHandlers["i2p.router.netdb.knownpeers"] = &I2PControlService::NetDbKnownPeersHandler;
|
|
||||||
m_RouterInfoHandlers["i2p.router.netdb.activepeers"] = &I2PControlService::NetDbActivePeersHandler;
|
|
||||||
m_RouterInfoHandlers["i2p.router.net.bw.inbound.1s"] = &I2PControlService::InboundBandwidth1S;
|
|
||||||
m_RouterInfoHandlers["i2p.router.net.bw.outbound.1s"] = &I2PControlService::OutboundBandwidth1S;
|
|
||||||
m_RouterInfoHandlers["i2p.router.net.status"] = &I2PControlService::NetStatusHandler;
|
|
||||||
m_RouterInfoHandlers["i2p.router.net.tunnels.participating"] = &I2PControlService::TunnelsParticipatingHandler;
|
|
||||||
m_RouterInfoHandlers["i2p.router.net.tunnels.successrate"] = &I2PControlService::TunnelsSuccessRateHandler;
|
|
||||||
m_RouterInfoHandlers["i2p.router.net.total.received.bytes"] = &I2PControlService::NetTotalReceivedBytes;
|
|
||||||
m_RouterInfoHandlers["i2p.router.net.total.sent.bytes"] = &I2PControlService::NetTotalSentBytes;
|
|
||||||
|
|
||||||
// RouterManager
|
// RouterManager
|
||||||
m_RouterManagerHandlers["Reseed"] = &I2PControlService::ReseedHandler;
|
m_RouterManagerHandlers["Reseed"] = &I2PControlService::ReseedHandler;
|
||||||
m_RouterManagerHandlers["Shutdown"] = &I2PControlService::ShutdownHandler;
|
m_RouterManagerHandlers["Shutdown"] = &I2PControlService::ShutdownHandler;
|
||||||
m_RouterManagerHandlers["ShutdownGraceful"] = &I2PControlService::ShutdownGracefulHandler;
|
m_RouterManagerHandlers["ShutdownGraceful"] = &I2PControlService::ShutdownGracefulHandler;
|
||||||
|
|
||||||
// NetworkSetting
|
|
||||||
m_NetworkSettingHandlers["i2p.router.net.bw.in"] = &I2PControlService::InboundBandwidthLimit;
|
|
||||||
m_NetworkSettingHandlers["i2p.router.net.bw.out"] = &I2PControlService::OutboundBandwidthLimit;
|
|
||||||
|
|
||||||
// ClientServicesInfo
|
|
||||||
m_ClientServicesInfoHandlers["I2PTunnel"] = &I2PControlService::I2PTunnelInfoHandler;
|
|
||||||
m_ClientServicesInfoHandlers["HTTPProxy"] = &I2PControlService::HTTPProxyInfoHandler;
|
|
||||||
m_ClientServicesInfoHandlers["SOCKS"] = &I2PControlService::SOCKSInfoHandler;
|
|
||||||
#ifdef WITH_SAM
|
|
||||||
m_ClientServicesInfoHandlers["SAM"] = &I2PControlService::SAMInfoHandler;
|
|
||||||
#endif
|
|
||||||
#ifdef WITH_BOB
|
|
||||||
m_ClientServicesInfoHandlers["BOB"] = &I2PControlService::BOBInfoHandler;
|
|
||||||
#endif
|
|
||||||
#ifdef WITH_I2CP
|
|
||||||
m_ClientServicesInfoHandlers["I2CP"] = &I2PControlService::I2CPInfoHandler;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
I2PControlService::~I2PControlService ()
|
I2PControlService::~I2PControlService ()
|
||||||
@@ -288,37 +246,6 @@ namespace client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, int value) const
|
|
||||||
{
|
|
||||||
ss << "\"" << name << "\":" << value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value, bool quotes) const
|
|
||||||
{
|
|
||||||
ss << "\"" << name << "\":";
|
|
||||||
if (value.length () > 0)
|
|
||||||
{
|
|
||||||
if (quotes)
|
|
||||||
ss << "\"" << value << "\"";
|
|
||||||
else
|
|
||||||
ss << value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ss << "null";
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, double value) const
|
|
||||||
{
|
|
||||||
ss << "\"" << name << "\":" << std::fixed << std::setprecision(2) << value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, const boost::property_tree::ptree& value) const
|
|
||||||
{
|
|
||||||
std::ostringstream buf;
|
|
||||||
boost::property_tree::write_json (buf, value, false);
|
|
||||||
ss << "\"" << name << "\":" << buf.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PControlService::SendResponse (std::shared_ptr<ssl_socket> socket,
|
void I2PControlService::SendResponse (std::shared_ptr<ssl_socket> socket,
|
||||||
std::shared_ptr<I2PControlBuffer> buf, std::ostringstream& response, bool isHtml)
|
std::shared_ptr<I2PControlBuffer> buf, std::ostringstream& response, bool isHtml)
|
||||||
{
|
{
|
||||||
@@ -354,6 +281,7 @@ namespace client
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handlers
|
// handlers
|
||||||
|
|
||||||
void I2PControlService::AuthenticateHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
void I2PControlService::AuthenticateHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
||||||
{
|
{
|
||||||
int api = params.get<int> ("API");
|
int api = params.get<int> ("API");
|
||||||
@@ -379,6 +307,7 @@ namespace client
|
|||||||
|
|
||||||
|
|
||||||
// I2PControl
|
// I2PControl
|
||||||
|
|
||||||
void I2PControlService::I2PControlHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
void I2PControlService::I2PControlHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
||||||
{
|
{
|
||||||
for (auto& it: params)
|
for (auto& it: params)
|
||||||
@@ -402,91 +331,6 @@ namespace client
|
|||||||
m_Tokens.clear ();
|
m_Tokens.clear ();
|
||||||
}
|
}
|
||||||
|
|
||||||
// RouterInfo
|
|
||||||
|
|
||||||
void I2PControlService::RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
|
||||||
{
|
|
||||||
bool first = true;
|
|
||||||
for (auto it = params.begin (); it != params.end (); it++)
|
|
||||||
{
|
|
||||||
LogPrint (eLogDebug, "I2PControl: RouterInfo request: ", it->first);
|
|
||||||
auto it1 = m_RouterInfoHandlers.find (it->first);
|
|
||||||
if (it1 != m_RouterInfoHandlers.end ())
|
|
||||||
{
|
|
||||||
if (!first) results << ",";
|
|
||||||
else first = false;
|
|
||||||
(this->*(it1->second))(results);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
LogPrint (eLogError, "I2PControl: RouterInfo unknown request ", it->first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PControlService::UptimeHandler (std::ostringstream& results)
|
|
||||||
{
|
|
||||||
InsertParam (results, "i2p.router.uptime", std::to_string (i2p::context.GetUptime ()*1000LL), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PControlService::VersionHandler (std::ostringstream& results)
|
|
||||||
{
|
|
||||||
InsertParam (results, "i2p.router.version", VERSION);
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PControlService::StatusHandler (std::ostringstream& results)
|
|
||||||
{
|
|
||||||
auto dest = i2p::client::context.GetSharedLocalDestination ();
|
|
||||||
InsertParam (results, "i2p.router.status", (dest && dest->IsReady ()) ? "1" : "0");
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PControlService::NetDbKnownPeersHandler (std::ostringstream& results)
|
|
||||||
{
|
|
||||||
InsertParam (results, "i2p.router.netdb.knownpeers", i2p::data::netdb.GetNumRouters ());
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PControlService::NetDbActivePeersHandler (std::ostringstream& results)
|
|
||||||
{
|
|
||||||
InsertParam (results, "i2p.router.netdb.activepeers", (int)i2p::transport::transports.GetPeers ().size ());
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PControlService::NetStatusHandler (std::ostringstream& results)
|
|
||||||
{
|
|
||||||
InsertParam (results, "i2p.router.net.status", (int)i2p::context.GetStatus ());
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PControlService::TunnelsParticipatingHandler (std::ostringstream& results)
|
|
||||||
{
|
|
||||||
int transit = i2p::tunnel::tunnels.GetTransitTunnels ().size ();
|
|
||||||
InsertParam (results, "i2p.router.net.tunnels.participating", transit);
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PControlService::TunnelsSuccessRateHandler (std::ostringstream& results)
|
|
||||||
{
|
|
||||||
int rate = i2p::tunnel::tunnels.GetTunnelCreationSuccessRate ();
|
|
||||||
InsertParam (results, "i2p.router.net.tunnels.successrate", rate);
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PControlService::InboundBandwidth1S (std::ostringstream& results)
|
|
||||||
{
|
|
||||||
double bw = i2p::transport::transports.GetInBandwidth ();
|
|
||||||
InsertParam (results, "i2p.router.net.bw.inbound.1s", bw);
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PControlService::OutboundBandwidth1S (std::ostringstream& results)
|
|
||||||
{
|
|
||||||
double bw = i2p::transport::transports.GetOutBandwidth ();
|
|
||||||
InsertParam (results, "i2p.router.net.bw.outbound.1s", bw);
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PControlService::NetTotalReceivedBytes (std::ostringstream& results)
|
|
||||||
{
|
|
||||||
InsertParam (results, "i2p.router.net.total.received.bytes", (double)i2p::transport::transports.GetTotalReceivedBytes ());
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PControlService::NetTotalSentBytes (std::ostringstream& results)
|
|
||||||
{
|
|
||||||
InsertParam (results, "i2p.router.net.total.sent.bytes", (double)i2p::transport::transports.GetTotalSentBytes ());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// RouterManager
|
// RouterManager
|
||||||
|
|
||||||
@@ -538,37 +382,6 @@ namespace client
|
|||||||
i2p::data::netdb.Reseed ();
|
i2p::data::netdb.Reseed ();
|
||||||
}
|
}
|
||||||
|
|
||||||
// network setting
|
|
||||||
void I2PControlService::NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
|
||||||
{
|
|
||||||
for (auto it = params.begin (); it != params.end (); it++)
|
|
||||||
{
|
|
||||||
LogPrint (eLogDebug, "I2PControl: NetworkSetting request: ", it->first);
|
|
||||||
auto it1 = m_NetworkSettingHandlers.find (it->first);
|
|
||||||
if (it1 != m_NetworkSettingHandlers.end ()) {
|
|
||||||
if (it != params.begin ()) results << ",";
|
|
||||||
(this->*(it1->second))(it->second.data (), results);
|
|
||||||
} else
|
|
||||||
LogPrint (eLogError, "I2PControl: NetworkSetting unknown request: ", it->first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PControlService::InboundBandwidthLimit (const std::string& value, std::ostringstream& results)
|
|
||||||
{
|
|
||||||
if (value != "null")
|
|
||||||
i2p::context.SetBandwidth (std::atoi(value.c_str()));
|
|
||||||
int bw = i2p::context.GetBandwidthLimit();
|
|
||||||
InsertParam (results, "i2p.router.net.bw.in", bw);
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PControlService::OutboundBandwidthLimit (const std::string& value, std::ostringstream& results)
|
|
||||||
{
|
|
||||||
if (value != "null")
|
|
||||||
i2p::context.SetBandwidth (std::atoi(value.c_str()));
|
|
||||||
int bw = i2p::context.GetBandwidthLimit();
|
|
||||||
InsertParam (results, "i2p.router.net.bw.out", bw);
|
|
||||||
}
|
|
||||||
|
|
||||||
// certificate
|
// certificate
|
||||||
void I2PControlService::CreateCertificate (const char *crt_path, const char *key_path)
|
void I2PControlService::CreateCertificate (const char *crt_path, const char *key_path)
|
||||||
{
|
{
|
||||||
@@ -617,184 +430,5 @@ namespace client
|
|||||||
}
|
}
|
||||||
EVP_PKEY_free (pkey);
|
EVP_PKEY_free (pkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClientServicesInfo
|
|
||||||
void I2PControlService::ClientServicesInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
|
||||||
{
|
|
||||||
for (auto it = params.begin (); it != params.end (); it++)
|
|
||||||
{
|
|
||||||
LogPrint (eLogDebug, "I2PControl: ClientServicesInfo request: ", it->first);
|
|
||||||
auto it1 = m_ClientServicesInfoHandlers.find (it->first);
|
|
||||||
if (it1 != m_ClientServicesInfoHandlers.end ())
|
|
||||||
{
|
|
||||||
if (it != params.begin ()) results << ",";
|
|
||||||
(this->*(it1->second))(results);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
LogPrint (eLogError, "I2PControl: ClientServicesInfo unknown request ", it->first);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PControlService::I2PTunnelInfoHandler (std::ostringstream& results)
|
|
||||||
{
|
|
||||||
boost::property_tree::ptree pt;
|
|
||||||
boost::property_tree::ptree client_tunnels, server_tunnels;
|
|
||||||
|
|
||||||
for (auto& it: i2p::client::context.GetClientTunnels ())
|
|
||||||
{
|
|
||||||
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
|
||||||
boost::property_tree::ptree ct;
|
|
||||||
ct.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
|
|
||||||
client_tunnels.add_child(it.second->GetName (), ct);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& serverTunnels = i2p::client::context.GetServerTunnels ();
|
|
||||||
if (!serverTunnels.empty ()) {
|
|
||||||
for (auto& it: serverTunnels)
|
|
||||||
{
|
|
||||||
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
|
||||||
boost::property_tree::ptree st;
|
|
||||||
st.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
|
|
||||||
st.put("port", it.second->GetLocalPort ());
|
|
||||||
server_tunnels.add_child(it.second->GetName (), st);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& clientForwards = i2p::client::context.GetClientForwards ();
|
|
||||||
if (!clientForwards.empty ())
|
|
||||||
{
|
|
||||||
for (auto& it: clientForwards)
|
|
||||||
{
|
|
||||||
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
|
||||||
boost::property_tree::ptree ct;
|
|
||||||
ct.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
|
|
||||||
client_tunnels.add_child(it.second->GetName (), ct);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& serverForwards = i2p::client::context.GetServerForwards ();
|
|
||||||
if (!serverForwards.empty ())
|
|
||||||
{
|
|
||||||
for (auto& it: serverForwards)
|
|
||||||
{
|
|
||||||
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
|
||||||
boost::property_tree::ptree st;
|
|
||||||
st.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
|
|
||||||
server_tunnels.add_child(it.second->GetName (), st);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pt.add_child("client", client_tunnels);
|
|
||||||
pt.add_child("server", server_tunnels);
|
|
||||||
|
|
||||||
InsertParam (results, "I2PTunnel", pt);
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PControlService::HTTPProxyInfoHandler (std::ostringstream& results)
|
|
||||||
{
|
|
||||||
boost::property_tree::ptree pt;
|
|
||||||
|
|
||||||
auto httpProxy = i2p::client::context.GetHttpProxy ();
|
|
||||||
if (httpProxy)
|
|
||||||
{
|
|
||||||
auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash();
|
|
||||||
pt.put("enabled", true);
|
|
||||||
pt.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
pt.put("enabled", false);
|
|
||||||
|
|
||||||
InsertParam (results, "HTTPProxy", pt);
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PControlService::SOCKSInfoHandler (std::ostringstream& results)
|
|
||||||
{
|
|
||||||
boost::property_tree::ptree pt;
|
|
||||||
|
|
||||||
auto socksProxy = i2p::client::context.GetSocksProxy ();
|
|
||||||
if (socksProxy)
|
|
||||||
{
|
|
||||||
auto& ident = socksProxy->GetLocalDestination ()->GetIdentHash();
|
|
||||||
pt.put("enabled", true);
|
|
||||||
pt.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
pt.put("enabled", false);
|
|
||||||
|
|
||||||
InsertParam (results, "SOCKS", pt);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef WITH_SAM
|
|
||||||
void I2PControlService::SAMInfoHandler (std::ostringstream& results)
|
|
||||||
{
|
|
||||||
boost::property_tree::ptree pt;
|
|
||||||
auto sam = i2p::client::context.GetSAMBridge ();
|
|
||||||
if (sam)
|
|
||||||
{
|
|
||||||
pt.put("enabled", true);
|
|
||||||
boost::property_tree::ptree sam_sessions;
|
|
||||||
for (auto& it: sam->GetSessions ())
|
|
||||||
{
|
|
||||||
boost::property_tree::ptree sam_session, sam_session_sockets;
|
|
||||||
auto& name = it.second->GetLocalDestination ()->GetNickname ();
|
|
||||||
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
|
||||||
sam_session.put("name", name);
|
|
||||||
sam_session.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
|
|
||||||
|
|
||||||
for (const auto& socket: sam->ListSockets(it.first))
|
|
||||||
{
|
|
||||||
boost::property_tree::ptree stream;
|
|
||||||
stream.put("type", socket->GetSocketType ());
|
|
||||||
stream.put("peer", socket->GetSocket ().remote_endpoint());
|
|
||||||
|
|
||||||
sam_session_sockets.push_back(std::make_pair("", stream));
|
|
||||||
}
|
|
||||||
sam_session.add_child("sockets", sam_session_sockets);
|
|
||||||
sam_sessions.add_child(it.first, sam_session);
|
|
||||||
}
|
|
||||||
|
|
||||||
pt.add_child("sessions", sam_sessions);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
pt.put("enabled", false);
|
|
||||||
|
|
||||||
InsertParam (results, "SAM", pt);
|
|
||||||
}
|
|
||||||
#endif // WITH_SAM
|
|
||||||
|
|
||||||
#ifdef WITH_BOB
|
|
||||||
void I2PControlService::BOBInfoHandler (std::ostringstream& results)
|
|
||||||
{
|
|
||||||
boost::property_tree::ptree pt;
|
|
||||||
auto bob = i2p::client::context.GetBOBCommandChannel ();
|
|
||||||
if (bob)
|
|
||||||
{
|
|
||||||
/* TODO more info */
|
|
||||||
pt.put("enabled", true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
pt.put("enabled", false);
|
|
||||||
|
|
||||||
InsertParam (results, "BOB", pt);
|
|
||||||
}
|
|
||||||
#endif // WITH_BOB
|
|
||||||
|
|
||||||
#ifdef WITH_I2CP
|
|
||||||
void I2PControlService::I2CPInfoHandler (std::ostringstream& results)
|
|
||||||
{
|
|
||||||
boost::property_tree::ptree pt;
|
|
||||||
auto i2cp = i2p::client::context.GetI2CPServer ();
|
|
||||||
if (i2cp)
|
|
||||||
{
|
|
||||||
/* TODO more info */
|
|
||||||
pt.put("enabled", true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
pt.put("enabled", false);
|
|
||||||
|
|
||||||
InsertParam (results, "I2CP", pt);
|
|
||||||
}
|
|
||||||
#endif // WITH_I2CP
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // WITH_I2PC
|
|
||||||
@@ -6,8 +6,6 @@
|
|||||||
* See full license text in LICENSE file at top of project tree
|
* See full license text in LICENSE file at top of project tree
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef WITH_I2PC
|
|
||||||
|
|
||||||
#ifndef I2P_CONTROL_H__
|
#ifndef I2P_CONTROL_H__
|
||||||
#define I2P_CONTROL_H__
|
#define I2P_CONTROL_H__
|
||||||
|
|
||||||
@@ -22,6 +20,7 @@
|
|||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <boost/asio/ssl.hpp>
|
#include <boost/asio/ssl.hpp>
|
||||||
#include <boost/property_tree/ptree.hpp>
|
#include <boost/property_tree/ptree.hpp>
|
||||||
|
#include "I2PControlHandlers.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
@@ -34,7 +33,7 @@ namespace client
|
|||||||
const char I2P_CONTROL_CERTIFICATE_COMMON_NAME[] = "i2pd.i2pcontrol";
|
const char I2P_CONTROL_CERTIFICATE_COMMON_NAME[] = "i2pd.i2pcontrol";
|
||||||
const char I2P_CONTROL_CERTIFICATE_ORGANIZATION[] = "Purple I2P";
|
const char I2P_CONTROL_CERTIFICATE_ORGANIZATION[] = "Purple I2P";
|
||||||
|
|
||||||
class I2PControlService
|
class I2PControlService: public I2PControlHandlers
|
||||||
{
|
{
|
||||||
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket;
|
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket;
|
||||||
|
|
||||||
@@ -65,67 +64,24 @@ namespace client
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void InsertParam (std::ostringstream& ss, const std::string& name, int value) const;
|
|
||||||
void InsertParam (std::ostringstream& ss, const std::string& name, double value) const;
|
|
||||||
void InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value, bool quotes = true) const;
|
|
||||||
void InsertParam (std::ostringstream& ss, const std::string& name, const boost::property_tree::ptree& value) const;
|
|
||||||
|
|
||||||
// methods
|
// methods
|
||||||
typedef void (I2PControlService::*MethodHandler)(const boost::property_tree::ptree& params, std::ostringstream& results);
|
typedef void (I2PControlService::*MethodHandler)(const boost::property_tree::ptree& params, std::ostringstream& results);
|
||||||
|
|
||||||
void AuthenticateHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
|
void AuthenticateHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
|
||||||
void EchoHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
|
void EchoHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
|
||||||
void I2PControlHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
|
void I2PControlHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
|
||||||
void RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
|
|
||||||
void RouterManagerHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
|
void RouterManagerHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
|
||||||
void NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
|
|
||||||
void ClientServicesInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
|
|
||||||
|
|
||||||
// I2PControl
|
// I2PControl
|
||||||
typedef void (I2PControlService::*I2PControlRequestHandler)(const std::string& value);
|
typedef void (I2PControlService::*I2PControlRequestHandler)(const std::string& value);
|
||||||
void PasswordHandler (const std::string& value);
|
void PasswordHandler (const std::string& value);
|
||||||
|
|
||||||
// RouterInfo
|
|
||||||
typedef void (I2PControlService::*RouterInfoRequestHandler)(std::ostringstream& results);
|
|
||||||
void UptimeHandler (std::ostringstream& results);
|
|
||||||
void VersionHandler (std::ostringstream& results);
|
|
||||||
void StatusHandler (std::ostringstream& results);
|
|
||||||
void NetDbKnownPeersHandler (std::ostringstream& results);
|
|
||||||
void NetDbActivePeersHandler (std::ostringstream& results);
|
|
||||||
void NetStatusHandler (std::ostringstream& results);
|
|
||||||
void TunnelsParticipatingHandler (std::ostringstream& results);
|
|
||||||
void TunnelsSuccessRateHandler (std::ostringstream& results);
|
|
||||||
void InboundBandwidth1S (std::ostringstream& results);
|
|
||||||
void OutboundBandwidth1S (std::ostringstream& results);
|
|
||||||
void NetTotalReceivedBytes (std::ostringstream& results);
|
|
||||||
void NetTotalSentBytes (std::ostringstream& results);
|
|
||||||
|
|
||||||
// RouterManager
|
// RouterManager
|
||||||
typedef void (I2PControlService::*RouterManagerRequestHandler)(std::ostringstream& results);
|
typedef void (I2PControlService::*RouterManagerRequestHandler)(std::ostringstream& results);
|
||||||
void ShutdownHandler (std::ostringstream& results);
|
void ShutdownHandler (std::ostringstream& results);
|
||||||
void ShutdownGracefulHandler (std::ostringstream& results);
|
void ShutdownGracefulHandler (std::ostringstream& results);
|
||||||
void ReseedHandler (std::ostringstream& results);
|
void ReseedHandler (std::ostringstream& results);
|
||||||
|
|
||||||
// NetworkSetting
|
|
||||||
typedef void (I2PControlService::*NetworkSettingRequestHandler)(const std::string& value, std::ostringstream& results);
|
|
||||||
void InboundBandwidthLimit (const std::string& value, std::ostringstream& results);
|
|
||||||
void OutboundBandwidthLimit (const std::string& value, std::ostringstream& results);
|
|
||||||
|
|
||||||
// ClientServicesInfo
|
|
||||||
typedef void (I2PControlService::*ClientServicesInfoRequestHandler)(std::ostringstream& results);
|
|
||||||
void I2PTunnelInfoHandler (std::ostringstream& results);
|
|
||||||
void HTTPProxyInfoHandler (std::ostringstream& results);
|
|
||||||
void SOCKSInfoHandler (std::ostringstream& results);
|
|
||||||
#ifdef WITH_SAM
|
|
||||||
void SAMInfoHandler (std::ostringstream& results);
|
|
||||||
#endif
|
|
||||||
#ifdef WITH_BOB
|
|
||||||
void BOBInfoHandler (std::ostringstream& results);
|
|
||||||
#endif
|
|
||||||
#ifdef WITH_I2CP
|
|
||||||
void I2CPInfoHandler (std::ostringstream& results);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::string m_Password;
|
std::string m_Password;
|
||||||
@@ -140,13 +96,9 @@ namespace client
|
|||||||
|
|
||||||
std::map<std::string, MethodHandler> m_MethodHandlers;
|
std::map<std::string, MethodHandler> m_MethodHandlers;
|
||||||
std::map<std::string, I2PControlRequestHandler> m_I2PControlHandlers;
|
std::map<std::string, I2PControlRequestHandler> m_I2PControlHandlers;
|
||||||
std::map<std::string, RouterInfoRequestHandler> m_RouterInfoHandlers;
|
|
||||||
std::map<std::string, RouterManagerRequestHandler> m_RouterManagerHandlers;
|
std::map<std::string, RouterManagerRequestHandler> m_RouterManagerHandlers;
|
||||||
std::map<std::string, NetworkSettingRequestHandler> m_NetworkSettingHandlers;
|
|
||||||
std::map<std::string, ClientServicesInfoRequestHandler> m_ClientServicesInfoHandlers;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif // WITH_I2PC
|
|
||||||
390
daemon/I2PControlHandlers.cpp
Normal file
390
daemon/I2PControlHandlers.cpp
Normal file
@@ -0,0 +1,390 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||||
|
*
|
||||||
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
|
*
|
||||||
|
* See full license text in LICENSE file at top of project tree
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
|
#include <boost/property_tree/json_parser.hpp>
|
||||||
|
|
||||||
|
#include "Log.h"
|
||||||
|
#include "RouterContext.h"
|
||||||
|
#include "NetDb.hpp"
|
||||||
|
#include "Tunnel.h"
|
||||||
|
#include "Transports.h"
|
||||||
|
#include "version.h"
|
||||||
|
#include "ClientContext.h"
|
||||||
|
#include "I2PControlHandlers.h"
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace client
|
||||||
|
{
|
||||||
|
I2PControlHandlers::I2PControlHandlers ()
|
||||||
|
{
|
||||||
|
// RouterInfo
|
||||||
|
m_RouterInfoHandlers["i2p.router.uptime"] = &I2PControlHandlers::UptimeHandler;
|
||||||
|
m_RouterInfoHandlers["i2p.router.version"] = &I2PControlHandlers::VersionHandler;
|
||||||
|
m_RouterInfoHandlers["i2p.router.status"] = &I2PControlHandlers::StatusHandler;
|
||||||
|
m_RouterInfoHandlers["i2p.router.netdb.knownpeers"] = &I2PControlHandlers::NetDbKnownPeersHandler;
|
||||||
|
m_RouterInfoHandlers["i2p.router.netdb.activepeers"] = &I2PControlHandlers::NetDbActivePeersHandler;
|
||||||
|
m_RouterInfoHandlers["i2p.router.net.bw.inbound.1s"] = &I2PControlHandlers::InboundBandwidth1S;
|
||||||
|
m_RouterInfoHandlers["i2p.router.net.bw.inbound.15s"] = &I2PControlHandlers::InboundBandwidth15S;
|
||||||
|
m_RouterInfoHandlers["i2p.router.net.bw.outbound.1s"] = &I2PControlHandlers::OutboundBandwidth1S;
|
||||||
|
m_RouterInfoHandlers["i2p.router.net.bw.outbound.15s"] = &I2PControlHandlers::OutboundBandwidth15S;
|
||||||
|
m_RouterInfoHandlers["i2p.router.net.status"] = &I2PControlHandlers::NetStatusHandler;
|
||||||
|
m_RouterInfoHandlers["i2p.router.net.tunnels.participating"] = &I2PControlHandlers::TunnelsParticipatingHandler;
|
||||||
|
m_RouterInfoHandlers["i2p.router.net.tunnels.successrate"] = &I2PControlHandlers::TunnelsSuccessRateHandler;
|
||||||
|
m_RouterInfoHandlers["i2p.router.net.total.received.bytes"] = &I2PControlHandlers::NetTotalReceivedBytes;
|
||||||
|
m_RouterInfoHandlers["i2p.router.net.total.sent.bytes"] = &I2PControlHandlers::NetTotalSentBytes;
|
||||||
|
|
||||||
|
// NetworkSetting
|
||||||
|
m_NetworkSettingHandlers["i2p.router.net.bw.in"] = &I2PControlHandlers::InboundBandwidthLimit;
|
||||||
|
m_NetworkSettingHandlers["i2p.router.net.bw.out"] = &I2PControlHandlers::OutboundBandwidthLimit;
|
||||||
|
|
||||||
|
// ClientServicesInfo
|
||||||
|
m_ClientServicesInfoHandlers["I2PTunnel"] = &I2PControlHandlers::I2PTunnelInfoHandler;
|
||||||
|
m_ClientServicesInfoHandlers["HTTPProxy"] = &I2PControlHandlers::HTTPProxyInfoHandler;
|
||||||
|
m_ClientServicesInfoHandlers["SOCKS"] = &I2PControlHandlers::SOCKSInfoHandler;
|
||||||
|
m_ClientServicesInfoHandlers["SAM"] = &I2PControlHandlers::SAMInfoHandler;
|
||||||
|
m_ClientServicesInfoHandlers["BOB"] = &I2PControlHandlers::BOBInfoHandler;
|
||||||
|
m_ClientServicesInfoHandlers["I2CP"] = &I2PControlHandlers::I2CPInfoHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlHandlers::InsertParam (std::ostringstream& ss, const std::string& name, int value) const
|
||||||
|
{
|
||||||
|
ss << "\"" << name << "\":" << value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlHandlers::InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value, bool quotes) const
|
||||||
|
{
|
||||||
|
ss << "\"" << name << "\":";
|
||||||
|
if (value.length () > 0)
|
||||||
|
{
|
||||||
|
if (quotes)
|
||||||
|
ss << "\"" << value << "\"";
|
||||||
|
else
|
||||||
|
ss << value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ss << "null";
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlHandlers::InsertParam (std::ostringstream& ss, const std::string& name, double value) const
|
||||||
|
{
|
||||||
|
ss << "\"" << name << "\":" << std::fixed << std::setprecision(2) << value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlHandlers::InsertParam (std::ostringstream& ss, const std::string& name, const boost::property_tree::ptree& value) const
|
||||||
|
{
|
||||||
|
std::ostringstream buf;
|
||||||
|
boost::property_tree::write_json (buf, value, false);
|
||||||
|
ss << "\"" << name << "\":" << buf.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
// RouterInfo
|
||||||
|
|
||||||
|
void I2PControlHandlers::RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
||||||
|
{
|
||||||
|
bool first = true;
|
||||||
|
for (auto it = params.begin (); it != params.end (); it++)
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "I2PControl: RouterInfo request: ", it->first);
|
||||||
|
auto it1 = m_RouterInfoHandlers.find (it->first);
|
||||||
|
if (it1 != m_RouterInfoHandlers.end ())
|
||||||
|
{
|
||||||
|
if (!first) results << ",";
|
||||||
|
else first = false;
|
||||||
|
(this->*(it1->second))(results);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint (eLogError, "I2PControl: RouterInfo unknown request ", it->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlHandlers::UptimeHandler (std::ostringstream& results)
|
||||||
|
{
|
||||||
|
InsertParam (results, "i2p.router.uptime", std::to_string (i2p::context.GetUptime ()*1000LL), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlHandlers::VersionHandler (std::ostringstream& results)
|
||||||
|
{
|
||||||
|
InsertParam (results, "i2p.router.version", VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlHandlers::StatusHandler (std::ostringstream& results)
|
||||||
|
{
|
||||||
|
auto dest = i2p::client::context.GetSharedLocalDestination ();
|
||||||
|
InsertParam (results, "i2p.router.status", (dest && dest->IsReady ()) ? "1" : "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlHandlers::NetDbKnownPeersHandler (std::ostringstream& results)
|
||||||
|
{
|
||||||
|
InsertParam (results, "i2p.router.netdb.knownpeers", i2p::data::netdb.GetNumRouters ());
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlHandlers::NetDbActivePeersHandler (std::ostringstream& results)
|
||||||
|
{
|
||||||
|
InsertParam (results, "i2p.router.netdb.activepeers", (int)i2p::transport::transports.GetPeers ().size ());
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlHandlers::NetStatusHandler (std::ostringstream& results)
|
||||||
|
{
|
||||||
|
InsertParam (results, "i2p.router.net.status", (int)i2p::context.GetStatus ());
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlHandlers::TunnelsParticipatingHandler (std::ostringstream& results)
|
||||||
|
{
|
||||||
|
int transit = i2p::tunnel::tunnels.GetTransitTunnels ().size ();
|
||||||
|
InsertParam (results, "i2p.router.net.tunnels.participating", transit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlHandlers::TunnelsSuccessRateHandler (std::ostringstream& results)
|
||||||
|
{
|
||||||
|
int rate = i2p::tunnel::tunnels.GetTunnelCreationSuccessRate ();
|
||||||
|
InsertParam (results, "i2p.router.net.tunnels.successrate", rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlHandlers::InboundBandwidth1S (std::ostringstream& results)
|
||||||
|
{
|
||||||
|
double bw = i2p::transport::transports.GetInBandwidth ();
|
||||||
|
InsertParam (results, "i2p.router.net.bw.inbound.1s", bw);
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlHandlers::InboundBandwidth15S (std::ostringstream& results)
|
||||||
|
{
|
||||||
|
double bw = i2p::transport::transports.GetInBandwidth15s ();
|
||||||
|
InsertParam (results, "i2p.router.net.bw.inbound.15s", bw);
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlHandlers::OutboundBandwidth1S (std::ostringstream& results)
|
||||||
|
{
|
||||||
|
double bw = i2p::transport::transports.GetOutBandwidth ();
|
||||||
|
InsertParam (results, "i2p.router.net.bw.outbound.1s", bw);
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlHandlers::OutboundBandwidth15S (std::ostringstream& results)
|
||||||
|
{
|
||||||
|
double bw = i2p::transport::transports.GetOutBandwidth15s ();
|
||||||
|
InsertParam (results, "i2p.router.net.bw.outbound.15s", bw);
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlHandlers::NetTotalReceivedBytes (std::ostringstream& results)
|
||||||
|
{
|
||||||
|
InsertParam (results, "i2p.router.net.total.received.bytes", (double)i2p::transport::transports.GetTotalReceivedBytes ());
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlHandlers::NetTotalSentBytes (std::ostringstream& results)
|
||||||
|
{
|
||||||
|
InsertParam (results, "i2p.router.net.total.sent.bytes", (double)i2p::transport::transports.GetTotalSentBytes ());
|
||||||
|
}
|
||||||
|
|
||||||
|
// network setting
|
||||||
|
void I2PControlHandlers::NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
||||||
|
{
|
||||||
|
for (auto it = params.begin (); it != params.end (); it++)
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "I2PControl: NetworkSetting request: ", it->first);
|
||||||
|
auto it1 = m_NetworkSettingHandlers.find (it->first);
|
||||||
|
if (it1 != m_NetworkSettingHandlers.end ()) {
|
||||||
|
if (it != params.begin ()) results << ",";
|
||||||
|
(this->*(it1->second))(it->second.data (), results);
|
||||||
|
} else
|
||||||
|
LogPrint (eLogError, "I2PControl: NetworkSetting unknown request: ", it->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlHandlers::InboundBandwidthLimit (const std::string& value, std::ostringstream& results)
|
||||||
|
{
|
||||||
|
if (value != "null")
|
||||||
|
i2p::context.SetBandwidth (std::atoi(value.c_str()));
|
||||||
|
int bw = i2p::context.GetBandwidthLimit();
|
||||||
|
InsertParam (results, "i2p.router.net.bw.in", bw);
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlHandlers::OutboundBandwidthLimit (const std::string& value, std::ostringstream& results)
|
||||||
|
{
|
||||||
|
if (value != "null")
|
||||||
|
i2p::context.SetBandwidth (std::atoi(value.c_str()));
|
||||||
|
int bw = i2p::context.GetBandwidthLimit();
|
||||||
|
InsertParam (results, "i2p.router.net.bw.out", bw);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientServicesInfo
|
||||||
|
|
||||||
|
void I2PControlHandlers::ClientServicesInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
||||||
|
{
|
||||||
|
for (auto it = params.begin (); it != params.end (); it++)
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "I2PControl: ClientServicesInfo request: ", it->first);
|
||||||
|
auto it1 = m_ClientServicesInfoHandlers.find (it->first);
|
||||||
|
if (it1 != m_ClientServicesInfoHandlers.end ())
|
||||||
|
{
|
||||||
|
if (it != params.begin ()) results << ",";
|
||||||
|
(this->*(it1->second))(results);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint (eLogError, "I2PControl: ClientServicesInfo unknown request ", it->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlHandlers::I2PTunnelInfoHandler (std::ostringstream& results)
|
||||||
|
{
|
||||||
|
boost::property_tree::ptree pt;
|
||||||
|
boost::property_tree::ptree client_tunnels, server_tunnels;
|
||||||
|
|
||||||
|
for (auto& it: i2p::client::context.GetClientTunnels ())
|
||||||
|
{
|
||||||
|
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
||||||
|
boost::property_tree::ptree ct;
|
||||||
|
ct.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
|
||||||
|
client_tunnels.add_child(it.second->GetName (), ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& serverTunnels = i2p::client::context.GetServerTunnels ();
|
||||||
|
if (!serverTunnels.empty ()) {
|
||||||
|
for (auto& it: serverTunnels)
|
||||||
|
{
|
||||||
|
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
||||||
|
boost::property_tree::ptree st;
|
||||||
|
st.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
|
||||||
|
st.put("port", it.second->GetLocalPort ());
|
||||||
|
server_tunnels.add_child(it.second->GetName (), st);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& clientForwards = i2p::client::context.GetClientForwards ();
|
||||||
|
if (!clientForwards.empty ())
|
||||||
|
{
|
||||||
|
for (auto& it: clientForwards)
|
||||||
|
{
|
||||||
|
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
||||||
|
boost::property_tree::ptree ct;
|
||||||
|
ct.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
|
||||||
|
client_tunnels.add_child(it.second->GetName (), ct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& serverForwards = i2p::client::context.GetServerForwards ();
|
||||||
|
if (!serverForwards.empty ())
|
||||||
|
{
|
||||||
|
for (auto& it: serverForwards)
|
||||||
|
{
|
||||||
|
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
||||||
|
boost::property_tree::ptree st;
|
||||||
|
st.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
|
||||||
|
server_tunnels.add_child(it.second->GetName (), st);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pt.add_child("client", client_tunnels);
|
||||||
|
pt.add_child("server", server_tunnels);
|
||||||
|
|
||||||
|
InsertParam (results, "I2PTunnel", pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlHandlers::HTTPProxyInfoHandler (std::ostringstream& results)
|
||||||
|
{
|
||||||
|
boost::property_tree::ptree pt;
|
||||||
|
|
||||||
|
auto httpProxy = i2p::client::context.GetHttpProxy ();
|
||||||
|
if (httpProxy)
|
||||||
|
{
|
||||||
|
auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash();
|
||||||
|
pt.put("enabled", true);
|
||||||
|
pt.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pt.put("enabled", false);
|
||||||
|
|
||||||
|
InsertParam (results, "HTTPProxy", pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlHandlers::SOCKSInfoHandler (std::ostringstream& results)
|
||||||
|
{
|
||||||
|
boost::property_tree::ptree pt;
|
||||||
|
|
||||||
|
auto socksProxy = i2p::client::context.GetSocksProxy ();
|
||||||
|
if (socksProxy)
|
||||||
|
{
|
||||||
|
auto& ident = socksProxy->GetLocalDestination ()->GetIdentHash();
|
||||||
|
pt.put("enabled", true);
|
||||||
|
pt.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pt.put("enabled", false);
|
||||||
|
|
||||||
|
InsertParam (results, "SOCKS", pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlHandlers::SAMInfoHandler (std::ostringstream& results)
|
||||||
|
{
|
||||||
|
boost::property_tree::ptree pt;
|
||||||
|
auto sam = i2p::client::context.GetSAMBridge ();
|
||||||
|
if (sam)
|
||||||
|
{
|
||||||
|
pt.put("enabled", true);
|
||||||
|
boost::property_tree::ptree sam_sessions;
|
||||||
|
for (auto& it: sam->GetSessions ())
|
||||||
|
{
|
||||||
|
boost::property_tree::ptree sam_session, sam_session_sockets;
|
||||||
|
auto& name = it.second->GetLocalDestination ()->GetNickname ();
|
||||||
|
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
||||||
|
sam_session.put("name", name);
|
||||||
|
sam_session.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
|
||||||
|
|
||||||
|
for (const auto& socket: sam->ListSockets(it.first))
|
||||||
|
{
|
||||||
|
boost::property_tree::ptree stream;
|
||||||
|
stream.put("type", socket->GetSocketType ());
|
||||||
|
stream.put("peer", socket->GetSocket ().remote_endpoint());
|
||||||
|
|
||||||
|
sam_session_sockets.push_back(std::make_pair("", stream));
|
||||||
|
}
|
||||||
|
sam_session.add_child("sockets", sam_session_sockets);
|
||||||
|
sam_sessions.add_child(it.first, sam_session);
|
||||||
|
}
|
||||||
|
|
||||||
|
pt.add_child("sessions", sam_sessions);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pt.put("enabled", false);
|
||||||
|
|
||||||
|
InsertParam (results, "SAM", pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlHandlers::BOBInfoHandler (std::ostringstream& results)
|
||||||
|
{
|
||||||
|
boost::property_tree::ptree pt;
|
||||||
|
auto bob = i2p::client::context.GetBOBCommandChannel ();
|
||||||
|
if (bob)
|
||||||
|
{
|
||||||
|
/* TODO more info */
|
||||||
|
pt.put("enabled", true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pt.put("enabled", false);
|
||||||
|
|
||||||
|
InsertParam (results, "BOB", pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PControlHandlers::I2CPInfoHandler (std::ostringstream& results)
|
||||||
|
{
|
||||||
|
boost::property_tree::ptree pt;
|
||||||
|
auto i2cp = i2p::client::context.GetI2CPServer ();
|
||||||
|
if (i2cp)
|
||||||
|
{
|
||||||
|
/* TODO more info */
|
||||||
|
pt.put("enabled", true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pt.put("enabled", false);
|
||||||
|
|
||||||
|
InsertParam (results, "I2CP", pt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
82
daemon/I2PControlHandlers.h
Normal file
82
daemon/I2PControlHandlers.h
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||||
|
*
|
||||||
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
|
*
|
||||||
|
* See full license text in LICENSE file at top of project tree
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef I2P_CONTROL_HANDLERS_H__
|
||||||
|
#define I2P_CONTROL_HANDLERS_H__
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <boost/property_tree/ptree.hpp>
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace client
|
||||||
|
{
|
||||||
|
class I2PControlHandlers
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
I2PControlHandlers ();
|
||||||
|
|
||||||
|
// methods
|
||||||
|
// TODO: make protected
|
||||||
|
void RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
|
||||||
|
void NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
|
||||||
|
void ClientServicesInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void InsertParam (std::ostringstream& ss, const std::string& name, int value) const;
|
||||||
|
void InsertParam (std::ostringstream& ss, const std::string& name, double value) const;
|
||||||
|
void InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value, bool quotes = true) const;
|
||||||
|
void InsertParam (std::ostringstream& ss, const std::string& name, const boost::property_tree::ptree& value) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// RouterInfo
|
||||||
|
typedef void (I2PControlHandlers::*RouterInfoRequestHandler)(std::ostringstream& results);
|
||||||
|
void UptimeHandler (std::ostringstream& results);
|
||||||
|
void VersionHandler (std::ostringstream& results);
|
||||||
|
void StatusHandler (std::ostringstream& results);
|
||||||
|
void NetDbKnownPeersHandler (std::ostringstream& results);
|
||||||
|
void NetDbActivePeersHandler (std::ostringstream& results);
|
||||||
|
void NetStatusHandler (std::ostringstream& results);
|
||||||
|
void TunnelsParticipatingHandler (std::ostringstream& results);
|
||||||
|
void TunnelsSuccessRateHandler (std::ostringstream& results);
|
||||||
|
void InboundBandwidth1S (std::ostringstream& results);
|
||||||
|
void InboundBandwidth15S (std::ostringstream& results);
|
||||||
|
void OutboundBandwidth1S (std::ostringstream& results);
|
||||||
|
void OutboundBandwidth15S (std::ostringstream& results);
|
||||||
|
void NetTotalReceivedBytes (std::ostringstream& results);
|
||||||
|
void NetTotalSentBytes (std::ostringstream& results);
|
||||||
|
|
||||||
|
// NetworkSetting
|
||||||
|
typedef void (I2PControlHandlers::*NetworkSettingRequestHandler)(const std::string& value, std::ostringstream& results);
|
||||||
|
void InboundBandwidthLimit (const std::string& value, std::ostringstream& results);
|
||||||
|
void OutboundBandwidthLimit (const std::string& value, std::ostringstream& results);
|
||||||
|
|
||||||
|
// ClientServicesInfo
|
||||||
|
typedef void (I2PControlHandlers::*ClientServicesInfoRequestHandler)(std::ostringstream& results);
|
||||||
|
void I2PTunnelInfoHandler (std::ostringstream& results);
|
||||||
|
void HTTPProxyInfoHandler (std::ostringstream& results);
|
||||||
|
void SOCKSInfoHandler (std::ostringstream& results);
|
||||||
|
void SAMInfoHandler (std::ostringstream& results);
|
||||||
|
void BOBInfoHandler (std::ostringstream& results);
|
||||||
|
void I2CPInfoHandler (std::ostringstream& results);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::map<std::string, RouterInfoRequestHandler> m_RouterInfoHandlers;
|
||||||
|
std::map<std::string, NetworkSettingRequestHandler> m_NetworkSettingHandlers;
|
||||||
|
std::map<std::string, ClientServicesInfoRequestHandler> m_ClientServicesInfoHandlers;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -159,8 +159,9 @@ namespace transport
|
|||||||
|
|
||||||
void UPnP::PortMapping ()
|
void UPnP::PortMapping ()
|
||||||
{
|
{
|
||||||
const auto& a = context.GetRouterInfo().GetAddresses();
|
auto a = context.GetRouterInfo().GetAddresses();
|
||||||
for (const auto& address : a)
|
if (!a) return;
|
||||||
|
for (const auto& address : *a)
|
||||||
{
|
{
|
||||||
if (!address->host.is_v6 () && address->port)
|
if (!address->host.is_v6 () && address->port)
|
||||||
TryPortMapping (address);
|
TryPortMapping (address);
|
||||||
@@ -210,8 +211,9 @@ namespace transport
|
|||||||
|
|
||||||
void UPnP::CloseMapping ()
|
void UPnP::CloseMapping ()
|
||||||
{
|
{
|
||||||
const auto& a = context.GetRouterInfo().GetAddresses();
|
auto a = context.GetRouterInfo().GetAddresses();
|
||||||
for (const auto& address : a)
|
if (!a) return;
|
||||||
|
for (const auto& address : *a)
|
||||||
{
|
{
|
||||||
if (!address->host.is_v6 () && address->port)
|
if (!address->host.is_v6 () && address->port)
|
||||||
CloseMapping (address);
|
CloseMapping (address);
|
||||||
@@ -248,10 +250,10 @@ namespace transport
|
|||||||
{
|
{
|
||||||
switch (address->transportStyle)
|
switch (address->transportStyle)
|
||||||
{
|
{
|
||||||
case i2p::data::RouterInfo::eTransportNTCP:
|
case i2p::data::RouterInfo::eTransportNTCP2:
|
||||||
return "TCP";
|
return "TCP";
|
||||||
break;
|
break;
|
||||||
case i2p::data::RouterInfo::eTransportSSU:
|
case i2p::data::RouterInfo::eTransportSSU2:
|
||||||
default:
|
default:
|
||||||
return "UDP";
|
return "UDP";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include "Tunnel.h"
|
#include "Tunnel.h"
|
||||||
#include "RouterContext.h"
|
#include "RouterContext.h"
|
||||||
#include "ClientContext.h"
|
#include "ClientContext.h"
|
||||||
|
#include "Transports.h"
|
||||||
|
|
||||||
void handle_signal(int sig)
|
void handle_signal(int sig)
|
||||||
{
|
{
|
||||||
@@ -54,6 +55,14 @@ void handle_signal(int sig)
|
|||||||
case SIGPIPE:
|
case SIGPIPE:
|
||||||
LogPrint(eLogInfo, "SIGPIPE received");
|
LogPrint(eLogInfo, "SIGPIPE received");
|
||||||
break;
|
break;
|
||||||
|
case SIGTSTP:
|
||||||
|
LogPrint(eLogInfo, "Daemon: Got SIGTSTP, disconnecting from network...");
|
||||||
|
i2p::transport::transports.SetOnline(false);
|
||||||
|
break;
|
||||||
|
case SIGCONT:
|
||||||
|
LogPrint(eLogInfo, "Daemon: Got SIGCONT, restoring connection to network...");
|
||||||
|
i2p::transport::transports.SetOnline(true);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,6 +180,9 @@ namespace i2p
|
|||||||
}
|
}
|
||||||
gracefulShutdownInterval = 0; // not specified
|
gracefulShutdownInterval = 0; // not specified
|
||||||
|
|
||||||
|
// handle signal TSTP
|
||||||
|
bool handleTSTP; i2p::config::GetOption("unix.handle_sigtstp", handleTSTP);
|
||||||
|
|
||||||
// Signal handler
|
// Signal handler
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
sa.sa_handler = handle_signal;
|
sa.sa_handler = handle_signal;
|
||||||
@@ -182,6 +194,11 @@ namespace i2p
|
|||||||
sigaction(SIGTERM, &sa, 0);
|
sigaction(SIGTERM, &sa, 0);
|
||||||
sigaction(SIGINT, &sa, 0);
|
sigaction(SIGINT, &sa, 0);
|
||||||
sigaction(SIGPIPE, &sa, 0);
|
sigaction(SIGPIPE, &sa, 0);
|
||||||
|
if (handleTSTP)
|
||||||
|
{
|
||||||
|
sigaction(SIGTSTP, &sa, 0);
|
||||||
|
sigaction(SIGCONT, &sa, 0);
|
||||||
|
}
|
||||||
|
|
||||||
return Daemon_Singleton::start();
|
return Daemon_Singleton::start();
|
||||||
}
|
}
|
||||||
|
|||||||
25
debian/changelog
vendored
25
debian/changelog
vendored
@@ -1,3 +1,28 @@
|
|||||||
|
i2pd (2.44.0-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* updated to version 2.44.0/0.9.56
|
||||||
|
|
||||||
|
-- orignal <orignal@i2pmail.org> Sun, 20 Nov 2022 19:00:00 +0000
|
||||||
|
|
||||||
|
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
|
||||||
|
* remove -O3 optimization flag
|
||||||
|
|
||||||
|
-- r4sas <r4sas@i2pmail.org> Tue, 24 May 2022 12:00:00 +0000
|
||||||
|
|
||||||
|
i2pd (2.42.0-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* updated to version 2.42.0/0.9.54
|
||||||
|
|
||||||
|
-- orignal <orignal@i2pmail.org> Sun, 22 May 2022 16:00:00 +0000
|
||||||
|
|
||||||
i2pd (2.41.0-1) unstable; urgency=medium
|
i2pd (2.41.0-1) unstable; urgency=medium
|
||||||
|
|
||||||
* updated to version 2.41.0/0.9.53
|
* updated to version 2.41.0/0.9.53
|
||||||
|
|||||||
7
debian/rules
vendored
7
debian/rules
vendored
@@ -1,17 +1,12 @@
|
|||||||
#!/usr/bin/make -f
|
#!/usr/bin/make -f
|
||||||
#export DH_VERBOSE=1
|
#export DH_VERBOSE=1
|
||||||
|
|
||||||
|
|
||||||
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||||
|
|
||||||
|
|
||||||
include /usr/share/dpkg/architecture.mk
|
include /usr/share/dpkg/architecture.mk
|
||||||
|
|
||||||
export DEB_CXXFLAGS_MAINT_APPEND = -Wall -pedantic -O3
|
export DEB_CXXFLAGS_MAINT_APPEND = -Wall -pedantic
|
||||||
|
|
||||||
export DEB_LDFLAGS_MAINT_APPEND =
|
export DEB_LDFLAGS_MAINT_APPEND =
|
||||||
|
|
||||||
|
|
||||||
%:
|
%:
|
||||||
dh $@ --parallel
|
dh $@ --parallel
|
||||||
|
|
||||||
|
|||||||
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
|
||||||
211
i18n/French.cpp
Normal file
211
i18n/French.cpp
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022, The PurpleI2P Project
|
||||||
|
*
|
||||||
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
|
*
|
||||||
|
* See full license text in LICENSE file at top of project tree
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include "I18N.h"
|
||||||
|
|
||||||
|
// French localization file
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace i18n
|
||||||
|
{
|
||||||
|
namespace french // language namespace
|
||||||
|
{
|
||||||
|
// language name in lowercase
|
||||||
|
static std::string language = "french";
|
||||||
|
|
||||||
|
// See for language plural forms here:
|
||||||
|
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
|
||||||
|
static int plural (int n) {
|
||||||
|
return n != 1 ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::map<std::string, std::string> strings
|
||||||
|
{
|
||||||
|
{"KiB", "Kio"},
|
||||||
|
{"MiB", "Mio"},
|
||||||
|
{"GiB", "Gio"},
|
||||||
|
{"building", "En construction"},
|
||||||
|
{"failed", "é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"},
|
||||||
|
{"Stopping in", "Arrêt dans"},
|
||||||
|
{"Family", "Famille"},
|
||||||
|
{"Tunnel creation success rate", "Taux de succès de création de tunnels"},
|
||||||
|
{"Received", "Reçu"},
|
||||||
|
{"KiB/s", "kio/s"},
|
||||||
|
{"Sent", "Envoyé"},
|
||||||
|
{"Transit", "Transité"},
|
||||||
|
{"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."},
|
||||||
|
{"", ""},
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::map<std::string, std::vector<std::string>> plurals
|
||||||
|
{
|
||||||
|
{"days", {"jour", "jours"}},
|
||||||
|
{"hours", {"heure", "heures"}},
|
||||||
|
{"minutes", {"minute", "minutes"}},
|
||||||
|
{"seconds", {"seconde", "secondes"}},
|
||||||
|
{"", {"", ""}},
|
||||||
|
};
|
||||||
|
|
||||||
|
std::shared_ptr<const i2p::i18n::Locale> GetLocale()
|
||||||
|
{
|
||||||
|
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
|
||||||
|
}
|
||||||
|
|
||||||
|
} // language
|
||||||
|
} // i18n
|
||||||
|
} // i2p
|
||||||
@@ -36,14 +36,15 @@ namespace german // language namespace
|
|||||||
{"GiB", "GiB"},
|
{"GiB", "GiB"},
|
||||||
{"building", "In Bau"},
|
{"building", "In Bau"},
|
||||||
{"failed", "fehlgeschlagen"},
|
{"failed", "fehlgeschlagen"},
|
||||||
{"expiring", "läuft ab in"},
|
{"expiring", "läuft ab"},
|
||||||
{"established", "hergestellt"},
|
{"established", "hergestellt"},
|
||||||
{"unknown", "Unbekannt"},
|
{"unknown", "Unbekannt"},
|
||||||
{"exploratory", "erforschende"},
|
{"exploratory", "erforschend"},
|
||||||
{"<b>i2pd</b> webconsole", "<b>i2pd</b> Webkonsole"},
|
{"Purple I2P Webconsole", "Purple I2P-Webkonsole"},
|
||||||
|
{"<b>i2pd</b> webconsole", "<b>i2pd</b>-Webkonsole"},
|
||||||
{"Main page", "Startseite"},
|
{"Main page", "Startseite"},
|
||||||
{"Router commands", "Router Befehle"},
|
{"Router commands", "Routerbefehle"},
|
||||||
{"Local Destinations", "Lokale Destination"},
|
{"Local Destinations", "Lokale Ziele"},
|
||||||
{"LeaseSets", "LeaseSets"},
|
{"LeaseSets", "LeaseSets"},
|
||||||
{"Tunnels", "Tunnel"},
|
{"Tunnels", "Tunnel"},
|
||||||
{"Transit Tunnels", "Transittunnel"},
|
{"Transit Tunnels", "Transittunnel"},
|
||||||
@@ -53,7 +54,7 @@ namespace german // language namespace
|
|||||||
{"ERROR", "FEHLER"},
|
{"ERROR", "FEHLER"},
|
||||||
{"OK", "OK"},
|
{"OK", "OK"},
|
||||||
{"Testing", "Testen"},
|
{"Testing", "Testen"},
|
||||||
{"Firewalled", "Hinter eine Firewall"},
|
{"Firewalled", "Hinter einer Firewall"},
|
||||||
{"Unknown", "Unbekannt"},
|
{"Unknown", "Unbekannt"},
|
||||||
{"Proxy", "Proxy"},
|
{"Proxy", "Proxy"},
|
||||||
{"Mesh", "Mesh"},
|
{"Mesh", "Mesh"},
|
||||||
@@ -81,15 +82,15 @@ namespace german // language namespace
|
|||||||
{"supported", "unterstützt"},
|
{"supported", "unterstützt"},
|
||||||
{"Routers", "Router"},
|
{"Routers", "Router"},
|
||||||
{"Floodfills", "Floodfills"},
|
{"Floodfills", "Floodfills"},
|
||||||
{"Client Tunnels", "Klienttunnel"},
|
{"Client Tunnels", "Clienttunnel"},
|
||||||
{"Services", "Services"},
|
{"Services", "Services"},
|
||||||
{"Enabled", "Aktiviert"},
|
{"Enabled", "Aktiviert"},
|
||||||
{"Disabled", "Deaktiviert"},
|
{"Disabled", "Deaktiviert"},
|
||||||
{"Encrypted B33 address", "Verschlüsselte B33 Adresse"},
|
{"Encrypted B33 address", "Verschlüsselte B33-Adresse"},
|
||||||
{"Address registration line", "Adresseregistrierungszeile"},
|
{"Address registration line", "Adressregistrierungszeile"},
|
||||||
{"Domain", "Domain"},
|
{"Domain", "Domain"},
|
||||||
{"Generate", "Generieren"},
|
{"Generate", "Generieren"},
|
||||||
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Hinweis:</b> Der resultierende String kann nur für die Registrierung einer 2LD Domain (beispiel.i2p) benutzt werden. Für die Registrierung von Subdomains kann i2pd-tools verwendet werden."},
|
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Hinweis:</b> Der resultierende String kann nur für die Registrierung einer 2LD-Domain (beispiel.i2p) benutzt werden. Für die Registrierung von Subdomains kann i2pd-tools verwendet werden."},
|
||||||
{"Address", "Adresse"},
|
{"Address", "Adresse"},
|
||||||
{"Type", "Typ"},
|
{"Type", "Typ"},
|
||||||
{"EncType", "Verschlüsselungstyp"},
|
{"EncType", "Verschlüsselungstyp"},
|
||||||
@@ -99,15 +100,15 @@ namespace german // language namespace
|
|||||||
{"Tags", "Tags"},
|
{"Tags", "Tags"},
|
||||||
{"Incoming", "Eingehend"},
|
{"Incoming", "Eingehend"},
|
||||||
{"Outgoing", "Ausgehend"},
|
{"Outgoing", "Ausgehend"},
|
||||||
{"Destination", "Destination"},
|
{"Destination", "Ziel"},
|
||||||
{"Amount", "Anzahl"},
|
{"Amount", "Anzahl"},
|
||||||
{"Incoming Tags", "Eingehende Tags"},
|
{"Incoming Tags", "Eingehende Tags"},
|
||||||
{"Tags sessions", "Tags Sitzungen"},
|
{"Tags sessions", "Tags-Sitzungen"},
|
||||||
{"Status", "Status"},
|
{"Status", "Status"},
|
||||||
{"Local Destination", "Lokale Destination"},
|
{"Local Destination", "Lokales Ziel"},
|
||||||
{"Streams", "Streams"},
|
{"Streams", "Streams"},
|
||||||
{"Close stream", "Stream schließen"},
|
{"Close stream", "Stream schließen"},
|
||||||
{"I2CP session not found", "I2CP Sitzung nicht gefunden"},
|
{"I2CP session not found", "I2CP-Sitzung nicht gefunden"},
|
||||||
{"I2CP is not enabled", "I2CP ist nicht aktiviert"},
|
{"I2CP is not enabled", "I2CP ist nicht aktiviert"},
|
||||||
{"Invalid", "Ungültig"},
|
{"Invalid", "Ungültig"},
|
||||||
{"Store type", "Speichertyp"},
|
{"Store type", "Speichertyp"},
|
||||||
@@ -117,67 +118,67 @@ namespace german // language namespace
|
|||||||
{"TunnelID", "TunnelID"},
|
{"TunnelID", "TunnelID"},
|
||||||
{"EndDate", "Enddatum"},
|
{"EndDate", "Enddatum"},
|
||||||
{"not floodfill", "kein Floodfill"},
|
{"not floodfill", "kein Floodfill"},
|
||||||
{"Queue size", "Warteschlangengröße"},
|
{"Queue size", "Größe der Warteschlange"},
|
||||||
{"Run peer test", "Peer-Test ausführen"},
|
{"Run peer test", "Peer-Test durchführen"},
|
||||||
{"Decline transit tunnels", "Transittunnel ablehnen"},
|
{"Decline transit tunnels", "Transittunnel ablehnen"},
|
||||||
{"Accept transit tunnels", "Transittunnel akzeptieren"},
|
{"Accept transit tunnels", "Transittunnel akzeptieren"},
|
||||||
{"Cancel graceful shutdown", "Beende das kontrollierte herunterfahren"},
|
{"Cancel graceful shutdown", "Beende das kontrollierte Herunterfahren"},
|
||||||
{"Start graceful shutdown", "Starte das kontrollierte Herunterfahren"},
|
{"Start graceful shutdown", "Starte das kontrollierte Herunterfahren"},
|
||||||
{"Force shutdown", "Herunterfahren erzwingen"},
|
{"Force shutdown", "Herunterfahren erzwingen"},
|
||||||
{"Reload external CSS styles", "Lade externe CSS-Styles neu"},
|
{"Reload external CSS styles", "Lade externe CSS-Stile neu"},
|
||||||
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Hinweis:</b> Alle hier durchgeführten Aktionen sind nicht dauerhaft und ändern die Konfigurationsdateien nicht."},
|
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Hinweis:</b> Alle hier durchgeführten Aktionen sind nicht dauerhaft und ändern die Konfigurationsdateien nicht."},
|
||||||
{"Logging level", "Protokollierungslevel"},
|
{"Logging level", "Protokollierungslevel"},
|
||||||
{"Transit tunnels limit", "Limit für Transittunnel"},
|
{"Transit tunnels limit", "Limit für Transittunnel"},
|
||||||
{"Change", "Verändern"},
|
{"Change", "Ändern"},
|
||||||
{"Change language", "Sprache ändern"},
|
{"Change language", "Sprache ändern"},
|
||||||
{"no transit tunnels currently built", "derzeit keine Transittunnel aufgebaut"},
|
{"no transit tunnels currently built", "derzeit keine Transittunnel aufgebaut"},
|
||||||
{"SAM disabled", "SAM deaktiviert"},
|
{"SAM disabled", "SAM deaktiviert"},
|
||||||
{"no sessions currently running", "Derzeit keine laufenden Sitzungen"},
|
{"no sessions currently running", "Derzeit keine laufenden Sitzungen"},
|
||||||
{"SAM session not found", "SAM Sitzung nicht gefunden"},
|
{"SAM session not found", "SAM-Sitzung nicht gefunden"},
|
||||||
{"SAM Session", "SAM Sitzung"},
|
{"SAM Session", "SAM-Sitzung"},
|
||||||
{"Server Tunnels", "Servertunnel"},
|
{"Server Tunnels", "Servertunnel"},
|
||||||
{"Client Forwards", "Klient-Weiterleitungen"},
|
{"Client Forwards", "Client-Weiterleitungen"},
|
||||||
{"Server Forwards", "Server-Weiterleitungen"},
|
{"Server Forwards", "Server-Weiterleitungen"},
|
||||||
{"Unknown page", "Unbekannte Seite"},
|
{"Unknown page", "Unbekannte Seite"},
|
||||||
{"Invalid token", "Ungültiger Token"},
|
{"Invalid token", "Ungültiger Token"},
|
||||||
{"SUCCESS", "ERFOLGREICH"},
|
{"SUCCESS", "ERFOLGREICH"},
|
||||||
{"Stream closed", "Stream geschlossen"},
|
{"Stream closed", "Stream geschlossen"},
|
||||||
{"Stream not found or already was closed", "Stream nicht gefunden oder bereits geschlossen"},
|
{"Stream not found or already was closed", "Stream nicht gefunden oder bereits geschlossen"},
|
||||||
{"Destination not found", "Destination nicht gefunden"},
|
{"Destination not found", "Ziel nicht gefunden"},
|
||||||
{"StreamID can't be null", "StreamID kann nicht null sein"},
|
{"StreamID can't be null", "StreamID kann nicht null sein"},
|
||||||
{"Return to destination page", "Zurück zur Destination-Seite"},
|
{"Return to destination page", "Zurück zur Ziel-Seite"},
|
||||||
{"You will be redirected in 5 seconds", "Du wirst in 5 Sekunden weitergeleitet"},
|
{"You will be redirected in 5 seconds", "Du wirst in 5 Sekunden weitergeleitet"},
|
||||||
{"Transit tunnels count must not exceed 65535", "Es darf maximal 65535 Transittunnel geben"},
|
{"Transit tunnels count must not exceed 65535", "Es darf maximal 65535 Transittunnel geben"},
|
||||||
{"Back to commands list", "Zurück zur Kommandoliste"},
|
{"Back to commands list", "Zurück zur Befehlsliste"},
|
||||||
{"Register at reg.i2p", "Auf reg.i2p registrieren"},
|
{"Register at reg.i2p", "Auf reg.i2p registrieren"},
|
||||||
{"Description", "Beschreibung"},
|
{"Description", "Beschreibung"},
|
||||||
{"A bit information about service on domain", "Ein bisschen Informationen über den Service auf der Domain"},
|
{"A bit information about service on domain", "Ein paar Informationen über den Service auf der Domain"},
|
||||||
{"Submit", "Einreichen"},
|
{"Submit", "Absenden"},
|
||||||
{"Domain can't end with .b32.i2p", "Domain kann nicht mit .b32.i2p enden"},
|
{"Domain can't end with .b32.i2p", "Domain kann nicht auf .b32.i2p enden"},
|
||||||
{"Domain must end with .i2p", "Domain muss mit .i2p enden"},
|
{"Domain must end with .i2p", "Domain muss auf .i2p enden"},
|
||||||
{"Such destination is not found", "Eine solche Destination konnte nicht gefunden werden"},
|
{"Such destination is not found", "Ein solches Ziel konnte nicht gefunden werden"},
|
||||||
{"Unknown command", "Unbekannter Befehl"},
|
{"Unknown command", "Unbekannter Befehl"},
|
||||||
{"Command accepted", "Befehl akzeptiert"},
|
{"Command accepted", "Befehl akzeptiert"},
|
||||||
{"Proxy error", "Proxy-Fehler"},
|
{"Proxy error", "Proxy-Fehler"},
|
||||||
{"Proxy info", "Proxy-Info"},
|
{"Proxy info", "Proxy-Info"},
|
||||||
{"Proxy error: Host not found", "Proxy-Fehler: Host nicht gefunden"},
|
{"Proxy error: Host not found", "Proxy-Fehler: Host nicht gefunden"},
|
||||||
{"Remote host not found in router's addressbook", "Remote-Host nicht im Router Adressbuch gefunden"},
|
{"Remote host not found in router's addressbook", "Remote-Host nicht im Router-Adressbuch gefunden"},
|
||||||
{"You may try to find this host on jump services below", "Vielleicht kannst du diesen Host auf einen der Jump-Services unten finden"},
|
{"You may try to find this host on jump services below", "Vielleicht kannst du diesen Host auf einem der nachfolgenden Jump-Services finden"},
|
||||||
{"Invalid request", "Ungültige Anfrage"},
|
{"Invalid request", "Ungültige Anfrage"},
|
||||||
{"Proxy unable to parse your request", "Proxy konnte die Anfrage nicht interpretieren"},
|
{"Proxy unable to parse your request", "Proxy konnte die Anfrage nicht verarbeiten"},
|
||||||
{"addresshelper is not supported", "addresshelper wird nicht unterstützt"},
|
{"addresshelper is not supported", "Addresshelfer wird nicht unterstützt"},
|
||||||
{"Host", "Host"},
|
{"Host", "Host"},
|
||||||
{"added to router's addressbook from helper", "vom Helfer zum Router Adressbuch hinzugefügt"},
|
{"added to router's addressbook from helper", "vom Helfer zum Router-Adressbuch hinzugefügt"},
|
||||||
{"Click here to proceed:", "Klicke hier um fortzufahren:"},
|
{"Click here to proceed:", "Klicke hier um fortzufahren:"},
|
||||||
{"Continue", "Fortsetzen"},
|
{"Continue", "Fortsetzen"},
|
||||||
{"Addresshelper found", "Adresshelfer gefunden"},
|
{"Addresshelper found", "Adresshelfer gefunden"},
|
||||||
{"already in router's addressbook", "bereits im Adressbuch des Routers"},
|
{"already in router's addressbook", "bereits im Adressbuch des Routers"},
|
||||||
{"Click here to update record:", "Klicke hier, um den Eintrag zu aktualisieren:"},
|
{"Click here to update record:", "Klicke hier, um den Eintrag zu aktualisieren:"},
|
||||||
{"invalid request uri", "ungültige Anfrage-URI"},
|
{"invalid request uri", "ungültige Anfrage-URI"},
|
||||||
{"Can't detect destination host from request", "Kann Anhand der Anfrage den Destination-Host nicht erkennen"},
|
{"Can't detect destination host from request", "Kann den Ziel-Host von der Anfrage nicht erkennen"},
|
||||||
{"Outproxy failure", "Outproxy-Fehler"},
|
{"Outproxy failure", "Outproxy-Fehler"},
|
||||||
{"bad outproxy settings", "ungültige Outproxy-Einstellungen"},
|
{"bad outproxy settings", "ungültige Outproxy-Einstellungen"},
|
||||||
{"not inside I2P network, but outproxy is not enabled", "nicht innerhalb des I2P-Netzwerks, aber Outproxy ist nicht aktiviert"},
|
{"not inside I2P network, but outproxy is not enabled", "außerhalb des I2P-Netzwerks, aber Outproxy ist nicht aktiviert"},
|
||||||
{"unknown outproxy url", "unbekannte Outproxy-URL"},
|
{"unknown outproxy url", "unbekannte Outproxy-URL"},
|
||||||
{"cannot resolve upstream proxy", "kann den Upstream-Proxy nicht auflösen"},
|
{"cannot resolve upstream proxy", "kann den Upstream-Proxy nicht auflösen"},
|
||||||
{"hostname too long", "Hostname zu lang"},
|
{"hostname too long", "Hostname zu lang"},
|
||||||
@@ -192,7 +193,7 @@ namespace german // language namespace
|
|||||||
{"http out proxy not implemented", "HTTP-Outproxy nicht implementiert"},
|
{"http out proxy not implemented", "HTTP-Outproxy nicht implementiert"},
|
||||||
{"cannot connect to upstream http proxy", "Kann nicht zu Upstream-HTTP-Proxy verbinden"},
|
{"cannot connect to upstream http proxy", "Kann nicht zu Upstream-HTTP-Proxy verbinden"},
|
||||||
{"Host is down", "Host ist offline"},
|
{"Host is down", "Host ist offline"},
|
||||||
{"Can't create connection to requested host, it may be down. Please try again later.", "Konnte keine Verbindung zum angefragten Host aufbaunen, vielleicht ist es offline. Versuche es später noch einmal."},
|
{"Can't create connection to requested host, it may be down. Please try again later.", "Konnte keine Verbindung zum angefragten Host aufbauen, vielleicht ist er offline. Versuche es später noch mal."},
|
||||||
{"", ""},
|
{"", ""},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
36
i18n/I18N.cpp
Normal file
36
i18n/I18N.cpp
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021-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 "ClientContext.h"
|
||||||
|
#include "I18N_langs.h"
|
||||||
|
#include "I18N.h"
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace i18n
|
||||||
|
{
|
||||||
|
void SetLanguage(const std::string &lang)
|
||||||
|
{
|
||||||
|
const auto it = i2p::i18n::languages.find(lang);
|
||||||
|
if (it == i2p::i18n::languages.end()) // fallback
|
||||||
|
i2p::client::context.SetLanguage (i2p::i18n::english::GetLocale());
|
||||||
|
else
|
||||||
|
i2p::client::context.SetLanguage (it->second.LocaleFunc());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string translate (const std::string& arg)
|
||||||
|
{
|
||||||
|
return i2p::client::context.GetLanguage ()->GetString (arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string translate (const std::string& arg, const std::string& arg2, const int& n)
|
||||||
|
{
|
||||||
|
return i2p::client::context.GetLanguage ()->GetPlural (arg, arg2, n);
|
||||||
|
}
|
||||||
|
} // i18n
|
||||||
|
} // i2p
|
||||||
62
i18n/I18N.h
62
i18n/I18N.h
@@ -9,30 +9,68 @@
|
|||||||
#ifndef __I18N_H__
|
#ifndef __I18N_H__
|
||||||
#define __I18N_H__
|
#define __I18N_H__
|
||||||
|
|
||||||
#include "ClientContext.h"
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include <utility>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace i18n
|
namespace i18n
|
||||||
{
|
{
|
||||||
inline void SetLanguage(const std::string &lang)
|
class Locale
|
||||||
{
|
{
|
||||||
const auto it = i2p::i18n::languages.find(lang);
|
public:
|
||||||
if (it == i2p::i18n::languages.end()) // fallback
|
Locale (
|
||||||
i2p::client::context.SetLanguage (i2p::i18n::english::GetLocale());
|
const std::string& language,
|
||||||
|
const std::map<std::string, std::string>& strings,
|
||||||
|
const std::map<std::string, std::vector<std::string>>& plurals,
|
||||||
|
std::function<int(int)> formula
|
||||||
|
): m_Language (language), m_Strings (strings), m_Plurals (plurals), m_Formula (formula) { };
|
||||||
|
|
||||||
|
// Get activated language name for webconsole
|
||||||
|
std::string GetLanguage() const
|
||||||
|
{
|
||||||
|
return m_Language;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetString (const std::string& arg) const
|
||||||
|
{
|
||||||
|
const auto it = m_Strings.find(arg);
|
||||||
|
if (it == m_Strings.end())
|
||||||
|
{
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
i2p::client::context.SetLanguage (it->second.LocaleFunc());
|
{
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string translate (const std::string& arg)
|
std::string GetPlural (const std::string& arg, const std::string& arg2, const int& n) const
|
||||||
{
|
{
|
||||||
return i2p::client::context.GetLanguage ()->GetString (arg);
|
const auto it = m_Plurals.find(arg2);
|
||||||
|
if (it == m_Plurals.end()) // not found, fallback to english
|
||||||
|
{
|
||||||
|
return n == 1 ? arg : arg2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int form = m_Formula(n);
|
||||||
|
return it->second[form];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string translate (const std::string& arg, const std::string& arg2, const int& n)
|
private:
|
||||||
{
|
const std::string m_Language;
|
||||||
return i2p::client::context.GetLanguage ()->GetPlural (arg, arg2, n);
|
const std::map<std::string, std::string> m_Strings;
|
||||||
}
|
const std::map<std::string, std::vector<std::string>> m_Plurals;
|
||||||
|
std::function<int(int)> m_Formula;
|
||||||
|
};
|
||||||
|
|
||||||
|
void SetLanguage(const std::string &lang);
|
||||||
|
std::string translate (const std::string& arg);
|
||||||
|
std::string translate (const std::string& arg, const std::string& arg2, const int& n);
|
||||||
} // i18n
|
} // i18n
|
||||||
} // i2p
|
} // i2p
|
||||||
|
|
||||||
|
|||||||
@@ -9,60 +9,12 @@
|
|||||||
#ifndef __I18N_LANGS_H__
|
#ifndef __I18N_LANGS_H__
|
||||||
#define __I18N_LANGS_H__
|
#define __I18N_LANGS_H__
|
||||||
|
|
||||||
|
#include "I18N.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace i18n
|
namespace i18n
|
||||||
{
|
{
|
||||||
class Locale
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Locale (
|
|
||||||
const std::string& language,
|
|
||||||
const std::map<std::string, std::string>& strings,
|
|
||||||
const std::map<std::string, std::vector<std::string>>& plurals,
|
|
||||||
std::function<int(int)> formula
|
|
||||||
): m_Language (language), m_Strings (strings), m_Plurals (plurals), m_Formula (formula) { };
|
|
||||||
|
|
||||||
// Get activated language name for webconsole
|
|
||||||
std::string GetLanguage() const
|
|
||||||
{
|
|
||||||
return m_Language;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string GetString (const std::string& arg) const
|
|
||||||
{
|
|
||||||
const auto it = m_Strings.find(arg);
|
|
||||||
if (it == m_Strings.end())
|
|
||||||
{
|
|
||||||
return arg;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string GetPlural (const std::string& arg, const std::string& arg2, const int& n) const
|
|
||||||
{
|
|
||||||
const auto it = m_Plurals.find(arg2);
|
|
||||||
if (it == m_Plurals.end()) // not found, fallback to english
|
|
||||||
{
|
|
||||||
return n == 1 ? arg : arg2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int form = m_Formula(n);
|
|
||||||
return it->second[form];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const std::string m_Language;
|
|
||||||
const std::map<std::string, std::string> m_Strings;
|
|
||||||
const std::map<std::string, std::vector<std::string>> m_Plurals;
|
|
||||||
std::function<int(int)> m_Formula;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct langData
|
struct langData
|
||||||
{
|
{
|
||||||
std::string LocaleName; // localized name
|
std::string LocaleName; // localized name
|
||||||
@@ -73,9 +25,13 @@ namespace i18n
|
|||||||
// Add localization here with language name as namespace
|
// Add localization here with language name as namespace
|
||||||
namespace afrikaans { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
namespace afrikaans { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||||
namespace armenian { 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 english { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||||
|
namespace french { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||||
namespace german { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
namespace german { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||||
|
namespace italian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||||
namespace russian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
namespace russian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||||
|
namespace spanish { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||||
namespace turkmen { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
namespace turkmen { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||||
namespace ukrainian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
namespace ukrainian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||||
namespace uzbek { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
namespace uzbek { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||||
@@ -86,12 +42,16 @@ namespace i18n
|
|||||||
static std::map<std::string, langData> languages
|
static std::map<std::string, langData> languages
|
||||||
{
|
{
|
||||||
{ "afrikaans", {"Afrikaans", "af", i2p::i18n::afrikaans::GetLocale} },
|
{ "afrikaans", {"Afrikaans", "af", i2p::i18n::afrikaans::GetLocale} },
|
||||||
{ "armenian", {"հայերէն", "hy", i2p::i18n::armenian::GetLocale} },
|
{ "armenian", {"hայերէն", "hy", i2p::i18n::armenian::GetLocale} },
|
||||||
|
{ "chinese", {"简体字", "zh-CN", i2p::i18n::chinese::GetLocale} },
|
||||||
{ "english", {"English", "en", i2p::i18n::english::GetLocale} },
|
{ "english", {"English", "en", i2p::i18n::english::GetLocale} },
|
||||||
|
{ "french", {"Français", "fr", i2p::i18n::french::GetLocale} },
|
||||||
{ "german", {"Deutsch", "de", i2p::i18n::german::GetLocale} },
|
{ "german", {"Deutsch", "de", i2p::i18n::german::GetLocale} },
|
||||||
{ "russian", {"русский язык", "ru", i2p::i18n::russian::GetLocale} },
|
{ "italian", {"Italiano", "it", i2p::i18n::italian::GetLocale} },
|
||||||
{ "turkmen", {"türkmen dili", "tk", i2p::i18n::turkmen::GetLocale} },
|
{ "russian", {"Русский язык", "ru", i2p::i18n::russian::GetLocale} },
|
||||||
{ "ukrainian", {"украї́нська мо́ва", "uk", i2p::i18n::ukrainian::GetLocale} },
|
{ "spanish", {"Español", "es", i2p::i18n::spanish::GetLocale} },
|
||||||
|
{ "turkmen", {"Türkmen dili", "tk", i2p::i18n::turkmen::GetLocale} },
|
||||||
|
{ "ukrainian", {"Украї́нська мо́ва", "uk", i2p::i18n::ukrainian::GetLocale} },
|
||||||
{ "uzbek", {"Oʻzbek", "uz", i2p::i18n::uzbek::GetLocale} },
|
{ "uzbek", {"Oʻzbek", "uz", i2p::i18n::uzbek::GetLocale} },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
216
i18n/Italian.cpp
Normal file
216
i18n/Italian.cpp
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
// Italian localization file
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace i18n
|
||||||
|
{
|
||||||
|
namespace italian // language namespace
|
||||||
|
{
|
||||||
|
// language name in lowercase
|
||||||
|
static std::string language = "italian";
|
||||||
|
|
||||||
|
// See for language plural forms here:
|
||||||
|
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
|
||||||
|
static int plural (int n) {
|
||||||
|
return n != 1 ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::map<std::string, std::string> strings
|
||||||
|
{
|
||||||
|
{"KiB", "KiB"},
|
||||||
|
{"MiB", "MiB"},
|
||||||
|
{"GiB", "GiB"},
|
||||||
|
{"building", "in costruzione"},
|
||||||
|
{"failed", "fallito"},
|
||||||
|
{"expiring", "in scadenza"},
|
||||||
|
{"established", "stabilita"},
|
||||||
|
{"unknown", "sconosciuto"},
|
||||||
|
{"exploratory", "esplorativo"},
|
||||||
|
{"Purple I2P Webconsole", "Terminale web Purple I2P"},
|
||||||
|
{"<b>i2pd</b> webconsole", "Terminal web <b>i2pd</b>"},
|
||||||
|
{"Main page", "Pagina principale"},
|
||||||
|
{"Router commands", "Comandi router"},
|
||||||
|
{"Local Destinations", "Destinazioni locali"},
|
||||||
|
{"LeaseSets", "LeaseSets"},
|
||||||
|
{"Tunnels", "Tunnel"},
|
||||||
|
{"Transit Tunnels", "Tunnel di transito"},
|
||||||
|
{"Transports", "Trasporti"},
|
||||||
|
{"I2P tunnels", "Tunnel I2P"},
|
||||||
|
{"SAM sessions", "Sessioni SAM"},
|
||||||
|
{"ERROR", "ERRORE"},
|
||||||
|
{"OK", "OK"},
|
||||||
|
{"Testing", "Testando"},
|
||||||
|
{"Firewalled", "Protetto da firewall"},
|
||||||
|
{"Unknown", "Sconosciuto"},
|
||||||
|
{"Proxy", "Proxy"},
|
||||||
|
{"Mesh", "Mesh"},
|
||||||
|
{"Error", "Errore"},
|
||||||
|
{"Clock skew", "Orologio disallineato"},
|
||||||
|
{"Offline", "Disconnesso"},
|
||||||
|
{"Symmetric NAT", "NAT simmetrico"},
|
||||||
|
{"Uptime", "In funzione da"},
|
||||||
|
{"Network status", "Stato della rete"},
|
||||||
|
{"Network status v6", "Stato della rete v6"},
|
||||||
|
{"Stopping in", "Arresto in"},
|
||||||
|
{"Family", "Famiglia"},
|
||||||
|
{"Tunnel creation success rate", "Percentuale di tunnel creati con successo"},
|
||||||
|
{"Received", "Ricevuti"},
|
||||||
|
{"KiB/s", "KiB/s"},
|
||||||
|
{"Sent", "Inviati"},
|
||||||
|
{"Transit", "Transitati"},
|
||||||
|
{"Data path", "Percorso dati"},
|
||||||
|
{"Hidden content. Press on text to see.", "Contenuto nascosto. Premi sul testo per vedere."},
|
||||||
|
{"Router Ident", "Identificativo del router"},
|
||||||
|
{"Router Family", "Famiglia del router"},
|
||||||
|
{"Router Caps", "Limiti del router"},
|
||||||
|
{"Version", "Versione"},
|
||||||
|
{"Our external address", "Il nostro indirizzo esterno"},
|
||||||
|
{"supported", "supportato"},
|
||||||
|
{"Routers", "Router"},
|
||||||
|
{"Floodfills", "Floodfill"},
|
||||||
|
{"Client Tunnels", "Tunnel client"},
|
||||||
|
{"Services", "Servizi"},
|
||||||
|
{"Enabled", "Abilitato"},
|
||||||
|
{"Disabled", "Disabilitato"},
|
||||||
|
{"Encrypted B33 address", "Indirizzo criptato B33"},
|
||||||
|
{"Address registration line", "Linea di registrazione indirizzo"},
|
||||||
|
{"Domain", "Dominio"},
|
||||||
|
{"Generate", "Genera"},
|
||||||
|
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Nota:</b> la stringa risultante può essere utilizzata solo per registrare domini 2LD (example.i2p). Per registrare i sottodomini, si prega di utilizzare i2pd-tools."},
|
||||||
|
{"Address", "Indirizzo"},
|
||||||
|
{"Type", "Tipologia"},
|
||||||
|
{"EncType", "Tipo di crittografia"},
|
||||||
|
{"Inbound tunnels", "Tunnel in entrata"},
|
||||||
|
{"ms", "ms"},
|
||||||
|
{"Outbound tunnels", "Tunnel in uscita"},
|
||||||
|
{"Tags", "Tag"},
|
||||||
|
{"Incoming", "In entrata"},
|
||||||
|
{"Outgoing", "In uscita"},
|
||||||
|
{"Destination", "Destinazione"},
|
||||||
|
{"Amount", "Quantità"},
|
||||||
|
{"Incoming Tags", "Tag in entrata"},
|
||||||
|
{"Tags sessions", "Sessioni dei tag"},
|
||||||
|
{"Status", "Stato"},
|
||||||
|
{"Local Destination", "Destinazione locale"},
|
||||||
|
{"Streams", "Flussi"},
|
||||||
|
{"Close stream", "Interrompi il flusso"},
|
||||||
|
{"I2CP session not found", "Sessione I2CP non trovata"},
|
||||||
|
{"I2CP is not enabled", "I2CP non è abilitato"},
|
||||||
|
{"Invalid", "Invalido"},
|
||||||
|
{"Store type", "Tipologia di archivio"},
|
||||||
|
{"Expires", "Scade"},
|
||||||
|
{"Non Expired Leases", "Lease non scaduti"},
|
||||||
|
{"Gateway", "Gateway"},
|
||||||
|
{"TunnelID", "TunnelID"},
|
||||||
|
{"EndDate", "Data di fine"},
|
||||||
|
{"not floodfill", "no floodfill"},
|
||||||
|
{"Queue size", "Dimensione della coda"},
|
||||||
|
{"Run peer test", "Esegui il test dei peer"},
|
||||||
|
{"Decline transit tunnels", "Rifiuta tunnel di transito"},
|
||||||
|
{"Accept transit tunnels", "Accetta tunnel di transito"},
|
||||||
|
{"Cancel graceful shutdown", "Annulla l'interruzione controllata"},
|
||||||
|
{"Start graceful shutdown", "Avvia l'interruzione controllata"},
|
||||||
|
{"Force shutdown", "Forza l'arresto"},
|
||||||
|
{"Reload external CSS styles", "Ricarica gli stili CSS esterni"},
|
||||||
|
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Nota:</b> qualsiasi azione effettuata qui non è persistente e non modifica i file di configurazione."},
|
||||||
|
{"Logging level", "Livello di log"},
|
||||||
|
{"Transit tunnels limit", "Limite di tunnel di transito"},
|
||||||
|
{"Change", "Modifica"},
|
||||||
|
{"Change language", "Modifica linguaggio"},
|
||||||
|
{"no transit tunnels currently built", "Attualmente non ci sono tunnel di transito instaurati"},
|
||||||
|
{"SAM disabled", "SAM disabilitato"},
|
||||||
|
{"no sessions currently running", "Attualmente non ci sono sessioni attive"},
|
||||||
|
{"SAM session not found", "Sessione SAM non trovata"},
|
||||||
|
{"SAM Session", "Sessione SAM"},
|
||||||
|
{"Server Tunnels", "Tunnel server"},
|
||||||
|
{"Client Forwards", "Client di inoltro"},
|
||||||
|
{"Server Forwards", "Server di inoltro"},
|
||||||
|
{"Unknown page", "Pagina sconosciuta"},
|
||||||
|
{"Invalid token", "Token non valido"},
|
||||||
|
{"SUCCESS", "SUCCESSO"},
|
||||||
|
{"Stream closed", "Flusso terminato"},
|
||||||
|
{"Stream not found or already was closed", "Il flusso non è stato trovato oppure è già stato terminato"},
|
||||||
|
{"Destination not found", "Destinazione non trovata"},
|
||||||
|
{"StreamID can't be null", "Lo StreamID non può essere null"},
|
||||||
|
{"Return to destination page", "Ritorna alla pagina di destinazione"},
|
||||||
|
{"You will be redirected in 5 seconds", "Verrai reindirizzato in 5 secondi"},
|
||||||
|
{"Transit tunnels count must not exceed 65535", "Il numero di tunnel di transito non può superare i 65535"},
|
||||||
|
{"Back to commands list", "Ritorna alla lista dei comandi"},
|
||||||
|
{"Register at reg.i2p", "Registra a reg.i2p"},
|
||||||
|
{"Description", "Descrizione"},
|
||||||
|
{"A bit information about service on domain", "Alcune informazioni riguardo il servizio sul dominio"},
|
||||||
|
{"Submit", "Invia"},
|
||||||
|
{"Domain can't end with .b32.i2p", "I domini non possono terminare con .b32.i2p"},
|
||||||
|
{"Domain must end with .i2p", "I domini devono terminare con .i2p"},
|
||||||
|
{"Such destination is not found", "Questa destinazione non è stata trovata"},
|
||||||
|
{"Unknown command", "Comando sconosciuto"},
|
||||||
|
{"Command accepted", "Comando accettato"},
|
||||||
|
{"Proxy error", "Errore del proxy"},
|
||||||
|
{"Proxy info", "Informazioni del proxy"},
|
||||||
|
{"Proxy error: Host not found", "Errore del proxy: Host non trovato"},
|
||||||
|
{"Remote host not found in router's addressbook", "L'host remoto non è stato trovato nella rubrica del router"},
|
||||||
|
{"You may try to find this host on jump services below", "Si può provare a trovare questo host sui servizi di salto qui sotto"},
|
||||||
|
{"Invalid request", "Richiesta non valida"},
|
||||||
|
{"Proxy unable to parse your request", "Il proxy non è in grado di elaborare la tua richiesta"},
|
||||||
|
{"addresshelper is not supported", "addresshelper non è supportato"},
|
||||||
|
{"Host", "Host"},
|
||||||
|
{"added to router's addressbook from helper", "aggiunto alla rubrica tramite l'helper"},
|
||||||
|
{"Click here to proceed:", "Clicca qui per procedere:"},
|
||||||
|
{"Continue", "Continua"},
|
||||||
|
{"Addresshelper found", "Addresshelper trovato"},
|
||||||
|
{"already in router's addressbook", "già presente nella rubrica del router"},
|
||||||
|
{"Click here to update record:", "Clicca qui per aggiornare l'elemento:"},
|
||||||
|
{"invalid request uri", "uri della richiesta non valido"},
|
||||||
|
{"Can't detect destination host from request", "Impossibile determinare l'host di destinazione dalla richiesta"},
|
||||||
|
{"Outproxy failure", "Fallimento del proxy di uscita"},
|
||||||
|
{"bad outproxy settings", "impostazioni errate del proxy di uscita"},
|
||||||
|
{"not inside I2P network, but outproxy is not enabled", "non all'interno della rete I2P, ma il proxy di uscita non è abilitato"},
|
||||||
|
{"unknown outproxy url", "url del proxy di uscita sconosciuto"},
|
||||||
|
{"cannot resolve upstream proxy", "impossibile identificare il flusso a monte del proxy"},
|
||||||
|
{"hostname too long", "il nome dell'host è troppo lungo"},
|
||||||
|
{"cannot connect to upstream socks proxy", "impossibile connettersi al flusso a monte del proxy socks"},
|
||||||
|
{"Cannot negotiate with socks proxy", "Impossibile negoziare con il proxy socks"},
|
||||||
|
{"CONNECT error", "Errore di connessione"},
|
||||||
|
{"Failed to Connect", "Connessione fallita"},
|
||||||
|
{"socks proxy error", "errore del proxy socks"},
|
||||||
|
{"failed to send request to upstream", "invio della richiesta a monte non riuscito"},
|
||||||
|
{"No Reply From socks proxy", "Nessuna risposta dal proxy socks"},
|
||||||
|
{"cannot connect", "impossibile connettersi"},
|
||||||
|
{"http out proxy not implemented", "proxy http di uscita non implementato"},
|
||||||
|
{"cannot connect to upstream http proxy", "impossibile connettersi al proxy http a monte"},
|
||||||
|
{"Host is down", "L'host è offline"},
|
||||||
|
{"Can't create connection to requested host, it may be down. Please try again later.", "Impossibile creare la connessione all'host richiesto, probabilmente è offline. Riprova più tardi."},
|
||||||
|
{"", ""},
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::map<std::string, std::vector<std::string>> plurals
|
||||||
|
{
|
||||||
|
{"days", {"giorno", "giorni"}},
|
||||||
|
{"hours", {"ora", "ore"}},
|
||||||
|
{"minutes", {"minuto", "minuti"}},
|
||||||
|
{"seconds", {"secondo", "secondi"}},
|
||||||
|
{"", {"", ""}},
|
||||||
|
};
|
||||||
|
|
||||||
|
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
|
||||||
216
i18n/Spanish.cpp
Normal file
216
i18n/Spanish.cpp
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
// Spanish localization file
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace i18n
|
||||||
|
{
|
||||||
|
namespace spanish // language namespace
|
||||||
|
{
|
||||||
|
// language name in lowercase
|
||||||
|
static std::string language = "spanish";
|
||||||
|
|
||||||
|
// See for language plural forms here:
|
||||||
|
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
|
||||||
|
static int plural (int n) {
|
||||||
|
return n != 1 ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::map<std::string, std::string> strings
|
||||||
|
{
|
||||||
|
{"KiB", "KiB"},
|
||||||
|
{"MiB", "MiB"},
|
||||||
|
{"GiB", "GiB"},
|
||||||
|
{"building", "pendiente"},
|
||||||
|
{"failed", "fallido"},
|
||||||
|
{"expiring", "expiró"},
|
||||||
|
{"established", "establecido"},
|
||||||
|
{"unknown", "desconocido"},
|
||||||
|
{"exploratory", "exploratorio"},
|
||||||
|
{"Purple I2P Webconsole", "Consola web de Purple I2P"},
|
||||||
|
{"<b>i2pd</b> webconsole", "Consola web de <b>i2pd</b>"},
|
||||||
|
{"Main page", "Inicio"},
|
||||||
|
{"Router commands", "Comandos de enrutador"},
|
||||||
|
{"Local Destinations", "Destinos locales"},
|
||||||
|
{"LeaseSets", "LeaseSets"},
|
||||||
|
{"Tunnels", "Túneles"},
|
||||||
|
{"Transit Tunnels", "Túneles de Tránsito"},
|
||||||
|
{"Transports", "Transportes"},
|
||||||
|
{"I2P tunnels", "Túneles I2P"},
|
||||||
|
{"SAM sessions", "Sesiones SAM"},
|
||||||
|
{"ERROR", "ERROR"},
|
||||||
|
{"OK", "VALE"},
|
||||||
|
{"Testing", "Probando"},
|
||||||
|
{"Firewalled", "Con cortafuegos"},
|
||||||
|
{"Unknown", "Desconocido"},
|
||||||
|
{"Proxy", "Proxy"},
|
||||||
|
{"Mesh", "Malla"},
|
||||||
|
{"Error", "Error"},
|
||||||
|
{"Clock skew", "Reloj desfasado"},
|
||||||
|
{"Offline", "Desconectado"},
|
||||||
|
{"Symmetric NAT", "NAT simétrico"},
|
||||||
|
{"Uptime", "Tiempo en línea"},
|
||||||
|
{"Network status", "Estado de red"},
|
||||||
|
{"Network status v6", "Estado de red v6"},
|
||||||
|
{"Stopping in", "Parando en"},
|
||||||
|
{"Family", "Familia"},
|
||||||
|
{"Tunnel creation success rate", "Tasa de éxito de creación de túneles"},
|
||||||
|
{"Received", "Recibido"},
|
||||||
|
{"KiB/s", "KiB/s"},
|
||||||
|
{"Sent", "Enviado"},
|
||||||
|
{"Transit", "Tránsito"},
|
||||||
|
{"Data path", "Ruta de datos"},
|
||||||
|
{"Hidden content. Press on text to see.", "Contenido oculto. Presione para ver."},
|
||||||
|
{"Router Ident", "Ident del Enrutador"},
|
||||||
|
{"Router Family", "Familia de enrutador"},
|
||||||
|
{"Router Caps", "Atributos del Enrutador"},
|
||||||
|
{"Version", "Versión"},
|
||||||
|
{"Our external address", "Nuestra dirección externa"},
|
||||||
|
{"supported", "soportado"},
|
||||||
|
{"Routers", "Enrutadores"},
|
||||||
|
{"Floodfills", "Inundaciones"},
|
||||||
|
{"Client Tunnels", "Túneles de cliente"},
|
||||||
|
{"Services", "Servicios"},
|
||||||
|
{"Enabled", "Activado"},
|
||||||
|
{"Disabled", "Desactivado"},
|
||||||
|
{"Encrypted B33 address", "Dirección encriptada B33"},
|
||||||
|
{"Address registration line", "Línea para registrar direcciones"},
|
||||||
|
{"Domain", "Dominio"},
|
||||||
|
{"Generate", "Generar"},
|
||||||
|
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Nota:</b> la cadena resultante solo se puede usar para registrar dominios 2LD (ejemplo.i2p). Para registrar subdominios, por favor utilice i2pd-tools."},
|
||||||
|
{"Address", "Dirección"},
|
||||||
|
{"Type", "Tipo"},
|
||||||
|
{"EncType", "TipoEncrip"},
|
||||||
|
{"Inbound tunnels", "Túneles entrantes"},
|
||||||
|
{"ms", "ms"},
|
||||||
|
{"Outbound tunnels", "Túneles salientes"},
|
||||||
|
{"Tags", "Etiquetas"},
|
||||||
|
{"Incoming", "Entrante"},
|
||||||
|
{"Outgoing", "Saliente"},
|
||||||
|
{"Destination", "Destino"},
|
||||||
|
{"Amount", "Cantidad"},
|
||||||
|
{"Incoming Tags", "Etiquetas entrantes"},
|
||||||
|
{"Tags sessions", "Sesiones de etiquetas"},
|
||||||
|
{"Status", "Estado"},
|
||||||
|
{"Local Destination", "Destino Local"},
|
||||||
|
{"Streams", "Flujos"},
|
||||||
|
{"Close stream", "Cerrar flujo"},
|
||||||
|
{"I2CP session not found", "Sesión I2CP no encontrada"},
|
||||||
|
{"I2CP is not enabled", "I2CP no está activado"},
|
||||||
|
{"Invalid", "Inválido"},
|
||||||
|
{"Store type", "Tipo de almacenamiento"},
|
||||||
|
{"Expires", "Caduca"},
|
||||||
|
{"Non Expired Leases", "Sesiones No Expiradas"},
|
||||||
|
{"Gateway", "Puerta de enlace"},
|
||||||
|
{"TunnelID", "TunnelID"},
|
||||||
|
{"EndDate", "FechaVenc"},
|
||||||
|
{"not floodfill", "no inundado"},
|
||||||
|
{"Queue size", "Tamaño de cola"},
|
||||||
|
{"Run peer test", "Ejecutar prueba de par"},
|
||||||
|
{"Decline transit tunnels", "Rechazar túneles de tránsito"},
|
||||||
|
{"Accept transit tunnels", "Aceptar túneles de tránsito"},
|
||||||
|
{"Cancel graceful shutdown", "Cancelar apagado con gracia"},
|
||||||
|
{"Start graceful shutdown", "Iniciar apagado con gracia"},
|
||||||
|
{"Force shutdown", "Forzar apagado"},
|
||||||
|
{"Reload external CSS styles", "Recargar estilos CSS externos"},
|
||||||
|
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Nota:</b> cualquier acción hecha aquí no es persistente y no cambia tus archivos de configuración."},
|
||||||
|
{"Logging level", "Nivel de registro de errores"},
|
||||||
|
{"Transit tunnels limit", "Límite de túneles de tránsito"},
|
||||||
|
{"Change", "Cambiar"},
|
||||||
|
{"Change language", "Cambiar idioma"},
|
||||||
|
{"no transit tunnels currently built", "no hay túneles de tránsito actualmente construidos"},
|
||||||
|
{"SAM disabled", "SAM desactivado"},
|
||||||
|
{"no sessions currently running", "no hay sesiones ejecutándose ahora"},
|
||||||
|
{"SAM session not found", "Sesión SAM no encontrada"},
|
||||||
|
{"SAM Session", "Sesión SAM"},
|
||||||
|
{"Server Tunnels", "Túneles de Servidor"},
|
||||||
|
{"Client Forwards", "Redirecciones de Cliente"},
|
||||||
|
{"Server Forwards", "Redirecciones de Servidor"},
|
||||||
|
{"Unknown page", "Página desconocida"},
|
||||||
|
{"Invalid token", "Token inválido"},
|
||||||
|
{"SUCCESS", "ÉXITO"},
|
||||||
|
{"Stream closed", "Transmisión cerrada"},
|
||||||
|
{"Stream not found or already was closed", "No se encontró la transmisión o ya se cerró"},
|
||||||
|
{"Destination not found", "Destino no encontrado"},
|
||||||
|
{"StreamID can't be null", "StreamID no puede ser nulo"},
|
||||||
|
{"Return to destination page", "Volver a la página de destino"},
|
||||||
|
{"You will be redirected in 5 seconds", "Serás redirigido en 5 segundos"},
|
||||||
|
{"Transit tunnels count must not exceed 65535", "La cantidad de túneles de tránsito no puede exceder 65535"},
|
||||||
|
{"Back to commands list", "Volver a lista de comandos"},
|
||||||
|
{"Register at reg.i2p", "Registrar en reg.i2p"},
|
||||||
|
{"Description", "Descripción"},
|
||||||
|
{"A bit information about service on domain", "Un poco de información sobre el servicio en el dominio"},
|
||||||
|
{"Submit", "Enviar"},
|
||||||
|
{"Domain can't end with .b32.i2p", "El dominio no puede terminar con .b32.i2p"},
|
||||||
|
{"Domain must end with .i2p", "El dominio debe terminar con .i2p"},
|
||||||
|
{"Such destination is not found", "No se encontró el destino"},
|
||||||
|
{"Unknown command", "Comando desconocido"},
|
||||||
|
{"Command accepted", "Comando aceptado"},
|
||||||
|
{"Proxy error", "Error de proxy"},
|
||||||
|
{"Proxy info", "Información del proxy"},
|
||||||
|
{"Proxy error: Host not found", "Error de proxy: Host no encontrado"},
|
||||||
|
{"Remote host not found in router's addressbook", "Servidor remoto no encontrado en la libreta de direcciones del enrutador"},
|
||||||
|
{"You may try to find this host on jump services below", "Puede intentar encontrar este dominio en los siguientes servicios de salto"},
|
||||||
|
{"Invalid request", "Solicitud inválida"},
|
||||||
|
{"Proxy unable to parse your request", "Proxy no puede procesar su solicitud"},
|
||||||
|
{"addresshelper is not supported", "ayudante de dirección no soportado"},
|
||||||
|
{"Host", "Dominio"},
|
||||||
|
{"added to router's addressbook from helper", "añadido a la libreta de direcciones desde el ayudante"},
|
||||||
|
{"Click here to proceed:", "Haga clic aquí para continuar:"},
|
||||||
|
{"Continue", "Continuar"},
|
||||||
|
{"Addresshelper found", "Se encontró ayudante de dirección"},
|
||||||
|
{"already in router's addressbook", "ya se encontró en libreta de direcciones"},
|
||||||
|
{"Click here to update record:", "Haga clic aquí para actualizar el registro:"},
|
||||||
|
{"invalid request uri", "uri de solicitud inválida"},
|
||||||
|
{"Can't detect destination host from request", "No se puede detectar el host de destino de la solicitud"},
|
||||||
|
{"Outproxy failure", "Fallo en el proxy saliente"},
|
||||||
|
{"bad outproxy settings", "configuración de outproxy incorrecta"},
|
||||||
|
{"not inside I2P network, but outproxy is not enabled", "no está dentro de la red I2P, pero el proxy de salida no está activado"},
|
||||||
|
{"unknown outproxy url", "url de proxy outproxy desconocido"},
|
||||||
|
{"cannot resolve upstream proxy", "no se puede resolver el proxy de upstream"},
|
||||||
|
{"hostname too long", "nombre de dominio muy largo"},
|
||||||
|
{"cannot connect to upstream socks proxy", "no se puede conectar al proxy socks principal"},
|
||||||
|
{"Cannot negotiate with socks proxy", "No se puede negociar con el proxy socks"},
|
||||||
|
{"CONNECT error", "Error de CONNECT"},
|
||||||
|
{"Failed to Connect", "Error al Conectar"},
|
||||||
|
{"socks proxy error", "error de proxy socks"},
|
||||||
|
{"failed to send request to upstream", "no se pudo enviar petición al principal"},
|
||||||
|
{"No Reply From socks proxy", "Sin respuesta del proxy socks"},
|
||||||
|
{"cannot connect", "no se puede conectar"},
|
||||||
|
{"http out proxy not implemented", "proxy externo http no implementado"},
|
||||||
|
{"cannot connect to upstream http proxy", "no se puede conectar al proxy http principal"},
|
||||||
|
{"Host is down", "Servidor caído"},
|
||||||
|
{"Can't create connection to requested host, it may be down. Please try again later.", "No se puede crear la conexión al servidor solicitado, puede estar caído. Intente de nuevo más tarde."},
|
||||||
|
{"", ""},
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::map<std::string, std::vector<std::string>> plurals
|
||||||
|
{
|
||||||
|
{"days", {"día", "días"}},
|
||||||
|
{"hours", {"hora", "horas"}},
|
||||||
|
{"minutes", {"minuto", "minutos"}},
|
||||||
|
{"seconds", {"segundo", "segundos"}},
|
||||||
|
{"", {"", ""}},
|
||||||
|
};
|
||||||
|
|
||||||
|
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
|
||||||
@@ -24,7 +24,7 @@ namespace data {
|
|||||||
size_t ByteStreamToBase32 (const uint8_t * InBuf, size_t len, char * outBuf, size_t outLen);
|
size_t ByteStreamToBase32 (const uint8_t * InBuf, size_t len, char * outBuf, size_t outLen);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Compute the size for a buffer to contain encoded base64 given that the size of the input is input_size bytes
|
* Compute the size for a buffer to contain encoded base64 given that the size of the input is input_size bytes
|
||||||
*/
|
*/
|
||||||
size_t Base64EncodingBufferSize(const size_t input_size);
|
size_t Base64EncodingBufferSize(const size_t input_size);
|
||||||
|
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
|
||||||
*
|
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
|
||||||
*
|
|
||||||
* See full license text in LICENSE file at top of project tree
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "BloomFilter.h"
|
|
||||||
#include "I2PEndian.h"
|
|
||||||
#include <array>
|
|
||||||
#include <openssl/sha.h>
|
|
||||||
|
|
||||||
namespace i2p
|
|
||||||
{
|
|
||||||
namespace util
|
|
||||||
{
|
|
||||||
|
|
||||||
/** @brief decaying bloom filter implementation */
|
|
||||||
class DecayingBloomFilter : public IBloomFilter
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
DecayingBloomFilter(const std::size_t size)
|
|
||||||
{
|
|
||||||
m_Size = size;
|
|
||||||
m_Data = new uint8_t[size];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @brief implements IBloomFilter::~IBloomFilter */
|
|
||||||
~DecayingBloomFilter()
|
|
||||||
{
|
|
||||||
delete [] m_Data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @brief implements IBloomFilter::Add */
|
|
||||||
bool Add(const uint8_t * data, std::size_t len)
|
|
||||||
{
|
|
||||||
std::size_t idx;
|
|
||||||
uint8_t mask;
|
|
||||||
Get(data, len, idx, mask);
|
|
||||||
if(m_Data[idx] & mask) return false; // filter hit
|
|
||||||
m_Data[idx] |= mask;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @brief implements IBloomFilter::Decay */
|
|
||||||
void Decay()
|
|
||||||
{
|
|
||||||
// reset bloom filter buffer
|
|
||||||
memset(m_Data, 0, m_Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
/** @brief get bit index for for data */
|
|
||||||
void Get(const uint8_t * data, std::size_t len, std::size_t & idx, uint8_t & bm)
|
|
||||||
{
|
|
||||||
bm = 1;
|
|
||||||
uint8_t digest[32];
|
|
||||||
// TODO: use blake2 because it's faster
|
|
||||||
SHA256(data, len, digest);
|
|
||||||
uint64_t i = buf64toh(digest);
|
|
||||||
idx = i % m_Size;
|
|
||||||
bm <<= (i % 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t * m_Data;
|
|
||||||
std::size_t m_Size;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
BloomFilterPtr BloomFilter(std::size_t capacity)
|
|
||||||
{
|
|
||||||
return std::make_shared<DecayingBloomFilter>(capacity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
|
||||||
*
|
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
|
||||||
*
|
|
||||||
* See full license text in LICENSE file at top of project tree
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef BLOOM_FILTER_H_
|
|
||||||
#define BLOOM_FILTER_H_
|
|
||||||
#include <memory>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace i2p
|
|
||||||
{
|
|
||||||
namespace util
|
|
||||||
{
|
|
||||||
|
|
||||||
/** @brief interface for bloom filter */
|
|
||||||
struct IBloomFilter
|
|
||||||
{
|
|
||||||
|
|
||||||
/** @brief destructor */
|
|
||||||
virtual ~IBloomFilter() {};
|
|
||||||
/** @brief add entry to bloom filter, return false if filter hit otherwise return true */
|
|
||||||
virtual bool Add(const uint8_t * data, std::size_t len) = 0;
|
|
||||||
/** @brief optionally decay old entries */
|
|
||||||
virtual void Decay() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::shared_ptr<IBloomFilter> BloomFilterPtr;
|
|
||||||
|
|
||||||
/** @brief create bloom filter */
|
|
||||||
BloomFilterPtr BloomFilter(std::size_t capacity = 1024 * 8);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -64,7 +64,7 @@ namespace config {
|
|||||||
("bandwidth", value<std::string>()->default_value(""), "Transit traffic bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)")
|
("bandwidth", value<std::string>()->default_value(""), "Transit traffic bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)")
|
||||||
("share", value<int>()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100)")
|
("share", value<int>()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100)")
|
||||||
("ntcp", bool_switch()->default_value(false), "Ignored. Always false")
|
("ntcp", bool_switch()->default_value(false), "Ignored. Always false")
|
||||||
("ssu", bool_switch()->default_value(true), "Enable SSU transport (default: enabled)")
|
("ssu", bool_switch()->default_value(false), "Ignored. Always false")
|
||||||
("ntcpproxy", value<std::string>()->default_value(""), "Ignored")
|
("ntcpproxy", value<std::string>()->default_value(""), "Ignored")
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
("svcctl", value<std::string>()->default_value(""), "Ignored")
|
("svcctl", value<std::string>()->default_value(""), "Ignored")
|
||||||
@@ -78,9 +78,9 @@ namespace config {
|
|||||||
("limits.coresize", value<uint32_t>()->default_value(0), "Maximum size of corefile in Kb (0 - use system limit)")
|
("limits.coresize", value<uint32_t>()->default_value(0), "Maximum size of corefile in Kb (0 - use system limit)")
|
||||||
("limits.openfiles", value<uint16_t>()->default_value(0), "Maximum number of open files (0 - use system default)")
|
("limits.openfiles", value<uint16_t>()->default_value(0), "Maximum number of open files (0 - use system default)")
|
||||||
("limits.transittunnels", value<uint16_t>()->default_value(2500), "Maximum active transit sessions (default:2500)")
|
("limits.transittunnels", value<uint16_t>()->default_value(2500), "Maximum active transit sessions (default:2500)")
|
||||||
("limits.ntcpsoft", value<uint16_t>()->default_value(0), "Threshold to start probabilistic backoff with ntcp sessions (default: use system limit)")
|
("limits.ntcpsoft", value<uint16_t>()->default_value(0), "Ignored")
|
||||||
("limits.ntcphard", value<uint16_t>()->default_value(0), "Maximum number of ntcp sessions (default: use system limit)")
|
("limits.ntcphard", value<uint16_t>()->default_value(0), "Ignored")
|
||||||
("limits.ntcpthreads", value<uint16_t>()->default_value(1), "Maximum number of threads used by NTCP DH worker (default: 1)")
|
("limits.ntcpthreads", value<uint16_t>()->default_value(1), "Ignored")
|
||||||
;
|
;
|
||||||
|
|
||||||
options_description httpserver("HTTP Server options");
|
options_description httpserver("HTTP Server options");
|
||||||
@@ -230,6 +230,7 @@ namespace config {
|
|||||||
|
|
||||||
options_description addressbook("AddressBook options");
|
options_description addressbook("AddressBook options");
|
||||||
addressbook.add_options()
|
addressbook.add_options()
|
||||||
|
("addressbook.enabled", value<bool>()->default_value(true), "Enable address book lookups and subscritions (default: enabled)")
|
||||||
("addressbook.defaulturl", value<std::string>()->default_value(
|
("addressbook.defaulturl", value<std::string>()->default_value(
|
||||||
"http://shx5vqsw7usdaunyzr2qmes2fq37oumybpudrd4jjj4e4vk4uusa.b32.i2p/hosts.txt"
|
"http://shx5vqsw7usdaunyzr2qmes2fq37oumybpudrd4jjj4e4vk4uusa.b32.i2p/hosts.txt"
|
||||||
), "AddressBook subscription URL for initial setup")
|
), "AddressBook subscription URL for initial setup")
|
||||||
@@ -272,10 +273,13 @@ namespace config {
|
|||||||
;
|
;
|
||||||
|
|
||||||
options_description ssu2("SSU2 Options");
|
options_description ssu2("SSU2 Options");
|
||||||
ntcp2.add_options()
|
ssu2.add_options()
|
||||||
("ssu2.enabled", value<bool>()->default_value(false), "Enable SSU2 (default: disabled)")
|
("ssu2.enabled", value<bool>()->default_value(true), "Enable SSU2 (default: enabled)")
|
||||||
("ssu2.published", value<bool>()->default_value(false), "Publish SSU2 (default: disabled)")
|
("ssu2.published", value<bool>()->default_value(true), "Publish SSU2 (default: enabled)")
|
||||||
("ssu2.port", value<uint16_t>()->default_value(0), "Port to listen for incoming SSU2 packets (default: auto)")
|
("ssu2.port", value<uint16_t>()->default_value(0), "Port to listen for incoming SSU2 packets (default: auto)")
|
||||||
|
("ssu2.mtu4", value<uint16_t>()->default_value(0), "MTU for ipv4 address (default: detect)")
|
||||||
|
("ssu2.mtu6", value<uint16_t>()->default_value(0), "MTU for ipv6 address (default: detect)")
|
||||||
|
("ssu2.proxy", value<std::string>()->default_value(""), "Socks5 proxy URL for SSU2 transport")
|
||||||
;
|
;
|
||||||
|
|
||||||
options_description nettime("Time sync options");
|
options_description nettime("Time sync options");
|
||||||
@@ -310,6 +314,13 @@ namespace config {
|
|||||||
("meshnets.yggaddress", value<std::string>()->default_value(""), "Yggdrasil address to publish")
|
("meshnets.yggaddress", value<std::string>()->default_value(""), "Yggdrasil address to publish")
|
||||||
;
|
;
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
options_description unix_specific("UNIX-specific options");
|
||||||
|
unix_specific.add_options()
|
||||||
|
("unix.handle_sigtstp", bool_switch()->default_value(false), "Handle SIGTSTP and SIGCONT signals (default: disabled)")
|
||||||
|
;
|
||||||
|
#endif
|
||||||
|
|
||||||
m_OptionsDesc
|
m_OptionsDesc
|
||||||
.add(general)
|
.add(general)
|
||||||
.add(limits)
|
.add(limits)
|
||||||
@@ -333,6 +344,9 @@ namespace config {
|
|||||||
.add(persist)
|
.add(persist)
|
||||||
.add(cpuext)
|
.add(cpuext)
|
||||||
.add(meshnets)
|
.add(meshnets)
|
||||||
|
#ifdef __linux__
|
||||||
|
.add(unix_specific)
|
||||||
|
#endif
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -239,55 +239,6 @@ namespace crypto
|
|||||||
|
|
||||||
static BIGNUM * (* g_ElggTable)[255] = nullptr;
|
static BIGNUM * (* g_ElggTable)[255] = nullptr;
|
||||||
|
|
||||||
// DH
|
|
||||||
|
|
||||||
DHKeys::DHKeys ()
|
|
||||||
{
|
|
||||||
m_DH = DH_new ();
|
|
||||||
DH_set0_pqg (m_DH, BN_dup (elgp), NULL, BN_dup (elgg));
|
|
||||||
DH_set0_key (m_DH, NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
DHKeys::~DHKeys ()
|
|
||||||
{
|
|
||||||
DH_free (m_DH);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DHKeys::GenerateKeys ()
|
|
||||||
{
|
|
||||||
BIGNUM * priv_key = NULL, * pub_key = NULL;
|
|
||||||
#if !defined(__x86_64__) // use short exponent for non x64
|
|
||||||
priv_key = BN_new ();
|
|
||||||
BN_rand (priv_key, ELGAMAL_SHORT_EXPONENT_NUM_BITS, 0, 1);
|
|
||||||
#endif
|
|
||||||
if (g_ElggTable)
|
|
||||||
{
|
|
||||||
#if defined(__x86_64__)
|
|
||||||
priv_key = BN_new ();
|
|
||||||
BN_rand (priv_key, ELGAMAL_FULL_EXPONENT_NUM_BITS, 0, 1);
|
|
||||||
#endif
|
|
||||||
auto ctx = BN_CTX_new ();
|
|
||||||
pub_key = ElggPow (priv_key, g_ElggTable, ctx);
|
|
||||||
DH_set0_key (m_DH, pub_key, priv_key);
|
|
||||||
BN_CTX_free (ctx);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DH_set0_key (m_DH, NULL, priv_key);
|
|
||||||
DH_generate_key (m_DH);
|
|
||||||
DH_get0_key (m_DH, (const BIGNUM **)&pub_key, (const BIGNUM **)&priv_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
bn2buf (pub_key, m_PublicKey, 256);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DHKeys::Agree (const uint8_t * pub, uint8_t * shared)
|
|
||||||
{
|
|
||||||
BIGNUM * pk = BN_bin2bn (pub, 256, NULL);
|
|
||||||
DH_compute_key (shared, pk, m_DH);
|
|
||||||
BN_free (pk);
|
|
||||||
}
|
|
||||||
|
|
||||||
// x25519
|
// x25519
|
||||||
X25519Keys::X25519Keys ()
|
X25519Keys::X25519Keys ()
|
||||||
{
|
{
|
||||||
@@ -601,77 +552,6 @@ namespace crypto
|
|||||||
BN_CTX_free (ctx);
|
BN_CTX_free (ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// HMAC
|
|
||||||
const uint64_t IPAD = 0x3636363636363636;
|
|
||||||
const uint64_t OPAD = 0x5C5C5C5C5C5C5C5C;
|
|
||||||
|
|
||||||
|
|
||||||
static const uint64_t ipads[] = { IPAD, IPAD, IPAD, IPAD };
|
|
||||||
static const uint64_t opads[] = { OPAD, OPAD, OPAD, OPAD };
|
|
||||||
|
|
||||||
void HMACMD5Digest (uint8_t * msg, size_t len, const MACKey& key, uint8_t * digest)
|
|
||||||
// key is 32 bytes
|
|
||||||
// digest is 16 bytes
|
|
||||||
// block size is 64 bytes
|
|
||||||
{
|
|
||||||
uint64_t buf[256];
|
|
||||||
uint64_t hash[12]; // 96 bytes
|
|
||||||
#if (defined(__x86_64__) || defined(__i386__)) && defined(__AVX__) // not all X86 targets supports AVX (like old Pentium, see #1600)
|
|
||||||
if(i2p::cpu::avx)
|
|
||||||
{
|
|
||||||
__asm__
|
|
||||||
(
|
|
||||||
"vmovups %[key], %%ymm0 \n"
|
|
||||||
"vmovups %[ipad], %%ymm1 \n"
|
|
||||||
"vmovups %%ymm1, 32(%[buf]) \n"
|
|
||||||
"vxorps %%ymm0, %%ymm1, %%ymm1 \n"
|
|
||||||
"vmovups %%ymm1, (%[buf]) \n"
|
|
||||||
"vmovups %[opad], %%ymm1 \n"
|
|
||||||
"vmovups %%ymm1, 32(%[hash]) \n"
|
|
||||||
"vxorps %%ymm0, %%ymm1, %%ymm1 \n"
|
|
||||||
"vmovups %%ymm1, (%[hash]) \n"
|
|
||||||
"vzeroall \n" // end of AVX
|
|
||||||
"movups %%xmm0, 80(%[hash]) \n" // zero last 16 bytes
|
|
||||||
:
|
|
||||||
: [key]"m"(*(const uint8_t *)key), [ipad]"m"(*ipads), [opad]"m"(*opads),
|
|
||||||
[buf]"r"(buf), [hash]"r"(hash)
|
|
||||||
: "memory", "%xmm0" // TODO: change to %ymm0 later
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
// ikeypad
|
|
||||||
buf[0] = key.GetLL ()[0] ^ IPAD;
|
|
||||||
buf[1] = key.GetLL ()[1] ^ IPAD;
|
|
||||||
buf[2] = key.GetLL ()[2] ^ IPAD;
|
|
||||||
buf[3] = key.GetLL ()[3] ^ IPAD;
|
|
||||||
buf[4] = IPAD;
|
|
||||||
buf[5] = IPAD;
|
|
||||||
buf[6] = IPAD;
|
|
||||||
buf[7] = IPAD;
|
|
||||||
// okeypad
|
|
||||||
hash[0] = key.GetLL ()[0] ^ OPAD;
|
|
||||||
hash[1] = key.GetLL ()[1] ^ OPAD;
|
|
||||||
hash[2] = key.GetLL ()[2] ^ OPAD;
|
|
||||||
hash[3] = key.GetLL ()[3] ^ OPAD;
|
|
||||||
hash[4] = OPAD;
|
|
||||||
hash[5] = OPAD;
|
|
||||||
hash[6] = OPAD;
|
|
||||||
hash[7] = OPAD;
|
|
||||||
// fill last 16 bytes with zeros (first hash size assumed 32 bytes in I2P)
|
|
||||||
memset (hash + 10, 0, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
// concatenate with msg
|
|
||||||
memcpy (buf + 8, msg, len);
|
|
||||||
// calculate first hash
|
|
||||||
MD5((uint8_t *)buf, len + 64, (uint8_t *)(hash + 8)); // 16 bytes
|
|
||||||
|
|
||||||
// calculate digest
|
|
||||||
MD5((uint8_t *)hash, 96, digest);
|
|
||||||
}
|
|
||||||
|
|
||||||
// AES
|
// AES
|
||||||
#ifdef __AES__
|
#ifdef __AES__
|
||||||
#define KeyExpansion256(round0,round1) \
|
#define KeyExpansion256(round0,round1) \
|
||||||
|
|||||||
@@ -29,7 +29,9 @@
|
|||||||
#include "CPU.h"
|
#include "CPU.h"
|
||||||
|
|
||||||
// recognize openssl version and features
|
// recognize openssl version and features
|
||||||
#if ((OPENSSL_VERSION_NUMBER < 0x010100000) || defined(LIBRESSL_VERSION_NUMBER)) // 1.0.2 and below or LibreSSL
|
#if (defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER >= 0x3050200fL)) // LibreSSL 3.5.2 and above
|
||||||
|
# define LEGACY_OPENSSL 0
|
||||||
|
#elif ((OPENSSL_VERSION_NUMBER < 0x010100000) || defined(LIBRESSL_VERSION_NUMBER)) // 1.0.2 and below or LibreSSL
|
||||||
# define LEGACY_OPENSSL 1
|
# define LEGACY_OPENSSL 1
|
||||||
# define X509_getm_notBefore X509_get_notBefore
|
# define X509_getm_notBefore X509_get_notBefore
|
||||||
# define X509_getm_notAfter X509_get_notAfter
|
# define X509_getm_notAfter X509_get_notAfter
|
||||||
@@ -39,7 +41,7 @@
|
|||||||
# define OPENSSL_HKDF 1
|
# define OPENSSL_HKDF 1
|
||||||
# define OPENSSL_EDDSA 1
|
# define OPENSSL_EDDSA 1
|
||||||
# define OPENSSL_X25519 1
|
# define OPENSSL_X25519 1
|
||||||
# if (OPENSSL_VERSION_NUMBER < 0x030000000) // 3.0.0, regression in SipHash
|
# if (OPENSSL_VERSION_NUMBER != 0x030000000) // 3.0.0, regression in SipHash
|
||||||
# define OPENSSL_SIPHASH 1
|
# define OPENSSL_SIPHASH 1
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
@@ -60,24 +62,6 @@ namespace crypto
|
|||||||
// RSA
|
// RSA
|
||||||
const BIGNUM * GetRSAE ();
|
const BIGNUM * GetRSAE ();
|
||||||
|
|
||||||
// DH
|
|
||||||
class DHKeys
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
DHKeys ();
|
|
||||||
~DHKeys ();
|
|
||||||
|
|
||||||
void GenerateKeys ();
|
|
||||||
const uint8_t * GetPublicKey () const { return m_PublicKey; };
|
|
||||||
void Agree (const uint8_t * pub, uint8_t * shared);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
DH * m_DH;
|
|
||||||
uint8_t m_PublicKey[256];
|
|
||||||
};
|
|
||||||
|
|
||||||
// x25519
|
// x25519
|
||||||
class X25519Keys
|
class X25519Keys
|
||||||
{
|
{
|
||||||
@@ -119,10 +103,6 @@ namespace crypto
|
|||||||
bool ECIESDecrypt (const EC_GROUP * curve, const BIGNUM * key, const uint8_t * encrypted, uint8_t * data); // 514 bytes encrypted, 222 data
|
bool ECIESDecrypt (const EC_GROUP * curve, const BIGNUM * key, const uint8_t * encrypted, uint8_t * data); // 514 bytes encrypted, 222 data
|
||||||
void GenerateECIESKeyPair (const EC_GROUP * curve, BIGNUM *& priv, EC_POINT *& pub);
|
void GenerateECIESKeyPair (const EC_GROUP * curve, BIGNUM *& priv, EC_POINT *& pub);
|
||||||
|
|
||||||
// HMAC
|
|
||||||
typedef i2p::data::Tag<32> MACKey;
|
|
||||||
void HMACMD5Digest (uint8_t * msg, size_t len, const MACKey& key, uint8_t * digest);
|
|
||||||
|
|
||||||
// AES
|
// AES
|
||||||
struct ChipherBlock
|
struct ChipherBlock
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "Base.h"
|
#include "Base.h"
|
||||||
|
#include "Gzip.h"
|
||||||
#include "Identity.h"
|
#include "Identity.h"
|
||||||
#include "LeaseSet.h"
|
#include "LeaseSet.h"
|
||||||
#include "I2NPProtocol.h"
|
#include "I2NPProtocol.h"
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
#include "Crypto.h"
|
#include "Crypto.h"
|
||||||
#include "Config.h"
|
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "FS.h"
|
#include "FS.h"
|
||||||
#include "Timestamp.h"
|
#include "Timestamp.h"
|
||||||
@@ -94,9 +93,7 @@ namespace client
|
|||||||
if (it != params->end ())
|
if (it != params->end ())
|
||||||
{
|
{
|
||||||
// oveeride isPublic
|
// oveeride isPublic
|
||||||
bool dontpublish = false;
|
m_IsPublic = (it->second != "true");
|
||||||
i2p::config::GetOption (it->second, dontpublish);
|
|
||||||
m_IsPublic = !dontpublish;
|
|
||||||
}
|
}
|
||||||
it = params->find (I2CP_PARAM_LEASESET_TYPE);
|
it = params->find (I2CP_PARAM_LEASESET_TYPE);
|
||||||
if (it != params->end ())
|
if (it != params->end ())
|
||||||
@@ -954,7 +951,7 @@ namespace client
|
|||||||
for (auto& it: encryptionKeyTypes)
|
for (auto& it: encryptionKeyTypes)
|
||||||
{
|
{
|
||||||
auto encryptionKey = new EncryptionKey (it);
|
auto encryptionKey = new EncryptionKey (it);
|
||||||
if (isPublic)
|
if (IsPublic ())
|
||||||
PersistTemporaryKeys (encryptionKey, isSingleKey);
|
PersistTemporaryKeys (encryptionKey, isSingleKey);
|
||||||
else
|
else
|
||||||
encryptionKey->GenerateKeys ();
|
encryptionKey->GenerateKeys ();
|
||||||
@@ -969,7 +966,7 @@ namespace client
|
|||||||
m_StandardEncryptionKey.reset (encryptionKey);
|
m_StandardEncryptionKey.reset (encryptionKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPublic)
|
if (IsPublic ())
|
||||||
LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created");
|
LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created");
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -982,7 +979,7 @@ namespace client
|
|||||||
m_StreamingAckDelay = std::stoi(it->second);
|
m_StreamingAckDelay = std::stoi(it->second);
|
||||||
it = params->find (I2CP_PARAM_STREAMING_ANSWER_PINGS);
|
it = params->find (I2CP_PARAM_STREAMING_ANSWER_PINGS);
|
||||||
if (it != params->end ())
|
if (it != params->end ())
|
||||||
i2p::config::GetOption (it->second, m_IsStreamingAnswerPings);
|
m_IsStreamingAnswerPings = (it->second == "true");
|
||||||
|
|
||||||
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
|
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
|
||||||
{
|
{
|
||||||
@@ -1099,7 +1096,13 @@ namespace client
|
|||||||
}
|
}
|
||||||
auto leaseSet = FindLeaseSet (dest);
|
auto leaseSet = FindLeaseSet (dest);
|
||||||
if (leaseSet)
|
if (leaseSet)
|
||||||
streamRequestComplete(CreateStream (leaseSet, port));
|
{
|
||||||
|
auto stream = CreateStream (leaseSet, port);
|
||||||
|
GetService ().post ([streamRequestComplete, stream]()
|
||||||
|
{
|
||||||
|
streamRequestComplete(stream);
|
||||||
|
});
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto s = GetSharedFromThis ();
|
auto s = GetSharedFromThis ();
|
||||||
@@ -1132,6 +1135,35 @@ namespace client
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Dest>
|
||||||
|
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStreamSync (const Dest& dest, int port)
|
||||||
|
{
|
||||||
|
std::shared_ptr<i2p::stream::Stream> stream;
|
||||||
|
std::condition_variable streamRequestComplete;
|
||||||
|
std::mutex streamRequestCompleteMutex;
|
||||||
|
std::unique_lock<std::mutex> l(streamRequestCompleteMutex);
|
||||||
|
CreateStream (
|
||||||
|
[&streamRequestComplete, &streamRequestCompleteMutex, &stream](std::shared_ptr<i2p::stream::Stream> s)
|
||||||
|
{
|
||||||
|
stream = s;
|
||||||
|
std::unique_lock<std::mutex> l(streamRequestCompleteMutex);
|
||||||
|
streamRequestComplete.notify_all ();
|
||||||
|
},
|
||||||
|
dest, port);
|
||||||
|
streamRequestComplete.wait (l);
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (const i2p::data::IdentHash& dest, int port)
|
||||||
|
{
|
||||||
|
return CreateStreamSync (dest, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, int port)
|
||||||
|
{
|
||||||
|
return CreateStreamSync (dest, port);
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port)
|
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port)
|
||||||
{
|
{
|
||||||
if (m_StreamingDestination)
|
if (m_StreamingDestination)
|
||||||
|
|||||||
@@ -247,6 +247,8 @@ namespace client
|
|||||||
// following methods operate with default streaming destination
|
// following methods operate with default streaming destination
|
||||||
void CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port = 0);
|
void CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port = 0);
|
||||||
void CreateStream (StreamRequestComplete streamRequestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> dest, int port = 0);
|
void CreateStream (StreamRequestComplete streamRequestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> dest, int port = 0);
|
||||||
|
std::shared_ptr<i2p::stream::Stream> CreateStream (const i2p::data::IdentHash& dest, int port = 0); // sync
|
||||||
|
std::shared_ptr<i2p::stream::Stream> CreateStream (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, int port = 0); // sync
|
||||||
std::shared_ptr<i2p::stream::Stream> CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0);
|
std::shared_ptr<i2p::stream::Stream> CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0);
|
||||||
void SendPing (const i2p::data::IdentHash& to);
|
void SendPing (const i2p::data::IdentHash& to);
|
||||||
void SendPing (std::shared_ptr<const i2p::data::BlindedPublicKey> to);
|
void SendPing (std::shared_ptr<const i2p::data::BlindedPublicKey> to);
|
||||||
@@ -282,6 +284,9 @@ namespace client
|
|||||||
void PersistTemporaryKeys (EncryptionKey * keys, bool isSingleKey);
|
void PersistTemporaryKeys (EncryptionKey * keys, bool isSingleKey);
|
||||||
void ReadAuthKey (const std::string& group, const std::map<std::string, std::string> * params);
|
void ReadAuthKey (const std::string& group, const std::map<std::string, std::string> * params);
|
||||||
|
|
||||||
|
template<typename Dest>
|
||||||
|
std::shared_ptr<i2p::stream::Stream> CreateStreamSync (const Dest& dest, int port);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
i2p::data::PrivateKeys m_Keys;
|
i2p::data::PrivateKeys m_Keys;
|
||||||
@@ -319,4 +324,5 @@ namespace client
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@@ -60,10 +60,38 @@ namespace fs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DetectDataDir(const std::string & cmdline_param, bool isService) {
|
void DetectDataDir(const std::string & cmdline_param, bool isService) {
|
||||||
|
// with 'datadir' option
|
||||||
if (cmdline_param != "") {
|
if (cmdline_param != "") {
|
||||||
dataDir = cmdline_param;
|
dataDir = cmdline_param;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(MAC_OSX) && !defined(ANDROID)
|
||||||
|
// with 'service' option
|
||||||
|
if (isService) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
wchar_t commonAppData[MAX_PATH];
|
||||||
|
if(SHGetFolderPathW(NULL, CSIDL_COMMON_APPDATA, NULL, 0, commonAppData) != S_OK)
|
||||||
|
{
|
||||||
|
#ifdef WIN32_APP
|
||||||
|
MessageBox(NULL, TEXT("Unable to get common AppData path!"), TEXT("I2Pd: error"), MB_ICONERROR | MB_OK);
|
||||||
|
#else
|
||||||
|
fprintf(stderr, "Error: Unable to get common AppData path!");
|
||||||
|
#endif
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dataDir = boost::filesystem::wpath(commonAppData).string() + "\\" + appName;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
dataDir = "/var/lib/" + appName;
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// detect directory as usual
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
wchar_t localAppData[MAX_PATH];
|
wchar_t localAppData[MAX_PATH];
|
||||||
|
|
||||||
@@ -117,12 +145,10 @@ namespace fs {
|
|||||||
dataDir = std::string (ext) + "/" + appName;
|
dataDir = std::string (ext) + "/" + appName;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif // ANDROID
|
||||||
// otherwise use /data/files
|
// use /home/user/.i2pd or /tmp/i2pd
|
||||||
char *home = getenv("HOME");
|
char *home = getenv("HOME");
|
||||||
if (isService) {
|
if (home != NULL && strlen(home) > 0) {
|
||||||
dataDir = "/var/lib/" + appName;
|
|
||||||
} else if (home != NULL && strlen(home) > 0) {
|
|
||||||
dataDir = std::string(home) + "/." + appName;
|
dataDir = std::string(home) + "/." + appName;
|
||||||
} else {
|
} else {
|
||||||
dataDir = "/tmp/" + appName;
|
dataDir = "/tmp/" + appName;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@@ -57,6 +57,7 @@ namespace data
|
|||||||
if ((err = inflate (&m_Inflator, Z_NO_FLUSH)) == Z_STREAM_END)
|
if ((err = inflate (&m_Inflator, Z_NO_FLUSH)) == Z_STREAM_END)
|
||||||
return outLen - m_Inflator.avail_out;
|
return outLen - m_Inflator.avail_out;
|
||||||
// else
|
// else
|
||||||
|
if (err)
|
||||||
LogPrint (eLogError, "Gzip: Inflate error ", err);
|
LogPrint (eLogError, "Gzip: Inflate error ", err);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -128,6 +129,7 @@ namespace data
|
|||||||
return outLen - m_Deflator.avail_out;
|
return outLen - m_Deflator.avail_out;
|
||||||
}
|
}
|
||||||
// else
|
// else
|
||||||
|
if (err)
|
||||||
LogPrint (eLogError, "Gzip: Deflate error ", err);
|
LogPrint (eLogError, "Gzip: Deflate error ", err);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -158,6 +160,7 @@ namespace data
|
|||||||
offset = outLen - m_Deflator.avail_out;
|
offset = outLen - m_Deflator.avail_out;
|
||||||
}
|
}
|
||||||
// else
|
// else
|
||||||
|
if (err)
|
||||||
LogPrint (eLogError, "Gzip: Deflate error ", err);
|
LogPrint (eLogError, "Gzip: Deflate error ", err);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@@ -135,6 +135,7 @@ namespace http
|
|||||||
? url.substr(pos_p, std::string::npos)
|
? url.substr(pos_p, std::string::npos)
|
||||||
: url.substr(pos_p, pos_c - pos_p);
|
: url.substr(pos_p, pos_c - pos_p);
|
||||||
/* stoi throws exception on failure, we don't need it */
|
/* stoi throws exception on failure, we don't need it */
|
||||||
|
port = 0;
|
||||||
for (char c : port_str) {
|
for (char c : port_str) {
|
||||||
if (c < '0' || c > '9')
|
if (c < '0' || c > '9')
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -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
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@@ -802,13 +802,8 @@ namespace i2p
|
|||||||
break;
|
break;
|
||||||
case eI2NPGarlic:
|
case eI2NPGarlic:
|
||||||
{
|
{
|
||||||
if (msg->from)
|
if (msg->from && msg->from->GetTunnelPool ())
|
||||||
{
|
|
||||||
if (msg->from->GetTunnelPool ())
|
|
||||||
msg->from->GetTunnelPool ()->ProcessGarlicMessage (msg);
|
msg->from->GetTunnelPool ()->ProcessGarlicMessage (msg);
|
||||||
else
|
|
||||||
LogPrint (eLogInfo, "I2NP: Local destination for garlic doesn't exist anymore");
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
i2p::context.ProcessGarlicMessage (msg);
|
i2p::context.ProcessGarlicMessage (msg);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@@ -49,13 +49,30 @@ namespace data
|
|||||||
|
|
||||||
IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type, CryptoKeyType cryptoType)
|
IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type, CryptoKeyType cryptoType)
|
||||||
{
|
{
|
||||||
|
/*uint8_t randomPaddingBlock[32];
|
||||||
|
RAND_bytes (randomPaddingBlock, 32);*/
|
||||||
if (cryptoType == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)
|
if (cryptoType == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)
|
||||||
|
{
|
||||||
|
/*memcpy (m_StandardIdentity.publicKey, publicKey ? publicKey : randomPaddingBlock, 32);
|
||||||
|
for (int i = 0; i < 7; i++) // 224 bytes
|
||||||
|
memcpy (m_StandardIdentity.publicKey + 32*(i + 1), randomPaddingBlock, 32);*/
|
||||||
|
if (publicKey)
|
||||||
{
|
{
|
||||||
memcpy (m_StandardIdentity.publicKey, publicKey, 32);
|
memcpy (m_StandardIdentity.publicKey, publicKey, 32);
|
||||||
RAND_bytes (m_StandardIdentity.publicKey + 32, 224);
|
RAND_bytes (m_StandardIdentity.publicKey + 32, 224);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
RAND_bytes (m_StandardIdentity.publicKey, 256);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (publicKey)
|
||||||
memcpy (m_StandardIdentity.publicKey, publicKey, 256);
|
memcpy (m_StandardIdentity.publicKey, publicKey, 256);
|
||||||
|
else
|
||||||
|
RAND_bytes (m_StandardIdentity.publicKey, 256);
|
||||||
|
/*for (int i = 0; i < 8; i++) // 256 bytes
|
||||||
|
memcpy (m_StandardIdentity.publicKey + 32*i, randomPaddingBlock, 32);*/
|
||||||
|
}
|
||||||
if (type != SIGNING_KEY_TYPE_DSA_SHA1)
|
if (type != SIGNING_KEY_TYPE_DSA_SHA1)
|
||||||
{
|
{
|
||||||
size_t excessLen = 0;
|
size_t excessLen = 0;
|
||||||
@@ -93,7 +110,9 @@ namespace data
|
|||||||
case SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519:
|
case SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519:
|
||||||
{
|
{
|
||||||
size_t padding = 128 - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; // 96 = 128 - 32
|
size_t padding = 128 - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; // 96 = 128 - 32
|
||||||
RAND_bytes (m_StandardIdentity.signingKey, padding);
|
/*for (int i = 0; i < 3; i++) // 96 bytes
|
||||||
|
memcpy (m_StandardIdentity.signingKey + 32*i, randomPaddingBlock, 32);*/
|
||||||
|
RAND_bytes (m_StandardIdentity.signingKey, 96);
|
||||||
memcpy (m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH);
|
memcpy (m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -695,7 +714,7 @@ namespace data
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrivateKeys PrivateKeys::CreateRandomKeys (SigningKeyType type, CryptoKeyType cryptoType)
|
PrivateKeys PrivateKeys::CreateRandomKeys (SigningKeyType type, CryptoKeyType cryptoType, bool isDestination)
|
||||||
{
|
{
|
||||||
if (type != SIGNING_KEY_TYPE_DSA_SHA1)
|
if (type != SIGNING_KEY_TYPE_DSA_SHA1)
|
||||||
{
|
{
|
||||||
@@ -705,9 +724,12 @@ namespace data
|
|||||||
GenerateSigningKeyPair (type, keys.m_SigningPrivateKey, signingPublicKey);
|
GenerateSigningKeyPair (type, keys.m_SigningPrivateKey, signingPublicKey);
|
||||||
// encryption
|
// encryption
|
||||||
uint8_t publicKey[256];
|
uint8_t publicKey[256];
|
||||||
|
if (isDestination)
|
||||||
|
RAND_bytes (keys.m_PrivateKey, 256);
|
||||||
|
else
|
||||||
GenerateCryptoKeyPair (cryptoType, keys.m_PrivateKey, publicKey);
|
GenerateCryptoKeyPair (cryptoType, keys.m_PrivateKey, publicKey);
|
||||||
// identity
|
// identity
|
||||||
keys.m_Public = std::make_shared<IdentityEx> (publicKey, signingPublicKey, type, cryptoType);
|
keys.m_Public = std::make_shared<IdentityEx> (isDestination ? nullptr : publicKey, signingPublicKey, type, cryptoType);
|
||||||
|
|
||||||
keys.CreateSigner ();
|
keys.CreateSigner ();
|
||||||
return keys;
|
return keys;
|
||||||
|
|||||||
@@ -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
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@@ -171,7 +171,7 @@ namespace data
|
|||||||
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> CreateDecryptor (const uint8_t * key) const;
|
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> CreateDecryptor (const uint8_t * key) const;
|
||||||
|
|
||||||
static std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> CreateDecryptor (CryptoKeyType cryptoType, const uint8_t * key);
|
static std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> CreateDecryptor (CryptoKeyType cryptoType, const uint8_t * key);
|
||||||
static PrivateKeys CreateRandomKeys (SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1, CryptoKeyType cryptoType = CRYPTO_KEY_TYPE_ELGAMAL);
|
static PrivateKeys CreateRandomKeys (SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1, CryptoKeyType cryptoType = CRYPTO_KEY_TYPE_ELGAMAL, bool isDestination = false);
|
||||||
static void GenerateSigningKeyPair (SigningKeyType type, uint8_t * priv, uint8_t * pub);
|
static void GenerateSigningKeyPair (SigningKeyType type, uint8_t * priv, uint8_t * pub);
|
||||||
static void GenerateCryptoKeyPair (CryptoKeyType type, uint8_t * priv, uint8_t * pub); // priv and pub are 256 bytes long
|
static void GenerateCryptoKeyPair (CryptoKeyType type, uint8_t * priv, uint8_t * pub); // priv and pub are 256 bytes long
|
||||||
static i2p::crypto::Signer * CreateSigner (SigningKeyType keyType, const uint8_t * priv);
|
static i2p::crypto::Signer * CreateSigner (SigningKeyType keyType, const uint8_t * priv);
|
||||||
|
|||||||
@@ -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
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@@ -37,14 +37,7 @@ namespace data
|
|||||||
|
|
||||||
void LeaseSet::Update (const uint8_t * buf, size_t len, bool verifySignature)
|
void LeaseSet::Update (const uint8_t * buf, size_t len, bool verifySignature)
|
||||||
{
|
{
|
||||||
if (len > m_BufferLen)
|
SetBuffer (buf, len);
|
||||||
{
|
|
||||||
auto oldBuffer = m_Buffer;
|
|
||||||
m_Buffer = new uint8_t[len];
|
|
||||||
delete[] oldBuffer;
|
|
||||||
}
|
|
||||||
memcpy (m_Buffer, buf, len);
|
|
||||||
m_BufferLen = len;
|
|
||||||
ReadFromBuffer (false, verifySignature);
|
ReadFromBuffer (false, verifySignature);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,9 +52,9 @@ namespace data
|
|||||||
if (readIdentity || !m_Identity)
|
if (readIdentity || !m_Identity)
|
||||||
m_Identity = std::make_shared<IdentityEx>(m_Buffer, m_BufferLen);
|
m_Identity = std::make_shared<IdentityEx>(m_Buffer, m_BufferLen);
|
||||||
size_t size = m_Identity->GetFullLen ();
|
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;
|
m_IsValid = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -74,7 +67,7 @@ namespace data
|
|||||||
size += m_Identity->GetSigningPublicKeyLen (); // unused signing key
|
size += m_Identity->GetSigningPublicKeyLen (); // unused signing key
|
||||||
if (size + 1 > m_BufferLen)
|
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;
|
m_IsValid = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -89,7 +82,7 @@ namespace data
|
|||||||
}
|
}
|
||||||
if (size + num*LEASE_SIZE > m_BufferLen)
|
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;
|
m_IsValid = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -125,7 +118,7 @@ namespace data
|
|||||||
auto signedSize = leases - m_Buffer;
|
auto signedSize = leases - m_Buffer;
|
||||||
if (signedSize + m_Identity->GetSignatureLen () > m_BufferLen)
|
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;
|
m_IsValid = false;
|
||||||
}
|
}
|
||||||
else if (!m_Identity->Verify (m_Buffer, signedSize, leases))
|
else if (!m_Identity->Verify (m_Buffer, signedSize, leases))
|
||||||
@@ -172,7 +165,7 @@ namespace data
|
|||||||
m_ExpirationTime = lease.endDate;
|
m_ExpirationTime = lease.endDate;
|
||||||
if (m_StoreLeases)
|
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
|
if (!ret.second) (*ret.first)->endDate = lease.endDate; // update existing
|
||||||
(*ret.first)->isUpdated = true;
|
(*ret.first)->isUpdated = true;
|
||||||
}
|
}
|
||||||
@@ -264,7 +257,17 @@ namespace data
|
|||||||
|
|
||||||
void LeaseSet::SetBuffer (const uint8_t * buf, size_t len)
|
void LeaseSet::SetBuffer (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
if (m_Buffer) delete[] m_Buffer;
|
if (len > MAX_LS_BUFFER_SIZE)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "LeaseSet: Buffer is too long ", len);
|
||||||
|
len = MAX_LS_BUFFER_SIZE;
|
||||||
|
}
|
||||||
|
if (m_Buffer && len > m_BufferLen)
|
||||||
|
{
|
||||||
|
delete[] m_Buffer;
|
||||||
|
m_Buffer = nullptr;
|
||||||
|
}
|
||||||
|
if (!m_Buffer)
|
||||||
m_Buffer = new uint8_t[len];
|
m_Buffer = new uint8_t[len];
|
||||||
m_BufferLen = len;
|
m_BufferLen = len;
|
||||||
memcpy (m_Buffer, buf, len);
|
memcpy (m_Buffer, buf, len);
|
||||||
@@ -274,7 +277,7 @@ namespace data
|
|||||||
{
|
{
|
||||||
if (len <= m_BufferLen) m_BufferLen = len;
|
if (len <= m_BufferLen) m_BufferLen = len;
|
||||||
else
|
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):
|
LeaseSet2::LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases, CryptoKeyType preferredCrypto):
|
||||||
@@ -320,7 +323,7 @@ namespace data
|
|||||||
else
|
else
|
||||||
identity = GetIdentity ();
|
identity = GetIdentity ();
|
||||||
size_t offset = identity->GetFullLen ();
|
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)
|
m_PublishedTimestamp = bufbe32toh (buf + offset); offset += 4; // published timestamp (seconds)
|
||||||
uint16_t expires = bufbe16toh (buf + offset); offset += 2; // expires (seconds)
|
uint16_t expires = bufbe16toh (buf + offset); offset += 2; // expires (seconds)
|
||||||
SetExpirationTime ((m_PublishedTimestamp + expires)*1000LL); // in milliseconds
|
SetExpirationTime ((m_PublishedTimestamp + expires)*1000LL); // in milliseconds
|
||||||
@@ -364,6 +367,10 @@ namespace data
|
|||||||
SetIsValid (verified);
|
SetIsValid (verified);
|
||||||
}
|
}
|
||||||
offset += m_TransientVerifier ? m_TransientVerifier->GetSignatureLen () : identity->GetSignatureLen ();
|
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);
|
SetBufferLen (offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,17 +395,17 @@ namespace data
|
|||||||
// properties
|
// properties
|
||||||
uint16_t propertiesLen = bufbe16toh (buf + offset); offset += 2;
|
uint16_t propertiesLen = bufbe16toh (buf + offset); offset += 2;
|
||||||
offset += propertiesLen; // skip for now. TODO: implement properties
|
offset += propertiesLen; // skip for now. TODO: implement properties
|
||||||
if (offset + 1 >= len) return 0;
|
|
||||||
// key sections
|
// key sections
|
||||||
CryptoKeyType preferredKeyType = m_EncryptionType;
|
CryptoKeyType preferredKeyType = m_EncryptionType;
|
||||||
bool preferredKeyFound = false;
|
bool preferredKeyFound = false;
|
||||||
|
if (offset + 1 > len) return 0;
|
||||||
int numKeySections = buf[offset]; offset++;
|
int numKeySections = buf[offset]; offset++;
|
||||||
for (int i = 0; i < numKeySections; i++)
|
for (int i = 0; i < numKeySections; i++)
|
||||||
{
|
{
|
||||||
|
if (offset + 4 > len) return 0;
|
||||||
uint16_t keyType = bufbe16toh (buf + offset); offset += 2; // encryption key type
|
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;
|
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
|
if (IsStoreLeases () && !preferredKeyFound) // create encryptor with leases only
|
||||||
{
|
{
|
||||||
// we pick first valid key if preferred not found
|
// we pick first valid key if preferred not found
|
||||||
@@ -413,7 +420,7 @@ namespace data
|
|||||||
offset += encryptionKeyLen;
|
offset += encryptionKeyLen;
|
||||||
}
|
}
|
||||||
// leases
|
// leases
|
||||||
if (offset + 1 >= len) return 0;
|
if (offset + 1 > len) return 0;
|
||||||
int numLeases = buf[offset]; offset++;
|
int numLeases = buf[offset]; offset++;
|
||||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
if (IsStoreLeases ())
|
if (IsStoreLeases ())
|
||||||
@@ -432,7 +439,8 @@ namespace data
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
offset += numLeases*LEASE2_SIZE; // 40 bytes per lease
|
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)
|
size_t LeaseSet2::ReadMetaLS2TypeSpecificPart (const uint8_t * buf, size_t len)
|
||||||
@@ -442,18 +450,18 @@ namespace data
|
|||||||
uint16_t propertiesLen = bufbe16toh (buf + offset); offset += 2;
|
uint16_t propertiesLen = bufbe16toh (buf + offset); offset += 2;
|
||||||
offset += propertiesLen; // skip for now. TODO: implement properties
|
offset += propertiesLen; // skip for now. TODO: implement properties
|
||||||
// entries
|
// entries
|
||||||
if (offset + 1 >= len) return 0;
|
if (offset + 1 > len) return 0;
|
||||||
int numEntries = buf[offset]; offset++;
|
int numEntries = buf[offset]; offset++;
|
||||||
for (int i = 0; i < numEntries; i++)
|
for (int i = 0; i < numEntries; i++)
|
||||||
{
|
{
|
||||||
if (offset + 40 >= len) return 0;
|
if (offset + LEASE2_SIZE > len) return 0;
|
||||||
offset += 32; // hash
|
offset += 32; // hash
|
||||||
offset += 3; // flags
|
offset += 3; // flags
|
||||||
offset += 1; // cost
|
offset += 1; // cost
|
||||||
offset += 4; // expires
|
offset += 4; // expires
|
||||||
}
|
}
|
||||||
// revocations
|
// revocations
|
||||||
if (offset + 1 >= len) return 0;
|
if (offset + 1 > len) return 0;
|
||||||
int numRevocations = buf[offset]; offset++;
|
int numRevocations = buf[offset]; offset++;
|
||||||
for (int i = 0; i < numRevocations; i++)
|
for (int i = 0; i < numRevocations; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -128,8 +128,8 @@ namespace data
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
validate lease set buffer signature and extract expiration timestamp
|
* validate lease set buffer signature and extract expiration timestamp
|
||||||
@returns true if the leaseset is well formed and signature is valid
|
* @returns true if the leaseset is well formed and signature is valid
|
||||||
*/
|
*/
|
||||||
bool LeaseSetBufferValidate(const uint8_t * ptr, size_t sz, uint64_t & expires);
|
bool LeaseSetBufferValidate(const uint8_t * ptr, size_t sz, uint64_t & expires);
|
||||||
|
|
||||||
|
|||||||
@@ -309,7 +309,7 @@ namespace transport
|
|||||||
|
|
||||||
KDF3Bob ();
|
KDF3Bob ();
|
||||||
if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m3p2Len - 16, GetH (), 32, GetK (), nonce, m3p2Buf, m3p2Len - 16, false)) // decrypt
|
if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m3p2Len - 16, GetH (), 32, GetK (), nonce, m3p2Buf, m3p2Len - 16, false)) // decrypt
|
||||||
// caclulate new h again for KDF data
|
// calculate new h again for KDF data
|
||||||
MixHash (m_SessionConfirmedBuffer + 48, m3p2Len); // h = SHA256(h || ciphertext)
|
MixHash (m_SessionConfirmedBuffer + 48, m3p2Len); // h = SHA256(h || ciphertext)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1169,9 +1169,9 @@ namespace transport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NTCP2Session::SendLocalRouterInfo ()
|
void NTCP2Session::SendLocalRouterInfo (bool update)
|
||||||
{
|
{
|
||||||
if (!IsOutgoing ()) // we send it in SessionConfirmed
|
if (update || !IsOutgoing ()) // we send it in SessionConfirmed for ougoing session
|
||||||
m_Server.GetService ().post (std::bind (&NTCP2Session::SendRouterInfo, shared_from_this ()));
|
m_Server.GetService ().post (std::bind (&NTCP2Session::SendRouterInfo, shared_from_this ()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1210,8 +1210,9 @@ namespace transport
|
|||||||
else
|
else
|
||||||
LogPrint(eLogInfo, "NTCP2: Proxy is not used");
|
LogPrint(eLogInfo, "NTCP2: Proxy is not used");
|
||||||
// start acceptors
|
// start acceptors
|
||||||
auto& addresses = context.GetRouterInfo ().GetAddresses ();
|
auto addresses = context.GetRouterInfo ().GetAddresses ();
|
||||||
for (const auto& address: addresses)
|
if (!addresses) return;
|
||||||
|
for (const auto& address: *addresses)
|
||||||
{
|
{
|
||||||
if (!address) continue;
|
if (!address) continue;
|
||||||
if (address->IsPublishedNTCP2 () && address->port)
|
if (address->IsPublishedNTCP2 () && address->port)
|
||||||
@@ -1424,7 +1425,14 @@ namespace transport
|
|||||||
LogPrint (eLogError, "NTCP2: Connected from error ", ec.message ());
|
LogPrint (eLogError, "NTCP2: Connected from error ", ec.message ());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
LogPrint (eLogError, "NTCP2: Accept error ", error.message ());
|
LogPrint (eLogError, "NTCP2: Accept error ", error.message ());
|
||||||
|
if (error == boost::asio::error::no_descriptors)
|
||||||
|
{
|
||||||
|
i2p::context.SetError (eRouterErrorNoDescriptors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (error != boost::asio::error::operation_aborted)
|
if (error != boost::asio::error::operation_aborted)
|
||||||
{
|
{
|
||||||
@@ -1456,6 +1464,15 @@ namespace transport
|
|||||||
else
|
else
|
||||||
LogPrint (eLogError, "NTCP2: Connected from error ", ec.message ());
|
LogPrint (eLogError, "NTCP2: Connected from error ", ec.message ());
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "NTCP2: Accept ipv6 error ", error.message ());
|
||||||
|
if (error == boost::asio::error::no_descriptors)
|
||||||
|
{
|
||||||
|
i2p::context.SetErrorV6 (eRouterErrorNoDescriptors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (error != boost::asio::error::operation_aborted)
|
if (error != boost::asio::error::operation_aborted)
|
||||||
{
|
{
|
||||||
@@ -1500,8 +1517,24 @@ namespace transport
|
|||||||
else
|
else
|
||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScheduleTermination ();
|
ScheduleTermination ();
|
||||||
|
|
||||||
|
// try to restart acceptors if no description
|
||||||
|
// we do it after timer to let timer take descriptor first
|
||||||
|
if (i2p::context.GetError () == eRouterErrorNoDescriptors)
|
||||||
|
{
|
||||||
|
i2p::context.SetError (eRouterErrorNone);
|
||||||
|
auto conn = std::make_shared<NTCP2Session> (*this);
|
||||||
|
m_NTCP2Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAccept, this,
|
||||||
|
conn, std::placeholders::_1));
|
||||||
|
}
|
||||||
|
if (i2p::context.GetErrorV6 () == eRouterErrorNoDescriptors)
|
||||||
|
{
|
||||||
|
i2p::context.SetErrorV6 (eRouterErrorNone);
|
||||||
|
auto conn = std::make_shared<NTCP2Session> (*this);
|
||||||
|
m_NTCP2V6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAcceptV6, this,
|
||||||
|
conn, std::placeholders::_1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1558,7 +1591,7 @@ namespace transport
|
|||||||
case eSocksProxy:
|
case eSocksProxy:
|
||||||
{
|
{
|
||||||
// TODO: support username/password auth etc
|
// TODO: support username/password auth etc
|
||||||
static const uint8_t buff[3] = {0x05, 0x01, 0x00};
|
static const uint8_t buff[3] = {SOCKS5_VER, 0x01, 0x00};
|
||||||
boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff, 3), boost::asio::transfer_all(),
|
boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff, 3), boost::asio::transfer_all(),
|
||||||
[] (const boost::system::error_code & ec, std::size_t transferred)
|
[] (const boost::system::error_code & ec, std::size_t transferred)
|
||||||
{
|
{
|
||||||
@@ -1672,21 +1705,21 @@ namespace transport
|
|||||||
size_t sz = 6; // header + port
|
size_t sz = 6; // header + port
|
||||||
auto buff = std::make_shared<std::vector<int8_t> >(256);
|
auto buff = std::make_shared<std::vector<int8_t> >(256);
|
||||||
auto readbuff = std::make_shared<std::vector<int8_t> >(256);
|
auto readbuff = std::make_shared<std::vector<int8_t> >(256);
|
||||||
(*buff)[0] = 0x05;
|
(*buff)[0] = SOCKS5_VER;
|
||||||
(*buff)[1] = 0x01;
|
(*buff)[1] = SOCKS5_CMD_CONNECT;
|
||||||
(*buff)[2] = 0x00;
|
(*buff)[2] = 0x00;
|
||||||
|
|
||||||
auto& ep = conn->GetRemoteEndpoint ();
|
auto& ep = conn->GetRemoteEndpoint ();
|
||||||
if(ep.address ().is_v4 ())
|
if(ep.address ().is_v4 ())
|
||||||
{
|
{
|
||||||
(*buff)[3] = 0x01;
|
(*buff)[3] = SOCKS5_ATYP_IPV4;
|
||||||
auto addrbytes = ep.address ().to_v4().to_bytes();
|
auto addrbytes = ep.address ().to_v4().to_bytes();
|
||||||
sz += 4;
|
sz += 4;
|
||||||
memcpy(buff->data () + 4, addrbytes.data(), 4);
|
memcpy(buff->data () + 4, addrbytes.data(), 4);
|
||||||
}
|
}
|
||||||
else if (ep.address ().is_v6 ())
|
else if (ep.address ().is_v6 ())
|
||||||
{
|
{
|
||||||
(*buff)[3] = 0x04;
|
(*buff)[3] = SOCKS5_ATYP_IPV6;
|
||||||
auto addrbytes = ep.address ().to_v6().to_bytes();
|
auto addrbytes = ep.address ().to_v6().to_bytes();
|
||||||
sz += 16;
|
sz += 16;
|
||||||
memcpy(buff->data () + 4, addrbytes.data(), 16);
|
memcpy(buff->data () + 4, addrbytes.data(), 16);
|
||||||
@@ -1708,22 +1741,24 @@ namespace transport
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), 10),
|
boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE), // read min reply size
|
||||||
|
boost::asio::transfer_all(),
|
||||||
[timer, conn, sz, readbuff](const boost::system::error_code & e, std::size_t transferred)
|
[timer, conn, sz, readbuff](const boost::system::error_code & e, std::size_t transferred)
|
||||||
{
|
{
|
||||||
if (e)
|
if (e)
|
||||||
{
|
|
||||||
LogPrint(eLogError, "NTCP2: SOCKS proxy read error ", e.message());
|
LogPrint(eLogError, "NTCP2: SOCKS proxy read error ", e.message());
|
||||||
}
|
else if (!(*readbuff)[1]) // succeeded
|
||||||
else if(transferred == sz)
|
|
||||||
{
|
|
||||||
if((*readbuff)[1] == 0x00)
|
|
||||||
{
|
{
|
||||||
|
boost::system::error_code ec;
|
||||||
|
size_t moreBytes = conn->GetSocket ().available(ec);
|
||||||
|
if (moreBytes) // read remaining portion of reply if ipv6 received
|
||||||
|
boost::asio::read (conn->GetSocket (), boost::asio::buffer(readbuff->data (), moreBytes), boost::asio::transfer_all (), ec);
|
||||||
timer->cancel();
|
timer->cancel();
|
||||||
conn->ClientLogin();
|
conn->ClientLogin();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
LogPrint(eLogError, "NTCP2: Proxy reply error ", (int)(*readbuff)[1]);
|
||||||
timer->cancel();
|
timer->cancel();
|
||||||
conn->Terminate();
|
conn->Terminate();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ namespace transport
|
|||||||
void ClientLogin (); // Alice
|
void ClientLogin (); // Alice
|
||||||
void ServerLogin (); // Bob
|
void ServerLogin (); // Bob
|
||||||
|
|
||||||
void SendLocalRouterInfo (); // after handshake
|
void SendLocalRouterInfo (bool update); // after handshake or by update
|
||||||
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
|
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -107,7 +107,10 @@ namespace data
|
|||||||
{
|
{
|
||||||
i2p::util::SetThreadName("NetDB");
|
i2p::util::SetThreadName("NetDB");
|
||||||
|
|
||||||
uint32_t lastSave = 0, lastPublish = 0, lastExploratory = 0, lastManageRequest = 0, lastDestinationCleanup = 0;
|
uint64_t lastSave = 0, lastPublish = 0, lastExploratory = 0, lastManageRequest = 0, lastDestinationCleanup = 0;
|
||||||
|
uint64_t lastProfilesCleanup = i2p::util::GetSecondsSinceEpoch ();
|
||||||
|
int16_t profilesCleanupVariance = 0;
|
||||||
|
|
||||||
while (m_IsRunning)
|
while (m_IsRunning)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -155,6 +158,7 @@ namespace data
|
|||||||
m_Requests.ManageRequests ();
|
m_Requests.ManageRequests ();
|
||||||
lastManageRequest = ts;
|
lastManageRequest = ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ts - lastSave >= 60) // save routers, manage leasesets and validate subscriptions every minute
|
if (ts - lastSave >= 60) // save routers, manage leasesets and validate subscriptions every minute
|
||||||
{
|
{
|
||||||
if (lastSave)
|
if (lastSave)
|
||||||
@@ -164,12 +168,20 @@ namespace data
|
|||||||
}
|
}
|
||||||
lastSave = ts;
|
lastSave = ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ts - lastDestinationCleanup >= i2p::garlic::INCOMING_TAGS_EXPIRATION_TIMEOUT)
|
if (ts - lastDestinationCleanup >= i2p::garlic::INCOMING_TAGS_EXPIRATION_TIMEOUT)
|
||||||
{
|
{
|
||||||
i2p::context.CleanupDestination ();
|
i2p::context.CleanupDestination ();
|
||||||
lastDestinationCleanup = ts;
|
lastDestinationCleanup = ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ts - lastProfilesCleanup >= (uint64_t)(i2p::data::PEER_PROFILE_AUTOCLEAN_TIMEOUT + profilesCleanupVariance))
|
||||||
|
{
|
||||||
|
DeleteObsoleteProfiles ();
|
||||||
|
lastProfilesCleanup = ts;
|
||||||
|
profilesCleanupVariance = (rand () % (2 * i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE) - i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE);
|
||||||
|
}
|
||||||
|
|
||||||
// publish
|
// publish
|
||||||
if (!m_HiddenMode && i2p::transport::transports.IsOnline ())
|
if (!m_HiddenMode && i2p::transport::transports.IsOnline ())
|
||||||
{
|
{
|
||||||
@@ -195,6 +207,7 @@ namespace data
|
|||||||
lastPublish = ts;
|
lastPublish = ts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ts - lastExploratory >= 30) // exploratory every 30 seconds
|
if (ts - lastExploratory >= 30) // exploratory every 30 seconds
|
||||||
{
|
{
|
||||||
auto numRouters = m_RouterInfos.size ();
|
auto numRouters = m_RouterInfos.size ();
|
||||||
@@ -227,11 +240,10 @@ namespace data
|
|||||||
m_HiddenMode = hide;
|
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;
|
bool updated;
|
||||||
AddRouterInfo (buf, len, updated);
|
return AddRouterInfo (buf, len, updated);
|
||||||
return updated;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const RouterInfo> NetDb::AddRouterInfo (const uint8_t * buf, int len, bool& updated)
|
std::shared_ptr<const RouterInfo> NetDb::AddRouterInfo (const uint8_t * buf, int len, bool& updated)
|
||||||
@@ -259,7 +271,10 @@ namespace data
|
|||||||
if (r->IsNewer (buf, len))
|
if (r->IsNewer (buf, len))
|
||||||
{
|
{
|
||||||
bool wasFloodfill = r->IsFloodfill ();
|
bool wasFloodfill = r->IsFloodfill ();
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
|
||||||
r->Update (buf, len);
|
r->Update (buf, len);
|
||||||
|
}
|
||||||
LogPrint (eLogInfo, "NetDb: RouterInfo updated: ", ident.ToBase64());
|
LogPrint (eLogInfo, "NetDb: RouterInfo updated: ", ident.ToBase64());
|
||||||
if (wasFloodfill != r->IsFloodfill ()) // if floodfill status updated
|
if (wasFloodfill != r->IsFloodfill ()) // if floodfill status updated
|
||||||
{
|
{
|
||||||
@@ -423,12 +438,15 @@ namespace data
|
|||||||
|
|
||||||
// try reseeding from floodfill first if specified
|
// try reseeding from floodfill first if specified
|
||||||
std::string riPath;
|
std::string riPath;
|
||||||
if(i2p::config::GetOption("reseed.floodfill", riPath)) {
|
if(i2p::config::GetOption("reseed.floodfill", riPath))
|
||||||
|
{
|
||||||
auto ri = std::make_shared<RouterInfo>(riPath);
|
auto ri = std::make_shared<RouterInfo>(riPath);
|
||||||
if (ri->IsFloodfill()) {
|
if (ri->IsFloodfill())
|
||||||
|
{
|
||||||
const uint8_t * riData = ri->GetBuffer();
|
const uint8_t * riData = ri->GetBuffer();
|
||||||
int riLen = ri->GetBufferLen();
|
int riLen = ri->GetBufferLen();
|
||||||
if(!i2p::data::netdb.AddRouterInfo(riData, riLen)) {
|
if (!i2p::data::netdb.AddRouterInfo(riData, riLen))
|
||||||
|
{
|
||||||
// bad router info
|
// bad router info
|
||||||
LogPrint(eLogError, "NetDb: Bad router info");
|
LogPrint(eLogError, "NetDb: Bad router info");
|
||||||
return;
|
return;
|
||||||
@@ -585,6 +603,7 @@ namespace data
|
|||||||
uint64_t expirationTimeout = NETDB_MAX_EXPIRATION_TIMEOUT*1000LL;
|
uint64_t expirationTimeout = NETDB_MAX_EXPIRATION_TIMEOUT*1000LL;
|
||||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch();
|
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch();
|
||||||
auto uptime = i2p::context.GetUptime ();
|
auto uptime = i2p::context.GetUptime ();
|
||||||
|
bool isLowRate = i2p::tunnel::tunnels.GetTunnelCreationSuccessRate () < NETDB_MIN_TUNNEL_CREATION_SUCCESS_RATE;
|
||||||
// routers don't expire if less than 90 or uptime is less than 1 hour
|
// routers don't expire if less than 90 or uptime is less than 1 hour
|
||||||
bool checkForExpiration = total > NETDB_MIN_ROUTERS && uptime > 600; // 10 minutes
|
bool checkForExpiration = total > NETDB_MIN_ROUTERS && uptime > 600; // 10 minutes
|
||||||
if (checkForExpiration && uptime > 3600) // 1 hour
|
if (checkForExpiration && uptime > 3600) // 1 hour
|
||||||
@@ -606,11 +625,12 @@ namespace data
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// make router reachable back if too few routers or floodfills
|
// make router reachable back if too few routers or floodfills
|
||||||
if (it.second->IsUnreachable () && (total - deletedCount < NETDB_MIN_ROUTERS ||
|
if (it.second->IsUnreachable () && (total - deletedCount < NETDB_MIN_ROUTERS || isLowRate ||
|
||||||
(it.second->IsFloodfill () && totalFloodfills - deletedFloodfillsCount < NETDB_MIN_FLOODFILLS)))
|
(it.second->IsFloodfill () && totalFloodfills - deletedFloodfillsCount < NETDB_MIN_FLOODFILLS)))
|
||||||
it.second->SetUnreachable (false);
|
it.second->SetUnreachable (false);
|
||||||
// find & mark expired routers
|
// find & mark expired routers
|
||||||
if (!it.second->IsReachable () && it.second->IsSSU (false))
|
if (!it.second->IsReachable () && (it.second->GetCompatibleTransports (true) & RouterInfo::eSSU2V4))
|
||||||
|
// non-reachable router, but reachable by ipv4 SSU2 means introducers
|
||||||
{
|
{
|
||||||
if (ts > it.second->GetTimestamp () + NETDB_INTRODUCEE_EXPIRATION_TIMEOUT*1000LL)
|
if (ts > it.second->GetTimestamp () + NETDB_INTRODUCEE_EXPIRATION_TIMEOUT*1000LL)
|
||||||
// RouterInfo expires after 1 hour if uses introducer
|
// RouterInfo expires after 1 hour if uses introducer
|
||||||
@@ -630,6 +650,8 @@ namespace data
|
|||||||
} // m_RouterInfos iteration
|
} // m_RouterInfos iteration
|
||||||
|
|
||||||
m_RouterInfoBuffersPool.CleanUpMt ();
|
m_RouterInfoBuffersPool.CleanUpMt ();
|
||||||
|
m_RouterInfoAddressesPool.CleanUpMt ();
|
||||||
|
m_RouterInfoAddressVectorsPool.CleanUpMt ();
|
||||||
|
|
||||||
if (updatedCount > 0)
|
if (updatedCount > 0)
|
||||||
LogPrint (eLogInfo, "NetDb: Saved ", updatedCount, " new/updated routers");
|
LogPrint (eLogInfo, "NetDb: Saved ", updatedCount, " new/updated routers");
|
||||||
@@ -730,6 +752,11 @@ namespace data
|
|||||||
{
|
{
|
||||||
const uint8_t * buf = m->GetPayload ();
|
const uint8_t * buf = m->GetPayload ();
|
||||||
size_t len = m->GetSize ();
|
size_t len = m->GetSize ();
|
||||||
|
if (len < DATABASE_STORE_HEADER_SIZE)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "NetDb: Database store msg is too short ", len, ". Dropped");
|
||||||
|
return;
|
||||||
|
}
|
||||||
IdentHash ident (buf + DATABASE_STORE_KEY_OFFSET);
|
IdentHash ident (buf + DATABASE_STORE_KEY_OFFSET);
|
||||||
if (ident.IsZero ())
|
if (ident.IsZero ())
|
||||||
{
|
{
|
||||||
@@ -740,6 +767,11 @@ namespace data
|
|||||||
size_t offset = DATABASE_STORE_HEADER_SIZE;
|
size_t offset = DATABASE_STORE_HEADER_SIZE;
|
||||||
if (replyToken)
|
if (replyToken)
|
||||||
{
|
{
|
||||||
|
if (len < offset + 36) // 32 + 4
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "NetDb: Database store msg with reply token is too short ", len, ". Dropped");
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto deliveryStatus = CreateDeliveryStatusMsg (replyToken);
|
auto deliveryStatus = CreateDeliveryStatusMsg (replyToken);
|
||||||
uint32_t tunnelID = bufbe32toh (buf + offset);
|
uint32_t tunnelID = bufbe32toh (buf + offset);
|
||||||
offset += 4;
|
offset += 4;
|
||||||
@@ -927,9 +959,9 @@ namespace data
|
|||||||
}
|
}
|
||||||
uint16_t numExcluded = bufbe16toh (excluded);
|
uint16_t numExcluded = bufbe16toh (excluded);
|
||||||
excluded += 2;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -938,10 +970,11 @@ namespace data
|
|||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "NetDb: Exploratory close to ", key, " ", numExcluded, " excluded");
|
LogPrint (eLogInfo, "NetDb: Exploratory close to ", key, " ", numExcluded, " excluded");
|
||||||
std::set<IdentHash> excludedRouters;
|
std::set<IdentHash> excludedRouters;
|
||||||
|
const uint8_t * excluded_ident = excluded;
|
||||||
for (int i = 0; i < numExcluded; i++)
|
for (int i = 0; i < numExcluded; i++)
|
||||||
{
|
{
|
||||||
excludedRouters.insert (excluded);
|
excludedRouters.insert (excluded_ident);
|
||||||
excluded += 32;
|
excluded_ident += 32;
|
||||||
}
|
}
|
||||||
std::vector<IdentHash> routers;
|
std::vector<IdentHash> routers;
|
||||||
for (int i = 0; i < 3; i++)
|
for (int i = 0; i < 3; i++)
|
||||||
@@ -964,8 +997,7 @@ namespace data
|
|||||||
if (router)
|
if (router)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "NetDb: Requested RouterInfo ", key, " found");
|
LogPrint (eLogDebug, "NetDb: Requested RouterInfo ", key, " found");
|
||||||
if (!router->GetBuffer ())
|
PopulateRouterInfoBuffer (router);
|
||||||
router->LoadBuffer (m_Storage.Path (router->GetIdentHashBase64 ()));
|
|
||||||
if (router->GetBuffer ())
|
if (router->GetBuffer ())
|
||||||
replyMsg = CreateDatabaseStoreMsg (router);
|
replyMsg = CreateDatabaseStoreMsg (router);
|
||||||
}
|
}
|
||||||
@@ -1180,32 +1212,23 @@ namespace data
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const RouterInfo> NetDb::GetRandomPeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const
|
std::shared_ptr<const RouterInfo> NetDb::GetRandomSSU2PeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const
|
||||||
{
|
{
|
||||||
return GetRandomRouter (
|
return GetRandomRouter (
|
||||||
[v4, &excluded](std::shared_ptr<const RouterInfo> router)->bool
|
[v4, &excluded](std::shared_ptr<const RouterInfo> router)->bool
|
||||||
{
|
{
|
||||||
return !router->IsHidden () && router->IsECIES () &&
|
return !router->IsHidden () && router->IsECIES () &&
|
||||||
router->IsPeerTesting (v4) && !excluded.count (router->GetIdentHash ());
|
router->IsSSU2PeerTesting (v4) && !excluded.count (router->GetIdentHash ());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const RouterInfo> NetDb::GetRandomSSUV6Router () const
|
std::shared_ptr<const RouterInfo> NetDb::GetRandomSSU2Introducer (bool v4, const std::set<IdentHash>& excluded) const
|
||||||
{
|
|
||||||
return GetRandomRouter (
|
|
||||||
[](std::shared_ptr<const RouterInfo> router)->bool
|
|
||||||
{
|
|
||||||
return !router->IsHidden () && router->IsECIES () && router->IsSSUV6 ();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<const RouterInfo> NetDb::GetRandomIntroducer (bool v4, const std::set<IdentHash>& excluded) const
|
|
||||||
{
|
{
|
||||||
return GetRandomRouter (
|
return GetRandomRouter (
|
||||||
[v4, &excluded](std::shared_ptr<const RouterInfo> router)->bool
|
[v4, &excluded](std::shared_ptr<const RouterInfo> router)->bool
|
||||||
{
|
{
|
||||||
return !router->IsHidden () && router->IsECIES () && !router->IsFloodfill () && // floodfills don't send relay tag
|
return !router->IsHidden () && router->IsSSU2Introducer (v4) &&
|
||||||
router->IsIntroducer (v4) && !excluded.count (router->GetIdentHash ());
|
!excluded.count (router->GetIdentHash ());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1409,6 +1432,13 @@ namespace data
|
|||||||
else
|
else
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
m_LeasesPool.CleanUpMt ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetDb::PopulateRouterInfoBuffer (std::shared_ptr<RouterInfo> r)
|
||||||
|
{
|
||||||
|
if (!r || r->GetBuffer ()) return;
|
||||||
|
r->LoadBuffer (m_Storage.Path (r->GetIdentHashBase64 ()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ namespace data
|
|||||||
{
|
{
|
||||||
const int NETDB_MIN_ROUTERS = 90;
|
const int NETDB_MIN_ROUTERS = 90;
|
||||||
const int NETDB_MIN_FLOODFILLS = 5;
|
const int NETDB_MIN_FLOODFILLS = 5;
|
||||||
|
const int NETDB_MIN_TUNNEL_CREATION_SUCCESS_RATE = 8; // in percents
|
||||||
const int NETDB_FLOODFILL_EXPIRATION_TIMEOUT = 60 * 60; // 1 hour, in seconds
|
const int NETDB_FLOODFILL_EXPIRATION_TIMEOUT = 60 * 60; // 1 hour, in seconds
|
||||||
const int NETDB_INTRODUCEE_EXPIRATION_TIMEOUT = 65 * 60;
|
const int NETDB_INTRODUCEE_EXPIRATION_TIMEOUT = 65 * 60;
|
||||||
const int NETDB_MIN_EXPIRATION_TIMEOUT = 90 * 60; // 1.5 hours
|
const int NETDB_MIN_EXPIRATION_TIMEOUT = 90 * 60; // 1.5 hours
|
||||||
@@ -69,7 +70,7 @@ namespace data
|
|||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
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 AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len);
|
||||||
bool AddLeaseSet (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);
|
bool AddLeaseSet2 (const IdentHash& ident, const uint8_t * buf, int len, uint8_t storeType);
|
||||||
@@ -89,9 +90,8 @@ namespace data
|
|||||||
std::shared_ptr<const RouterInfo> GetRandomRouter () const;
|
std::shared_ptr<const RouterInfo> GetRandomRouter () const;
|
||||||
std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const;
|
std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const;
|
||||||
std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const;
|
std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const;
|
||||||
std::shared_ptr<const RouterInfo> GetRandomPeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const;
|
std::shared_ptr<const RouterInfo> GetRandomSSU2PeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const;
|
||||||
std::shared_ptr<const RouterInfo> GetRandomSSUV6Router () const; // TODO: change to v6 peer test later
|
std::shared_ptr<const RouterInfo> GetRandomSSU2Introducer (bool v4, const std::set<IdentHash>& excluded) const;
|
||||||
std::shared_ptr<const RouterInfo> GetRandomIntroducer (bool v4, const std::set<IdentHash>& excluded) const;
|
|
||||||
std::shared_ptr<const RouterInfo> GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
|
std::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::vector<IdentHash> GetClosestFloodfills (const IdentHash& destination, size_t num,
|
||||||
std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
|
std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
|
||||||
@@ -123,6 +123,16 @@ namespace data
|
|||||||
|
|
||||||
void ClearRouterInfos () { m_RouterInfos.clear (); };
|
void ClearRouterInfos () { m_RouterInfos.clear (); };
|
||||||
std::shared_ptr<RouterInfo::Buffer> NewRouterInfoBuffer () { return m_RouterInfoBuffersPool.AcquireSharedMt (); };
|
std::shared_ptr<RouterInfo::Buffer> NewRouterInfoBuffer () { return m_RouterInfoBuffersPool.AcquireSharedMt (); };
|
||||||
|
void PopulateRouterInfoBuffer (std::shared_ptr<RouterInfo> r);
|
||||||
|
std::shared_ptr<RouterInfo::Address> NewRouterInfoAddress () { return m_RouterInfoAddressesPool.AcquireSharedMt (); };
|
||||||
|
boost::shared_ptr<RouterInfo::Addresses> NewRouterInfoAddresses ()
|
||||||
|
{
|
||||||
|
return boost::shared_ptr<RouterInfo::Addresses>(m_RouterInfoAddressVectorsPool.AcquireMt (),
|
||||||
|
std::bind <void (i2p::util::MemoryPoolMt<RouterInfo::Addresses>::*)(RouterInfo::Addresses *)>
|
||||||
|
(&i2p::util::MemoryPoolMt<RouterInfo::Addresses>::ReleaseMt,
|
||||||
|
&m_RouterInfoAddressVectorsPool, std::placeholders::_1));
|
||||||
|
};
|
||||||
|
std::shared_ptr<Lease> NewLease (const Lease& lease) { return m_LeasesPool.AcquireSharedMt (lease); };
|
||||||
|
|
||||||
uint32_t GetPublishReplyToken () const { return m_PublishReplyToken; };
|
uint32_t GetPublishReplyToken () const { return m_PublishReplyToken; };
|
||||||
|
|
||||||
@@ -179,6 +189,9 @@ namespace data
|
|||||||
uint32_t m_PublishReplyToken = 0;
|
uint32_t m_PublishReplyToken = 0;
|
||||||
|
|
||||||
i2p::util::MemoryPoolMt<RouterInfo::Buffer> m_RouterInfoBuffersPool;
|
i2p::util::MemoryPoolMt<RouterInfo::Buffer> m_RouterInfoBuffersPool;
|
||||||
|
i2p::util::MemoryPoolMt<RouterInfo::Address> m_RouterInfoAddressesPool;
|
||||||
|
i2p::util::MemoryPoolMt<RouterInfo::Addresses> m_RouterInfoAddressVectorsPool;
|
||||||
|
i2p::util::MemoryPoolMt<Lease> m_LeasesPool;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern NetDb netdb;
|
extern NetDb netdb;
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
#include "Poly1305.h"
|
|
||||||
/**
|
/**
|
||||||
This code is licensed under the MCGSI Public License
|
* This code is licensed under the MCGSI Public License
|
||||||
Copyright 2018 Jeff Becker
|
* Copyright 2018 Jeff Becker
|
||||||
|
*
|
||||||
Kovri go write your own code
|
*Kovri go write your own code
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Poly1305.h"
|
||||||
|
|
||||||
#if !OPENSSL_AEAD_CHACHA20_POLY1305
|
#if !OPENSSL_AEAD_CHACHA20_POLY1305
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
* Kovri go write your own code
|
* Kovri go write your own code
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef LIBI2PD_POLY1305_H
|
#ifndef LIBI2PD_POLY1305_H
|
||||||
#define LIBI2PD_POLY1305_H
|
#define LIBI2PD_POLY1305_H
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@@ -29,6 +29,8 @@ namespace data
|
|||||||
const char PEER_PROFILE_USAGE_REJECTED[] = "rejected";
|
const char PEER_PROFILE_USAGE_REJECTED[] = "rejected";
|
||||||
|
|
||||||
const int PEER_PROFILE_EXPIRATION_TIMEOUT = 72; // in hours (3 days)
|
const int PEER_PROFILE_EXPIRATION_TIMEOUT = 72; // in hours (3 days)
|
||||||
|
const int PEER_PROFILE_AUTOCLEAN_TIMEOUT = 24 * 3600; // in seconds (1 day)
|
||||||
|
const int PEER_PROFILE_AUTOCLEAN_VARIANCE = 3 * 3600; // in seconds (3 hours)
|
||||||
|
|
||||||
class RouterProfile
|
class RouterProfile
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ namespace i2p
|
|||||||
RouterContext::RouterContext ():
|
RouterContext::RouterContext ():
|
||||||
m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false),
|
m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false),
|
||||||
m_ShareRatio (100), m_Status (eRouterStatusUnknown), m_StatusV6 (eRouterStatusUnknown),
|
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,14 +60,9 @@ namespace i2p
|
|||||||
i2p::data::LocalRouterInfo routerInfo;
|
i2p::data::LocalRouterInfo routerInfo;
|
||||||
routerInfo.SetRouterIdentity (GetIdentity ());
|
routerInfo.SetRouterIdentity (GetIdentity ());
|
||||||
uint16_t port; i2p::config::GetOption("port", port);
|
uint16_t port; i2p::config::GetOption("port", port);
|
||||||
if (!port)
|
if (!port) port = SelectRandomPort ();
|
||||||
{
|
|
||||||
port = rand () % (30777 - 9111) + 9111; // I2P network ports range
|
|
||||||
if (port == 9150) port = 9151; // Tor browser
|
|
||||||
}
|
|
||||||
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
|
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
|
||||||
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
|
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
|
||||||
bool ssu; i2p::config::GetOption("ssu", ssu);
|
|
||||||
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
||||||
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
|
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
|
||||||
bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg);
|
bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg);
|
||||||
@@ -113,15 +108,14 @@ namespace i2p
|
|||||||
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv);
|
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ssu)
|
|
||||||
{
|
|
||||||
routerInfo.AddSSUAddress (host.c_str(), port, nullptr);
|
|
||||||
caps |= i2p::data::RouterInfo::eReachable; // R
|
|
||||||
}
|
|
||||||
if (ssu2)
|
if (ssu2)
|
||||||
{
|
{
|
||||||
if (ssu2Published)
|
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 = port;
|
||||||
|
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address_v4::from_string (host), ssu2Port);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
addressCaps |= i2p::data::RouterInfo::AddressCaps::eV4;
|
addressCaps |= i2p::data::RouterInfo::AddressCaps::eV4;
|
||||||
@@ -158,15 +152,14 @@ namespace i2p
|
|||||||
addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6;
|
addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ssu)
|
|
||||||
{
|
|
||||||
routerInfo.AddSSUAddress (host.c_str(), port, nullptr);
|
|
||||||
caps |= i2p::data::RouterInfo::eReachable; // R
|
|
||||||
}
|
|
||||||
if (ssu2)
|
if (ssu2)
|
||||||
{
|
{
|
||||||
if (ssu2Published)
|
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 = port;
|
||||||
|
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address_v6::from_string (host), ssu2Port);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!ipv4) // no other ssu2 addresses yet
|
if (!ipv4) // no other ssu2 addresses yet
|
||||||
@@ -192,6 +185,13 @@ namespace i2p
|
|||||||
m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ());
|
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 ()
|
void RouterContext::UpdateRouterInfo ()
|
||||||
{
|
{
|
||||||
m_RouterInfo.CreateBuffer (m_Keys);
|
m_RouterInfo.CreateBuffer (m_Keys);
|
||||||
@@ -250,6 +250,7 @@ namespace i2p
|
|||||||
if (status != m_StatusV6)
|
if (status != m_StatusV6)
|
||||||
{
|
{
|
||||||
m_StatusV6 = status;
|
m_StatusV6 = status;
|
||||||
|
m_ErrorV6 = eRouterErrorNone;
|
||||||
switch (m_StatusV6)
|
switch (m_StatusV6)
|
||||||
{
|
{
|
||||||
case eRouterStatusOK:
|
case eRouterStatusOK:
|
||||||
@@ -266,10 +267,12 @@ namespace i2p
|
|||||||
|
|
||||||
void RouterContext::UpdatePort (int port)
|
void RouterContext::UpdatePort (int port)
|
||||||
{
|
{
|
||||||
|
auto addresses = m_RouterInfo.GetAddresses ();
|
||||||
|
if (!addresses) return;
|
||||||
bool updated = false;
|
bool updated = false;
|
||||||
for (auto& address : m_RouterInfo.GetAddresses ())
|
for (auto& address : *addresses)
|
||||||
{
|
{
|
||||||
if (!address->IsNTCP2 () && !address->IsSSU2 () && address->port != port)
|
if (address->port != port && address->transportStyle == i2p::data::RouterInfo::eTransportSSU2)
|
||||||
{
|
{
|
||||||
address->port = port;
|
address->port = port;
|
||||||
updated = true;
|
updated = true;
|
||||||
@@ -282,8 +285,10 @@ namespace i2p
|
|||||||
void RouterContext::PublishNTCP2Address (int port, bool publish, bool v4, bool v6, bool ygg)
|
void RouterContext::PublishNTCP2Address (int port, bool publish, bool v4, bool v6, bool ygg)
|
||||||
{
|
{
|
||||||
if (!m_NTCP2Keys) return;
|
if (!m_NTCP2Keys) return;
|
||||||
|
auto addresses = m_RouterInfo.GetAddresses ();
|
||||||
|
if (!addresses) return;
|
||||||
bool updated = false;
|
bool updated = false;
|
||||||
for (auto& address : m_RouterInfo.GetAddresses ())
|
for (auto& address : *addresses)
|
||||||
{
|
{
|
||||||
if (address->IsNTCP2 () && (address->port != port || address->published != publish))
|
if (address->IsNTCP2 () && (address->port != port || address->published != publish))
|
||||||
{
|
{
|
||||||
@@ -297,12 +302,7 @@ namespace i2p
|
|||||||
}
|
}
|
||||||
if (isAddr)
|
if (isAddr)
|
||||||
{
|
{
|
||||||
if (!port && !address->port)
|
if (!port && !address->port) port = SelectRandomPort ();
|
||||||
{
|
|
||||||
// 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;
|
if (port) address->port = port;
|
||||||
address->published = publish;
|
address->published = publish;
|
||||||
memcpy (address->i, m_NTCP2Keys->iv, 16);
|
memcpy (address->i, m_NTCP2Keys->iv, 16);
|
||||||
@@ -316,20 +316,26 @@ namespace i2p
|
|||||||
|
|
||||||
void RouterContext::UpdateNTCP2Address (bool enable)
|
void RouterContext::UpdateNTCP2Address (bool enable)
|
||||||
{
|
{
|
||||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
auto addresses = m_RouterInfo.GetAddresses ();
|
||||||
|
if (!addresses) return;
|
||||||
bool found = false, updated = false;
|
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 ())
|
if ((*it)->IsNTCP2 ())
|
||||||
{
|
{
|
||||||
found = true;
|
found = true;
|
||||||
if (!enable)
|
if (enable)
|
||||||
{
|
{
|
||||||
addresses.erase (it);
|
(*it)->s = m_NTCP2Keys->staticPublicKey;
|
||||||
|
memcpy ((*it)->i, m_NTCP2Keys->iv, 16);
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
it = addresses->erase (it);
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
break;
|
else
|
||||||
}
|
it++;
|
||||||
}
|
}
|
||||||
if (enable && !found)
|
if (enable && !found)
|
||||||
{
|
{
|
||||||
@@ -342,19 +348,33 @@ namespace i2p
|
|||||||
|
|
||||||
void RouterContext::PublishSSU2Address (int port, bool publish, bool v4, bool v6)
|
void RouterContext::PublishSSU2Address (int port, bool publish, bool v4, bool v6)
|
||||||
{
|
{
|
||||||
if (!m_SSU2Keys || (publish && !port)) return;
|
if (!m_SSU2Keys) return;
|
||||||
bool updated = false;
|
auto addresses = m_RouterInfo.GetAddresses ();
|
||||||
for (auto& address : m_RouterInfo.GetAddresses ())
|
if (!addresses) return;
|
||||||
|
int newPort = 0;
|
||||||
|
if (!port)
|
||||||
{
|
{
|
||||||
if (address->IsSSU2 () && (address->port != port || address->published != publish) &&
|
for (const auto& address : *addresses)
|
||||||
|
if (address->port)
|
||||||
|
{
|
||||||
|
newPort = address->port;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!newPort) newPort = SelectRandomPort ();
|
||||||
|
}
|
||||||
|
bool updated = false;
|
||||||
|
for (auto& address : *addresses)
|
||||||
|
{
|
||||||
|
if (address->IsSSU2 () && (!address->port || address->port != port || address->published != publish) &&
|
||||||
((v4 && address->IsV4 ()) || (v6 && address->IsV6 ())))
|
((v4 && address->IsV4 ()) || (v6 && address->IsV6 ())))
|
||||||
{
|
{
|
||||||
address->port = port;
|
if (port) address->port = port;
|
||||||
|
else if (!address->port) address->port = newPort;
|
||||||
address->published = publish;
|
address->published = publish;
|
||||||
if (publish)
|
if (publish)
|
||||||
address->caps |= i2p::data::RouterInfo::eSSUIntroducer;
|
address->caps |= (i2p::data::RouterInfo::eSSUIntroducer | i2p::data::RouterInfo::eSSUTesting);
|
||||||
else
|
else
|
||||||
address->caps &= ~i2p::data::RouterInfo::eSSUIntroducer;
|
address->caps &= ~(i2p::data::RouterInfo::eSSUIntroducer | i2p::data::RouterInfo::eSSUTesting);
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -364,29 +384,44 @@ namespace i2p
|
|||||||
|
|
||||||
void RouterContext::UpdateSSU2Address (bool enable)
|
void RouterContext::UpdateSSU2Address (bool enable)
|
||||||
{
|
{
|
||||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
auto addresses = m_RouterInfo.GetAddresses ();
|
||||||
|
if (!addresses) return;
|
||||||
bool found = false, updated = false;
|
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 ())
|
if ((*it)->IsSSU2 ())
|
||||||
{
|
{
|
||||||
found = true;
|
found = true;
|
||||||
if (!enable)
|
if (enable)
|
||||||
{
|
{
|
||||||
addresses.erase (it);
|
(*it)->s = m_SSU2Keys->staticPublicKey;
|
||||||
|
(*it)->i = m_SSU2Keys->intro;
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
it = addresses->erase (it);
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
break;
|
else
|
||||||
}
|
it++;
|
||||||
}
|
}
|
||||||
if (enable && !found)
|
if (enable && !found)
|
||||||
{
|
{
|
||||||
uint8_t addressCaps = 0;
|
|
||||||
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
|
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
|
||||||
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
|
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
|
||||||
|
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 (ipv4) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV4;
|
||||||
if (ipv6) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6;
|
if (ipv6) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6;
|
||||||
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addressCaps);
|
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addressCaps);
|
||||||
|
}
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
if (updated)
|
if (updated)
|
||||||
@@ -395,46 +430,69 @@ namespace i2p
|
|||||||
|
|
||||||
void RouterContext::UpdateAddress (const boost::asio::ip::address& host)
|
void RouterContext::UpdateAddress (const boost::asio::ip::address& host)
|
||||||
{
|
{
|
||||||
|
auto addresses = m_RouterInfo.GetAddresses ();
|
||||||
|
if (!addresses) return;
|
||||||
bool updated = false;
|
bool updated = false;
|
||||||
for (auto& address : m_RouterInfo.GetAddresses ())
|
for (auto& address : *addresses)
|
||||||
{
|
{
|
||||||
if (address->host != host && address->IsCompatible (host) &&
|
if (address->host != host && address->IsCompatible (host) &&
|
||||||
!i2p::util::net::IsYggdrasilAddress (address->host))
|
!i2p::util::net::IsYggdrasilAddress (address->host))
|
||||||
{
|
{
|
||||||
|
// update host
|
||||||
address->host = host;
|
address->host = host;
|
||||||
if (host.is_v6 () && address->transportStyle == i2p::data::RouterInfo::eTransportSSU)
|
updated = true;
|
||||||
|
}
|
||||||
|
if (host.is_v6 () && address->IsV6 () && address->ssu &&
|
||||||
|
(!address->ssu->mtu || updated) && m_StatusV6 != eRouterStatusProxy)
|
||||||
{
|
{
|
||||||
// update MTU
|
// update MTU
|
||||||
auto mtu = i2p::util::net::GetMTU (host);
|
auto mtu = i2p::util::net::GetMTU (host);
|
||||||
if (mtu)
|
if (mtu)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "Router: Our v6 MTU=", mtu);
|
LogPrint (eLogDebug, "Router: Our v6 MTU=", mtu);
|
||||||
if (mtu > 1472) { // TODO: magic constant
|
int maxMTU = i2p::util::net::GetMaxMTU (host.to_v6 ());
|
||||||
mtu = 1472;
|
if (mtu > maxMTU)
|
||||||
LogPrint(eLogWarning, "Router: MTU dropped to upper limit of 1472 bytes");
|
{
|
||||||
}
|
mtu = maxMTU;
|
||||||
if (address->ssu) address->ssu->mtu = mtu;
|
LogPrint(eLogWarning, "Router: MTU dropped to upper limit of ", maxMTU, " bytes");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
address->ssu->mtu = mtu;
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
if (updated || ts > m_LastUpdateTime + ROUTER_INFO_UPDATE_INTERVAL)
|
if (updated || ts > m_LastUpdateTime + ROUTER_INFO_UPDATE_INTERVAL)
|
||||||
UpdateRouterInfo ();
|
UpdateRouterInfo ();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RouterContext::AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer)
|
bool RouterContext::AddSSU2Introducer (const i2p::data::RouterInfo::Introducer& introducer, bool v4)
|
||||||
{
|
{
|
||||||
bool ret = m_RouterInfo.AddIntroducer (introducer);
|
bool ret = m_RouterInfo.AddSSU2Introducer (introducer, v4);
|
||||||
if (ret)
|
if (ret)
|
||||||
UpdateRouterInfo ();
|
UpdateRouterInfo ();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::RemoveIntroducer (const boost::asio::ip::udp::endpoint& e)
|
void RouterContext::RemoveSSU2Introducer (const i2p::data::IdentHash& h, bool v4)
|
||||||
{
|
{
|
||||||
if (m_RouterInfo.RemoveIntroducer (e))
|
if (m_RouterInfo.RemoveSSU2Introducer (h, v4))
|
||||||
|
UpdateRouterInfo ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RouterContext::ClearSSU2Introducers (bool v4)
|
||||||
|
{
|
||||||
|
auto addresses = m_RouterInfo.GetAddresses ();
|
||||||
|
if (!addresses) return;
|
||||||
|
bool updated = false;
|
||||||
|
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 ();
|
UpdateRouterInfo ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -536,22 +594,6 @@ namespace i2p
|
|||||||
return m_RouterInfo.GetCaps () & i2p::data::RouterInfo::eUnreachable;
|
return m_RouterInfo.GetCaps () & i2p::data::RouterInfo::eUnreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::RemoveNTCPAddress (bool v4only)
|
|
||||||
{
|
|
||||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
|
||||||
for (auto it = addresses.begin (); it != addresses.end ();)
|
|
||||||
{
|
|
||||||
if ((*it)->transportStyle == i2p::data::RouterInfo::eTransportNTCP && !(*it)->IsNTCP2 () &&
|
|
||||||
(!v4only || (*it)->host.is_v4 ()))
|
|
||||||
{
|
|
||||||
it = addresses.erase (it);
|
|
||||||
if (v4only) break; // otherwise might be more than one address
|
|
||||||
}
|
|
||||||
else
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RouterContext::SetUnreachable (bool v4, bool v6)
|
void RouterContext::SetUnreachable (bool v4, bool v6)
|
||||||
{
|
{
|
||||||
if (v4 || (v6 && !SupportsV4 ()))
|
if (v4 || (v6 && !SupportsV4 ()))
|
||||||
@@ -566,15 +608,18 @@ namespace i2p
|
|||||||
}
|
}
|
||||||
uint16_t port = 0;
|
uint16_t port = 0;
|
||||||
// delete previous introducers
|
// delete previous introducers
|
||||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
auto addresses = m_RouterInfo.GetAddresses ();
|
||||||
for (auto& addr : addresses)
|
if (addresses)
|
||||||
if (addr->ssu && !addr->IsSSU2 () && ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ())))
|
{
|
||||||
|
for (auto& addr : *addresses)
|
||||||
|
if (addr->ssu && ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ())))
|
||||||
{
|
{
|
||||||
addr->published = false;
|
addr->published = false;
|
||||||
addr->caps &= ~i2p::data::RouterInfo::eSSUIntroducer; // can't be introducer
|
addr->caps &= ~i2p::data::RouterInfo::eSSUIntroducer; // can't be introducer
|
||||||
addr->ssu->introducers.clear ();
|
addr->ssu->introducers.clear ();
|
||||||
port = addr->port;
|
port = addr->port;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// unpublish NTCP2 addreeses
|
// unpublish NTCP2 addreeses
|
||||||
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
||||||
if (ntcp2)
|
if (ntcp2)
|
||||||
@@ -598,14 +643,18 @@ namespace i2p
|
|||||||
}
|
}
|
||||||
uint16_t port = 0;
|
uint16_t port = 0;
|
||||||
// delete previous introducers
|
// delete previous introducers
|
||||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
bool isSSU2Published; i2p::config::GetOption ("ssu2.published", isSSU2Published);
|
||||||
for (auto& addr : addresses)
|
auto addresses = m_RouterInfo.GetAddresses ();
|
||||||
if (addr->ssu && !addr->IsSSU2 () && ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ())))
|
if (addresses)
|
||||||
|
{
|
||||||
|
for (auto& addr : *addresses)
|
||||||
|
if (addr->ssu && isSSU2Published && ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ())))
|
||||||
{
|
{
|
||||||
addr->published = true;
|
addr->published = true;
|
||||||
addr->caps |= i2p::data::RouterInfo::eSSUIntroducer;
|
addr->caps |= i2p::data::RouterInfo::eSSUIntroducer;
|
||||||
addr->ssu->introducers.clear ();
|
addr->ssu->introducers.clear ();
|
||||||
port = addr->port;
|
if (addr->port) port = addr->port;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// publish NTCP2
|
// publish NTCP2
|
||||||
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
||||||
@@ -629,19 +678,18 @@ namespace i2p
|
|||||||
if (supportsV6)
|
if (supportsV6)
|
||||||
{
|
{
|
||||||
// insert v6 addresses if necessary
|
// insert v6 addresses if necessary
|
||||||
bool foundSSU = false, foundNTCP2 = false, foundSSU2 = false;
|
bool foundNTCP2 = false, foundSSU2 = false;
|
||||||
uint16_t port = 0;
|
uint16_t port = 0;
|
||||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
auto addresses = m_RouterInfo.GetAddresses ();
|
||||||
for (auto& addr: addresses)
|
if (addresses)
|
||||||
|
{
|
||||||
|
for (auto& addr: *addresses)
|
||||||
{
|
{
|
||||||
if (addr->IsV6 () && !i2p::util::net::IsYggdrasilAddress (addr->host))
|
if (addr->IsV6 () && !i2p::util::net::IsYggdrasilAddress (addr->host))
|
||||||
{
|
{
|
||||||
switch (addr->transportStyle)
|
switch (addr->transportStyle)
|
||||||
{
|
{
|
||||||
case i2p::data::RouterInfo::eTransportSSU:
|
case i2p::data::RouterInfo::eTransportNTCP2:
|
||||||
foundSSU = true;
|
|
||||||
break;
|
|
||||||
case i2p::data::RouterInfo::eTransportNTCP:
|
|
||||||
foundNTCP2 = true;
|
foundNTCP2 = true;
|
||||||
break;
|
break;
|
||||||
case i2p::data::RouterInfo::eTransportSSU2:
|
case i2p::data::RouterInfo::eTransportSSU2:
|
||||||
@@ -652,16 +700,11 @@ namespace i2p
|
|||||||
}
|
}
|
||||||
port = addr->port;
|
port = addr->port;
|
||||||
}
|
}
|
||||||
if (!port) i2p::config::GetOption("port", port);
|
|
||||||
// SSU
|
|
||||||
if (!foundSSU)
|
|
||||||
{
|
|
||||||
bool ssu; i2p::config::GetOption("ssu", ssu);
|
|
||||||
if (ssu)
|
|
||||||
{
|
|
||||||
std::string host = "::1"; // TODO: read host
|
|
||||||
m_RouterInfo.AddSSUAddress (host.c_str (), port, nullptr);
|
|
||||||
}
|
}
|
||||||
|
if (!port)
|
||||||
|
{
|
||||||
|
i2p::config::GetOption("port", port);
|
||||||
|
if (!port) port = SelectRandomPort ();
|
||||||
}
|
}
|
||||||
// NTCP2
|
// NTCP2
|
||||||
if (!foundNTCP2)
|
if (!foundNTCP2)
|
||||||
@@ -695,6 +738,7 @@ namespace i2p
|
|||||||
if (ssu2Published)
|
if (ssu2Published)
|
||||||
{
|
{
|
||||||
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
|
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
|
||||||
|
if (!ssu2Port) ssu2Port = port;
|
||||||
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address::from_string ("::1"), ssu2Port);
|
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address::from_string ("::1"), ssu2Port);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -716,20 +760,19 @@ namespace i2p
|
|||||||
// update
|
// update
|
||||||
if (supportsV4)
|
if (supportsV4)
|
||||||
{
|
{
|
||||||
bool foundSSU = false, foundNTCP2 = false, foundSSU2 = false;
|
bool foundNTCP2 = false, foundSSU2 = false;
|
||||||
std::string host = "127.0.0.1";
|
std::string host = "127.0.0.1";
|
||||||
uint16_t port = 0;
|
uint16_t port = 0;
|
||||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
auto addresses = m_RouterInfo.GetAddresses ();
|
||||||
for (auto& addr: addresses)
|
if (addresses)
|
||||||
|
{
|
||||||
|
for (auto& addr: *addresses)
|
||||||
{
|
{
|
||||||
if (addr->IsV4 ())
|
if (addr->IsV4 ())
|
||||||
{
|
{
|
||||||
switch (addr->transportStyle)
|
switch (addr->transportStyle)
|
||||||
{
|
{
|
||||||
case i2p::data::RouterInfo::eTransportSSU:
|
case i2p::data::RouterInfo::eTransportNTCP2:
|
||||||
foundSSU = true;
|
|
||||||
break;
|
|
||||||
case i2p::data::RouterInfo::eTransportNTCP:
|
|
||||||
foundNTCP2 = true;
|
foundNTCP2 = true;
|
||||||
break;
|
break;
|
||||||
case i2p::data::RouterInfo::eTransportSSU2:
|
case i2p::data::RouterInfo::eTransportSSU2:
|
||||||
@@ -740,13 +783,11 @@ namespace i2p
|
|||||||
}
|
}
|
||||||
if (addr->port) port = addr->port;
|
if (addr->port) port = addr->port;
|
||||||
}
|
}
|
||||||
if (!port) i2p::config::GetOption("port", port);
|
}
|
||||||
// SSU
|
if (!port)
|
||||||
if (!foundSSU)
|
|
||||||
{
|
{
|
||||||
bool ssu; i2p::config::GetOption("ssu", ssu);
|
i2p::config::GetOption("port", port);
|
||||||
if (ssu)
|
if (!port) port = SelectRandomPort ();
|
||||||
m_RouterInfo.AddSSUAddress (host.c_str (), port, nullptr);
|
|
||||||
}
|
}
|
||||||
// NTCP2
|
// NTCP2
|
||||||
if (!foundNTCP2)
|
if (!foundNTCP2)
|
||||||
@@ -775,10 +816,11 @@ namespace i2p
|
|||||||
if (ssu2Published)
|
if (ssu2Published)
|
||||||
{
|
{
|
||||||
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
|
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
|
||||||
|
if (!ssu2Port) ssu2Port = port;
|
||||||
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address::from_string ("127.0.0.1"), ssu2Port);
|
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address::from_string ("127.0.0.1"), ssu2Port);
|
||||||
}
|
}
|
||||||
else
|
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 ();
|
m_RouterInfo.EnableV4 ();
|
||||||
@@ -797,8 +839,10 @@ namespace i2p
|
|||||||
i2p::config::GetOption ("ntcp2.port", port);
|
i2p::config::GetOption ("ntcp2.port", port);
|
||||||
if (!port) i2p::config::GetOption("port", port);
|
if (!port) i2p::config::GetOption("port", port);
|
||||||
bool foundMesh = false;
|
bool foundMesh = false;
|
||||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
auto addresses = m_RouterInfo.GetAddresses ();
|
||||||
for (auto& addr: addresses)
|
if (addresses)
|
||||||
|
{
|
||||||
|
for (auto& addr: *addresses)
|
||||||
{
|
{
|
||||||
if (!port) port = addr->port;
|
if (!port) port = addr->port;
|
||||||
if (i2p::util::net::IsYggdrasilAddress (addr->host))
|
if (i2p::util::net::IsYggdrasilAddress (addr->host))
|
||||||
@@ -807,6 +851,7 @@ namespace i2p
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!foundMesh)
|
if (!foundMesh)
|
||||||
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, host, port);
|
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, host, port);
|
||||||
}
|
}
|
||||||
@@ -815,12 +860,28 @@ namespace i2p
|
|||||||
UpdateRouterInfo ();
|
UpdateRouterInfo ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RouterContext::SetMTU (int mtu, bool v4)
|
||||||
|
{
|
||||||
|
if (mtu < 1280 || mtu > 1500) return;
|
||||||
|
auto addresses = m_RouterInfo.GetAddresses ();
|
||||||
|
if (!addresses) return;
|
||||||
|
for (auto& addr: *addresses)
|
||||||
|
{
|
||||||
|
if (addr->ssu && ((v4 && addr->IsV4 ()) || (!v4 && addr->IsV6 ())))
|
||||||
|
{
|
||||||
|
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)
|
void RouterContext::UpdateNTCP2V6Address (const boost::asio::ip::address& host)
|
||||||
{
|
{
|
||||||
bool isYgg = i2p::util::net::IsYggdrasilAddress (host);
|
bool isYgg = i2p::util::net::IsYggdrasilAddress (host);
|
||||||
bool updated = false;
|
bool updated = false;
|
||||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
auto addresses = m_RouterInfo.GetAddresses ();
|
||||||
for (auto& addr: addresses)
|
if (!addresses) return;
|
||||||
|
for (auto& addr: *addresses)
|
||||||
{
|
{
|
||||||
if (addr->IsPublishedNTCP2 ())
|
if (addr->IsPublishedNTCP2 ())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -37,10 +37,9 @@ namespace garlic
|
|||||||
eRouterStatusOK = 0,
|
eRouterStatusOK = 0,
|
||||||
eRouterStatusTesting = 1,
|
eRouterStatusTesting = 1,
|
||||||
eRouterStatusFirewalled = 2,
|
eRouterStatusFirewalled = 2,
|
||||||
eRouterStatusError = 3,
|
eRouterStatusUnknown = 3,
|
||||||
eRouterStatusUnknown = 4,
|
eRouterStatusProxy = 4,
|
||||||
eRouterStatusProxy = 5,
|
eRouterStatusMesh = 5
|
||||||
eRouterStatusMesh = 6
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum RouterError
|
enum RouterError
|
||||||
@@ -48,7 +47,8 @@ namespace garlic
|
|||||||
eRouterErrorNone = 0,
|
eRouterErrorNone = 0,
|
||||||
eRouterErrorClockSkew = 1,
|
eRouterErrorClockSkew = 1,
|
||||||
eRouterErrorOffline = 2,
|
eRouterErrorOffline = 2,
|
||||||
eRouterErrorSymmetricNAT = 3
|
eRouterErrorSymmetricNAT = 3,
|
||||||
|
eRouterErrorNoDescriptors = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
class RouterContext: public i2p::garlic::GarlicDestination
|
class RouterContext: public i2p::garlic::GarlicDestination
|
||||||
@@ -104,9 +104,11 @@ namespace garlic
|
|||||||
RouterStatus GetStatus () const { return m_Status; };
|
RouterStatus GetStatus () const { return m_Status; };
|
||||||
void SetStatus (RouterStatus status);
|
void SetStatus (RouterStatus status);
|
||||||
RouterError GetError () const { return m_Error; };
|
RouterError GetError () const { return m_Error; };
|
||||||
void SetError (RouterError error) { m_Status = eRouterStatusError; m_Error = error; };
|
void SetError (RouterError error) { m_Error = error; };
|
||||||
RouterStatus GetStatusV6 () const { return m_StatusV6; };
|
RouterStatus GetStatusV6 () const { return m_StatusV6; };
|
||||||
void SetStatusV6 (RouterStatus status);
|
void SetStatusV6 (RouterStatus status);
|
||||||
|
RouterError GetErrorV6 () const { return m_ErrorV6; };
|
||||||
|
void SetErrorV6 (RouterError error) { m_ErrorV6 = error; };
|
||||||
int GetNetID () const { return m_NetID; };
|
int GetNetID () const { return m_NetID; };
|
||||||
void SetNetID (int netID) { m_NetID = netID; };
|
void SetNetID (int netID) { m_NetID = netID; };
|
||||||
bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data);
|
bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data);
|
||||||
@@ -118,9 +120,9 @@ namespace garlic
|
|||||||
void UpdateNTCP2Address (bool enable);
|
void UpdateNTCP2Address (bool enable);
|
||||||
void PublishSSU2Address (int port, bool publish, bool v4, bool v6);
|
void PublishSSU2Address (int port, bool publish, bool v4, bool v6);
|
||||||
void UpdateSSU2Address (bool enable);
|
void UpdateSSU2Address (bool enable);
|
||||||
void RemoveNTCPAddress (bool v4only = true); // delete NTCP address for older routers. TODO: remove later
|
bool AddSSU2Introducer (const i2p::data::RouterInfo::Introducer& introducer, bool v4);
|
||||||
bool AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer);
|
void RemoveSSU2Introducer (const i2p::data::IdentHash& h, bool v4);
|
||||||
void RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
|
void ClearSSU2Introducers (bool v4);
|
||||||
bool IsUnreachable () const;
|
bool IsUnreachable () const;
|
||||||
void SetUnreachable (bool v4, bool v6);
|
void SetUnreachable (bool v4, bool v6);
|
||||||
void SetReachable (bool v4, bool v6);
|
void SetReachable (bool v4, bool v6);
|
||||||
@@ -139,6 +141,7 @@ namespace garlic
|
|||||||
void SetSupportsV6 (bool supportsV6);
|
void SetSupportsV6 (bool supportsV6);
|
||||||
void SetSupportsV4 (bool supportsV4);
|
void SetSupportsV4 (bool supportsV4);
|
||||||
void SetSupportsMesh (bool supportsmesh, const boost::asio::ip::address_v6& host);
|
void SetSupportsMesh (bool supportsmesh, const boost::asio::ip::address_v6& host);
|
||||||
|
void SetMTU (int mtu, bool v4);
|
||||||
i2p::crypto::NoiseSymmetricState& GetCurrentNoiseState () { return m_CurrentNoiseState; };
|
i2p::crypto::NoiseSymmetricState& GetCurrentNoiseState () { return m_CurrentNoiseState; };
|
||||||
|
|
||||||
void UpdateNTCP2V6Address (const boost::asio::ip::address& host); // called from Daemon. TODO: remove
|
void UpdateNTCP2V6Address (const boost::asio::ip::address& host); // called from Daemon. TODO: remove
|
||||||
@@ -173,8 +176,10 @@ namespace garlic
|
|||||||
void UpdateRouterInfo ();
|
void UpdateRouterInfo ();
|
||||||
void NewNTCP2Keys ();
|
void NewNTCP2Keys ();
|
||||||
void NewSSU2Keys ();
|
void NewSSU2Keys ();
|
||||||
|
bool IsSSU2Only () const; // SSU2 and no SSU
|
||||||
bool Load ();
|
bool Load ();
|
||||||
void SaveKeys ();
|
void SaveKeys ();
|
||||||
|
uint16_t SelectRandomPort () const;
|
||||||
|
|
||||||
bool DecryptECIESTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, size_t clearTextSize);
|
bool DecryptECIESTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, size_t clearTextSize);
|
||||||
|
|
||||||
@@ -190,7 +195,7 @@ namespace garlic
|
|||||||
uint64_t m_BandwidthLimit; // allowed bandwidth
|
uint64_t m_BandwidthLimit; // allowed bandwidth
|
||||||
int m_ShareRatio;
|
int m_ShareRatio;
|
||||||
RouterStatus m_Status, m_StatusV6;
|
RouterStatus m_Status, m_StatusV6;
|
||||||
RouterError m_Error;
|
RouterError m_Error, m_ErrorV6;
|
||||||
int m_NetID;
|
int m_NetID;
|
||||||
std::mutex m_GarlicMutex;
|
std::mutex m_GarlicMutex;
|
||||||
std::unique_ptr<NTCP2PrivateKeys> m_NTCP2Keys;
|
std::unique_ptr<NTCP2PrivateKeys> m_NTCP2Keys;
|
||||||
|
|||||||
@@ -206,26 +206,25 @@ namespace data
|
|||||||
s.read ((char *)&m_Timestamp, sizeof (m_Timestamp));
|
s.read ((char *)&m_Timestamp, sizeof (m_Timestamp));
|
||||||
m_Timestamp = be64toh (m_Timestamp);
|
m_Timestamp = be64toh (m_Timestamp);
|
||||||
// read addresses
|
// read addresses
|
||||||
auto addresses = boost::make_shared<Addresses>();
|
auto addresses = netdb.NewRouterInfoAddresses ();
|
||||||
uint8_t numAddresses;
|
uint8_t numAddresses;
|
||||||
s.read ((char *)&numAddresses, sizeof (numAddresses));
|
s.read ((char *)&numAddresses, sizeof (numAddresses));
|
||||||
addresses->reserve (numAddresses);
|
addresses->reserve (numAddresses);
|
||||||
for (int i = 0; i < numAddresses; i++)
|
for (int i = 0; i < numAddresses; i++)
|
||||||
{
|
{
|
||||||
uint8_t supportedTransports = 0;
|
uint8_t supportedTransports = 0;
|
||||||
auto address = std::make_shared<Address> ();
|
auto address = netdb.NewRouterInfoAddress ();
|
||||||
uint8_t cost; // ignore
|
uint8_t cost; // ignore
|
||||||
s.read ((char *)&cost, sizeof (cost));
|
s.read ((char *)&cost, sizeof (cost));
|
||||||
s.read ((char *)&address->date, sizeof (address->date));
|
s.read ((char *)&address->date, sizeof (address->date));
|
||||||
bool isHost = false, isIntroKey = false, isStaticKey = false, isV2 = false;
|
bool isHost = false, isStaticKey = false, isV2 = false;
|
||||||
Tag<32> iV2; // for 'i' field in SSU, TODO: remove later
|
|
||||||
char transportStyle[6];
|
char transportStyle[6];
|
||||||
ReadString (transportStyle, 6, s);
|
ReadString (transportStyle, 6, s);
|
||||||
if (!strncmp (transportStyle, "NTCP", 4)) // NTCP or NTCP2
|
if (!strncmp (transportStyle, "NTCP", 4)) // NTCP or NTCP2
|
||||||
address->transportStyle = eTransportNTCP;
|
address->transportStyle = eTransportNTCP2;
|
||||||
else if (!strncmp (transportStyle, "SSU", 3)) // SSU or SSU2
|
else if (!strncmp (transportStyle, "SSU", 3)) // SSU or SSU2
|
||||||
{
|
{
|
||||||
address->transportStyle = (transportStyle[3] == '2') ? eTransportSSU2 : eTransportSSU;
|
address->transportStyle = eTransportSSU2;
|
||||||
address->ssu.reset (new SSUExt ());
|
address->ssu.reset (new SSUExt ());
|
||||||
address->ssu->mtu = 0;
|
address->ssu->mtu = 0;
|
||||||
}
|
}
|
||||||
@@ -257,20 +256,31 @@ namespace data
|
|||||||
if (!ecode && !address->host.is_unspecified ()) isHost = true;
|
if (!ecode && !address->host.is_unspecified ()) isHost = true;
|
||||||
}
|
}
|
||||||
else if (!strcmp (key, "port"))
|
else if (!strcmp (key, "port"))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
address->port = boost::lexical_cast<int>(value);
|
address->port = boost::lexical_cast<int>(value);
|
||||||
|
}
|
||||||
|
catch (std::exception& ex)
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "RouterInfo: 'port' exception ", ex.what ());
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (!strcmp (key, "mtu"))
|
else if (!strcmp (key, "mtu"))
|
||||||
{
|
{
|
||||||
if (address->ssu)
|
if (address->ssu)
|
||||||
address->ssu->mtu = boost::lexical_cast<int>(value);
|
|
||||||
else
|
|
||||||
LogPrint (eLogWarning, "RouterInfo: Unexpected field 'mtu' for NTCP");
|
|
||||||
}
|
|
||||||
else if (!strcmp (key, "key"))
|
|
||||||
{
|
{
|
||||||
if (address->ssu)
|
try
|
||||||
isIntroKey = (Base64ToByteStream (value, strlen (value), address->i, 32) == 32);
|
{
|
||||||
|
address->ssu->mtu = boost::lexical_cast<int>(value);
|
||||||
|
}
|
||||||
|
catch (std::exception& ex)
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "RouterInfo: 'mtu' exception ", ex.what ());
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogWarning, "RouterInfo: Unexpected field 'key' for NTCP");
|
LogPrint (eLogWarning, "RouterInfo: Unexpected field 'mtu' for NTCP2");
|
||||||
}
|
}
|
||||||
else if (!strcmp (key, "caps"))
|
else if (!strcmp (key, "caps"))
|
||||||
address->caps = ExtractAddressCaps (value);
|
address->caps = ExtractAddressCaps (value);
|
||||||
@@ -288,8 +298,6 @@ namespace data
|
|||||||
}
|
}
|
||||||
else if (address->IsSSU2 ())
|
else if (address->IsSSU2 ())
|
||||||
Base64ToByteStream (value, strlen (value), address->i, 32);
|
Base64ToByteStream (value, strlen (value), address->i, 32);
|
||||||
else
|
|
||||||
Base64ToByteStream (value, strlen (value), iV2, 32);
|
|
||||||
}
|
}
|
||||||
else if (!strcmp (key, "v"))
|
else if (!strcmp (key, "v"))
|
||||||
{
|
{
|
||||||
@@ -322,22 +330,40 @@ namespace data
|
|||||||
}
|
}
|
||||||
Introducer& introducer = address->ssu->introducers.at (index);
|
Introducer& introducer = address->ssu->introducers.at (index);
|
||||||
if (!strcmp (key, "ihost"))
|
if (!strcmp (key, "ihost"))
|
||||||
{
|
introducer.isH = false; // SSU1
|
||||||
boost::system::error_code ecode;
|
|
||||||
introducer.iHost = boost::asio::ip::address::from_string (value, ecode);
|
|
||||||
}
|
|
||||||
else if (!strcmp (key, "iport"))
|
else if (!strcmp (key, "iport"))
|
||||||
introducer.iPort = boost::lexical_cast<int>(value);
|
introducer.isH = false; // SSU1
|
||||||
else if (!strcmp (key, "itag"))
|
else if (!strcmp (key, "itag"))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
introducer.iTag = boost::lexical_cast<uint32_t>(value);
|
introducer.iTag = boost::lexical_cast<uint32_t>(value);
|
||||||
else if (!strcmp (key, "ikey") || !strcmp (key, "ih"))
|
}
|
||||||
Base64ToByteStream (value, strlen (value), introducer.iKey, 32);
|
catch (std::exception& ex)
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "RouterInfo: 'itag' exception ", ex.what ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!strcmp (key, "ih"))
|
||||||
|
{
|
||||||
|
Base64ToByteStream (value, strlen (value), introducer.iH, 32);
|
||||||
|
introducer.isH = true;
|
||||||
|
}
|
||||||
else if (!strcmp (key, "iexp"))
|
else if (!strcmp (key, "iexp"))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
introducer.iExp = boost::lexical_cast<uint32_t>(value);
|
introducer.iExp = boost::lexical_cast<uint32_t>(value);
|
||||||
}
|
}
|
||||||
|
catch (std::exception& ex)
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "RouterInfo: 'iexp' exception ", ex.what ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!s) return;
|
if (!s) return;
|
||||||
}
|
}
|
||||||
if (address->transportStyle == eTransportNTCP)
|
if (address->transportStyle == eTransportNTCP2)
|
||||||
{
|
{
|
||||||
if (isStaticKey)
|
if (isStaticKey)
|
||||||
{
|
{
|
||||||
@@ -361,46 +387,7 @@ namespace data
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (address->transportStyle == eTransportSSU)
|
else if (address->transportStyle == eTransportSSU2 && isV2)
|
||||||
{
|
|
||||||
if (isIntroKey)
|
|
||||||
{
|
|
||||||
if (isHost)
|
|
||||||
supportedTransports |= address->host.is_v4 () ? eSSUV4 : eSSUV6;
|
|
||||||
else if (address->caps & AddressCaps::eV6)
|
|
||||||
{
|
|
||||||
supportedTransports |= eSSUV6;
|
|
||||||
if (address->caps & AddressCaps::eV4) supportedTransports |= eSSUV4; // in additional to v6
|
|
||||||
}
|
|
||||||
else
|
|
||||||
supportedTransports |= eSSUV4; // in case if host or 6 caps is not preasented, we assume 4
|
|
||||||
if (address->ssu && !address->ssu->introducers.empty ())
|
|
||||||
{
|
|
||||||
// exclude invalid introducers
|
|
||||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
|
||||||
int numValid = 0;
|
|
||||||
for (auto& it: address->ssu->introducers)
|
|
||||||
{
|
|
||||||
if (!it.iExp) it.iExp = m_Timestamp/1000 + NETDB_INTRODUCEE_EXPIRATION_TIMEOUT;
|
|
||||||
if (ts <= it.iExp && it.iPort > 0 &&
|
|
||||||
((it.iHost.is_v4 () && address->IsV4 ()) || (it.iHost.is_v6 () && address->IsV6 ())))
|
|
||||||
numValid++;
|
|
||||||
else
|
|
||||||
it.iPort = 0;
|
|
||||||
}
|
|
||||||
if (numValid)
|
|
||||||
m_ReachableTransports |= supportedTransports;
|
|
||||||
else
|
|
||||||
address->ssu->introducers.resize (0);
|
|
||||||
}
|
|
||||||
else if (isHost && address->port)
|
|
||||||
{
|
|
||||||
address->published = true;
|
|
||||||
m_ReachableTransports |= supportedTransports;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (address->transportStyle == eTransportSSU2 || (isV2 && address->transportStyle == eTransportSSU))
|
|
||||||
{
|
{
|
||||||
if (address->IsV4 ()) supportedTransports |= eSSU2V4;
|
if (address->IsV4 ()) supportedTransports |= eSSU2V4;
|
||||||
if (address->IsV6 ()) supportedTransports |= eSSU2V6;
|
if (address->IsV6 ()) supportedTransports |= eSSU2V6;
|
||||||
@@ -408,32 +395,34 @@ namespace data
|
|||||||
{
|
{
|
||||||
if (address->host.is_v4 ()) m_ReachableTransports |= eSSU2V4;
|
if (address->host.is_v4 ()) m_ReachableTransports |= eSSU2V4;
|
||||||
if (address->host.is_v6 ()) m_ReachableTransports |= eSSU2V6;
|
if (address->host.is_v6 ()) m_ReachableTransports |= eSSU2V6;
|
||||||
|
address->published = true;
|
||||||
|
}
|
||||||
|
if (address->ssu && !address->ssu->introducers.empty ())
|
||||||
|
{
|
||||||
|
// exclude invalid introducers
|
||||||
|
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
|
int numValid = 0;
|
||||||
|
for (auto& it: address->ssu->introducers)
|
||||||
|
{
|
||||||
|
if (it.iTag && ts < it.iExp && it.isH)
|
||||||
|
numValid++;
|
||||||
|
else
|
||||||
|
it.iTag = 0;
|
||||||
|
}
|
||||||
|
if (numValid)
|
||||||
|
m_ReachableTransports |= supportedTransports;
|
||||||
|
else
|
||||||
|
address->ssu->introducers.resize (0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (supportedTransports)
|
if (supportedTransports)
|
||||||
{
|
{
|
||||||
if (!(m_SupportedTransports & supportedTransports)) // avoid duplicates
|
if (!(m_SupportedTransports & supportedTransports)) // avoid duplicates
|
||||||
{
|
|
||||||
addresses->push_back(address);
|
addresses->push_back(address);
|
||||||
if (address->transportStyle == eTransportSSU && isV2)
|
|
||||||
{
|
|
||||||
// create additional SSU2 address. TODO: remove later
|
|
||||||
auto ssu2addr = std::make_shared<Address> ();
|
|
||||||
ssu2addr->transportStyle = eTransportSSU2;
|
|
||||||
ssu2addr->host = address->host; ssu2addr->port = address->port;
|
|
||||||
ssu2addr->s = address->s; ssu2addr->i = iV2;
|
|
||||||
ssu2addr->date = address->date; ssu2addr->caps = address->caps;
|
|
||||||
ssu2addr->published = address->published;
|
|
||||||
ssu2addr->ssu.reset (new SSUExt ()); ssu2addr->ssu->mtu = address->ssu->mtu;
|
|
||||||
for (const auto& introducer: address->ssu->introducers)
|
|
||||||
if (!introducer.iPort) // SSU2
|
|
||||||
ssu2addr->ssu->introducers.push_back (introducer);
|
|
||||||
addresses->push_back(ssu2addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_SupportedTransports |= supportedTransports;
|
m_SupportedTransports |= supportedTransports;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// update addresses
|
||||||
#if (BOOST_VERSION >= 105300)
|
#if (BOOST_VERSION >= 105300)
|
||||||
boost::atomic_store (&m_Addresses, addresses);
|
boost::atomic_store (&m_Addresses, addresses);
|
||||||
#else
|
#else
|
||||||
@@ -562,10 +551,10 @@ namespace data
|
|||||||
case CAPS_FLAG_V6:
|
case CAPS_FLAG_V6:
|
||||||
caps |= AddressCaps::eV6;
|
caps |= AddressCaps::eV6;
|
||||||
break;
|
break;
|
||||||
case CAPS_FLAG_SSU_TESTING:
|
case CAPS_FLAG_SSU2_TESTING:
|
||||||
caps |= AddressCaps::eSSUTesting;
|
caps |= AddressCaps::eSSUTesting;
|
||||||
break;
|
break;
|
||||||
case CAPS_FLAG_SSU_INTRODUCER:
|
case CAPS_FLAG_SSU2_INTRODUCER:
|
||||||
caps |= AddressCaps::eSSUIntroducer;
|
caps |= AddressCaps::eSSUIntroducer;
|
||||||
break;
|
break;
|
||||||
default: ;
|
default: ;
|
||||||
@@ -628,36 +617,13 @@ namespace data
|
|||||||
return l+1;
|
return l+1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RouterInfo::AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu)
|
|
||||||
{
|
|
||||||
auto addr = std::make_shared<Address>();
|
|
||||||
addr->host = boost::asio::ip::address::from_string (host);
|
|
||||||
addr->port = port;
|
|
||||||
addr->transportStyle = eTransportSSU;
|
|
||||||
addr->published = true;
|
|
||||||
addr->caps = i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer; // BC;
|
|
||||||
addr->date = 0;
|
|
||||||
addr->ssu.reset (new SSUExt ());
|
|
||||||
addr->ssu->mtu = mtu;
|
|
||||||
if (key)
|
|
||||||
memcpy (addr->i, key, 32);
|
|
||||||
else
|
|
||||||
RAND_bytes (addr->i, 32);
|
|
||||||
for (const auto& it: *m_Addresses) // don't insert same address twice
|
|
||||||
if (*it == *addr) return;
|
|
||||||
m_SupportedTransports |= addr->host.is_v6 () ? eSSUV6 : eSSUV4;
|
|
||||||
m_ReachableTransports |= addr->host.is_v6 () ? eSSUV6 : eSSUV4;
|
|
||||||
m_Addresses->push_back(std::move(addr));
|
|
||||||
}
|
|
||||||
|
|
||||||
void RouterInfo::AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,
|
void RouterInfo::AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,
|
||||||
const boost::asio::ip::address& host, int port, uint8_t caps)
|
const boost::asio::ip::address& host, int port, uint8_t caps)
|
||||||
{
|
{
|
||||||
auto addr = std::make_shared<Address>();
|
auto addr = std::make_shared<Address>();
|
||||||
addr->host = host;
|
addr->host = host;
|
||||||
addr->port = port;
|
addr->port = port;
|
||||||
addr->transportStyle = eTransportNTCP;
|
addr->transportStyle = eTransportNTCP2;
|
||||||
addr->caps = caps;
|
addr->caps = caps;
|
||||||
addr->date = 0;
|
addr->date = 0;
|
||||||
if (port) addr->published = true;
|
if (port) addr->published = true;
|
||||||
@@ -680,6 +646,7 @@ namespace data
|
|||||||
{
|
{
|
||||||
auto addr = std::make_shared<Address>();
|
auto addr = std::make_shared<Address>();
|
||||||
addr->transportStyle = eTransportSSU2;
|
addr->transportStyle = eTransportSSU2;
|
||||||
|
addr->port = 0;
|
||||||
addr->caps = caps;
|
addr->caps = caps;
|
||||||
addr->date = 0;
|
addr->date = 0;
|
||||||
addr->ssu.reset (new SSUExt ());
|
addr->ssu.reset (new SSUExt ());
|
||||||
@@ -699,7 +666,7 @@ namespace data
|
|||||||
addr->host = host;
|
addr->host = host;
|
||||||
addr->port = port;
|
addr->port = port;
|
||||||
addr->published = true;
|
addr->published = true;
|
||||||
addr->caps = 0;
|
addr->caps = i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer; // BC;
|
||||||
addr->date = 0;
|
addr->date = 0;
|
||||||
addr->ssu.reset (new SSUExt ());
|
addr->ssu.reset (new SSUExt ());
|
||||||
addr->ssu->mtu = 0;
|
addr->ssu->mtu = 0;
|
||||||
@@ -718,51 +685,6 @@ namespace data
|
|||||||
m_Addresses->push_back(std::move(addr));
|
m_Addresses->push_back(std::move(addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RouterInfo::AddIntroducer (const Introducer& introducer)
|
|
||||||
{
|
|
||||||
for (auto& addr : *m_Addresses)
|
|
||||||
{
|
|
||||||
if (addr->transportStyle == eTransportSSU &&
|
|
||||||
((addr->IsV4 () && introducer.iHost.is_v4 ()) || (addr->IsV6 () && introducer.iHost.is_v6 ())))
|
|
||||||
{
|
|
||||||
for (auto& intro: addr->ssu->introducers)
|
|
||||||
if (intro.iTag == introducer.iTag) return false; // already presented
|
|
||||||
addr->ssu->introducers.push_back (introducer);
|
|
||||||
m_ReachableTransports |= (addr->IsV4 () ? eSSUV4 : eSSUV6);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RouterInfo::RemoveIntroducer (const boost::asio::ip::udp::endpoint& e)
|
|
||||||
{
|
|
||||||
for (auto& addr: *m_Addresses)
|
|
||||||
{
|
|
||||||
if (addr->transportStyle == eTransportSSU &&
|
|
||||||
((addr->IsV4 () && e.address ().is_v4 ()) || (addr->IsV6 () && e.address ().is_v6 ())))
|
|
||||||
{
|
|
||||||
for (auto it = addr->ssu->introducers.begin (); it != addr->ssu->introducers.end (); ++it)
|
|
||||||
if (boost::asio::ip::udp::endpoint (it->iHost, it->iPort) == e)
|
|
||||||
{
|
|
||||||
addr->ssu->introducers.erase (it);
|
|
||||||
if (addr->ssu->introducers.empty ())
|
|
||||||
m_ReachableTransports &= ~(addr->IsV4 () ? eSSUV4 : eSSUV6);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RouterInfo::IsSSU (bool v4only) const
|
|
||||||
{
|
|
||||||
if (v4only)
|
|
||||||
return m_SupportedTransports & eSSUV4;
|
|
||||||
else
|
|
||||||
return m_SupportedTransports & (eSSUV4 | eSSUV6);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RouterInfo::IsNTCP2 (bool v4only) const
|
bool RouterInfo::IsNTCP2 (bool v4only) const
|
||||||
{
|
{
|
||||||
if (v4only)
|
if (v4only)
|
||||||
@@ -869,24 +791,6 @@ namespace data
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSUAddress (bool v4only) const
|
|
||||||
{
|
|
||||||
return GetAddress (
|
|
||||||
[v4only](std::shared_ptr<const RouterInfo::Address> address)->bool
|
|
||||||
{
|
|
||||||
return (address->transportStyle == eTransportSSU) && (!v4only || address->IsV4 ());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSUV6Address () const
|
|
||||||
{
|
|
||||||
return GetAddress (
|
|
||||||
[](std::shared_ptr<const RouterInfo::Address> address)->bool
|
|
||||||
{
|
|
||||||
return (address->transportStyle == eTransportSSU) && address->IsV6();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSU2V4Address () const
|
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSU2V4Address () const
|
||||||
{
|
{
|
||||||
return GetAddress (
|
return GetAddress (
|
||||||
@@ -905,6 +809,30 @@ namespace data
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSU2Address (bool v4) const
|
||||||
|
{
|
||||||
|
if (v4)
|
||||||
|
{
|
||||||
|
if (m_SupportedTransports & eSSU2V4)
|
||||||
|
return GetSSU2V4Address ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (m_SupportedTransports & eSSU2V6)
|
||||||
|
return GetSSU2V6Address ();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::shared_ptr<RouterInfo::Addresses> RouterInfo::GetAddresses () const
|
||||||
|
{
|
||||||
|
#if (BOOST_VERSION >= 105300)
|
||||||
|
return boost::atomic_load (&m_Addresses);
|
||||||
|
#else
|
||||||
|
return m_Addresses;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Filter>
|
template<typename Filter>
|
||||||
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetAddress (Filter filter) const
|
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetAddress (Filter filter) const
|
||||||
{
|
{
|
||||||
@@ -936,7 +864,8 @@ namespace data
|
|||||||
return GetAddress (
|
return GetAddress (
|
||||||
[key, isV6](std::shared_ptr<const RouterInfo::Address> address)->bool
|
[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 ()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -985,28 +914,28 @@ namespace data
|
|||||||
bool RouterInfo::IsEligibleFloodfill () const
|
bool RouterInfo::IsEligibleFloodfill () const
|
||||||
{
|
{
|
||||||
// floodfill must be reachable by ipv4, >= 0.9.38 and not DSA
|
// floodfill must be reachable by ipv4, >= 0.9.38 and not DSA
|
||||||
return IsReachableBy (eNTCP2V4 | eSSUV4) && m_Version >= NETDB_MIN_FLOODFILL_VERSION &&
|
return IsReachableBy (eNTCP2V4 | eSSU2V4) && m_Version >= NETDB_MIN_FLOODFILL_VERSION &&
|
||||||
GetIdentity ()->GetSigningKeyType () != SIGNING_KEY_TYPE_DSA_SHA1;
|
GetIdentity ()->GetSigningKeyType () != SIGNING_KEY_TYPE_DSA_SHA1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RouterInfo::IsPeerTesting (bool v4) const
|
bool RouterInfo::IsSSU2PeerTesting (bool v4) const
|
||||||
{
|
{
|
||||||
if (!(m_SupportedTransports & (v4 ? eSSUV4 : eSSUV6))) return false;
|
if (!(m_SupportedTransports & (v4 ? eSSU2V4 : eSSU2V6))) return false;
|
||||||
return (bool)GetAddress (
|
return (bool)GetAddress (
|
||||||
[v4](std::shared_ptr<const RouterInfo::Address> address)->bool
|
[v4](std::shared_ptr<const RouterInfo::Address> address)->bool
|
||||||
{
|
{
|
||||||
return (address->transportStyle == eTransportSSU) && address->IsPeerTesting () &&
|
return (address->IsSSU2 ()) && address->IsPeerTesting () &&
|
||||||
((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())) && address->IsReachableSSU ();
|
((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())) && address->IsReachableSSU ();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RouterInfo::IsIntroducer (bool v4) const
|
bool RouterInfo::IsSSU2Introducer (bool v4) const
|
||||||
{
|
{
|
||||||
if (!(m_SupportedTransports & (v4 ? eSSUV4 : eSSUV6))) return false;
|
if (!(m_SupportedTransports & (v4 ? eSSU2V4 : eSSU2V6))) return false;
|
||||||
return (bool)GetAddress (
|
return (bool)GetAddress (
|
||||||
[v4](std::shared_ptr<const RouterInfo::Address> address)->bool
|
[v4](std::shared_ptr<const RouterInfo::Address> address)->bool
|
||||||
{
|
{
|
||||||
return (address->transportStyle == eTransportSSU) && address->IsIntroducer () &&
|
return (address->IsSSU2 ()) && address->IsIntroducer () &&
|
||||||
((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())) && !address->host.is_unspecified ();
|
((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())) && !address->host.is_unspecified ();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1015,8 +944,7 @@ namespace data
|
|||||||
{
|
{
|
||||||
for (auto& addr: *m_Addresses)
|
for (auto& addr: *m_Addresses)
|
||||||
{
|
{
|
||||||
// TODO: implement SSU
|
if (!addr->published && (addr->transportStyle == eTransportNTCP2 || addr->transportStyle == eTransportSSU2))
|
||||||
if (!addr->published && (addr->transportStyle == eTransportNTCP || addr->transportStyle == eTransportSSU2))
|
|
||||||
{
|
{
|
||||||
addr->caps &= ~(eV4 | eV6);
|
addr->caps &= ~(eV4 | eV6);
|
||||||
addr->caps |= transports;
|
addr->caps |= transports;
|
||||||
@@ -1031,20 +959,22 @@ namespace data
|
|||||||
for (const auto& addr: *m_Addresses)
|
for (const auto& addr: *m_Addresses)
|
||||||
{
|
{
|
||||||
uint8_t transports = 0;
|
uint8_t transports = 0;
|
||||||
if (addr->transportStyle == eTransportNTCP)
|
switch (addr->transportStyle)
|
||||||
{
|
{
|
||||||
|
case eTransportNTCP2:
|
||||||
if (addr->IsV4 ()) transports |= eNTCP2V4;
|
if (addr->IsV4 ()) transports |= eNTCP2V4;
|
||||||
if (addr->IsV6 ())
|
if (addr->IsV6 ())
|
||||||
transports |= (i2p::util::net::IsYggdrasilAddress (addr->host) ? eNTCP2V6Mesh : eNTCP2V6);
|
transports |= (i2p::util::net::IsYggdrasilAddress (addr->host) ? eNTCP2V6Mesh : eNTCP2V6);
|
||||||
if (addr->IsPublishedNTCP2 ())
|
if (addr->IsPublishedNTCP2 ())
|
||||||
m_ReachableTransports |= transports;
|
m_ReachableTransports |= transports;
|
||||||
}
|
break;
|
||||||
else if (addr->transportStyle == eTransportSSU)
|
case eTransportSSU2:
|
||||||
{
|
if (addr->IsV4 ()) transports |= eSSU2V4;
|
||||||
if (addr->IsV4 ()) transports |= eSSUV4;
|
if (addr->IsV6 ()) transports |= eSSU2V6;
|
||||||
if (addr->IsV6 ()) transports |= eSSUV6;
|
|
||||||
if (addr->IsReachableSSU ())
|
if (addr->IsReachableSSU ())
|
||||||
m_ReachableTransports |= transports;
|
m_ReachableTransports |= transports;
|
||||||
|
break;
|
||||||
|
default: ;
|
||||||
}
|
}
|
||||||
m_SupportedTransports |= transports;
|
m_SupportedTransports |= transports;
|
||||||
}
|
}
|
||||||
@@ -1125,29 +1055,30 @@ namespace data
|
|||||||
|
|
||||||
void LocalRouterInfo::WriteToStream (std::ostream& s) const
|
void LocalRouterInfo::WriteToStream (std::ostream& s) const
|
||||||
{
|
{
|
||||||
|
auto addresses = GetAddresses ();
|
||||||
|
if (!addresses) return;
|
||||||
|
|
||||||
uint64_t ts = htobe64 (GetTimestamp ());
|
uint64_t ts = htobe64 (GetTimestamp ());
|
||||||
s.write ((const char *)&ts, sizeof (ts));
|
s.write ((const char *)&ts, sizeof (ts));
|
||||||
|
|
||||||
// addresses
|
// addresses
|
||||||
const Addresses& addresses = GetAddresses ();
|
uint8_t numAddresses = addresses->size ();
|
||||||
uint8_t numAddresses = addresses.size ();
|
|
||||||
s.write ((char *)&numAddresses, sizeof (numAddresses));
|
s.write ((char *)&numAddresses, sizeof (numAddresses));
|
||||||
for (const auto& addr_ptr : addresses)
|
for (const auto& addr_ptr : *addresses)
|
||||||
{
|
{
|
||||||
const Address& address = *addr_ptr;
|
const Address& address = *addr_ptr;
|
||||||
// calculate cost
|
// calculate cost
|
||||||
uint8_t cost = 0x7f;
|
uint8_t cost = 0x7f;
|
||||||
if (address.transportStyle == eTransportNTCP)
|
if (address.transportStyle == eTransportNTCP2)
|
||||||
cost = address.published ? COST_NTCP2_PUBLISHED : COST_NTCP2_NON_PUBLISHED;
|
cost = address.published ? COST_NTCP2_PUBLISHED : COST_NTCP2_NON_PUBLISHED;
|
||||||
else if (address.transportStyle == eTransportSSU)
|
|
||||||
cost = address.published ? COST_SSU_DIRECT : COST_SSU_THROUGH_INTRODUCERS;
|
|
||||||
else if (address.transportStyle == eTransportSSU2)
|
else if (address.transportStyle == eTransportSSU2)
|
||||||
cost = address.published ? COST_SSU2_DIRECT : COST_SSU2_NON_PUBLISHED;
|
cost = address.published ? COST_SSU2_DIRECT : COST_SSU2_NON_PUBLISHED;
|
||||||
|
else
|
||||||
|
continue; // skip unknown address
|
||||||
s.write ((const char *)&cost, sizeof (cost));
|
s.write ((const char *)&cost, sizeof (cost));
|
||||||
s.write ((const char *)&address.date, sizeof (address.date));
|
s.write ((const char *)&address.date, sizeof (address.date));
|
||||||
std::stringstream properties;
|
std::stringstream properties;
|
||||||
bool isPublished = false;
|
bool isPublished = false;
|
||||||
if (address.transportStyle == eTransportNTCP)
|
if (address.transportStyle == eTransportNTCP2)
|
||||||
{
|
{
|
||||||
if (address.IsNTCP2 ())
|
if (address.IsNTCP2 ())
|
||||||
{
|
{
|
||||||
@@ -1169,43 +1100,6 @@ namespace data
|
|||||||
else
|
else
|
||||||
continue; // don't write NTCP address
|
continue; // don't write NTCP address
|
||||||
}
|
}
|
||||||
else if (address.transportStyle == eTransportSSU)
|
|
||||||
{
|
|
||||||
WriteString ("SSU", s);
|
|
||||||
// caps
|
|
||||||
WriteString ("caps", properties);
|
|
||||||
properties << '=';
|
|
||||||
std::string caps;
|
|
||||||
if (address.IsPeerTesting ()) caps += CAPS_FLAG_SSU_TESTING;
|
|
||||||
if (address.host.is_v4 ())
|
|
||||||
{
|
|
||||||
if (address.published)
|
|
||||||
{
|
|
||||||
isPublished = true;
|
|
||||||
if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
caps += CAPS_FLAG_V4;
|
|
||||||
}
|
|
||||||
else if (address.host.is_v6 ())
|
|
||||||
{
|
|
||||||
if (address.published)
|
|
||||||
{
|
|
||||||
isPublished = true;
|
|
||||||
if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
caps += CAPS_FLAG_V6;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (address.IsV4 ()) caps += CAPS_FLAG_V4;
|
|
||||||
if (address.IsV6 ()) caps += CAPS_FLAG_V6;
|
|
||||||
if (caps.empty ()) caps += CAPS_FLAG_V4;
|
|
||||||
}
|
|
||||||
WriteString (caps, properties);
|
|
||||||
properties << ';';
|
|
||||||
}
|
|
||||||
else if (address.transportStyle == eTransportSSU2)
|
else if (address.transportStyle == eTransportSSU2)
|
||||||
{
|
{
|
||||||
WriteString ("SSU2", s);
|
WriteString ("SSU2", s);
|
||||||
@@ -1214,7 +1108,8 @@ namespace data
|
|||||||
if (address.published)
|
if (address.published)
|
||||||
{
|
{
|
||||||
isPublished = true;
|
isPublished = true;
|
||||||
if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER;
|
if (address.IsPeerTesting ()) caps += CAPS_FLAG_SSU2_TESTING;
|
||||||
|
if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU2_INTRODUCER;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1233,7 +1128,7 @@ namespace data
|
|||||||
else
|
else
|
||||||
WriteString ("", s);
|
WriteString ("", s);
|
||||||
|
|
||||||
if (isPublished)
|
if (isPublished && !address.host.is_unspecified ())
|
||||||
{
|
{
|
||||||
WriteString ("host", properties);
|
WriteString ("host", properties);
|
||||||
properties << '=';
|
properties << '=';
|
||||||
@@ -1247,7 +1142,7 @@ namespace data
|
|||||||
size_t len = address.IsSSU2 () ? 32 : 16;
|
size_t len = address.IsSSU2 () ? 32 : 16;
|
||||||
WriteString (address.i.ToBase64 (len), properties); properties << ';';
|
WriteString (address.i.ToBase64 (len), properties); properties << ';';
|
||||||
}
|
}
|
||||||
if (address.transportStyle == eTransportSSU || address.IsSSU2 ())
|
if (address.transportStyle == eTransportSSU2)
|
||||||
{
|
{
|
||||||
// write introducers if any
|
// write introducers if any
|
||||||
if (address.ssu && !address.ssu->introducers.empty())
|
if (address.ssu && !address.ssu->introducers.empty())
|
||||||
@@ -1264,45 +1159,18 @@ namespace data
|
|||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
if (address.transportStyle == eTransportSSU)
|
|
||||||
{
|
|
||||||
i = 0;
|
i = 0;
|
||||||
for (const auto& introducer: address.ssu->introducers)
|
for (const auto& introducer: address.ssu->introducers)
|
||||||
{
|
{
|
||||||
WriteString ("ihost" + boost::lexical_cast<std::string>(i), properties);
|
|
||||||
properties << '=';
|
|
||||||
WriteString (introducer.iHost.to_string (), properties);
|
|
||||||
properties << ';';
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i = 0;
|
|
||||||
for (const auto& introducer: address.ssu->introducers)
|
|
||||||
{
|
|
||||||
if (address.IsSSU2 ())
|
|
||||||
WriteString ("ih" + boost::lexical_cast<std::string>(i), properties);
|
WriteString ("ih" + boost::lexical_cast<std::string>(i), properties);
|
||||||
else
|
|
||||||
WriteString ("ikey" + boost::lexical_cast<std::string>(i), properties);
|
|
||||||
properties << '=';
|
properties << '=';
|
||||||
char value[64];
|
char value[64];
|
||||||
size_t l = ByteStreamToBase64 (introducer.iKey, 32, value, 64);
|
size_t l = ByteStreamToBase64 (introducer.iH, 32, value, 64);
|
||||||
value[l] = 0;
|
value[l] = 0;
|
||||||
WriteString (value, properties);
|
WriteString (value, properties);
|
||||||
properties << ';';
|
properties << ';';
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
if (address.transportStyle == eTransportSSU)
|
|
||||||
{
|
|
||||||
i = 0;
|
|
||||||
for (const auto& introducer: address.ssu->introducers)
|
|
||||||
{
|
|
||||||
WriteString ("iport" + boost::lexical_cast<std::string>(i), properties);
|
|
||||||
properties << '=';
|
|
||||||
WriteString (boost::lexical_cast<std::string>(introducer.iPort), properties);
|
|
||||||
properties << ';';
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i = 0;
|
i = 0;
|
||||||
for (const auto& introducer: address.ssu->introducers)
|
for (const auto& introducer: address.ssu->introducers)
|
||||||
{
|
{
|
||||||
@@ -1314,18 +1182,8 @@ namespace data
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (address.transportStyle == eTransportSSU)
|
|
||||||
{
|
if (address.transportStyle == eTransportSSU2)
|
||||||
// write intro key
|
|
||||||
WriteString ("key", properties);
|
|
||||||
properties << '=';
|
|
||||||
char value[64];
|
|
||||||
size_t l = ByteStreamToBase64 (address.i, 32, value, 64);
|
|
||||||
value[l] = 0;
|
|
||||||
WriteString (value, properties);
|
|
||||||
properties << ';';
|
|
||||||
}
|
|
||||||
if (address.transportStyle == eTransportSSU || address.IsSSU2 ())
|
|
||||||
{
|
{
|
||||||
// write mtu
|
// write mtu
|
||||||
if (address.ssu && address.ssu->mtu)
|
if (address.ssu && address.ssu->mtu)
|
||||||
@@ -1336,7 +1194,7 @@ namespace data
|
|||||||
properties << ';';
|
properties << ';';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isPublished || (address.ssu && !address.IsSSU2 ()))
|
if (isPublished && address.port)
|
||||||
{
|
{
|
||||||
WriteString ("port", properties);
|
WriteString ("port", properties);
|
||||||
properties << '=';
|
properties << '=';
|
||||||
@@ -1404,5 +1262,44 @@ namespace data
|
|||||||
{
|
{
|
||||||
return std::make_shared<Buffer> ();
|
return std::make_shared<Buffer> ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LocalRouterInfo::AddSSU2Introducer (const Introducer& introducer, bool v4)
|
||||||
|
{
|
||||||
|
auto addresses = GetAddresses ();
|
||||||
|
if (!addresses) return false;
|
||||||
|
for (auto& addr : *addresses)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
auto addresses = GetAddresses ();
|
||||||
|
if (!addresses) return false;
|
||||||
|
for (auto& addr: *addresses)
|
||||||
|
{
|
||||||
|
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->iH)
|
||||||
|
{
|
||||||
|
addr->ssu->introducers.erase (it);
|
||||||
|
if (addr->ssu->introducers.empty ())
|
||||||
|
SetReachableTransports (GetReachableTransports () & ~(addr->IsV4 () ? eSSU2V4 : eSSU2V6));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,14 +47,12 @@ namespace data
|
|||||||
|
|
||||||
const char CAPS_FLAG_V4 = '4';
|
const char CAPS_FLAG_V4 = '4';
|
||||||
const char CAPS_FLAG_V6 = '6';
|
const char CAPS_FLAG_V6 = '6';
|
||||||
const char CAPS_FLAG_SSU_TESTING = 'B';
|
const char CAPS_FLAG_SSU2_TESTING = 'B';
|
||||||
const char CAPS_FLAG_SSU_INTRODUCER = 'C';
|
const char CAPS_FLAG_SSU2_INTRODUCER = 'C';
|
||||||
|
|
||||||
const uint8_t COST_NTCP2_PUBLISHED = 3;
|
const uint8_t COST_NTCP2_PUBLISHED = 3;
|
||||||
const uint8_t COST_NTCP2_NON_PUBLISHED = 14;
|
const uint8_t COST_NTCP2_NON_PUBLISHED = 14;
|
||||||
const uint8_t COST_SSU2_DIRECT = 8;
|
const uint8_t COST_SSU2_DIRECT = 8;
|
||||||
const uint8_t COST_SSU_DIRECT = 9;
|
|
||||||
const uint8_t COST_SSU_THROUGH_INTRODUCERS = 11;
|
|
||||||
const uint8_t COST_SSU2_NON_PUBLISHED = 15;
|
const uint8_t COST_SSU2_NON_PUBLISHED = 15;
|
||||||
|
|
||||||
const size_t MAX_RI_BUFFER_SIZE = 3072; // if RouterInfo exceeds 3K we consider it as malformed, might extend later
|
const size_t MAX_RI_BUFFER_SIZE = 3072; // if RouterInfo exceeds 3K we consider it as malformed, might extend later
|
||||||
@@ -66,11 +64,9 @@ namespace data
|
|||||||
{
|
{
|
||||||
eNTCP2V4 = 0x01,
|
eNTCP2V4 = 0x01,
|
||||||
eNTCP2V6 = 0x02,
|
eNTCP2V6 = 0x02,
|
||||||
eSSUV4 = 0x04,
|
eSSU2V4 = 0x04,
|
||||||
eSSUV6 = 0x08,
|
eSSU2V6 = 0x08,
|
||||||
eNTCP2V6Mesh = 0x10,
|
eNTCP2V6Mesh = 0x10,
|
||||||
eSSU2V4 = 0x20,
|
|
||||||
eSSU2V6 = 0x40,
|
|
||||||
eAllTransports = 0xFF
|
eAllTransports = 0xFF
|
||||||
};
|
};
|
||||||
typedef uint8_t CompatibleTransports;
|
typedef uint8_t CompatibleTransports;
|
||||||
@@ -96,20 +92,17 @@ namespace data
|
|||||||
enum TransportStyle
|
enum TransportStyle
|
||||||
{
|
{
|
||||||
eTransportUnknown = 0,
|
eTransportUnknown = 0,
|
||||||
eTransportNTCP,
|
eTransportNTCP2,
|
||||||
eTransportSSU,
|
|
||||||
eTransportSSU2
|
eTransportSSU2
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Tag<32> IntroKey; // should be castable to MacKey and AESKey
|
|
||||||
struct Introducer
|
struct Introducer
|
||||||
{
|
{
|
||||||
Introducer (): iPort (0), iExp (0) {};
|
Introducer (): iTag (0), iExp (0), isH (false) {};
|
||||||
boost::asio::ip::address iHost;
|
IdentHash iH;
|
||||||
int iPort;
|
|
||||||
IntroKey iKey; // or ih for SSU2
|
|
||||||
uint32_t iTag;
|
uint32_t iTag;
|
||||||
uint32_t iExp;
|
uint32_t iExp;
|
||||||
|
bool isH; // TODO: remove later
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SSUExt
|
struct SSUExt
|
||||||
@@ -146,7 +139,7 @@ namespace data
|
|||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsNTCP2 () const { return transportStyle == eTransportNTCP; };
|
bool IsNTCP2 () const { return transportStyle == eTransportNTCP2; };
|
||||||
bool IsSSU2 () const { return transportStyle == eTransportSSU2; };
|
bool IsSSU2 () const { return transportStyle == eTransportSSU2; };
|
||||||
bool IsPublishedNTCP2 () const { return IsNTCP2 () && published; };
|
bool IsPublishedNTCP2 () const { return IsNTCP2 () && published; };
|
||||||
bool IsReachableSSU () const { return (bool)ssu && (published || UsesIntroducer ()); };
|
bool IsReachableSSU () const { return (bool)ssu && (published || UsesIntroducer ()); };
|
||||||
@@ -183,38 +176,32 @@ namespace data
|
|||||||
int GetVersion () const { return m_Version; };
|
int GetVersion () const { return m_Version; };
|
||||||
virtual void SetProperty (const std::string& key, const std::string& value) {};
|
virtual void SetProperty (const std::string& key, const std::string& value) {};
|
||||||
virtual void ClearProperties () {};
|
virtual void ClearProperties () {};
|
||||||
Addresses& GetAddresses () { return *m_Addresses; }; // should be called for local RI only, otherwise must return shared_ptr
|
boost::shared_ptr<Addresses> GetAddresses () const; // should be called for local RI only, otherwise must return shared_ptr
|
||||||
std::shared_ptr<const Address> GetNTCP2AddressWithStaticKey (const uint8_t * key) const;
|
std::shared_ptr<const Address> GetNTCP2AddressWithStaticKey (const uint8_t * key) const;
|
||||||
std::shared_ptr<const Address> GetSSU2AddressWithStaticKey (const uint8_t * key, bool isV6) const;
|
std::shared_ptr<const Address> GetSSU2AddressWithStaticKey (const uint8_t * key, bool isV6) const;
|
||||||
std::shared_ptr<const Address> GetPublishedNTCP2V4Address () const;
|
std::shared_ptr<const Address> GetPublishedNTCP2V4Address () const;
|
||||||
std::shared_ptr<const Address> GetPublishedNTCP2V6Address () const;
|
std::shared_ptr<const Address> GetPublishedNTCP2V6Address () const;
|
||||||
std::shared_ptr<const Address> GetSSUAddress (bool v4only = true) const;
|
|
||||||
std::shared_ptr<const Address> GetSSUV6Address () const;
|
|
||||||
std::shared_ptr<const Address> GetYggdrasilAddress () const;
|
std::shared_ptr<const Address> GetYggdrasilAddress () const;
|
||||||
std::shared_ptr<const Address> GetSSU2V4Address () const;
|
std::shared_ptr<const Address> GetSSU2V4Address () const;
|
||||||
std::shared_ptr<const Address> GetSSU2V6Address () const;
|
std::shared_ptr<const Address> GetSSU2V6Address () const;
|
||||||
|
std::shared_ptr<const Address> GetSSU2Address (bool v4) const;
|
||||||
|
|
||||||
void AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu = 0);
|
|
||||||
void AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,
|
void AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,
|
||||||
const boost::asio::ip::address& host = boost::asio::ip::address(), int port = 0, uint8_t caps = 0);
|
const boost::asio::ip::address& host = boost::asio::ip::address(), int port = 0, uint8_t caps = 0);
|
||||||
void AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey, uint8_t caps = 0); // non published
|
void AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey, uint8_t caps = 0); // non published
|
||||||
void AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey,
|
void AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey,
|
||||||
const boost::asio::ip::address& host, int port); // published
|
const boost::asio::ip::address& host, int port); // published
|
||||||
bool AddIntroducer (const Introducer& introducer);
|
|
||||||
bool RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
|
|
||||||
void SetUnreachableAddressesTransportCaps (uint8_t transports); // bitmask of AddressCaps
|
void SetUnreachableAddressesTransportCaps (uint8_t transports); // bitmask of AddressCaps
|
||||||
void UpdateSupportedTransports ();
|
void UpdateSupportedTransports ();
|
||||||
bool IsFloodfill () const { return m_Caps & Caps::eFloodfill; };
|
bool IsFloodfill () const { return m_Caps & Caps::eFloodfill; };
|
||||||
bool IsReachable () const { return m_Caps & Caps::eReachable; };
|
bool IsReachable () const { return m_Caps & Caps::eReachable; };
|
||||||
bool IsECIES () const { return m_RouterIdentity->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; };
|
bool IsECIES () const { return m_RouterIdentity->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; };
|
||||||
bool IsSSU (bool v4only = true) const;
|
|
||||||
bool IsSSUV6 () const { return m_SupportedTransports & eSSUV6; };
|
|
||||||
bool IsNTCP2 (bool v4only = true) const;
|
bool IsNTCP2 (bool v4only = true) const;
|
||||||
bool IsNTCP2V6 () const { return m_SupportedTransports & eNTCP2V6; };
|
bool IsNTCP2V6 () const { return m_SupportedTransports & eNTCP2V6; };
|
||||||
bool IsSSU2V4 () const { return m_SupportedTransports & eSSU2V4; };
|
bool IsSSU2V4 () const { return m_SupportedTransports & eSSU2V4; };
|
||||||
bool IsSSU2V6 () const { return m_SupportedTransports & eSSU2V6; };
|
bool IsSSU2V6 () const { return m_SupportedTransports & eSSU2V6; };
|
||||||
bool IsV6 () const { return m_SupportedTransports & (eSSUV6 | eNTCP2V6 | eSSU2V6); };
|
bool IsV6 () const { return m_SupportedTransports & (eNTCP2V6 | eSSU2V6); };
|
||||||
bool IsV4 () const { return m_SupportedTransports & (eSSUV4 | eNTCP2V4 | eSSU2V4); };
|
bool IsV4 () const { return m_SupportedTransports & (eNTCP2V4 | eSSU2V4); };
|
||||||
bool IsMesh () const { return m_SupportedTransports & eNTCP2V6Mesh; };
|
bool IsMesh () const { return m_SupportedTransports & eNTCP2V6Mesh; };
|
||||||
void EnableV6 ();
|
void EnableV6 ();
|
||||||
void DisableV6 ();
|
void DisableV6 ();
|
||||||
@@ -231,8 +218,8 @@ namespace data
|
|||||||
bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; };
|
bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; };
|
||||||
bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; };
|
bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; };
|
||||||
bool IsEligibleFloodfill () const;
|
bool IsEligibleFloodfill () const;
|
||||||
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; };
|
uint8_t GetCaps () const { return m_Caps; };
|
||||||
void SetCaps (uint8_t caps) { m_Caps = caps; };
|
void SetCaps (uint8_t caps) { m_Caps = caps; };
|
||||||
@@ -271,7 +258,8 @@ namespace data
|
|||||||
void UpdateBuffer (const uint8_t * buf, size_t len);
|
void UpdateBuffer (const uint8_t * buf, size_t len);
|
||||||
void SetBufferLen (size_t len) { m_BufferLen = len; };
|
void SetBufferLen (size_t len) { m_BufferLen = len; };
|
||||||
void RefreshTimestamp ();
|
void RefreshTimestamp ();
|
||||||
const Addresses& GetAddresses () const { return *m_Addresses; };
|
CompatibleTransports GetReachableTransports () const { return m_ReachableTransports; };
|
||||||
|
void SetReachableTransports (CompatibleTransports transports) { m_ReachableTransports = transports; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@@ -306,6 +294,7 @@ namespace data
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
LocalRouterInfo () = default;
|
LocalRouterInfo () = default;
|
||||||
|
LocalRouterInfo (const std::string& fullPath): RouterInfo (fullPath) {};
|
||||||
void CreateBuffer (const PrivateKeys& privateKeys);
|
void CreateBuffer (const PrivateKeys& privateKeys);
|
||||||
void UpdateCaps (uint8_t caps);
|
void UpdateCaps (uint8_t caps);
|
||||||
|
|
||||||
@@ -314,6 +303,9 @@ namespace data
|
|||||||
std::string GetProperty (const std::string& key) const;
|
std::string GetProperty (const std::string& key) const;
|
||||||
void ClearProperties () override { m_Properties.clear (); };
|
void ClearProperties () override { m_Properties.clear (); };
|
||||||
|
|
||||||
|
bool AddSSU2Introducer (const Introducer& introducer, bool v4);
|
||||||
|
bool RemoveSSU2Introducer (const IdentHash& h, bool v4);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void WriteToStream (std::ostream& s) const;
|
void WriteToStream (std::ostream& s) const;
|
||||||
|
|||||||
996
libi2pd/SSU.cpp
996
libi2pd/SSU.cpp
@@ -1,996 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
|
||||||
*
|
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
|
||||||
*
|
|
||||||
* See full license text in LICENSE file at top of project tree
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include "Log.h"
|
|
||||||
#include "Timestamp.h"
|
|
||||||
#include "RouterContext.h"
|
|
||||||
#include "NetDb.hpp"
|
|
||||||
#include "Config.h"
|
|
||||||
#include "util.h"
|
|
||||||
#include "SSU.h"
|
|
||||||
|
|
||||||
#if defined(__linux__) && !defined(_NETINET_IN_H)
|
|
||||||
#include <linux/in6.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <boost/winapi/error_codes.hpp>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace i2p
|
|
||||||
{
|
|
||||||
namespace transport
|
|
||||||
{
|
|
||||||
SSUServer::SSUServer (int port):
|
|
||||||
m_IsRunning(false), m_Thread (nullptr),
|
|
||||||
m_ReceiversThread (nullptr), m_ReceiversThreadV6 (nullptr), m_Work (m_Service),
|
|
||||||
m_ReceiversWork (m_ReceiversService), m_ReceiversWorkV6 (m_ReceiversServiceV6),
|
|
||||||
m_Endpoint (boost::asio::ip::udp::v4 (), port), m_EndpointV6 (boost::asio::ip::udp::v6 (), port),
|
|
||||||
m_Socket (m_ReceiversService), m_SocketV6 (m_ReceiversServiceV6),
|
|
||||||
m_IntroducersUpdateTimer (m_Service), m_IntroducersUpdateTimerV6 (m_Service),
|
|
||||||
m_PeerTestsCleanupTimer (m_Service), m_TerminationTimer (m_Service), m_TerminationTimerV6 (m_Service),
|
|
||||||
m_IsSyncClockFromPeers (true)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
SSUServer::~SSUServer ()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::OpenSocket ()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
m_Socket.open (boost::asio::ip::udp::v4());
|
|
||||||
m_Socket.set_option (boost::asio::socket_base::receive_buffer_size (SSU_SOCKET_RECEIVE_BUFFER_SIZE));
|
|
||||||
m_Socket.set_option (boost::asio::socket_base::send_buffer_size (SSU_SOCKET_SEND_BUFFER_SIZE));
|
|
||||||
m_Socket.bind (m_Endpoint);
|
|
||||||
LogPrint (eLogInfo, "SSU: Start listening v4 port ", m_Endpoint.port());
|
|
||||||
}
|
|
||||||
catch ( std::exception & ex )
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "SSU: Failed to bind to v4 port ", m_Endpoint.port(), ": ", ex.what());
|
|
||||||
ThrowFatal ("Unable to start IPv4 SSU transport at port ", m_Endpoint.port(), ": ", ex.what ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::OpenSocketV6 ()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
m_SocketV6.open (boost::asio::ip::udp::v6());
|
|
||||||
m_SocketV6.set_option (boost::asio::ip::v6_only (true));
|
|
||||||
m_SocketV6.set_option (boost::asio::socket_base::receive_buffer_size (SSU_SOCKET_RECEIVE_BUFFER_SIZE));
|
|
||||||
m_SocketV6.set_option (boost::asio::socket_base::send_buffer_size (SSU_SOCKET_SEND_BUFFER_SIZE));
|
|
||||||
#if defined(__linux__) && !defined(_NETINET_IN_H)
|
|
||||||
if (m_EndpointV6.address() == boost::asio::ip::address().from_string("::")) // only if not binded to address
|
|
||||||
{
|
|
||||||
// Set preference to use public IPv6 address -- tested on linux, not works on windows, and not tested on others
|
|
||||||
#if (BOOST_VERSION >= 105500)
|
|
||||||
typedef boost::asio::detail::socket_option::integer<BOOST_ASIO_OS_DEF(IPPROTO_IPV6), IPV6_ADDR_PREFERENCES> ipv6PreferAddr;
|
|
||||||
#else
|
|
||||||
typedef boost::asio::detail::socket_option::integer<IPPROTO_IPV6, IPV6_ADDR_PREFERENCES> ipv6PreferAddr;
|
|
||||||
#endif
|
|
||||||
m_SocketV6.set_option (ipv6PreferAddr(IPV6_PREFER_SRC_PUBLIC | IPV6_PREFER_SRC_HOME | IPV6_PREFER_SRC_NONCGA));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
m_SocketV6.bind (m_EndpointV6);
|
|
||||||
LogPrint (eLogInfo, "SSU: Start listening v6 port ", m_EndpointV6.port());
|
|
||||||
}
|
|
||||||
catch ( std::exception & ex )
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "SSU: Failed to bind to v6 port ", m_EndpointV6.port(), ": ", ex.what());
|
|
||||||
ThrowFatal ("Unable to start IPv6 SSU transport at port ", m_Endpoint.port(), ": ", ex.what ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::Start ()
|
|
||||||
{
|
|
||||||
i2p::config::GetOption("nettime.frompeers", m_IsSyncClockFromPeers);
|
|
||||||
m_IsRunning = true;
|
|
||||||
m_Thread = new std::thread (std::bind (&SSUServer::Run, this));
|
|
||||||
if (context.SupportsV4 ())
|
|
||||||
{
|
|
||||||
OpenSocket ();
|
|
||||||
m_ReceiversThread = new std::thread (std::bind (&SSUServer::RunReceivers, this));
|
|
||||||
m_ReceiversService.post (std::bind (&SSUServer::Receive, this));
|
|
||||||
ScheduleTermination ();
|
|
||||||
ScheduleIntroducersUpdateTimer (); // wait for 30 seconds and decide if we need introducers
|
|
||||||
}
|
|
||||||
if (context.SupportsV6 ())
|
|
||||||
{
|
|
||||||
OpenSocketV6 ();
|
|
||||||
m_ReceiversThreadV6 = new std::thread (std::bind (&SSUServer::RunReceiversV6, this));
|
|
||||||
m_ReceiversServiceV6.post (std::bind (&SSUServer::ReceiveV6, this));
|
|
||||||
ScheduleTerminationV6 ();
|
|
||||||
ScheduleIntroducersUpdateTimerV6 (); // wait for 30 seconds and decide if we need introducers
|
|
||||||
}
|
|
||||||
SchedulePeerTestsCleanupTimer ();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::Stop ()
|
|
||||||
{
|
|
||||||
DeleteAllSessions ();
|
|
||||||
m_IsRunning = false;
|
|
||||||
m_TerminationTimer.cancel ();
|
|
||||||
m_TerminationTimerV6.cancel ();
|
|
||||||
m_IntroducersUpdateTimer.cancel ();
|
|
||||||
m_IntroducersUpdateTimerV6.cancel ();
|
|
||||||
m_Service.stop ();
|
|
||||||
m_Socket.close ();
|
|
||||||
m_SocketV6.close ();
|
|
||||||
m_ReceiversService.stop ();
|
|
||||||
m_ReceiversServiceV6.stop ();
|
|
||||||
if (m_ReceiversThread)
|
|
||||||
{
|
|
||||||
m_ReceiversThread->join ();
|
|
||||||
delete m_ReceiversThread;
|
|
||||||
m_ReceiversThread = nullptr;
|
|
||||||
}
|
|
||||||
if (m_ReceiversThreadV6)
|
|
||||||
{
|
|
||||||
m_ReceiversThreadV6->join ();
|
|
||||||
delete m_ReceiversThreadV6;
|
|
||||||
m_ReceiversThreadV6 = nullptr;
|
|
||||||
}
|
|
||||||
if (m_Thread)
|
|
||||||
{
|
|
||||||
m_Thread->join ();
|
|
||||||
delete m_Thread;
|
|
||||||
m_Thread = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::Run ()
|
|
||||||
{
|
|
||||||
i2p::util::SetThreadName("SSU");
|
|
||||||
|
|
||||||
while (m_IsRunning)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
m_Service.run ();
|
|
||||||
}
|
|
||||||
catch (std::exception& ex)
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "SSU: Server runtime exception: ", ex.what ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::RunReceivers ()
|
|
||||||
{
|
|
||||||
i2p::util::SetThreadName("SSUv4");
|
|
||||||
|
|
||||||
while (m_IsRunning)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
m_ReceiversService.run ();
|
|
||||||
}
|
|
||||||
catch (std::exception& ex)
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "SSU: Receivers runtime exception: ", ex.what ());
|
|
||||||
if (m_IsRunning)
|
|
||||||
{
|
|
||||||
// restart socket
|
|
||||||
m_Socket.close ();
|
|
||||||
OpenSocket ();
|
|
||||||
Receive ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::RunReceiversV6 ()
|
|
||||||
{
|
|
||||||
i2p::util::SetThreadName("SSUv6");
|
|
||||||
|
|
||||||
while (m_IsRunning)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
m_ReceiversServiceV6.run ();
|
|
||||||
}
|
|
||||||
catch (std::exception& ex)
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "SSU: v6 receivers runtime exception: ", ex.what ());
|
|
||||||
if (m_IsRunning)
|
|
||||||
{
|
|
||||||
m_SocketV6.close ();
|
|
||||||
OpenSocketV6 ();
|
|
||||||
ReceiveV6 ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::SetLocalAddress (const boost::asio::ip::address& localAddress)
|
|
||||||
{
|
|
||||||
if (localAddress.is_v6 ())
|
|
||||||
m_EndpointV6.address (localAddress);
|
|
||||||
else if (localAddress.is_v4 ())
|
|
||||||
m_Endpoint.address (localAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::AddRelay (uint32_t tag, std::shared_ptr<SSUSession> relay)
|
|
||||||
{
|
|
||||||
m_Relays.emplace (tag, relay);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::RemoveRelay (uint32_t tag)
|
|
||||||
{
|
|
||||||
m_Relays.erase (tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<SSUSession> SSUServer::FindRelaySession (uint32_t tag)
|
|
||||||
{
|
|
||||||
auto it = m_Relays.find (tag);
|
|
||||||
if (it != m_Relays.end ())
|
|
||||||
{
|
|
||||||
if (it->second->GetState () == eSessionStateEstablished)
|
|
||||||
return it->second;
|
|
||||||
else
|
|
||||||
m_Relays.erase (it);
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to)
|
|
||||||
{
|
|
||||||
boost::system::error_code ec;
|
|
||||||
if (to.protocol () == boost::asio::ip::udp::v4())
|
|
||||||
m_Socket.send_to (boost::asio::buffer (buf, len), to, 0, ec);
|
|
||||||
else
|
|
||||||
m_SocketV6.send_to (boost::asio::buffer (buf, len), to, 0, ec);
|
|
||||||
|
|
||||||
if (ec)
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "SSU: Send exception: ", ec.message (), " while trying to send data to ", to.address (), ":", to.port (), " (length: ", len, ")");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::Receive ()
|
|
||||||
{
|
|
||||||
SSUPacket * packet = m_PacketsPool.AcquireMt ();
|
|
||||||
m_Socket.async_receive_from (boost::asio::buffer (packet->buf, SSU_MTU_V4), packet->from,
|
|
||||||
std::bind (&SSUServer::HandleReceivedFrom, this, std::placeholders::_1, std::placeholders::_2, packet));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::ReceiveV6 ()
|
|
||||||
{
|
|
||||||
SSUPacket * packet = m_PacketsPool.AcquireMt ();
|
|
||||||
m_SocketV6.async_receive_from (boost::asio::buffer (packet->buf, SSU_MTU_V6), packet->from,
|
|
||||||
std::bind (&SSUServer::HandleReceivedFromV6, this, std::placeholders::_1, std::placeholders::_2, packet));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet)
|
|
||||||
{
|
|
||||||
if (!ecode
|
|
||||||
|| ecode == boost::asio::error::connection_refused
|
|
||||||
|| ecode == boost::asio::error::connection_reset
|
|
||||||
|| ecode == boost::asio::error::network_unreachable
|
|
||||||
|| ecode == boost::asio::error::host_unreachable
|
|
||||||
#ifdef _WIN32 // windows can throw WinAPI error, which is not handled by ASIO
|
|
||||||
|| ecode.value() == boost::winapi::ERROR_CONNECTION_REFUSED_
|
|
||||||
|| ecode.value() == boost::winapi::ERROR_NETWORK_UNREACHABLE_
|
|
||||||
|| ecode.value() == boost::winapi::ERROR_HOST_UNREACHABLE_
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
// just try continue reading when received ICMP response otherwise socket can crash,
|
|
||||||
// but better to find out which host were sent it and mark that router as unreachable
|
|
||||||
{
|
|
||||||
packet->len = bytes_transferred;
|
|
||||||
std::vector<SSUPacket *> packets;
|
|
||||||
packets.push_back (packet);
|
|
||||||
|
|
||||||
boost::system::error_code ec;
|
|
||||||
size_t moreBytes = m_Socket.available(ec);
|
|
||||||
if (!ec)
|
|
||||||
{
|
|
||||||
while (moreBytes && packets.size () < 25)
|
|
||||||
{
|
|
||||||
packet = m_PacketsPool.AcquireMt ();
|
|
||||||
packet->len = m_Socket.receive_from (boost::asio::buffer (packet->buf, SSU_MTU_V4), packet->from, 0, ec);
|
|
||||||
if (!ec)
|
|
||||||
{
|
|
||||||
packets.push_back (packet);
|
|
||||||
moreBytes = m_Socket.available(ec);
|
|
||||||
if (ec) break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "SSU: receive_from error: code ", ec.value(), ": ", ec.message ());
|
|
||||||
m_PacketsPool.ReleaseMt (packet);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Service.post (std::bind (&SSUServer::HandleReceivedPackets, this, packets, &m_Sessions));
|
|
||||||
Receive ();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_PacketsPool.ReleaseMt (packet);
|
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "SSU: Receive error: code ", ecode.value(), ": ", ecode.message ());
|
|
||||||
m_Socket.close ();
|
|
||||||
OpenSocket ();
|
|
||||||
Receive ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::HandleReceivedFromV6 (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet)
|
|
||||||
{
|
|
||||||
if (!ecode
|
|
||||||
|| ecode == boost::asio::error::connection_refused
|
|
||||||
|| ecode == boost::asio::error::connection_reset
|
|
||||||
|| ecode == boost::asio::error::network_unreachable
|
|
||||||
|| ecode == boost::asio::error::host_unreachable
|
|
||||||
#ifdef _WIN32 // windows can throw WinAPI error, which is not handled by ASIO
|
|
||||||
|| ecode.value() == boost::winapi::ERROR_CONNECTION_REFUSED_
|
|
||||||
|| ecode.value() == boost::winapi::ERROR_NETWORK_UNREACHABLE_
|
|
||||||
|| ecode.value() == boost::winapi::ERROR_HOST_UNREACHABLE_
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
// just try continue reading when received ICMP response otherwise socket can crash,
|
|
||||||
// but better to find out which host were sent it and mark that router as unreachable
|
|
||||||
{
|
|
||||||
packet->len = bytes_transferred;
|
|
||||||
std::vector<SSUPacket *> packets;
|
|
||||||
packets.push_back (packet);
|
|
||||||
|
|
||||||
boost::system::error_code ec;
|
|
||||||
size_t moreBytes = m_SocketV6.available (ec);
|
|
||||||
if (!ec)
|
|
||||||
{
|
|
||||||
while (moreBytes && packets.size () < 25)
|
|
||||||
{
|
|
||||||
packet = m_PacketsPool.AcquireMt ();
|
|
||||||
packet->len = m_SocketV6.receive_from (boost::asio::buffer (packet->buf, SSU_MTU_V6), packet->from, 0, ec);
|
|
||||||
if (!ec)
|
|
||||||
{
|
|
||||||
packets.push_back (packet);
|
|
||||||
moreBytes = m_SocketV6.available(ec);
|
|
||||||
if (ec) break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "SSU: v6 receive_from error: code ", ec.value(), ": ", ec.message ());
|
|
||||||
m_PacketsPool.ReleaseMt (packet);;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Service.post (std::bind (&SSUServer::HandleReceivedPackets, this, packets, &m_SessionsV6));
|
|
||||||
ReceiveV6 ();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_PacketsPool.ReleaseMt (packet);
|
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "SSU: v6 receive error: code ", ecode.value(), ": ", ecode.message ());
|
|
||||||
m_SocketV6.close ();
|
|
||||||
OpenSocketV6 ();
|
|
||||||
ReceiveV6 ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::HandleReceivedPackets (std::vector<SSUPacket *> packets,
|
|
||||||
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > * sessions)
|
|
||||||
{
|
|
||||||
if (!m_IsRunning) return;
|
|
||||||
std::shared_ptr<SSUSession> session;
|
|
||||||
for (auto& packet: packets)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!session || session->GetRemoteEndpoint () != packet->from) // we received packet for other session than previous
|
|
||||||
{
|
|
||||||
if (session)
|
|
||||||
{
|
|
||||||
session->FlushData ();
|
|
||||||
session = nullptr;
|
|
||||||
}
|
|
||||||
auto it = sessions->find (packet->from);
|
|
||||||
if (it != sessions->end ())
|
|
||||||
session = it->second;
|
|
||||||
if (!session && packet->len > 0)
|
|
||||||
{
|
|
||||||
session = std::make_shared<SSUSession> (*this, packet->from);
|
|
||||||
session->WaitForConnect ();
|
|
||||||
(*sessions)[packet->from] = session;
|
|
||||||
LogPrint (eLogDebug, "SSU: New session from ", packet->from.address ().to_string (), ":", packet->from.port (), " created");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (session)
|
|
||||||
session->ProcessNextMessage (packet->buf, packet->len, packet->from);
|
|
||||||
}
|
|
||||||
catch (std::exception& ex)
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "SSU: HandleReceivedPackets ", ex.what ());
|
|
||||||
if (session) session->FlushData ();
|
|
||||||
session = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_PacketsPool.ReleaseMt (packets);
|
|
||||||
if (session) session->FlushData ();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<SSUSession> SSUServer::FindSession (const boost::asio::ip::udp::endpoint& e) const
|
|
||||||
{
|
|
||||||
auto& sessions = e.address ().is_v6 () ? m_SessionsV6 : m_Sessions;
|
|
||||||
auto it = sessions.find (e);
|
|
||||||
if (it != sessions.end ())
|
|
||||||
return it->second;
|
|
||||||
else
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SSUServer::CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest, bool v4only)
|
|
||||||
{
|
|
||||||
auto address = router->GetSSUAddress (v4only || !context.SupportsV6 ());
|
|
||||||
if (address)
|
|
||||||
return CreateSession (router, address, peerTest);
|
|
||||||
else
|
|
||||||
LogPrint (eLogWarning, "SSU: Router ", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), " doesn't have SSU address");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SSUServer::CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
|
|
||||||
std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest)
|
|
||||||
{
|
|
||||||
if (router && address)
|
|
||||||
{
|
|
||||||
if (address->UsesIntroducer ())
|
|
||||||
m_Service.post (std::bind (&SSUServer::CreateSessionThroughIntroducer, this, router, address, peerTest)); // always V4 thread
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (address->host.is_unspecified () || !address->port) return false;
|
|
||||||
boost::asio::ip::udp::endpoint remoteEndpoint (address->host, address->port);
|
|
||||||
m_Service.post (std::bind (&SSUServer::CreateDirectSession, this, router, remoteEndpoint, peerTest));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::CreateDirectSession (std::shared_ptr<const i2p::data::RouterInfo> router, boost::asio::ip::udp::endpoint remoteEndpoint, bool peerTest)
|
|
||||||
{
|
|
||||||
auto& sessions = remoteEndpoint.address ().is_v6 () ? m_SessionsV6 : m_Sessions;
|
|
||||||
auto it = sessions.find (remoteEndpoint);
|
|
||||||
if (it != sessions.end ())
|
|
||||||
{
|
|
||||||
auto session = it->second;
|
|
||||||
if (peerTest && session->GetState () == eSessionStateEstablished)
|
|
||||||
session->SendPeerTest ();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// otherwise create new session
|
|
||||||
auto session = std::make_shared<SSUSession> (*this, remoteEndpoint, router, peerTest);
|
|
||||||
sessions[remoteEndpoint] = session;
|
|
||||||
|
|
||||||
// connect
|
|
||||||
LogPrint (eLogDebug, "SSU: Creating new session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), "] ",
|
|
||||||
remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port ());
|
|
||||||
session->Connect ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router,
|
|
||||||
std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest)
|
|
||||||
{
|
|
||||||
if (router && address && address->UsesIntroducer ())
|
|
||||||
{
|
|
||||||
if (address->IsV4 () && !i2p::context.SupportsV4 ()) return;
|
|
||||||
if (address->IsV6 () && !i2p::context.SupportsV6 ()) return;
|
|
||||||
if (!address->host.is_unspecified () && address->port)
|
|
||||||
{
|
|
||||||
// we rarely come here
|
|
||||||
auto& sessions = address->host.is_v6 () ? m_SessionsV6 : m_Sessions;
|
|
||||||
boost::asio::ip::udp::endpoint remoteEndpoint (address->host, address->port);
|
|
||||||
auto it = sessions.find (remoteEndpoint);
|
|
||||||
// check if session is presented already
|
|
||||||
if (it != sessions.end ())
|
|
||||||
{
|
|
||||||
auto session = it->second;
|
|
||||||
if (peerTest && session->GetState () == eSessionStateEstablished)
|
|
||||||
session->SendPeerTest ();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// create new session
|
|
||||||
int numIntroducers = address->ssu->introducers.size ();
|
|
||||||
if (numIntroducers > 0)
|
|
||||||
{
|
|
||||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
|
||||||
std::shared_ptr<SSUSession> introducerSession;
|
|
||||||
const i2p::data::RouterInfo::Introducer * introducer = nullptr;
|
|
||||||
// we might have a session to introducer already
|
|
||||||
auto offset = rand ();
|
|
||||||
for (int i = 0; i < numIntroducers; i++)
|
|
||||||
{
|
|
||||||
auto intr = &(address->ssu->introducers[(offset + i)%numIntroducers]);
|
|
||||||
if (!intr->iPort) continue; // skip invalid introducer
|
|
||||||
if (intr->iExp > 0 && ts > intr->iExp) continue; // skip expired introducer
|
|
||||||
boost::asio::ip::udp::endpoint ep (intr->iHost, intr->iPort);
|
|
||||||
if (ep.address ().is_v4 () && address->IsV4 ()) // ipv4
|
|
||||||
{
|
|
||||||
if (!introducer) introducer = intr;
|
|
||||||
auto it = m_Sessions.find (ep);
|
|
||||||
if (it != m_Sessions.end ())
|
|
||||||
{
|
|
||||||
introducerSession = it->second;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ep.address ().is_v6 () && address->IsV6 ()) // ipv6
|
|
||||||
{
|
|
||||||
if (!introducer) introducer = intr;
|
|
||||||
auto it = m_SessionsV6.find (ep);
|
|
||||||
if (it != m_SessionsV6.end ())
|
|
||||||
{
|
|
||||||
introducerSession = it->second;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!introducer)
|
|
||||||
{
|
|
||||||
LogPrint (eLogWarning, "SSU: Can't connect to unreachable router and no compatibe non-expired introducers presented");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (introducerSession) // session found
|
|
||||||
LogPrint (eLogWarning, "SSU: Session to introducer already exists");
|
|
||||||
else // create new
|
|
||||||
{
|
|
||||||
LogPrint (eLogDebug, "SSU: Creating new session to introducer ", introducer->iHost);
|
|
||||||
boost::asio::ip::udp::endpoint introducerEndpoint (introducer->iHost, introducer->iPort);
|
|
||||||
introducerSession = std::make_shared<SSUSession> (*this, introducerEndpoint, router);
|
|
||||||
if (introducerEndpoint.address ().is_v4 ())
|
|
||||||
m_Sessions[introducerEndpoint] = introducerSession;
|
|
||||||
else if (introducerEndpoint.address ().is_v6 ())
|
|
||||||
m_SessionsV6[introducerEndpoint] = introducerSession;
|
|
||||||
}
|
|
||||||
if (!address->host.is_unspecified () && address->port)
|
|
||||||
{
|
|
||||||
// create session
|
|
||||||
boost::asio::ip::udp::endpoint remoteEndpoint (address->host, address->port);
|
|
||||||
auto session = std::make_shared<SSUSession> (*this, remoteEndpoint, router, peerTest);
|
|
||||||
if (address->host.is_v4 ())
|
|
||||||
m_Sessions[remoteEndpoint] = session;
|
|
||||||
else if (address->host.is_v6 ())
|
|
||||||
m_SessionsV6[remoteEndpoint] = session;
|
|
||||||
|
|
||||||
// introduce
|
|
||||||
LogPrint (eLogInfo, "SSU: Introduce new session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()),
|
|
||||||
"] through introducer ", introducer->iHost, ":", introducer->iPort);
|
|
||||||
session->WaitForIntroduction ();
|
|
||||||
if ((address->host.is_v4 () && i2p::context.GetStatus () == eRouterStatusFirewalled) ||
|
|
||||||
(address->host.is_v6 () && i2p::context.GetStatusV6 () == eRouterStatusFirewalled))
|
|
||||||
{
|
|
||||||
uint8_t buf[1];
|
|
||||||
Send (buf, 0, remoteEndpoint); // send HolePunch
|
|
||||||
}
|
|
||||||
}
|
|
||||||
introducerSession->Introduce (*introducer, router);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
LogPrint (eLogWarning, "SSU: Can't connect to unreachable router and no introducers present");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::DeleteSession (std::shared_ptr<SSUSession> session)
|
|
||||||
{
|
|
||||||
if (session)
|
|
||||||
{
|
|
||||||
session->Close ();
|
|
||||||
auto& ep = session->GetRemoteEndpoint ();
|
|
||||||
if (ep.address ().is_v6 ())
|
|
||||||
m_SessionsV6.erase (ep);
|
|
||||||
else
|
|
||||||
m_Sessions.erase (ep);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::DeleteAllSessions ()
|
|
||||||
{
|
|
||||||
for (auto& it: m_Sessions)
|
|
||||||
it.second->Close ();
|
|
||||||
m_Sessions.clear ();
|
|
||||||
|
|
||||||
for (auto& it: m_SessionsV6)
|
|
||||||
it.second->Close ();
|
|
||||||
m_SessionsV6.clear ();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Filter>
|
|
||||||
std::shared_ptr<SSUSession> SSUServer::GetRandomV4Session (Filter filter) // v4 only
|
|
||||||
{
|
|
||||||
std::vector<std::shared_ptr<SSUSession> > filteredSessions;
|
|
||||||
for (const auto& s :m_Sessions)
|
|
||||||
if (filter (s.second)) filteredSessions.push_back (s.second);
|
|
||||||
if (filteredSessions.size () > 0)
|
|
||||||
{
|
|
||||||
auto ind = rand () % filteredSessions.size ();
|
|
||||||
return filteredSessions[ind];
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<SSUSession> SSUServer::GetRandomEstablishedV4Session (std::shared_ptr<const SSUSession> excluded) // v4 only
|
|
||||||
{
|
|
||||||
return GetRandomV4Session (
|
|
||||||
[excluded](std::shared_ptr<SSUSession> session)->bool
|
|
||||||
{
|
|
||||||
return session->GetState () == eSessionStateEstablished && session != excluded;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Filter>
|
|
||||||
std::shared_ptr<SSUSession> SSUServer::GetRandomV6Session (Filter filter) // v6 only
|
|
||||||
{
|
|
||||||
std::vector<std::shared_ptr<SSUSession> > filteredSessions;
|
|
||||||
for (const auto& s :m_SessionsV6)
|
|
||||||
if (filter (s.second)) filteredSessions.push_back (s.second);
|
|
||||||
if (filteredSessions.size () > 0)
|
|
||||||
{
|
|
||||||
auto ind = rand () % filteredSessions.size ();
|
|
||||||
return filteredSessions[ind];
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<SSUSession> SSUServer::GetRandomEstablishedV6Session (std::shared_ptr<const SSUSession> excluded) // v6 only
|
|
||||||
{
|
|
||||||
return GetRandomV6Session (
|
|
||||||
[excluded](std::shared_ptr<SSUSession> session)->bool
|
|
||||||
{
|
|
||||||
return session->GetState () == eSessionStateEstablished && session != excluded;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::list<std::shared_ptr<SSUSession> > SSUServer::FindIntroducers (int maxNumIntroducers,
|
|
||||||
bool v4, std::set<i2p::data::IdentHash>& excluded)
|
|
||||||
{
|
|
||||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
|
||||||
std::list<std::shared_ptr<SSUSession> > ret;
|
|
||||||
const auto& sessions = v4 ? m_Sessions : m_SessionsV6;
|
|
||||||
for (const auto& s : sessions)
|
|
||||||
{
|
|
||||||
if (s.second->GetRelayTag () && s.second->GetState () == eSessionStateEstablished &&
|
|
||||||
ts < s.second->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_EXPIRATION)
|
|
||||||
ret.push_back (s.second);
|
|
||||||
else if (s.second->GetRemoteIdentity ())
|
|
||||||
excluded.insert (s.second->GetRemoteIdentity ()->GetIdentHash ());
|
|
||||||
}
|
|
||||||
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 SSUServer::RescheduleIntroducersUpdateTimer ()
|
|
||||||
{
|
|
||||||
m_IntroducersUpdateTimer.cancel ();
|
|
||||||
m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INTERVAL/2));
|
|
||||||
m_IntroducersUpdateTimer.async_wait (std::bind (&SSUServer::HandleIntroducersUpdateTimer,
|
|
||||||
this, std::placeholders::_1, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::ScheduleIntroducersUpdateTimer ()
|
|
||||||
{
|
|
||||||
m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INTERVAL));
|
|
||||||
m_IntroducersUpdateTimer.async_wait (std::bind (&SSUServer::HandleIntroducersUpdateTimer,
|
|
||||||
this, std::placeholders::_1, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::RescheduleIntroducersUpdateTimerV6 ()
|
|
||||||
{
|
|
||||||
m_IntroducersUpdateTimerV6.cancel ();
|
|
||||||
m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INTERVAL/2));
|
|
||||||
m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSUServer::HandleIntroducersUpdateTimer,
|
|
||||||
this, std::placeholders::_1, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::ScheduleIntroducersUpdateTimerV6 ()
|
|
||||||
{
|
|
||||||
m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INTERVAL));
|
|
||||||
m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSUServer::HandleIntroducersUpdateTimer,
|
|
||||||
this, std::placeholders::_1, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::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
|
|
||||||
m_Introducers.clear ();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// we are firewalled
|
|
||||||
if (!i2p::context.IsUnreachable ()) i2p::context.SetUnreachable (true, false); // v4
|
|
||||||
}
|
|
||||||
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
|
|
||||||
m_IntroducersV6.clear ();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// we are firewalled
|
|
||||||
auto addr = i2p::context.GetRouterInfo ().GetSSUV6Address ();
|
|
||||||
if (addr && addr->ssu && addr->ssu->introducers.empty ())
|
|
||||||
i2p::context.SetUnreachable (false, true); // v6
|
|
||||||
}
|
|
||||||
|
|
||||||
std::list<boost::asio::ip::udp::endpoint> newList;
|
|
||||||
size_t numIntroducers = 0;
|
|
||||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
|
||||||
std::set<i2p::data::IdentHash> excluded;
|
|
||||||
auto& introducers = v4 ? m_Introducers : m_IntroducersV6;
|
|
||||||
for (const auto& it : introducers)
|
|
||||||
{
|
|
||||||
auto session = FindSession (it);
|
|
||||||
if (session)
|
|
||||||
{
|
|
||||||
if (ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_EXPIRATION)
|
|
||||||
session->SendKeepAlive ();
|
|
||||||
if (ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION)
|
|
||||||
{
|
|
||||||
newList.push_back (it);
|
|
||||||
numIntroducers++;
|
|
||||||
if (session->GetRemoteIdentity ())
|
|
||||||
excluded.insert (session->GetRemoteIdentity ()->GetIdentHash ());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
session = nullptr;
|
|
||||||
}
|
|
||||||
if (!session)
|
|
||||||
i2p::context.RemoveIntroducer (it);
|
|
||||||
}
|
|
||||||
if (numIntroducers < SSU_MAX_NUM_INTRODUCERS)
|
|
||||||
{
|
|
||||||
// create new
|
|
||||||
auto sessions = FindIntroducers (SSU_MAX_NUM_INTRODUCERS, v4, excluded); // try to find if duplicates
|
|
||||||
if (sessions.empty () && !introducers.empty ())
|
|
||||||
{
|
|
||||||
// bump creation time for previous introducers if no new sessions found
|
|
||||||
LogPrint (eLogDebug, "SSU: No new introducers found. Trying to reuse existing");
|
|
||||||
for (const auto& it : introducers)
|
|
||||||
{
|
|
||||||
auto session = FindSession (it);
|
|
||||||
if (session)
|
|
||||||
session->SetCreationTime (session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION);
|
|
||||||
}
|
|
||||||
// try again
|
|
||||||
excluded.clear ();
|
|
||||||
sessions = FindIntroducers (SSU_MAX_NUM_INTRODUCERS, v4, excluded);
|
|
||||||
}
|
|
||||||
for (const auto& it1: sessions)
|
|
||||||
{
|
|
||||||
const auto& ep = it1->GetRemoteEndpoint ();
|
|
||||||
i2p::data::RouterInfo::Introducer introducer;
|
|
||||||
introducer.iHost = ep.address ();
|
|
||||||
introducer.iPort = ep.port ();
|
|
||||||
introducer.iTag = it1->GetRelayTag ();
|
|
||||||
introducer.iKey = it1->GetIntroKey ();
|
|
||||||
introducer.iExp = it1->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_EXPIRATION;
|
|
||||||
if (i2p::context.AddIntroducer (introducer))
|
|
||||||
{
|
|
||||||
newList.push_back (ep);
|
|
||||||
if (newList.size () >= SSU_MAX_NUM_INTRODUCERS) break;
|
|
||||||
}
|
|
||||||
if (it1->GetRemoteIdentity ())
|
|
||||||
excluded.insert (it1->GetRemoteIdentity ()->GetIdentHash ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
introducers = newList;
|
|
||||||
if (introducers.size () < SSU_MAX_NUM_INTRODUCERS)
|
|
||||||
{
|
|
||||||
for (auto i = introducers.size (); i < SSU_MAX_NUM_INTRODUCERS; i++)
|
|
||||||
{
|
|
||||||
auto introducer = i2p::data::netdb.GetRandomIntroducer (v4, excluded);
|
|
||||||
if (introducer)
|
|
||||||
{
|
|
||||||
auto address = v4 ? introducer->GetSSUAddress (true) : introducer->GetSSUV6Address ();
|
|
||||||
if (address && !address->host.is_unspecified () && address->port)
|
|
||||||
{
|
|
||||||
boost::asio::ip::udp::endpoint ep (address->host, address->port);
|
|
||||||
if (std::find (introducers.begin (), introducers.end (), ep) == introducers.end ()) // not connected yet
|
|
||||||
{
|
|
||||||
CreateDirectSession (introducer, ep, false);
|
|
||||||
excluded.insert (introducer->GetIdentHash ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LogPrint (eLogDebug, "SSU: Can't find more introducers");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (v4)
|
|
||||||
ScheduleIntroducersUpdateTimer ();
|
|
||||||
else
|
|
||||||
ScheduleIntroducersUpdateTimerV6 ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::NewPeerTest (uint32_t nonce, PeerTestParticipant role, std::shared_ptr<SSUSession> session)
|
|
||||||
{
|
|
||||||
m_PeerTests[nonce] = { i2p::util::GetMillisecondsSinceEpoch (), role, session };
|
|
||||||
}
|
|
||||||
|
|
||||||
PeerTestParticipant SSUServer::GetPeerTestParticipant (uint32_t nonce)
|
|
||||||
{
|
|
||||||
auto it = m_PeerTests.find (nonce);
|
|
||||||
if (it != m_PeerTests.end ())
|
|
||||||
return it->second.role;
|
|
||||||
else
|
|
||||||
return ePeerTestParticipantUnknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<SSUSession> SSUServer::GetPeerTestSession (uint32_t nonce)
|
|
||||||
{
|
|
||||||
auto it = m_PeerTests.find (nonce);
|
|
||||||
if (it != m_PeerTests.end ())
|
|
||||||
return it->second.session;
|
|
||||||
else
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::UpdatePeerTest (uint32_t nonce, PeerTestParticipant role)
|
|
||||||
{
|
|
||||||
auto it = m_PeerTests.find (nonce);
|
|
||||||
if (it != m_PeerTests.end ())
|
|
||||||
it->second.role = role;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::RemovePeerTest (uint32_t nonce)
|
|
||||||
{
|
|
||||||
m_PeerTests.erase (nonce);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::SchedulePeerTestsCleanupTimer ()
|
|
||||||
{
|
|
||||||
m_PeerTestsCleanupTimer.expires_from_now (boost::posix_time::seconds(SSU_PEER_TEST_TIMEOUT));
|
|
||||||
m_PeerTestsCleanupTimer.async_wait (std::bind (&SSUServer::HandlePeerTestsCleanupTimer,
|
|
||||||
this, std::placeholders::_1));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::HandlePeerTestsCleanupTimer (const boost::system::error_code& ecode)
|
|
||||||
{
|
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
|
||||||
{
|
|
||||||
int numDeleted = 0;
|
|
||||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
|
|
||||||
for (auto it = m_PeerTests.begin (); it != m_PeerTests.end ();)
|
|
||||||
{
|
|
||||||
if (ts > it->second.creationTime + SSU_PEER_TEST_TIMEOUT*1000LL)
|
|
||||||
{
|
|
||||||
numDeleted++;
|
|
||||||
it = m_PeerTests.erase (it);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
if (numDeleted > 0)
|
|
||||||
LogPrint (eLogDebug, "SSU: ", numDeleted, " peer tests have been expired");
|
|
||||||
// some cleaups. TODO: use separate timer
|
|
||||||
m_FragmentsPool.CleanUp ();
|
|
||||||
m_IncompleteMessagesPool.CleanUp ();
|
|
||||||
m_SentMessagesPool.CleanUp ();
|
|
||||||
|
|
||||||
SchedulePeerTestsCleanupTimer ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::ScheduleTermination ()
|
|
||||||
{
|
|
||||||
uint64_t timeout = SSU_TERMINATION_CHECK_TIMEOUT + (rand () % SSU_TERMINATION_CHECK_TIMEOUT)/5;
|
|
||||||
m_TerminationTimer.expires_from_now (boost::posix_time::seconds(timeout));
|
|
||||||
m_TerminationTimer.async_wait (std::bind (&SSUServer::HandleTerminationTimer,
|
|
||||||
this, std::placeholders::_1));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::HandleTerminationTimer (const boost::system::error_code& ecode)
|
|
||||||
{
|
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
|
||||||
{
|
|
||||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
|
||||||
for (auto& it: m_Sessions)
|
|
||||||
if (it.second->IsTerminationTimeoutExpired (ts))
|
|
||||||
{
|
|
||||||
auto session = it.second;
|
|
||||||
if (it.first != session->GetRemoteEndpoint ())
|
|
||||||
LogPrint (eLogWarning, "SSU: Remote endpoint ", session->GetRemoteEndpoint (), " doesn't match key ", it.first, " adjusted");
|
|
||||||
m_Service.post ([session]
|
|
||||||
{
|
|
||||||
LogPrint (eLogWarning, "SSU: No activity with ", session->GetRemoteEndpoint (), " for ", session->GetTerminationTimeout (), " seconds");
|
|
||||||
session->Failed ();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
it.second->CleanUp (ts);
|
|
||||||
ScheduleTermination ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::ScheduleTerminationV6 ()
|
|
||||||
{
|
|
||||||
uint64_t timeout = SSU_TERMINATION_CHECK_TIMEOUT + (rand () % SSU_TERMINATION_CHECK_TIMEOUT)/5;
|
|
||||||
m_TerminationTimerV6.expires_from_now (boost::posix_time::seconds(timeout));
|
|
||||||
m_TerminationTimerV6.async_wait (std::bind (&SSUServer::HandleTerminationTimerV6,
|
|
||||||
this, std::placeholders::_1));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUServer::HandleTerminationTimerV6 (const boost::system::error_code& ecode)
|
|
||||||
{
|
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
|
||||||
{
|
|
||||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
|
||||||
for (auto& it: m_SessionsV6)
|
|
||||||
if (it.second->IsTerminationTimeoutExpired (ts))
|
|
||||||
{
|
|
||||||
auto session = it.second;
|
|
||||||
if (it.first != session->GetRemoteEndpoint ())
|
|
||||||
LogPrint (eLogWarning, "SSU: Remote endpoint ", session->GetRemoteEndpoint (), " doesn't match key ", it.first);
|
|
||||||
m_Service.post ([session]
|
|
||||||
{
|
|
||||||
LogPrint (eLogWarning, "SSU: No activity with ", session->GetRemoteEndpoint (), " for ", session->GetTerminationTimeout (), " seconds");
|
|
||||||
session->Failed ();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
it.second->CleanUp (ts);
|
|
||||||
ScheduleTerminationV6 ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
159
libi2pd/SSU.h
159
libi2pd/SSU.h
@@ -1,159 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
|
||||||
*
|
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
|
||||||
*
|
|
||||||
* See full license text in LICENSE file at top of project tree
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef SSU_H__
|
|
||||||
#define SSU_H__
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <map>
|
|
||||||
#include <list>
|
|
||||||
#include <set>
|
|
||||||
#include <thread>
|
|
||||||
#include <mutex>
|
|
||||||
#include <boost/asio.hpp>
|
|
||||||
#include "Crypto.h"
|
|
||||||
#include "util.h"
|
|
||||||
#include "I2PEndian.h"
|
|
||||||
#include "Identity.h"
|
|
||||||
#include "RouterInfo.h"
|
|
||||||
#include "I2NPProtocol.h"
|
|
||||||
#include "SSUSession.h"
|
|
||||||
|
|
||||||
namespace i2p
|
|
||||||
{
|
|
||||||
namespace transport
|
|
||||||
{
|
|
||||||
const int SSU_KEEP_ALIVE_INTERVAL = 30; // 30 seconds
|
|
||||||
const int SSU_PEER_TEST_TIMEOUT = 60; // 60 seconds
|
|
||||||
const int SSU_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour
|
|
||||||
const int SSU_TO_INTRODUCER_SESSION_EXPIRATION = 4800; // 80 minutes
|
|
||||||
const int SSU_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds
|
|
||||||
const size_t SSU_MAX_NUM_INTRODUCERS = 3;
|
|
||||||
const size_t SSU_SOCKET_RECEIVE_BUFFER_SIZE = 0x1FFFF; // 128K
|
|
||||||
const size_t SSU_SOCKET_SEND_BUFFER_SIZE = 0x1FFFF; // 128K
|
|
||||||
|
|
||||||
struct SSUPacket
|
|
||||||
{
|
|
||||||
i2p::crypto::AESAlignedBuffer<SSU_MTU_V6 + 18> buf; // max MTU + iv + size
|
|
||||||
boost::asio::ip::udp::endpoint from;
|
|
||||||
size_t len;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SSUServer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
SSUServer (int port);
|
|
||||||
~SSUServer ();
|
|
||||||
void Start ();
|
|
||||||
void Stop ();
|
|
||||||
bool CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false, bool v4only = false);
|
|
||||||
bool CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
|
|
||||||
std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest = false);
|
|
||||||
void CreateDirectSession (std::shared_ptr<const i2p::data::RouterInfo> router, boost::asio::ip::udp::endpoint remoteEndpoint, bool peerTest);
|
|
||||||
std::shared_ptr<SSUSession> FindSession (const boost::asio::ip::udp::endpoint& e) const;
|
|
||||||
std::shared_ptr<SSUSession> GetRandomEstablishedV4Session (std::shared_ptr<const SSUSession> excluded);
|
|
||||||
std::shared_ptr<SSUSession> GetRandomEstablishedV6Session (std::shared_ptr<const SSUSession> excluded);
|
|
||||||
void DeleteSession (std::shared_ptr<SSUSession> session);
|
|
||||||
void DeleteAllSessions ();
|
|
||||||
|
|
||||||
boost::asio::io_service& GetService () { return m_Service; };
|
|
||||||
i2p::util::MemoryPool<Fragment>& GetFragmentsPool () { return m_FragmentsPool; };
|
|
||||||
i2p::util::MemoryPool<IncompleteMessage>& GetIncompleteMessagesPool () { return m_IncompleteMessagesPool; };
|
|
||||||
i2p::util::MemoryPool<SentMessage>& GetSentMessagesPool () { return m_SentMessagesPool; };
|
|
||||||
|
|
||||||
uint16_t GetPort () const { return m_Endpoint.port (); };
|
|
||||||
bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; };
|
|
||||||
void SetLocalAddress (const boost::asio::ip::address& localAddress);
|
|
||||||
|
|
||||||
void Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to);
|
|
||||||
void AddRelay (uint32_t tag, std::shared_ptr<SSUSession> relay);
|
|
||||||
void RemoveRelay (uint32_t tag);
|
|
||||||
std::shared_ptr<SSUSession> FindRelaySession (uint32_t tag);
|
|
||||||
void RescheduleIntroducersUpdateTimer ();
|
|
||||||
void RescheduleIntroducersUpdateTimerV6 ();
|
|
||||||
|
|
||||||
void NewPeerTest (uint32_t nonce, PeerTestParticipant role, std::shared_ptr<SSUSession> session = nullptr);
|
|
||||||
PeerTestParticipant GetPeerTestParticipant (uint32_t nonce);
|
|
||||||
std::shared_ptr<SSUSession> GetPeerTestSession (uint32_t nonce);
|
|
||||||
void UpdatePeerTest (uint32_t nonce, PeerTestParticipant role);
|
|
||||||
void RemovePeerTest (uint32_t nonce);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void OpenSocket ();
|
|
||||||
void OpenSocketV6 ();
|
|
||||||
void Run ();
|
|
||||||
void RunReceivers ();
|
|
||||||
void RunReceiversV6 ();
|
|
||||||
void Receive ();
|
|
||||||
void ReceiveV6 ();
|
|
||||||
void HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet);
|
|
||||||
void HandleReceivedFromV6 (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet);
|
|
||||||
void HandleReceivedPackets (std::vector<SSUPacket *> packets,
|
|
||||||
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> >* sessions);
|
|
||||||
|
|
||||||
void CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router,
|
|
||||||
std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest = false);
|
|
||||||
template<typename Filter>
|
|
||||||
std::shared_ptr<SSUSession> GetRandomV4Session (Filter filter);
|
|
||||||
template<typename Filter>
|
|
||||||
std::shared_ptr<SSUSession> GetRandomV6Session (Filter filter);
|
|
||||||
|
|
||||||
std::list<std::shared_ptr<SSUSession> > FindIntroducers (int maxNumIntroducers, bool v4, std::set<i2p::data::IdentHash>& excluded);
|
|
||||||
void ScheduleIntroducersUpdateTimer ();
|
|
||||||
void ScheduleIntroducersUpdateTimerV6 ();
|
|
||||||
void HandleIntroducersUpdateTimer (const boost::system::error_code& ecode, bool v4);
|
|
||||||
|
|
||||||
void SchedulePeerTestsCleanupTimer ();
|
|
||||||
void HandlePeerTestsCleanupTimer (const boost::system::error_code& ecode);
|
|
||||||
|
|
||||||
// timer
|
|
||||||
void ScheduleTermination ();
|
|
||||||
void HandleTerminationTimer (const boost::system::error_code& ecode);
|
|
||||||
void ScheduleTerminationV6 ();
|
|
||||||
void HandleTerminationTimerV6 (const boost::system::error_code& ecode);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
struct PeerTest
|
|
||||||
{
|
|
||||||
uint64_t creationTime;
|
|
||||||
PeerTestParticipant role;
|
|
||||||
std::shared_ptr<SSUSession> session; // for Bob to Alice
|
|
||||||
};
|
|
||||||
|
|
||||||
volatile bool m_IsRunning;
|
|
||||||
std::thread * m_Thread, * m_ReceiversThread, * m_ReceiversThreadV6;
|
|
||||||
boost::asio::io_service m_Service, m_ReceiversService, m_ReceiversServiceV6;
|
|
||||||
boost::asio::io_service::work m_Work, m_ReceiversWork, m_ReceiversWorkV6;
|
|
||||||
boost::asio::ip::udp::endpoint m_Endpoint, m_EndpointV6;
|
|
||||||
boost::asio::ip::udp::socket m_Socket, m_SocketV6;
|
|
||||||
boost::asio::deadline_timer m_IntroducersUpdateTimer, m_IntroducersUpdateTimerV6,
|
|
||||||
m_PeerTestsCleanupTimer, m_TerminationTimer, m_TerminationTimerV6;
|
|
||||||
bool m_IsSyncClockFromPeers;
|
|
||||||
std::list<boost::asio::ip::udp::endpoint> m_Introducers, m_IntroducersV6; // introducers we are connected to
|
|
||||||
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > m_Sessions, m_SessionsV6;
|
|
||||||
std::map<uint32_t, std::shared_ptr<SSUSession> > m_Relays; // we are introducer
|
|
||||||
std::map<uint32_t, PeerTest> m_PeerTests; // nonce -> creation time in milliseconds
|
|
||||||
|
|
||||||
i2p::util::MemoryPool<Fragment> m_FragmentsPool;
|
|
||||||
i2p::util::MemoryPool<IncompleteMessage> m_IncompleteMessagesPool;
|
|
||||||
i2p::util::MemoryPool<SentMessage> m_SentMessagesPool;
|
|
||||||
i2p::util::MemoryPoolMt<SSUPacket> m_PacketsPool;
|
|
||||||
|
|
||||||
public:
|
|
||||||
// for HTTP only
|
|
||||||
const decltype(m_Sessions)& GetSessions () const { return m_Sessions; };
|
|
||||||
const decltype(m_SessionsV6)& GetSessionsV6 () const { return m_SessionsV6; };
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
2444
libi2pd/SSU2.cpp
2444
libi2pd/SSU2.cpp
File diff suppressed because it is too large
Load Diff
295
libi2pd/SSU2.h
295
libi2pd/SSU2.h
@@ -9,234 +9,33 @@
|
|||||||
#ifndef SSU2_H__
|
#ifndef SSU2_H__
|
||||||
#define SSU2_H__
|
#define SSU2_H__
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <functional>
|
|
||||||
#include <map>
|
|
||||||
#include <set>
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <boost/asio.hpp>
|
#include <mutex>
|
||||||
#include "Crypto.h"
|
#include "util.h"
|
||||||
#include "RouterInfo.h"
|
#include "SSU2Session.h"
|
||||||
#include "TransportSession.h"
|
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace transport
|
namespace transport
|
||||||
{
|
{
|
||||||
const int SSU2_CONNECT_TIMEOUT = 5; // 5 seconds
|
const int SSU2_TERMINATION_CHECK_TIMEOUT = 30; // in seconds
|
||||||
const int SSU2_TERMINATION_TIMEOUT = 330; // 5.5 minutes
|
const int SSU2_RESEND_CHECK_TIMEOUT = 400; // in milliseconds
|
||||||
const int SSU2_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds
|
const int SSU2_RESEND_CHECK_TIMEOUT_VARIANCE = 100; // in milliseconds
|
||||||
const int SSU2_TOKEN_EXPIRATION_TIMEOUT = 9; // in seconds
|
const int SSU2_RESEND_CHECK_MORE_TIMEOUT = 10; // in milliseconds
|
||||||
const int SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT = 10; // in seconds
|
const size_t SSU2_MAX_RESEND_PACKETS = 128; // packets to resend at the time
|
||||||
const size_t SSU2_SOCKET_RECEIVE_BUFFER_SIZE = 0x1FFFF; // 128K
|
const size_t SSU2_SOCKET_RECEIVE_BUFFER_SIZE = 0x1FFFF; // 128K
|
||||||
const size_t SSU2_SOCKET_SEND_BUFFER_SIZE = 0x1FFFF; // 128K
|
const size_t SSU2_SOCKET_SEND_BUFFER_SIZE = 0x1FFFF; // 128K
|
||||||
const size_t SSU2_MTU = 1488;
|
const size_t SSU2_MAX_NUM_INTRODUCERS = 3;
|
||||||
const size_t SSU2_MAX_PAYLOAD_SIZE = SSU2_MTU - 32;
|
const int SSU2_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour
|
||||||
const int SSU2_RESEND_INTERVAL = 3; // in seconds
|
const int SSU2_TO_INTRODUCER_SESSION_EXPIRATION = 4800; // 80 minutes
|
||||||
const int SSU2_MAX_NUM_RESENDS = 5;
|
const int SSU2_KEEP_ALIVE_INTERVAL = 30; // in seconds
|
||||||
const int SSU2_INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds
|
const int SSU2_PROXY_CONNECT_RETRY_TIMEOUT = 30; // in seconds
|
||||||
const size_t SSU2_MAX_WINDOW_SIZE = 128; // in packets
|
|
||||||
|
|
||||||
enum SSU2MessageType
|
|
||||||
{
|
|
||||||
eSSU2SessionRequest = 0,
|
|
||||||
eSSU2SessionCreated = 1,
|
|
||||||
eSSU2SessionConfirmed = 2,
|
|
||||||
eSSU2Data = 6,
|
|
||||||
eSSU2Retry = 9,
|
|
||||||
eSSU2TokenRequest = 10
|
|
||||||
};
|
|
||||||
|
|
||||||
enum SSU2BlockType
|
|
||||||
{
|
|
||||||
eSSU2BlkDateTime = 0,
|
|
||||||
eSSU2BlkOptions, // 1
|
|
||||||
eSSU2BlkRouterInfo, // 2
|
|
||||||
eSSU2BlkI2NPMessage, // 3
|
|
||||||
eSSU2BlkFirstFragment, // 4
|
|
||||||
eSSU2BlkFollowOnFragment, // 5
|
|
||||||
eSSU2BlkTermination, // 6
|
|
||||||
eSSU2BlkRelayRequest, // 7
|
|
||||||
eSSU2BlkRelayResponse, // 8
|
|
||||||
eSSU2BlkRelayIntro, // 9
|
|
||||||
eSSU2BlkPeerTest, // 10
|
|
||||||
eSSU2BlkNextNonce, // 11
|
|
||||||
eSSU2BlkAck, // 12
|
|
||||||
eSSU2BlkAddress, // 13
|
|
||||||
eSSU2BlkIntroKey, // 14
|
|
||||||
eSSU2BlkRelayTagRequest, // 15
|
|
||||||
eSSU2BlkRelayTag, // 16
|
|
||||||
eSSU2BlkNewToken, // 17
|
|
||||||
eSSU2BlkPathChallenge, // 18
|
|
||||||
eSSU2BlkPathResponse, // 19
|
|
||||||
eSSU2BlkFirstPacketNumber, // 20
|
|
||||||
eSSU2BlkPadding = 254
|
|
||||||
};
|
|
||||||
|
|
||||||
enum SSU2SessionState
|
|
||||||
{
|
|
||||||
eSSU2SessionStateUnknown,
|
|
||||||
eSSU2SessionStateIntroduced,
|
|
||||||
eSSU2SessionStateEstablished,
|
|
||||||
eSSU2SessionStateTerminated,
|
|
||||||
eSSU2SessionStateFailed
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SSU2IncompleteMessage
|
|
||||||
{
|
|
||||||
struct Fragment
|
|
||||||
{
|
|
||||||
uint8_t buf[SSU2_MTU];
|
|
||||||
size_t len;
|
|
||||||
bool isLast;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::shared_ptr<I2NPMessage> msg;
|
|
||||||
int nextFragmentNum;
|
|
||||||
uint32_t lastFragmentInsertTime; // in seconds
|
|
||||||
std::map<int, std::shared_ptr<Fragment> > outOfSequenceFragments;
|
|
||||||
};
|
|
||||||
|
|
||||||
// RouterInfo flags
|
|
||||||
const uint8_t SSU2_ROUTER_INFO_FLAG_REQUEST_FLOOD = 0x01;
|
|
||||||
const uint8_t SSU2_ROUTER_INFO_FLAG_GZIP = 0x02;
|
|
||||||
|
|
||||||
class SSU2Server;
|
|
||||||
class SSU2Session: public TransportSession, public std::enable_shared_from_this<SSU2Session>
|
|
||||||
{
|
|
||||||
union Header
|
|
||||||
{
|
|
||||||
uint64_t ll[2];
|
|
||||||
uint8_t buf[16];
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint64_t connID;
|
|
||||||
uint32_t packetNum;
|
|
||||||
uint8_t type;
|
|
||||||
uint8_t flags[3];
|
|
||||||
} h;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SentPacket
|
|
||||||
{
|
|
||||||
uint8_t payload[SSU2_MAX_PAYLOAD_SIZE];
|
|
||||||
size_t payloadSize = 0;
|
|
||||||
uint32_t nextResendTime; // in seconds
|
|
||||||
int numResends = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SessionConfirmedFragment
|
|
||||||
{
|
|
||||||
Header header;
|
|
||||||
uint8_t payload[SSU2_MAX_PAYLOAD_SIZE];
|
|
||||||
size_t payloadSize;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::function<void ()> OnEstablished;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
SSU2Session (SSU2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter = nullptr,
|
|
||||||
std::shared_ptr<const i2p::data::RouterInfo::Address> addr = nullptr);
|
|
||||||
~SSU2Session ();
|
|
||||||
|
|
||||||
void SetRemoteEndpoint (const boost::asio::ip::udp::endpoint& ep) { m_RemoteEndpoint = ep; };
|
|
||||||
const boost::asio::ip::udp::endpoint& GetRemoteEndpoint () const { return m_RemoteEndpoint; };
|
|
||||||
void SetOnEstablished (OnEstablished e) { m_OnEstablished = e; };
|
|
||||||
|
|
||||||
void Connect ();
|
|
||||||
bool Introduce (std::shared_ptr<SSU2Session> session, uint32_t relayTag);
|
|
||||||
void Terminate ();
|
|
||||||
void TerminateByTimeout ();
|
|
||||||
void CleanUp (uint64_t ts);
|
|
||||||
void FlushData ();
|
|
||||||
void Done () override;
|
|
||||||
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) override;
|
|
||||||
void Resend (uint64_t ts);
|
|
||||||
bool IsEstablished () const { return m_State == eSSU2SessionStateEstablished; };
|
|
||||||
uint64_t GetConnID () const { return m_SourceConnID; };
|
|
||||||
SSU2SessionState GetState () const { return m_State; };
|
|
||||||
void SetState (SSU2SessionState state) { m_State = state; };
|
|
||||||
|
|
||||||
bool ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len);
|
|
||||||
bool ProcessSessionCreated (uint8_t * buf, size_t len);
|
|
||||||
bool ProcessSessionConfirmed (uint8_t * buf, size_t len);
|
|
||||||
bool ProcessRetry (uint8_t * buf, size_t len);
|
|
||||||
void ProcessData (uint8_t * buf, size_t len);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void Established ();
|
|
||||||
void PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs);
|
|
||||||
bool SendQueue ();
|
|
||||||
void SendFragmentedMessage (std::shared_ptr<I2NPMessage> msg);
|
|
||||||
|
|
||||||
void ProcessSessionRequest (Header& header, uint8_t * buf, size_t len);
|
|
||||||
void ProcessTokenRequest (Header& header, uint8_t * buf, size_t len);
|
|
||||||
|
|
||||||
void SendSessionRequest (uint64_t token = 0);
|
|
||||||
void SendSessionCreated (const uint8_t * X);
|
|
||||||
void SendSessionConfirmed (const uint8_t * Y);
|
|
||||||
void KDFDataPhase (uint8_t * keydata_ab, uint8_t * keydata_ba);
|
|
||||||
void SendTokenRequest ();
|
|
||||||
void SendRetry ();
|
|
||||||
uint32_t SendData (const uint8_t * buf, size_t len); // returns packet num
|
|
||||||
void SendQuickAck ();
|
|
||||||
void SendTermination ();
|
|
||||||
|
|
||||||
void HandlePayload (const uint8_t * buf, size_t len);
|
|
||||||
void HandleAck (const uint8_t * buf, size_t len);
|
|
||||||
void HandleAckRange (uint32_t firstPacketNum, uint32_t lastPacketNum);
|
|
||||||
bool ExtractEndpoint (const uint8_t * buf, size_t size, boost::asio::ip::udp::endpoint& ep);
|
|
||||||
size_t CreateEndpoint (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep);
|
|
||||||
std::shared_ptr<const i2p::data::RouterInfo> ExtractRouterInfo (const uint8_t * buf, size_t size);
|
|
||||||
void CreateNonce (uint64_t seqn, uint8_t * nonce);
|
|
||||||
bool UpdateReceivePacketNum (uint32_t packetNum); // for Ack, returns false if duplicate
|
|
||||||
void HandleFirstFragment (const uint8_t * buf, size_t len);
|
|
||||||
void HandleFollowOnFragment (const uint8_t * buf, size_t len);
|
|
||||||
bool ConcatOutOfSequenceFragments (std::shared_ptr<SSU2IncompleteMessage> m); // true if message complete
|
|
||||||
void HandleRelayRequest (const uint8_t * buf, size_t len);
|
|
||||||
void HandleRelayIntro (const uint8_t * buf, size_t len);
|
|
||||||
void HandleRelayResponse (const uint8_t * buf, size_t len);
|
|
||||||
|
|
||||||
size_t CreateAddressBlock (const boost::asio::ip::udp::endpoint& ep, uint8_t * buf, size_t len);
|
|
||||||
size_t CreateAckBlock (uint8_t * buf, size_t len);
|
|
||||||
size_t CreatePaddingBlock (uint8_t * buf, size_t len, size_t minSize = 0);
|
|
||||||
size_t CreateI2NPBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage>&& msg);
|
|
||||||
size_t CreateFirstFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage> msg);
|
|
||||||
size_t CreateFollowOnFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage> msg, uint8_t& fragmentNum, uint32_t msgID);
|
|
||||||
size_t CreateRelayIntroBlock (uint8_t * buf, size_t len, const uint8_t * introData, size_t introDataLen);
|
|
||||||
size_t CreateRelayResponseBlock (uint8_t * buf, size_t len, uint32_t nonce); // Charlie
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
SSU2Server& m_Server;
|
|
||||||
std::shared_ptr<i2p::crypto::X25519Keys> m_EphemeralKeys;
|
|
||||||
std::unique_ptr<i2p::crypto::NoiseSymmetricState> m_NoiseState;
|
|
||||||
std::unique_ptr<SessionConfirmedFragment> m_SessionConfirmedFragment1; // for Bob if applicable
|
|
||||||
std::shared_ptr<const i2p::data::RouterInfo::Address> m_Address;
|
|
||||||
boost::asio::ip::udp::endpoint m_RemoteEndpoint;
|
|
||||||
uint64_t m_DestConnID, m_SourceConnID;
|
|
||||||
SSU2SessionState m_State;
|
|
||||||
uint8_t m_KeyDataSend[64], m_KeyDataReceive[64];
|
|
||||||
uint32_t m_SendPacketNum, m_ReceivePacketNum;
|
|
||||||
std::set<uint32_t> m_OutOfSequencePackets; // packet nums > receive packet num
|
|
||||||
std::map<uint32_t, std::shared_ptr<SentPacket> > m_SentPackets; // packetNum -> packet
|
|
||||||
std::map<uint32_t, std::shared_ptr<SSU2IncompleteMessage> > m_IncompleteMessages; // I2NP
|
|
||||||
std::map<uint32_t, std::pair <std::shared_ptr<SSU2Session>, uint64_t > > m_RelaySessions; // nonce->(Alice, timestamp) for Bob or nonce->(Charlie, timestamp) for Alice
|
|
||||||
std::list<std::shared_ptr<I2NPMessage> > m_SendQueue;
|
|
||||||
i2p::I2NPMessagesHandler m_Handler;
|
|
||||||
bool m_IsDataReceived;
|
|
||||||
size_t m_WindowSize;
|
|
||||||
uint32_t m_RelayTag; // between Bob and Charlie
|
|
||||||
OnEstablished m_OnEstablished; // callback from Established
|
|
||||||
};
|
|
||||||
|
|
||||||
class SSU2Server: private i2p::util::RunnableServiceWithWork
|
class SSU2Server: private i2p::util::RunnableServiceWithWork
|
||||||
{
|
{
|
||||||
struct Packet
|
struct Packet
|
||||||
{
|
{
|
||||||
uint8_t buf[SSU2_MTU];
|
uint8_t buf[SSU2_MAX_PACKET_SIZE];
|
||||||
size_t len;
|
size_t len;
|
||||||
boost::asio::ip::udp::endpoint from;
|
boost::asio::ip::udp::endpoint from;
|
||||||
};
|
};
|
||||||
@@ -259,11 +58,22 @@ namespace transport
|
|||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
boost::asio::io_service& GetService () { return GetIOService (); };
|
boost::asio::io_service& GetService () { return GetIOService (); };
|
||||||
|
void SetLocalAddress (const boost::asio::ip::address& localAddress);
|
||||||
|
bool SetProxy (const std::string& address, uint16_t port);
|
||||||
|
bool UsesProxy () const { return m_IsThroughProxy; };
|
||||||
|
bool IsSupported (const boost::asio::ip::address& addr) const;
|
||||||
|
uint16_t GetPort (bool v4) const;
|
||||||
|
bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; };
|
||||||
|
|
||||||
void AddSession (std::shared_ptr<SSU2Session> session);
|
void AddSession (std::shared_ptr<SSU2Session> session);
|
||||||
void RemoveSession (uint64_t connID);
|
void RemoveSession (uint64_t connID);
|
||||||
void AddSessionByRouterHash (std::shared_ptr<SSU2Session> session);
|
void AddSessionByRouterHash (std::shared_ptr<SSU2Session> session);
|
||||||
void AddPendingOutgoingSession (std::shared_ptr<SSU2Session> session);
|
bool AddPendingOutgoingSession (std::shared_ptr<SSU2Session> session);
|
||||||
|
void RemovePendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep);
|
||||||
|
std::shared_ptr<SSU2Session> FindSession (const i2p::data::IdentHash& ident) const;
|
||||||
|
std::shared_ptr<SSU2Session> FindPendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep) const;
|
||||||
|
std::shared_ptr<SSU2Session> GetRandomSession (i2p::data::RouterInfo::CompatibleTransports remoteTransports,
|
||||||
|
const i2p::data::IdentHash& excluded) const;
|
||||||
|
|
||||||
void AddRelay (uint32_t tag, std::shared_ptr<SSU2Session> relay);
|
void AddRelay (uint32_t tag, std::shared_ptr<SSU2Session> relay);
|
||||||
void RemoveRelay (uint32_t tag);
|
void RemoveRelay (uint32_t tag);
|
||||||
@@ -273,14 +83,20 @@ namespace transport
|
|||||||
const boost::asio::ip::udp::endpoint& to);
|
const boost::asio::ip::udp::endpoint& to);
|
||||||
void Send (const uint8_t * header, size_t headerLen, const uint8_t * headerX, size_t headerXLen,
|
void Send (const uint8_t * header, size_t headerLen, const uint8_t * headerX, size_t headerXLen,
|
||||||
const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to);
|
const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to);
|
||||||
void SendHolePunch (const boost::asio::ip::udp::endpoint& to);
|
|
||||||
|
|
||||||
bool CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
|
bool CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
|
||||||
std::shared_ptr<const i2p::data::RouterInfo::Address> address);
|
std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest = false);
|
||||||
|
bool StartPeerTest (std::shared_ptr<const i2p::data::RouterInfo> router, bool v4);
|
||||||
|
|
||||||
void UpdateOutgoingToken (const boost::asio::ip::udp::endpoint& ep, uint64_t token, uint32_t exp);
|
void UpdateOutgoingToken (const boost::asio::ip::udp::endpoint& ep, uint64_t token, uint32_t exp);
|
||||||
uint64_t FindOutgoingToken (const boost::asio::ip::udp::endpoint& ep) const;
|
uint64_t FindOutgoingToken (const boost::asio::ip::udp::endpoint& ep);
|
||||||
uint64_t GetIncomingToken (const boost::asio::ip::udp::endpoint& ep);
|
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:
|
private:
|
||||||
|
|
||||||
@@ -295,24 +111,55 @@ namespace transport
|
|||||||
void ScheduleTermination ();
|
void ScheduleTermination ();
|
||||||
void HandleTerminationTimer (const boost::system::error_code& ecode);
|
void HandleTerminationTimer (const boost::system::error_code& ecode);
|
||||||
|
|
||||||
void ScheduleResend ();
|
void ScheduleResend (bool more);
|
||||||
void HandleResendTimer (const boost::system::error_code& ecode);
|
void HandleResendTimer (const boost::system::error_code& ecode);
|
||||||
|
|
||||||
void ConnectThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router,
|
void ConnectThroughIntroducer (std::shared_ptr<SSU2Session> session);
|
||||||
std::shared_ptr<const i2p::data::RouterInfo::Address> address);
|
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 ();
|
||||||
|
|
||||||
|
void SendThroughProxy (const uint8_t * header, size_t headerLen, const uint8_t * headerX, size_t headerXLen,
|
||||||
|
const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to);
|
||||||
|
void ProcessNextPacketFromProxy (uint8_t * buf, size_t len);
|
||||||
|
void ConnectToProxy ();
|
||||||
|
void ReconnectToProxy ();
|
||||||
|
void HandshakeWithProxy ();
|
||||||
|
void ReadHandshakeWithProxyReply ();
|
||||||
|
void SendUDPAssociateRequest ();
|
||||||
|
void ReadUDPAssociateReply ();
|
||||||
|
void ReadUDPAssociateSocket (); // handle if closed by peer
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
ReceiveService m_ReceiveService;
|
ReceiveService m_ReceiveService;
|
||||||
boost::asio::ip::udp::socket m_SocketV4, m_SocketV6;
|
boost::asio::ip::udp::socket m_SocketV4, m_SocketV6;
|
||||||
|
boost::asio::ip::address m_AddressV4, m_AddressV6;
|
||||||
std::unordered_map<uint64_t, std::shared_ptr<SSU2Session> > m_Sessions;
|
std::unordered_map<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::shared_ptr<SSU2Session> > m_PendingOutgoingSessions;
|
||||||
|
mutable std::mutex m_PendingOutgoingSessionsMutex;
|
||||||
std::map<boost::asio::ip::udp::endpoint, std::pair<uint64_t, uint32_t> > m_IncomingTokens, m_OutgoingTokens; // remote endpoint -> (token, expires in seconds)
|
std::map<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::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;
|
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;
|
std::shared_ptr<SSU2Session> m_LastSession;
|
||||||
|
bool m_IsPublished; // if we maintain introducers
|
||||||
|
bool m_IsSyncClockFromPeers;
|
||||||
|
|
||||||
|
// proxy
|
||||||
|
bool m_IsThroughProxy;
|
||||||
|
uint8_t m_UDPRequestHeader[SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE];
|
||||||
|
std::unique_ptr<boost::asio::ip::tcp::endpoint> m_ProxyEndpoint;
|
||||||
|
std::unique_ptr<boost::asio::ip::tcp::socket> m_UDPAssociateSocket;
|
||||||
|
std::unique_ptr<boost::asio::ip::udp::endpoint> m_ProxyRelayEndpoint;
|
||||||
|
std::unique_ptr<boost::asio::deadline_timer> m_ProxyConnectRetryTimer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|||||||
2833
libi2pd/SSU2Session.cpp
Normal file
2833
libi2pd/SSU2Session.cpp
Normal file
File diff suppressed because it is too large
Load Diff
365
libi2pd/SSU2Session.h
Normal file
365
libi2pd/SSU2Session.h
Normal file
@@ -0,0 +1,365 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022, The PurpleI2P Project
|
||||||
|
*
|
||||||
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
|
*
|
||||||
|
* See full license text in LICENSE file at top of project tree
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SSU2_SESSION_H__
|
||||||
|
#define SSU2_SESSION_H__
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <list>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include "Crypto.h"
|
||||||
|
#include "RouterInfo.h"
|
||||||
|
#include "RouterContext.h"
|
||||||
|
#include "TransportSession.h"
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace transport
|
||||||
|
{
|
||||||
|
const int SSU2_CONNECT_TIMEOUT = 5; // 5 seconds
|
||||||
|
const int SSU2_TERMINATION_TIMEOUT = 330; // 5.5 minutes
|
||||||
|
const int SSU2_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_MAX_PACKET_SIZE = 1500;
|
||||||
|
const size_t SSU2_MIN_PACKET_SIZE = 1280;
|
||||||
|
const int SSU2_HANDSHAKE_RESEND_INTERVAL = 1000; // in milliseconds
|
||||||
|
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_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;
|
||||||
|
|
||||||
|
// flags
|
||||||
|
const uint8_t SSU2_FLAG_IMMEDIATE_ACK_REQUESTED = 0x01;
|
||||||
|
|
||||||
|
enum SSU2MessageType
|
||||||
|
{
|
||||||
|
eSSU2SessionRequest = 0,
|
||||||
|
eSSU2SessionCreated = 1,
|
||||||
|
eSSU2SessionConfirmed = 2,
|
||||||
|
eSSU2Data = 6,
|
||||||
|
eSSU2PeerTest = 7,
|
||||||
|
eSSU2Retry = 9,
|
||||||
|
eSSU2TokenRequest = 10,
|
||||||
|
eSSU2HolePunch = 11
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SSU2BlockType
|
||||||
|
{
|
||||||
|
eSSU2BlkDateTime = 0,
|
||||||
|
eSSU2BlkOptions, // 1
|
||||||
|
eSSU2BlkRouterInfo, // 2
|
||||||
|
eSSU2BlkI2NPMessage, // 3
|
||||||
|
eSSU2BlkFirstFragment, // 4
|
||||||
|
eSSU2BlkFollowOnFragment, // 5
|
||||||
|
eSSU2BlkTermination, // 6
|
||||||
|
eSSU2BlkRelayRequest, // 7
|
||||||
|
eSSU2BlkRelayResponse, // 8
|
||||||
|
eSSU2BlkRelayIntro, // 9
|
||||||
|
eSSU2BlkPeerTest, // 10
|
||||||
|
eSSU2BlkNextNonce, // 11
|
||||||
|
eSSU2BlkAck, // 12
|
||||||
|
eSSU2BlkAddress, // 13
|
||||||
|
eSSU2BlkIntroKey, // 14
|
||||||
|
eSSU2BlkRelayTagRequest, // 15
|
||||||
|
eSSU2BlkRelayTag, // 16
|
||||||
|
eSSU2BlkNewToken, // 17
|
||||||
|
eSSU2BlkPathChallenge, // 18
|
||||||
|
eSSU2BlkPathResponse, // 19
|
||||||
|
eSSU2BlkFirstPacketNumber, // 20
|
||||||
|
eSSU2BlkPadding = 254
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SSU2SessionState
|
||||||
|
{
|
||||||
|
eSSU2SessionStateUnknown,
|
||||||
|
eSSU2SessionStateTokenReceived,
|
||||||
|
eSSU2SessionStateSessionRequestSent,
|
||||||
|
eSSU2SessionStateSessionRequestReceived,
|
||||||
|
eSSU2SessionStateSessionCreatedSent,
|
||||||
|
eSSU2SessionStateSessionCreatedReceived,
|
||||||
|
eSSU2SessionStateSessionConfirmedSent,
|
||||||
|
eSSU2SessionStateEstablished,
|
||||||
|
eSSU2SessionStateClosing,
|
||||||
|
eSSU2SessionStateClosingConfirmed,
|
||||||
|
eSSU2SessionStateTerminated,
|
||||||
|
eSSU2SessionStateFailed,
|
||||||
|
eSSU2SessionStateIntroduced,
|
||||||
|
eSSU2SessionStatePeerTest,
|
||||||
|
eSSU2SessionStatePeerTestReceived, // 5 before 4
|
||||||
|
eSSU2SessionStateTokenRequestReceived
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SSU2PeerTestCode
|
||||||
|
{
|
||||||
|
eSSU2PeerTestCodeAccept = 0,
|
||||||
|
eSSU2PeerTestCodeBobReasonUnspecified = 1,
|
||||||
|
eSSU2PeerTestCodeBobNoCharlieAvailable = 2,
|
||||||
|
eSSU2PeerTestCodeBobLimitExceeded = 3,
|
||||||
|
eSSU2PeerTestCodeBobSignatureFailure = 4,
|
||||||
|
eSSU2PeerTestCodeCharlieReasonUnspecified = 64,
|
||||||
|
eSSU2PeerTestCodeCharlieUnsupportedAddress = 65,
|
||||||
|
eSSU2PeerTestCodeCharlieLimitExceeded = 66,
|
||||||
|
eSSU2PeerTestCodeCharlieSignatureFailure = 67,
|
||||||
|
eSSU2PeerTestCodeCharlieAliceIsAlreadyConnected = 68,
|
||||||
|
eSSU2PeerTestCodeCharlieAliceIsBanned = 69,
|
||||||
|
eSSU2PeerTestCodeCharlieAliceIsUnknown = 70,
|
||||||
|
eSSU2PeerTestCodeUnspecified = 128
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SSU2RelayResponseCode
|
||||||
|
{
|
||||||
|
eSSU2RelayResponseCodeAccept = 0,
|
||||||
|
eSSU2RelayResponseCodeBobRelayTagNotFound = 5,
|
||||||
|
eSSU2RelayResponseCodeCharlieUnsupportedAddress = 65,
|
||||||
|
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_MAX_PACKET_SIZE];
|
||||||
|
size_t len;
|
||||||
|
bool isLast;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::shared_ptr<I2NPMessage> msg;
|
||||||
|
int nextFragmentNum;
|
||||||
|
uint32_t lastFragmentInsertTime; // in seconds
|
||||||
|
std::map<int, std::shared_ptr<Fragment> > outOfSequenceFragments;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
class SSU2Server;
|
||||||
|
class SSU2Session: public TransportSession, public std::enable_shared_from_this<SSU2Session>
|
||||||
|
{
|
||||||
|
union Header
|
||||||
|
{
|
||||||
|
uint64_t ll[2];
|
||||||
|
uint8_t buf[16];
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint64_t connID;
|
||||||
|
uint32_t packetNum;
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t flags[3];
|
||||||
|
} h;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct 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;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
SSU2Session (SSU2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter = nullptr,
|
||||||
|
std::shared_ptr<const i2p::data::RouterInfo::Address> addr = nullptr);
|
||||||
|
~SSU2Session ();
|
||||||
|
|
||||||
|
void SetRemoteEndpoint (const boost::asio::ip::udp::endpoint& ep) { m_RemoteEndpoint = ep; };
|
||||||
|
const boost::asio::ip::udp::endpoint& GetRemoteEndpoint () const { return m_RemoteEndpoint; };
|
||||||
|
i2p::data::RouterInfo::CompatibleTransports GetRemoteTransports () const { return m_RemoteTransports; };
|
||||||
|
std::shared_ptr<const i2p::data::RouterInfo::Address> GetAddress () const { return m_Address; };
|
||||||
|
void SetOnEstablished (OnEstablished e) { m_OnEstablished = e; };
|
||||||
|
OnEstablished GetOnEstablished () const { return m_OnEstablished; };
|
||||||
|
|
||||||
|
void Connect ();
|
||||||
|
bool Introduce (std::shared_ptr<SSU2Session> session, uint32_t relayTag);
|
||||||
|
void WaitForIntroduction ();
|
||||||
|
void SendPeerTest (); // Alice, Data message
|
||||||
|
void SendKeepAlive ();
|
||||||
|
void RequestTermination (SSU2TerminationReason reason);
|
||||||
|
void CleanUp (uint64_t ts);
|
||||||
|
void FlushData ();
|
||||||
|
void Done () override;
|
||||||
|
void SendLocalRouterInfo (bool update) override;
|
||||||
|
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) override;
|
||||||
|
uint32_t GetRelayTag () const override { return m_RelayTag; };
|
||||||
|
size_t Resend (uint64_t ts); // return number or resent packets
|
||||||
|
bool IsEstablished () const { return m_State == eSSU2SessionStateEstablished; };
|
||||||
|
uint64_t GetConnID () const { return m_SourceConnID; };
|
||||||
|
SSU2SessionState GetState () const { return m_State; };
|
||||||
|
void SetState (SSU2SessionState state) { m_State = state; };
|
||||||
|
|
||||||
|
bool ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len);
|
||||||
|
bool ProcessSessionCreated (uint8_t * buf, size_t len);
|
||||||
|
bool ProcessSessionConfirmed (uint8_t * buf, size_t len);
|
||||||
|
bool ProcessRetry (uint8_t * buf, size_t len);
|
||||||
|
bool ProcessHolePunch (uint8_t * buf, size_t len);
|
||||||
|
bool ProcessPeerTest (uint8_t * buf, size_t len);
|
||||||
|
void ProcessData (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from);
|
||||||
|
|
||||||
|
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 (); // 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);
|
||||||
|
|
||||||
|
void SendSessionRequest (uint64_t token = 0);
|
||||||
|
void SendSessionCreated (const uint8_t * X);
|
||||||
|
void SendSessionConfirmed (const uint8_t * Y);
|
||||||
|
void KDFDataPhase (uint8_t * keydata_ab, uint8_t * keydata_ba);
|
||||||
|
void SendTokenRequest ();
|
||||||
|
void SendRetry ();
|
||||||
|
uint32_t SendData (const uint8_t * buf, size_t len, uint8_t flags = 0); // returns packet num
|
||||||
|
void SendQuickAck ();
|
||||||
|
void SendTermination ();
|
||||||
|
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 SendPathChallenge ();
|
||||||
|
|
||||||
|
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, 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
|
||||||
|
void HandleFirstFragment (const uint8_t * buf, size_t len);
|
||||||
|
void HandleFollowOnFragment (const uint8_t * buf, size_t len);
|
||||||
|
bool ConcatOutOfSequenceFragments (std::shared_ptr<SSU2IncompleteMessage> m); // true if message complete
|
||||||
|
void HandleRelayRequest (const uint8_t * buf, size_t len);
|
||||||
|
void HandleRelayIntro (const uint8_t * buf, size_t len);
|
||||||
|
void HandleRelayResponse (const uint8_t * buf, size_t len);
|
||||||
|
void HandlePeerTest (const uint8_t * buf, size_t len);
|
||||||
|
|
||||||
|
size_t CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep);
|
||||||
|
size_t CreateRouterInfoBlock (uint8_t * buf, size_t len, std::shared_ptr<const i2p::data::RouterInfo> r);
|
||||||
|
size_t CreateAckBlock (uint8_t * buf, size_t len);
|
||||||
|
size_t CreatePaddingBlock (uint8_t * buf, size_t len, size_t minSize = 0);
|
||||||
|
size_t CreateI2NPBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage>&& msg);
|
||||||
|
size_t CreateFirstFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage> msg);
|
||||||
|
size_t CreateFollowOnFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage> msg, uint8_t& fragmentNum, uint32_t msgID);
|
||||||
|
size_t CreateRelayIntroBlock (uint8_t * buf, size_t len, const uint8_t * introData, size_t introDataLen);
|
||||||
|
size_t CreateRelayResponseBlock (uint8_t * buf, size_t len, 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_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
|
||||||
|
uint64_t m_DestConnID, m_SourceConnID;
|
||||||
|
SSU2SessionState m_State;
|
||||||
|
uint8_t m_KeyDataSend[64], m_KeyDataReceive[64];
|
||||||
|
uint32_t m_SendPacketNum, m_ReceivePacketNum;
|
||||||
|
std::set<uint32_t> m_OutOfSequencePackets; // packet nums > receive packet num
|
||||||
|
std::map<uint32_t, std::shared_ptr<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, 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;
|
||||||
|
std::unique_ptr<i2p::data::IdentHash> m_PathChallenge;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline uint64_t CreateHeaderMask (const uint8_t * kh, const uint8_t * nonce)
|
||||||
|
{
|
||||||
|
uint64_t data = 0;
|
||||||
|
i2p::crypto::ChaCha20 ((uint8_t *)&data, 8, kh, nonce, (uint8_t *)&data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,516 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
|
||||||
*
|
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
|
||||||
*
|
|
||||||
* See full license text in LICENSE file at top of project tree
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "Log.h"
|
|
||||||
#include "Timestamp.h"
|
|
||||||
#include "NetDb.hpp"
|
|
||||||
#include "SSU.h"
|
|
||||||
#include "SSUData.h"
|
|
||||||
|
|
||||||
namespace i2p
|
|
||||||
{
|
|
||||||
namespace transport
|
|
||||||
{
|
|
||||||
void IncompleteMessage::AttachNextFragment (const uint8_t * fragment, size_t fragmentSize)
|
|
||||||
{
|
|
||||||
if (msg->len + fragmentSize > msg->maxLen)
|
|
||||||
{
|
|
||||||
LogPrint (eLogWarning, "SSU: I2NP message size ", msg->maxLen, " is not enough");
|
|
||||||
auto newMsg = NewI2NPMessage ();
|
|
||||||
*newMsg = *msg;
|
|
||||||
msg = newMsg;
|
|
||||||
}
|
|
||||||
if (msg->Concat (fragment, fragmentSize) < fragmentSize)
|
|
||||||
LogPrint (eLogError, "SSU: I2NP buffer overflow ", msg->maxLen);
|
|
||||||
nextFragmentNum++;
|
|
||||||
}
|
|
||||||
|
|
||||||
SSUData::SSUData (SSUSession& session):
|
|
||||||
m_Session (session), m_ResendTimer (session.GetService ()),
|
|
||||||
m_MaxPacketSize (session.IsV6 () ? SSU_V6_MAX_PACKET_SIZE : SSU_V4_MAX_PACKET_SIZE),
|
|
||||||
m_PacketSize (m_MaxPacketSize), m_LastMessageReceivedTime (0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
SSUData::~SSUData ()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUData::Start ()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUData::Stop ()
|
|
||||||
{
|
|
||||||
m_ResendTimer.cancel ();
|
|
||||||
m_IncompleteMessages.clear ();
|
|
||||||
m_SentMessages.clear ();
|
|
||||||
m_ReceivedMessages.clear ();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUData::AdjustPacketSize (std::shared_ptr<const i2p::data::RouterInfo> remoteRouter)
|
|
||||||
{
|
|
||||||
if (!remoteRouter) return;
|
|
||||||
auto ssuAddress = remoteRouter->GetSSUAddress ();
|
|
||||||
if (ssuAddress && ssuAddress->ssu->mtu)
|
|
||||||
{
|
|
||||||
if (m_Session.IsV6 ())
|
|
||||||
m_PacketSize = ssuAddress->ssu->mtu - IPV6_HEADER_SIZE - UDP_HEADER_SIZE;
|
|
||||||
else
|
|
||||||
m_PacketSize = ssuAddress->ssu->mtu - IPV4_HEADER_SIZE - UDP_HEADER_SIZE;
|
|
||||||
if (m_PacketSize > 0)
|
|
||||||
{
|
|
||||||
// make sure packet size multiple of 16
|
|
||||||
m_PacketSize >>= 4;
|
|
||||||
m_PacketSize <<= 4;
|
|
||||||
if (m_PacketSize > m_MaxPacketSize) m_PacketSize = m_MaxPacketSize;
|
|
||||||
LogPrint (eLogDebug, "SSU: MTU=", ssuAddress->ssu->mtu, " packet size=", m_PacketSize);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LogPrint (eLogWarning, "SSU: Unexpected MTU ", ssuAddress->ssu->mtu);
|
|
||||||
m_PacketSize = m_MaxPacketSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUData::UpdatePacketSize (const i2p::data::IdentHash& remoteIdent)
|
|
||||||
{
|
|
||||||
auto routerInfo = i2p::data::netdb.FindRouter (remoteIdent);
|
|
||||||
if (routerInfo)
|
|
||||||
AdjustPacketSize (routerInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUData::ProcessSentMessageAck (uint32_t msgID)
|
|
||||||
{
|
|
||||||
auto it = m_SentMessages.find (msgID);
|
|
||||||
if (it != m_SentMessages.end ())
|
|
||||||
{
|
|
||||||
m_SentMessages.erase (it);
|
|
||||||
if (m_SentMessages.empty ())
|
|
||||||
m_ResendTimer.cancel ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUData::ProcessAcks (uint8_t *& buf, uint8_t flag)
|
|
||||||
{
|
|
||||||
if (flag & DATA_FLAG_EXPLICIT_ACKS_INCLUDED)
|
|
||||||
{
|
|
||||||
// explicit ACKs
|
|
||||||
uint8_t numAcks =*buf;
|
|
||||||
buf++;
|
|
||||||
for (int i = 0; i < numAcks; i++)
|
|
||||||
ProcessSentMessageAck (bufbe32toh (buf+i*4));
|
|
||||||
buf += numAcks*4;
|
|
||||||
}
|
|
||||||
if (flag & DATA_FLAG_ACK_BITFIELDS_INCLUDED)
|
|
||||||
{
|
|
||||||
// explicit ACK bitfields
|
|
||||||
uint8_t numBitfields =*buf;
|
|
||||||
buf++;
|
|
||||||
for (int i = 0; i < numBitfields; i++)
|
|
||||||
{
|
|
||||||
uint32_t msgID = bufbe32toh (buf);
|
|
||||||
buf += 4; // msgID
|
|
||||||
auto it = m_SentMessages.find (msgID);
|
|
||||||
// process individual Ack bitfields
|
|
||||||
bool isNonLast = false;
|
|
||||||
int fragment = 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
uint8_t bitfield = *buf;
|
|
||||||
isNonLast = bitfield & 0x80;
|
|
||||||
bitfield &= 0x7F; // clear MSB
|
|
||||||
if (bitfield && it != m_SentMessages.end ())
|
|
||||||
{
|
|
||||||
int numSentFragments = it->second->fragments.size ();
|
|
||||||
// process bits
|
|
||||||
uint8_t mask = 0x01;
|
|
||||||
for (int j = 0; j < 7; j++)
|
|
||||||
{
|
|
||||||
if (bitfield & mask)
|
|
||||||
{
|
|
||||||
if (fragment < numSentFragments)
|
|
||||||
it->second->fragments[fragment] = nullptr;
|
|
||||||
}
|
|
||||||
fragment++;
|
|
||||||
mask <<= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buf++;
|
|
||||||
}
|
|
||||||
while (isNonLast);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUData::ProcessFragments (uint8_t * buf)
|
|
||||||
{
|
|
||||||
uint8_t numFragments = *buf; // number of fragments
|
|
||||||
buf++;
|
|
||||||
for (int i = 0; i < numFragments; i++)
|
|
||||||
{
|
|
||||||
uint32_t msgID = bufbe32toh (buf); // message ID
|
|
||||||
buf += 4;
|
|
||||||
uint8_t frag[4] = {0};
|
|
||||||
memcpy (frag + 1, buf, 3);
|
|
||||||
buf += 3;
|
|
||||||
uint32_t fragmentInfo = bufbe32toh (frag); // fragment info
|
|
||||||
uint16_t fragmentSize = fragmentInfo & 0x3FFF; // bits 0 - 13
|
|
||||||
bool isLast = fragmentInfo & 0x010000; // bit 16
|
|
||||||
uint8_t fragmentNum = fragmentInfo >> 17; // bits 23 - 17
|
|
||||||
if (fragmentSize >= SSU_V4_MAX_PACKET_SIZE)
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "SSU: Fragment size ", fragmentSize, " exceeds max SSU packet size");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find message with msgID
|
|
||||||
auto it = m_IncompleteMessages.find (msgID);
|
|
||||||
if (it == m_IncompleteMessages.end ())
|
|
||||||
{
|
|
||||||
// create new message
|
|
||||||
auto msg = NewI2NPShortMessage ();
|
|
||||||
msg->len -= I2NP_SHORT_HEADER_SIZE;
|
|
||||||
it = m_IncompleteMessages.insert (std::make_pair (msgID,
|
|
||||||
m_Session.GetServer ().GetIncompleteMessagesPool ().AcquireShared (std::move (msg)))).first;
|
|
||||||
}
|
|
||||||
auto& incompleteMessage = it->second;
|
|
||||||
// mark fragment as received
|
|
||||||
if (fragmentNum < 64)
|
|
||||||
incompleteMessage->receivedFragmentsBits |= (uint64_t(0x01) << fragmentNum);
|
|
||||||
else
|
|
||||||
LogPrint (eLogWarning, "SSU: Fragment number ", fragmentNum, " exceeds 64");
|
|
||||||
|
|
||||||
// handle current fragment
|
|
||||||
if (fragmentNum == incompleteMessage->nextFragmentNum)
|
|
||||||
{
|
|
||||||
// expected fragment
|
|
||||||
incompleteMessage->AttachNextFragment (buf, fragmentSize);
|
|
||||||
if (!isLast && !incompleteMessage->savedFragments.empty ())
|
|
||||||
{
|
|
||||||
// try saved fragments
|
|
||||||
for (auto it1 = incompleteMessage->savedFragments.begin (); it1 != incompleteMessage->savedFragments.end ();)
|
|
||||||
{
|
|
||||||
auto& savedFragment = *it1;
|
|
||||||
if (savedFragment->fragmentNum == incompleteMessage->nextFragmentNum)
|
|
||||||
{
|
|
||||||
incompleteMessage->AttachNextFragment (savedFragment->buf, savedFragment->len);
|
|
||||||
isLast = savedFragment->isLast;
|
|
||||||
incompleteMessage->savedFragments.erase (it1++);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (isLast)
|
|
||||||
LogPrint (eLogDebug, "SSU: Message ", msgID, " complete");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (fragmentNum < incompleteMessage->nextFragmentNum)
|
|
||||||
// duplicate fragment
|
|
||||||
LogPrint (eLogWarning, "SSU: Duplicate fragment ", (int)fragmentNum, " of message ", msgID, ", ignored");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// missing fragment
|
|
||||||
LogPrint (eLogWarning, "SSU: Missing fragments from ", (int)incompleteMessage->nextFragmentNum, " to ", fragmentNum - 1, " of message ", msgID);
|
|
||||||
auto savedFragment = m_Session.GetServer ().GetFragmentsPool ().AcquireShared (fragmentNum, buf, fragmentSize, isLast);
|
|
||||||
if (incompleteMessage->savedFragments.insert (savedFragment).second)
|
|
||||||
incompleteMessage->lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch ();
|
|
||||||
else
|
|
||||||
LogPrint (eLogWarning, "SSU: Fragment ", (int)fragmentNum, " of message ", msgID, " already saved");
|
|
||||||
}
|
|
||||||
isLast = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isLast)
|
|
||||||
{
|
|
||||||
// delete incomplete message
|
|
||||||
auto msg = incompleteMessage->msg;
|
|
||||||
incompleteMessage->msg = nullptr;
|
|
||||||
m_IncompleteMessages.erase (msgID);
|
|
||||||
// process message
|
|
||||||
SendMsgAck (msgID);
|
|
||||||
msg->FromSSU (msgID);
|
|
||||||
if (m_Session.GetState () == eSessionStateEstablished)
|
|
||||||
{
|
|
||||||
if (!m_ReceivedMessages.count (msgID))
|
|
||||||
{
|
|
||||||
m_LastMessageReceivedTime = i2p::util::GetSecondsSinceEpoch ();
|
|
||||||
m_ReceivedMessages.emplace (msgID, m_LastMessageReceivedTime);
|
|
||||||
if (!msg->IsExpired ())
|
|
||||||
{
|
|
||||||
m_Handler.PutNextMessage (std::move (msg));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
LogPrint (eLogDebug, "SSU: message expired");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
LogPrint (eLogWarning, "SSU: Message ", msgID, " already received");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// we expect DeliveryStatus
|
|
||||||
if (msg->GetTypeID () == eI2NPDeliveryStatus)
|
|
||||||
{
|
|
||||||
LogPrint (eLogDebug, "SSU: session established");
|
|
||||||
m_Session.Established ();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
LogPrint (eLogError, "SSU: unexpected message ", (int)msg->GetTypeID ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
SendFragmentAck (msgID, incompleteMessage->receivedFragmentsBits);
|
|
||||||
buf += fragmentSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUData::FlushReceivedMessage ()
|
|
||||||
{
|
|
||||||
m_Handler.Flush ();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUData::ProcessMessage (uint8_t * buf, size_t len)
|
|
||||||
{
|
|
||||||
//uint8_t * start = buf;
|
|
||||||
uint8_t flag = *buf;
|
|
||||||
buf++;
|
|
||||||
LogPrint (eLogDebug, "SSU: Process data, flags=", (int)flag, ", len=", len);
|
|
||||||
// process acks if presented
|
|
||||||
if (flag & (DATA_FLAG_ACK_BITFIELDS_INCLUDED | DATA_FLAG_EXPLICIT_ACKS_INCLUDED))
|
|
||||||
ProcessAcks (buf, flag);
|
|
||||||
// extended data if presented
|
|
||||||
if (flag & DATA_FLAG_EXTENDED_DATA_INCLUDED)
|
|
||||||
{
|
|
||||||
uint8_t extendedDataSize = *buf;
|
|
||||||
buf++; // size
|
|
||||||
LogPrint (eLogDebug, "SSU: extended data of ", extendedDataSize, " bytes present");
|
|
||||||
buf += extendedDataSize;
|
|
||||||
}
|
|
||||||
// process data
|
|
||||||
ProcessFragments (buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUData::Send (std::shared_ptr<i2p::I2NPMessage> msg)
|
|
||||||
{
|
|
||||||
uint32_t msgID = msg->ToSSU ();
|
|
||||||
if (m_SentMessages.find (msgID) != m_SentMessages.end())
|
|
||||||
{
|
|
||||||
LogPrint (eLogWarning, "SSU: message ", msgID, " already sent");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (m_SentMessages.empty ()) // schedule resend at first message only
|
|
||||||
ScheduleResend ();
|
|
||||||
|
|
||||||
auto ret = m_SentMessages.emplace (msgID, m_Session.GetServer ().GetSentMessagesPool ().AcquireShared ());
|
|
||||||
auto& sentMessage = ret.first->second;
|
|
||||||
if (ret.second)
|
|
||||||
{
|
|
||||||
sentMessage->nextResendTime = i2p::util::GetSecondsSinceEpoch () + RESEND_INTERVAL;
|
|
||||||
sentMessage->numResends = 0;
|
|
||||||
}
|
|
||||||
auto& fragments = sentMessage->fragments;
|
|
||||||
size_t payloadSize = m_PacketSize - sizeof (SSUHeader) - 9; // 9 = flag + #frg(1) + messageID(4) + frag info (3)
|
|
||||||
size_t len = msg->GetLength ();
|
|
||||||
uint8_t * msgBuf = msg->GetSSUHeader ();
|
|
||||||
|
|
||||||
uint32_t fragmentNum = 0;
|
|
||||||
while (len > 0 && fragmentNum <= 127)
|
|
||||||
{
|
|
||||||
auto fragment = m_Session.GetServer ().GetFragmentsPool ().AcquireShared ();
|
|
||||||
fragment->fragmentNum = fragmentNum;
|
|
||||||
uint8_t * payload = fragment->buf + sizeof (SSUHeader);
|
|
||||||
*payload = DATA_FLAG_WANT_REPLY; // for compatibility
|
|
||||||
payload++;
|
|
||||||
*payload = 1; // always 1 message fragment per message
|
|
||||||
payload++;
|
|
||||||
htobe32buf (payload, msgID);
|
|
||||||
payload += 4;
|
|
||||||
bool isLast = (len <= payloadSize) || fragmentNum == 127; // 127 fragments max
|
|
||||||
size_t size = isLast ? len : payloadSize;
|
|
||||||
uint32_t fragmentInfo = (fragmentNum << 17);
|
|
||||||
if (isLast)
|
|
||||||
fragmentInfo |= 0x010000;
|
|
||||||
|
|
||||||
fragmentInfo |= size;
|
|
||||||
fragmentInfo = htobe32 (fragmentInfo);
|
|
||||||
memcpy (payload, (uint8_t *)(&fragmentInfo) + 1, 3);
|
|
||||||
payload += 3;
|
|
||||||
memcpy (payload, msgBuf, size);
|
|
||||||
|
|
||||||
size += payload - fragment->buf;
|
|
||||||
uint8_t rem = size & 0x0F;
|
|
||||||
if (rem) // make sure 16 bytes boundary
|
|
||||||
{
|
|
||||||
auto padding = 16 - rem;
|
|
||||||
memset (fragment->buf + size, 0, padding);
|
|
||||||
size += padding;
|
|
||||||
}
|
|
||||||
fragment->len = size;
|
|
||||||
fragments.push_back (fragment);
|
|
||||||
|
|
||||||
// encrypt message with session key
|
|
||||||
uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18];
|
|
||||||
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, fragment->buf, size, buf);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
m_Session.Send (buf, size);
|
|
||||||
}
|
|
||||||
catch (boost::system::system_error& ec)
|
|
||||||
{
|
|
||||||
LogPrint (eLogWarning, "SSU: Can't send data fragment ", ec.what ());
|
|
||||||
}
|
|
||||||
if (!isLast)
|
|
||||||
{
|
|
||||||
len -= payloadSize;
|
|
||||||
msgBuf += payloadSize;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
len = 0;
|
|
||||||
fragmentNum++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUData::SendMsgAck (uint32_t msgID)
|
|
||||||
{
|
|
||||||
uint8_t buf[48 + 18] = {0}; // actual length is 44 = 37 + 7 but pad it to multiple of 16
|
|
||||||
uint8_t * payload = buf + sizeof (SSUHeader);
|
|
||||||
*payload = DATA_FLAG_EXPLICIT_ACKS_INCLUDED; // flag
|
|
||||||
payload++;
|
|
||||||
*payload = 1; // number of ACKs
|
|
||||||
payload++;
|
|
||||||
htobe32buf (payload, msgID); // msgID
|
|
||||||
payload += 4;
|
|
||||||
*payload = 0; // number of fragments
|
|
||||||
|
|
||||||
// encrypt message with session key
|
|
||||||
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, 48);
|
|
||||||
m_Session.Send (buf, 48);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUData::SendFragmentAck (uint32_t msgID, uint64_t bits)
|
|
||||||
{
|
|
||||||
if (!bits) return;
|
|
||||||
uint8_t buf[64 + 18] = {0};
|
|
||||||
uint8_t * payload = buf + sizeof (SSUHeader);
|
|
||||||
*payload = DATA_FLAG_ACK_BITFIELDS_INCLUDED; // flag
|
|
||||||
payload++;
|
|
||||||
*payload = 1; // number of ACK bitfields
|
|
||||||
payload++;
|
|
||||||
// one ack
|
|
||||||
*(uint32_t *)(payload) = htobe32 (msgID); // msgID
|
|
||||||
payload += 4;
|
|
||||||
size_t len = 0;
|
|
||||||
while (bits)
|
|
||||||
{
|
|
||||||
*payload = (bits & 0x7F); // next 7 bits
|
|
||||||
bits >>= 7;
|
|
||||||
if (bits) *payload &= 0x80; // 0x80 means non-last
|
|
||||||
payload++; len++;
|
|
||||||
}
|
|
||||||
*payload = 0; // number of fragments
|
|
||||||
len = (len <= 4) ? 48 : 64; // 48 = 37 + 7 + 4
|
|
||||||
// encrypt message with session key
|
|
||||||
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, len);
|
|
||||||
m_Session.Send (buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUData::ScheduleResend()
|
|
||||||
{
|
|
||||||
m_ResendTimer.cancel ();
|
|
||||||
m_ResendTimer.expires_from_now (boost::posix_time::seconds(RESEND_INTERVAL));
|
|
||||||
auto s = m_Session.shared_from_this();
|
|
||||||
m_ResendTimer.async_wait ([s](const boost::system::error_code& ecode)
|
|
||||||
{ s->m_Data.HandleResendTimer (ecode); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUData::HandleResendTimer (const boost::system::error_code& ecode)
|
|
||||||
{
|
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
|
||||||
{
|
|
||||||
uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18];
|
|
||||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
|
||||||
int numResent = 0;
|
|
||||||
for (auto it = m_SentMessages.begin (); it != m_SentMessages.end ();)
|
|
||||||
{
|
|
||||||
if (ts >= it->second->nextResendTime)
|
|
||||||
{
|
|
||||||
if (it->second->numResends < MAX_NUM_RESENDS)
|
|
||||||
{
|
|
||||||
for (auto& f: it->second->fragments)
|
|
||||||
if (f)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, f->buf, f->len, buf);
|
|
||||||
m_Session.Send (buf, f->len); // resend
|
|
||||||
numResent++;
|
|
||||||
}
|
|
||||||
catch (boost::system::system_error& ec)
|
|
||||||
{
|
|
||||||
LogPrint (eLogWarning, "SSU: Can't resend message ", it->first, " data fragment: ", ec.what ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
it->second->numResends++;
|
|
||||||
it->second->nextResendTime += it->second->numResends*RESEND_INTERVAL;
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LogPrint (eLogInfo, "SSU: message ", it->first, " has not been ACKed after ", MAX_NUM_RESENDS, " attempts, deleted");
|
|
||||||
it = m_SentMessages.erase (it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
if (m_SentMessages.empty ()) return; // nothing to resend
|
|
||||||
if (numResent < MAX_OUTGOING_WINDOW_SIZE)
|
|
||||||
ScheduleResend ();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "SSU: resend window exceeds max size. Session terminated");
|
|
||||||
m_Session.Close ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SSUData::CleanUp (uint64_t ts)
|
|
||||||
{
|
|
||||||
for (auto it = m_IncompleteMessages.begin (); it != m_IncompleteMessages.end ();)
|
|
||||||
{
|
|
||||||
if (ts > it->second->lastFragmentInsertTime + INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT)
|
|
||||||
{
|
|
||||||
LogPrint (eLogWarning, "SSU: message ", it->first, " was not completed in ", INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT, " seconds, deleted");
|
|
||||||
it = m_IncompleteMessages.erase (it);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_ReceivedMessages.size () > MAX_NUM_RECEIVED_MESSAGES || ts > m_LastMessageReceivedTime + DECAY_INTERVAL)
|
|
||||||
// decay
|
|
||||||
m_ReceivedMessages.clear ();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// delete old received messages
|
|
||||||
for (auto it = m_ReceivedMessages.begin (); it != m_ReceivedMessages.end ();)
|
|
||||||
{
|
|
||||||
if (ts > it->second + RECEIVED_MESSAGES_CLEANUP_TIMEOUT)
|
|
||||||
it = m_ReceivedMessages.erase (it);
|
|
||||||
else
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
|
||||||
*
|
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
|
||||||
*
|
|
||||||
* See full license text in LICENSE file at top of project tree
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef SSU_DATA_H__
|
|
||||||
#define SSU_DATA_H__
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <memory>
|
|
||||||
#include <boost/asio.hpp>
|
|
||||||
#include "I2NPProtocol.h"
|
|
||||||
#include "Identity.h"
|
|
||||||
#include "RouterInfo.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
|
|
||||||
const int MAX_NUM_RESENDS = 5;
|
|
||||||
const int DECAY_INTERVAL = 20; // in seconds
|
|
||||||
const int INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds
|
|
||||||
const int RECEIVED_MESSAGES_CLEANUP_TIMEOUT = 40; // in seconds
|
|
||||||
const unsigned int MAX_NUM_RECEIVED_MESSAGES = 1000; // how many msgID we store for duplicates check
|
|
||||||
const int MAX_OUTGOING_WINDOW_SIZE = 200; // how many unacked message we can store
|
|
||||||
// data flags
|
|
||||||
const uint8_t DATA_FLAG_EXTENDED_DATA_INCLUDED = 0x02;
|
|
||||||
const uint8_t DATA_FLAG_WANT_REPLY = 0x04;
|
|
||||||
const uint8_t DATA_FLAG_REQUEST_PREVIOUS_ACKS = 0x08;
|
|
||||||
const uint8_t DATA_FLAG_EXPLICIT_CONGESTION_NOTIFICATION = 0x10;
|
|
||||||
const uint8_t DATA_FLAG_ACK_BITFIELDS_INCLUDED = 0x40;
|
|
||||||
const uint8_t DATA_FLAG_EXPLICIT_ACKS_INCLUDED = 0x80;
|
|
||||||
|
|
||||||
struct Fragment
|
|
||||||
{
|
|
||||||
int fragmentNum;
|
|
||||||
size_t len;
|
|
||||||
bool isLast;
|
|
||||||
uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18]; // use biggest
|
|
||||||
|
|
||||||
Fragment () = default;
|
|
||||||
Fragment (int n, const uint8_t * b, int l, bool last):
|
|
||||||
fragmentNum (n), len (l), isLast (last) { memcpy (buf, b, len); };
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FragmentCmp
|
|
||||||
{
|
|
||||||
bool operator() (const std::shared_ptr<Fragment>& f1, const std::shared_ptr<Fragment>& f2) const
|
|
||||||
{
|
|
||||||
return f1->fragmentNum < f2->fragmentNum;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct IncompleteMessage
|
|
||||||
{
|
|
||||||
std::shared_ptr<I2NPMessage> msg;
|
|
||||||
int nextFragmentNum;
|
|
||||||
uint32_t lastFragmentInsertTime; // in seconds
|
|
||||||
uint64_t receivedFragmentsBits;
|
|
||||||
std::set<std::shared_ptr<Fragment>, FragmentCmp> savedFragments;
|
|
||||||
|
|
||||||
IncompleteMessage (std::shared_ptr<I2NPMessage>&& m): msg (m), nextFragmentNum (0),
|
|
||||||
lastFragmentInsertTime (0), receivedFragmentsBits (0) {};
|
|
||||||
void AttachNextFragment (const uint8_t * fragment, size_t fragmentSize);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SentMessage
|
|
||||||
{
|
|
||||||
std::vector<std::shared_ptr<Fragment> > fragments;
|
|
||||||
uint32_t nextResendTime; // in seconds
|
|
||||||
int numResends;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SSUSession;
|
|
||||||
class SSUData
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
SSUData (SSUSession& session);
|
|
||||||
~SSUData ();
|
|
||||||
|
|
||||||
void Start ();
|
|
||||||
void Stop ();
|
|
||||||
void CleanUp (uint64_t ts);
|
|
||||||
|
|
||||||
void ProcessMessage (uint8_t * buf, size_t len);
|
|
||||||
void FlushReceivedMessage ();
|
|
||||||
void Send (std::shared_ptr<i2p::I2NPMessage> msg);
|
|
||||||
|
|
||||||
void AdjustPacketSize (std::shared_ptr<const i2p::data::RouterInfo> remoteRouter);
|
|
||||||
void UpdatePacketSize (const i2p::data::IdentHash& remoteIdent);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void SendMsgAck (uint32_t msgID);
|
|
||||||
void SendFragmentAck (uint32_t msgID, uint64_t bits);
|
|
||||||
void ProcessAcks (uint8_t *& buf, uint8_t flag);
|
|
||||||
void ProcessFragments (uint8_t * buf);
|
|
||||||
void ProcessSentMessageAck (uint32_t msgID);
|
|
||||||
|
|
||||||
void ScheduleResend ();
|
|
||||||
void HandleResendTimer (const boost::system::error_code& ecode);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
SSUSession& m_Session;
|
|
||||||
std::map<uint32_t, std::shared_ptr<IncompleteMessage> > m_IncompleteMessages;
|
|
||||||
std::map<uint32_t, std::shared_ptr<SentMessage> > m_SentMessages;
|
|
||||||
std::unordered_map<uint32_t, uint64_t> m_ReceivedMessages; // msgID -> timestamp in seconds
|
|
||||||
boost::asio::deadline_timer m_ResendTimer;
|
|
||||||
int m_MaxPacketSize, m_PacketSize;
|
|
||||||
i2p::I2NPMessagesHandler m_Handler;
|
|
||||||
uint32_t m_LastMessageReceivedTime; // in second
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,180 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
|
||||||
*
|
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
|
||||||
*
|
|
||||||
* See full license text in LICENSE file at top of project tree
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef SSU_SESSION_H__
|
|
||||||
#define SSU_SESSION_H__
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <set>
|
|
||||||
#include <memory>
|
|
||||||
#include "Crypto.h"
|
|
||||||
#include "I2NPProtocol.h"
|
|
||||||
#include "TransportSession.h"
|
|
||||||
#include "SSUData.h"
|
|
||||||
|
|
||||||
namespace i2p
|
|
||||||
{
|
|
||||||
namespace transport
|
|
||||||
{
|
|
||||||
const uint8_t SSU_HEADER_EXTENDED_OPTIONS_INCLUDED = 0x04;
|
|
||||||
struct SSUHeader
|
|
||||||
{
|
|
||||||
uint8_t mac[16];
|
|
||||||
uint8_t iv[16];
|
|
||||||
uint8_t flag;
|
|
||||||
uint8_t time[4];
|
|
||||||
|
|
||||||
uint8_t GetPayloadType () const { return flag >> 4; };
|
|
||||||
bool IsExtendedOptions () const { return flag & SSU_HEADER_EXTENDED_OPTIONS_INCLUDED; };
|
|
||||||
};
|
|
||||||
|
|
||||||
const int SSU_CONNECT_TIMEOUT = 5; // 5 seconds
|
|
||||||
const int SSU_TERMINATION_TIMEOUT = 330; // 5.5 minutes
|
|
||||||
const int SSU_CLOCK_SKEW = 60; // in seconds
|
|
||||||
const int SSU_CLOCK_THRESHOLD = 15; // in seconds, if more we should adjust
|
|
||||||
const size_t SSU_MAX_I2NP_MESSAGE_SIZE = 32768;
|
|
||||||
|
|
||||||
// payload types (4 bits)
|
|
||||||
const uint8_t PAYLOAD_TYPE_SESSION_REQUEST = 0;
|
|
||||||
const uint8_t PAYLOAD_TYPE_SESSION_CREATED = 1;
|
|
||||||
const uint8_t PAYLOAD_TYPE_SESSION_CONFIRMED = 2;
|
|
||||||
const uint8_t PAYLOAD_TYPE_RELAY_REQUEST = 3;
|
|
||||||
const uint8_t PAYLOAD_TYPE_RELAY_RESPONSE = 4;
|
|
||||||
const uint8_t PAYLOAD_TYPE_RELAY_INTRO = 5;
|
|
||||||
const uint8_t PAYLOAD_TYPE_DATA = 6;
|
|
||||||
const uint8_t PAYLOAD_TYPE_PEER_TEST = 7;
|
|
||||||
const uint8_t PAYLOAD_TYPE_SESSION_DESTROYED = 8;
|
|
||||||
|
|
||||||
// extended options
|
|
||||||
const uint16_t EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG = 0x0001;
|
|
||||||
|
|
||||||
enum SessionState
|
|
||||||
{
|
|
||||||
eSessionStateUnknown,
|
|
||||||
eSessionStateIntroduced,
|
|
||||||
eSessionStateEstablished,
|
|
||||||
eSessionStateClosed,
|
|
||||||
eSessionStateFailed
|
|
||||||
};
|
|
||||||
|
|
||||||
enum PeerTestParticipant
|
|
||||||
{
|
|
||||||
ePeerTestParticipantUnknown = 0,
|
|
||||||
ePeerTestParticipantAlice1,
|
|
||||||
ePeerTestParticipantAlice2,
|
|
||||||
ePeerTestParticipantBob,
|
|
||||||
ePeerTestParticipantCharlie
|
|
||||||
};
|
|
||||||
|
|
||||||
class SSUServer;
|
|
||||||
class SSUSession: public TransportSession, public std::enable_shared_from_this<SSUSession>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint,
|
|
||||||
std::shared_ptr<const i2p::data::RouterInfo> router = nullptr, bool peerTest = false);
|
|
||||||
void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
|
|
||||||
~SSUSession ();
|
|
||||||
|
|
||||||
void Connect ();
|
|
||||||
void WaitForConnect ();
|
|
||||||
void Introduce (const i2p::data::RouterInfo::Introducer& introducer,
|
|
||||||
std::shared_ptr<const i2p::data::RouterInfo> to); // Alice to Charlie
|
|
||||||
void WaitForIntroduction ();
|
|
||||||
void Close ();
|
|
||||||
void Done ();
|
|
||||||
void Failed ();
|
|
||||||
const boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
|
|
||||||
SSUServer& GetServer () { return m_Server; };
|
|
||||||
|
|
||||||
bool IsV6 () const { return m_RemoteEndpoint.address ().is_v6 (); };
|
|
||||||
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
|
|
||||||
void SendPeerTest (); // Alice
|
|
||||||
|
|
||||||
SessionState GetState () const { return m_State; };
|
|
||||||
size_t GetNumSentBytes () const { return m_NumSentBytes; };
|
|
||||||
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
boost::asio::io_service& GetService ();
|
|
||||||
void CreateAESandMacKey (const uint8_t * pubKey);
|
|
||||||
size_t GetSSUHeaderSize (const uint8_t * buf) const;
|
|
||||||
void PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs);
|
|
||||||
void ProcessMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); // call for established session
|
|
||||||
void ProcessSessionRequest (const uint8_t * buf, size_t len);
|
|
||||||
void SendSessionRequest ();
|
|
||||||
void SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer, uint32_t nonce);
|
|
||||||
void ProcessSessionCreated (uint8_t * buf, size_t len);
|
|
||||||
void SendSessionCreated (const uint8_t * x, bool sendRelayTag = true);
|
|
||||||
void ProcessSessionConfirmed (const uint8_t * buf, size_t len);
|
|
||||||
void SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, size_t ourAddressLen);
|
|
||||||
void ProcessRelayRequest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from);
|
|
||||||
void SendRelayResponse (uint32_t nonce, const boost::asio::ip::udp::endpoint& from,
|
|
||||||
const uint8_t * introKey, const boost::asio::ip::udp::endpoint& to);
|
|
||||||
void SendRelayIntro (std::shared_ptr<SSUSession> session, const boost::asio::ip::udp::endpoint& from);
|
|
||||||
void ProcessRelayResponse (const uint8_t * buf, size_t len);
|
|
||||||
void ProcessRelayIntro (const uint8_t * buf, size_t len);
|
|
||||||
void Established ();
|
|
||||||
void ScheduleConnectTimer ();
|
|
||||||
void HandleConnectTimer (const boost::system::error_code& ecode);
|
|
||||||
void ProcessPeerTest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
|
|
||||||
void SendPeerTest (uint32_t nonce, const boost::asio::ip::address& address, uint16_t port, const uint8_t * introKey, bool toAddress = true, bool sendAddress = true);
|
|
||||||
void ProcessData (uint8_t * buf, size_t len);
|
|
||||||
void SendSessionDestroyed ();
|
|
||||||
void Send (uint8_t type, const uint8_t * payload, size_t len); // with session key
|
|
||||||
void Send (const uint8_t * buf, size_t size);
|
|
||||||
|
|
||||||
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey,
|
|
||||||
const uint8_t * iv, const i2p::crypto::MACKey& macKey, uint8_t flag = 0);
|
|
||||||
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len); // with session key
|
|
||||||
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * in, size_t len, uint8_t * out); // with session key
|
|
||||||
void Decrypt (uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey);
|
|
||||||
void DecryptSessionKey (uint8_t * buf, size_t len);
|
|
||||||
bool Validate (uint8_t * buf, size_t len, const i2p::crypto::MACKey& macKey);
|
|
||||||
|
|
||||||
void Reset ();
|
|
||||||
|
|
||||||
static size_t ExtractIPAddressAndPort (const uint8_t * buf, size_t len, boost::asio::ip::address& ip, uint16_t& port); // returns actual buf size
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
friend class SSUData; // TODO: change in later
|
|
||||||
SSUServer& m_Server;
|
|
||||||
const boost::asio::ip::udp::endpoint m_RemoteEndpoint;
|
|
||||||
boost::asio::deadline_timer m_ConnectTimer;
|
|
||||||
bool m_IsPeerTest;
|
|
||||||
SessionState m_State;
|
|
||||||
bool m_IsSessionKey;
|
|
||||||
uint32_t m_RelayTag; // received from peer
|
|
||||||
uint32_t m_SentRelayTag; // sent by us
|
|
||||||
i2p::crypto::CBCEncryption m_SessionKeyEncryption;
|
|
||||||
i2p::crypto::CBCDecryption m_SessionKeyDecryption;
|
|
||||||
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
|
|
||||||
std::map<uint32_t, std::pair <std::shared_ptr<const i2p::data::RouterInfo>, uint64_t > > m_RelayRequests; // nonce->(Charlie, timestamp)
|
|
||||||
std::shared_ptr<i2p::crypto::DHKeys> m_DHKeysPair; // X - for client and Y - for server
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -435,7 +435,7 @@ namespace stream
|
|||||||
LogPrint(eLogError, "Streaming: Packet ", seqn, "sent from the future, sendTime=", sentPacket->sendTime);
|
LogPrint(eLogError, "Streaming: Packet ", seqn, "sent from the future, sendTime=", sentPacket->sendTime);
|
||||||
rtt = 1;
|
rtt = 1;
|
||||||
}
|
}
|
||||||
m_RTT = (m_RTT*seqn + rtt)/(seqn + 1);
|
m_RTT = std::round ((m_RTT*seqn + rtt)/(seqn + 1.0));
|
||||||
m_RTO = m_RTT*1.5; // TODO: implement it better
|
m_RTO = m_RTT*1.5; // TODO: implement it better
|
||||||
LogPrint (eLogDebug, "Streaming: Packet ", seqn, " acknowledged rtt=", rtt, " sentTime=", sentPacket->sendTime);
|
LogPrint (eLogDebug, "Streaming: Packet ", seqn, " acknowledged rtt=", rtt, " sentTime=", sentPacket->sendTime);
|
||||||
m_SentPackets.erase (it++);
|
m_SentPackets.erase (it++);
|
||||||
@@ -474,6 +474,29 @@ namespace stream
|
|||||||
Close (); // check is all outgoing messages have been sent and we can send close
|
Close (); // check is all outgoing messages have been sent and we can send close
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t Stream::Receive (uint8_t * buf, size_t len, int timeout)
|
||||||
|
{
|
||||||
|
if (!len) return 0;
|
||||||
|
size_t ret = 0;
|
||||||
|
std::condition_variable newDataReceived;
|
||||||
|
std::mutex newDataReceivedMutex;
|
||||||
|
std::unique_lock<std::mutex> l(newDataReceivedMutex);
|
||||||
|
AsyncReceive (boost::asio::buffer (buf, len),
|
||||||
|
[&ret, &newDataReceived, &newDataReceivedMutex](const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||||
|
{
|
||||||
|
if (ecode == boost::asio::error::timed_out)
|
||||||
|
ret = 0;
|
||||||
|
else
|
||||||
|
ret = bytes_transferred;
|
||||||
|
std::unique_lock<std::mutex> l(newDataReceivedMutex);
|
||||||
|
newDataReceived.notify_all ();
|
||||||
|
},
|
||||||
|
timeout);
|
||||||
|
if (newDataReceived.wait_for (l, std::chrono::seconds (timeout)) == std::cv_status::timeout)
|
||||||
|
ret = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
size_t Stream::Send (const uint8_t * buf, size_t len)
|
size_t Stream::Send (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
AsyncSend (buf, len, nullptr);
|
AsyncSend (buf, len, nullptr);
|
||||||
@@ -729,7 +752,7 @@ namespace stream
|
|||||||
Terminate ();
|
Terminate ();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LogPrint (eLogWarning, "Streaming: Unexpected stream status ", (int)m_Status, "sSID=", m_SendStreamID);
|
LogPrint (eLogWarning, "Streaming: Unexpected stream status=", (int)m_Status, " for sSID=", m_SendStreamID);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -855,7 +878,7 @@ namespace stream
|
|||||||
for (const auto& it: packets)
|
for (const auto& it: packets)
|
||||||
{
|
{
|
||||||
auto msg = m_RoutingSession->WrapSingleMessage (m_LocalDestination.CreateDataMessage (
|
auto msg = m_RoutingSession->WrapSingleMessage (m_LocalDestination.CreateDataMessage (
|
||||||
it->GetBuffer (), it->GetLength (), m_Port, !m_RoutingSession->IsRatchets ()));
|
it->GetBuffer (), it->GetLength (), m_Port, !m_RoutingSession->IsRatchets (), it->IsSYN ()));
|
||||||
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
||||||
{
|
{
|
||||||
i2p::tunnel::eDeliveryTypeTunnel,
|
i2p::tunnel::eDeliveryTypeTunnel,
|
||||||
@@ -1085,8 +1108,6 @@ namespace stream
|
|||||||
m_Owner (owner), m_LocalPort (localPort), m_Gzip (gzip),
|
m_Owner (owner), m_LocalPort (localPort), m_Gzip (gzip),
|
||||||
m_PendingIncomingTimer (m_Owner->GetService ())
|
m_PendingIncomingTimer (m_Owner->GetService ())
|
||||||
{
|
{
|
||||||
if (m_Gzip)
|
|
||||||
m_Deflator.reset (new i2p::data::GzipDeflator);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamingDestination::~StreamingDestination ()
|
StreamingDestination::~StreamingDestination ()
|
||||||
@@ -1285,7 +1306,13 @@ namespace stream
|
|||||||
auto it = m_Streams.find (recvStreamID);
|
auto it = m_Streams.find (recvStreamID);
|
||||||
if (it == m_Streams.end ())
|
if (it == m_Streams.end ())
|
||||||
return false;
|
return false;
|
||||||
DeleteStream (it->second);
|
auto s = it->second;
|
||||||
|
m_Owner->GetService ().post ([this, s] ()
|
||||||
|
{
|
||||||
|
s->Close (); // try to send FIN
|
||||||
|
s->Terminate (false);
|
||||||
|
DeleteStream (s);
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1335,6 +1362,26 @@ namespace stream
|
|||||||
acceptor (stream);
|
acceptor (stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Stream> StreamingDestination::AcceptStream (int timeout)
|
||||||
|
{
|
||||||
|
std::shared_ptr<i2p::stream::Stream> stream;
|
||||||
|
std::condition_variable streamAccept;
|
||||||
|
std::mutex streamAcceptMutex;
|
||||||
|
std::unique_lock<std::mutex> l(streamAcceptMutex);
|
||||||
|
AcceptOnce (
|
||||||
|
[&streamAccept, &streamAcceptMutex, &stream](std::shared_ptr<i2p::stream::Stream> s)
|
||||||
|
{
|
||||||
|
stream = s;
|
||||||
|
std::unique_lock<std::mutex> l(streamAcceptMutex);
|
||||||
|
streamAccept.notify_all ();
|
||||||
|
});
|
||||||
|
if (timeout)
|
||||||
|
streamAccept.wait_for (l, std::chrono::seconds (timeout));
|
||||||
|
else
|
||||||
|
streamAccept.wait (l);
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
void StreamingDestination::HandlePendingIncomingTimer (const boost::system::error_code& ecode)
|
void StreamingDestination::HandlePendingIncomingTimer (const boost::system::error_code& ecode)
|
||||||
{
|
{
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
@@ -1359,7 +1406,7 @@ namespace stream
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<I2NPMessage> StreamingDestination::CreateDataMessage (
|
std::shared_ptr<I2NPMessage> StreamingDestination::CreateDataMessage (
|
||||||
const uint8_t * payload, size_t len, uint16_t toPort, bool checksum)
|
const uint8_t * payload, size_t len, uint16_t toPort, bool checksum, bool gzip)
|
||||||
{
|
{
|
||||||
size_t size;
|
size_t size;
|
||||||
auto msg = m_I2NPMsgsPool.AcquireShared ();
|
auto msg = m_I2NPMsgsPool.AcquireShared ();
|
||||||
@@ -1367,8 +1414,8 @@ namespace stream
|
|||||||
buf += 4; // reserve for lengthlength
|
buf += 4; // reserve for lengthlength
|
||||||
msg->len += 4;
|
msg->len += 4;
|
||||||
|
|
||||||
if (m_Gzip && m_Deflator)
|
if (m_Gzip || gzip)
|
||||||
size = m_Deflator->Deflate (payload, len, buf, msg->maxLen - msg->len);
|
size = m_Deflator.Deflate (payload, len, buf, msg->maxLen - msg->len);
|
||||||
else
|
else
|
||||||
size = i2p::data::GzipNoCompression (payload, len, buf, msg->maxLen - msg->len);
|
size = i2p::data::GzipNoCompression (payload, len, buf, msg->maxLen - msg->len);
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@@ -185,6 +185,7 @@ namespace stream
|
|||||||
template<typename Buffer, typename ReceiveHandler>
|
template<typename Buffer, typename ReceiveHandler>
|
||||||
void AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout = 0);
|
void AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout = 0);
|
||||||
size_t ReadSome (uint8_t * buf, size_t len) { return ConcatenatePackets (buf, len); };
|
size_t ReadSome (uint8_t * buf, size_t len) { return ConcatenatePackets (buf, len); };
|
||||||
|
size_t Receive (uint8_t * buf, size_t len, int timeout);
|
||||||
|
|
||||||
void AsyncClose() { m_Service.post(std::bind(&Stream::Close, shared_from_this())); };
|
void AsyncClose() { m_Service.post(std::bind(&Stream::Close, shared_from_this())); };
|
||||||
|
|
||||||
@@ -278,13 +279,14 @@ namespace stream
|
|||||||
bool IsAcceptorSet () const { return m_Acceptor != nullptr; };
|
bool IsAcceptorSet () const { return m_Acceptor != nullptr; };
|
||||||
void AcceptOnce (const Acceptor& acceptor);
|
void AcceptOnce (const Acceptor& acceptor);
|
||||||
void AcceptOnceAcceptor (std::shared_ptr<Stream> stream, Acceptor acceptor, Acceptor prev);
|
void AcceptOnceAcceptor (std::shared_ptr<Stream> stream, Acceptor acceptor, Acceptor prev);
|
||||||
|
std::shared_ptr<Stream> AcceptStream (int timeout = 0); // sync
|
||||||
|
|
||||||
std::shared_ptr<i2p::client::ClientDestination> GetOwner () const { return m_Owner; };
|
std::shared_ptr<i2p::client::ClientDestination> GetOwner () const { return m_Owner; };
|
||||||
void SetOwner (std::shared_ptr<i2p::client::ClientDestination> owner) { m_Owner = owner; };
|
void SetOwner (std::shared_ptr<i2p::client::ClientDestination> owner) { m_Owner = owner; };
|
||||||
uint16_t GetLocalPort () const { return m_LocalPort; };
|
uint16_t GetLocalPort () const { return m_LocalPort; };
|
||||||
|
|
||||||
void HandleDataMessagePayload (const uint8_t * buf, size_t len);
|
void HandleDataMessagePayload (const uint8_t * buf, size_t len);
|
||||||
std::shared_ptr<I2NPMessage> CreateDataMessage (const uint8_t * payload, size_t len, uint16_t toPort, bool checksum = true);
|
std::shared_ptr<I2NPMessage> CreateDataMessage (const uint8_t * payload, size_t len, uint16_t toPort, bool checksum = true, bool gzip = false);
|
||||||
|
|
||||||
Packet * NewPacket () { return m_PacketsPool.Acquire(); }
|
Packet * NewPacket () { return m_PacketsPool.Acquire(); }
|
||||||
void DeletePacket (Packet * p) { return m_PacketsPool.Release(p); }
|
void DeletePacket (Packet * p) { return m_PacketsPool.Release(p); }
|
||||||
@@ -315,7 +317,7 @@ namespace stream
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
i2p::data::GzipInflator m_Inflator;
|
i2p::data::GzipInflator m_Inflator;
|
||||||
std::unique_ptr<i2p::data::GzipDeflator> m_Deflator;
|
i2p::data::GzipDeflator m_Deflator;
|
||||||
|
|
||||||
// for HTTP only
|
// for HTTP only
|
||||||
const decltype(m_Streams)& GetStreams () const { return m_Streams; };
|
const decltype(m_Streams)& GetStreams () const { return m_Streams; };
|
||||||
@@ -336,11 +338,10 @@ namespace stream
|
|||||||
int t = (timeout > MAX_RECEIVE_TIMEOUT) ? MAX_RECEIVE_TIMEOUT : timeout;
|
int t = (timeout > MAX_RECEIVE_TIMEOUT) ? MAX_RECEIVE_TIMEOUT : timeout;
|
||||||
s->m_ReceiveTimer.expires_from_now (boost::posix_time::seconds(t));
|
s->m_ReceiveTimer.expires_from_now (boost::posix_time::seconds(t));
|
||||||
int left = timeout - t;
|
int left = timeout - t;
|
||||||
auto self = s->shared_from_this();
|
s->m_ReceiveTimer.async_wait (
|
||||||
self->m_ReceiveTimer.async_wait (
|
[s, buffer, handler, left](const boost::system::error_code & ec)
|
||||||
[self, buffer, handler, left](const boost::system::error_code & ec)
|
|
||||||
{
|
{
|
||||||
self->HandleReceiveTimer(ec, buffer, handler, left);
|
s->HandleReceiveTimer(ec, buffer, handler, left);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ namespace util
|
|||||||
uint32_t GetHoursSinceEpoch ();
|
uint32_t GetHoursSinceEpoch ();
|
||||||
|
|
||||||
void GetCurrentDate (char * date); // returns date as YYYYMMDD string, 9 bytes
|
void GetCurrentDate (char * date); // returns date as YYYYMMDD string, 9 bytes
|
||||||
void GetDateString (uint64_t timestamp, char * date); // timestap is seconds since epoch, returns date as YYYYMMDD string, 9 bytes
|
void GetDateString (uint64_t timestamp, char * date); // timestamp is seconds since epoch, returns date as YYYYMMDD string, 9 bytes
|
||||||
void AdjustTimeOffset (int64_t offset); // in seconds from current
|
void AdjustTimeOffset (int64_t offset); // in seconds from current
|
||||||
|
|
||||||
class NTPTimeSync
|
class NTPTimeSync
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@@ -24,6 +24,10 @@ namespace i2p
|
|||||||
{
|
{
|
||||||
namespace transport
|
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
|
class SignedData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -33,6 +37,12 @@ namespace transport
|
|||||||
{
|
{
|
||||||
m_Stream << other.m_Stream.rdbuf ();
|
m_Stream << other.m_Stream.rdbuf ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Reset ()
|
||||||
|
{
|
||||||
|
m_Stream.str("");
|
||||||
|
}
|
||||||
|
|
||||||
void Insert (const uint8_t * buf, size_t len)
|
void Insert (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
m_Stream.write ((char *)buf, len);
|
m_Stream.write ((char *)buf, len);
|
||||||
@@ -69,6 +79,7 @@ namespace transport
|
|||||||
{
|
{
|
||||||
if (router)
|
if (router)
|
||||||
m_RemoteIdentity = router->GetRouterIdentity ();
|
m_RemoteIdentity = router->GetRouterIdentity ();
|
||||||
|
m_CreationTime = m_LastActivityTimestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~TransportSession () {};
|
virtual ~TransportSession () {};
|
||||||
@@ -96,8 +107,13 @@ namespace transport
|
|||||||
bool IsTerminationTimeoutExpired (uint64_t ts) const
|
bool IsTerminationTimeoutExpired (uint64_t ts) const
|
||||||
{ return ts >= m_LastActivityTimestamp + GetTerminationTimeout (); };
|
{ return ts >= m_LastActivityTimestamp + GetTerminationTimeout (); };
|
||||||
|
|
||||||
virtual void SendLocalRouterInfo () { SendI2NPMessages ({ CreateDatabaseStoreMsg () }); };
|
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;
|
virtual void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) = 0;
|
||||||
|
virtual bool IsEstablished () const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
@@ -107,7 +123,17 @@ namespace transport
|
|||||||
bool m_IsOutgoing;
|
bool m_IsOutgoing;
|
||||||
int m_TerminationTimeout;
|
int m_TerminationTimeout;
|
||||||
uint64_t m_LastActivityTimestamp;
|
uint64_t m_LastActivityTimestamp;
|
||||||
|
uint32_t m_CreationTime; // seconds since epoch
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SOCKS5 proxy
|
||||||
|
const uint8_t SOCKS5_VER = 0x05;
|
||||||
|
const uint8_t SOCKS5_CMD_CONNECT = 0x01;
|
||||||
|
const uint8_t SOCKS5_CMD_UDP_ASSOCIATE = 0x03;
|
||||||
|
const uint8_t SOCKS5_ATYP_IPV4 = 0x01;
|
||||||
|
const uint8_t SOCKS5_ATYP_IPV6 = 0x04;
|
||||||
|
const size_t SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE = 10;
|
||||||
|
const size_t SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE = 22;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -136,12 +136,14 @@ namespace transport
|
|||||||
Transports::Transports ():
|
Transports::Transports ():
|
||||||
m_IsOnline (true), m_IsRunning (false), m_IsNAT (true), m_CheckReserved(true), m_Thread (nullptr),
|
m_IsOnline (true), m_IsRunning (false), m_IsNAT (true), m_CheckReserved(true), m_Thread (nullptr),
|
||||||
m_Service (nullptr), m_Work (nullptr), m_PeerCleanupTimer (nullptr), m_PeerTestTimer (nullptr),
|
m_Service (nullptr), m_Work (nullptr), m_PeerCleanupTimer (nullptr), m_PeerTestTimer (nullptr),
|
||||||
m_SSUServer (nullptr), m_SSU2Server (nullptr), m_NTCP2Server (nullptr),
|
m_UpdateBandwidthTimer (nullptr), m_SSU2Server (nullptr), m_NTCP2Server (nullptr),
|
||||||
m_X25519KeysPairSupplier (15), // 15 pre-generated keys
|
m_X25519KeysPairSupplier (15), // 15 pre-generated keys
|
||||||
m_TotalSentBytes (0), m_TotalReceivedBytes (0), m_TotalTransitTransmittedBytes (0),
|
m_TotalSentBytes (0), m_TotalReceivedBytes (0), m_TotalTransitTransmittedBytes (0),
|
||||||
m_InBandwidth (0), m_OutBandwidth (0), m_TransitBandwidth (0),
|
m_InBandwidth (0), m_OutBandwidth (0), m_TransitBandwidth (0),
|
||||||
m_LastInBandwidthUpdateBytes (0), m_LastOutBandwidthUpdateBytes (0),
|
m_LastInBandwidthUpdateBytes (0), m_LastOutBandwidthUpdateBytes (0), m_LastTransitBandwidthUpdateBytes (0),
|
||||||
m_LastTransitBandwidthUpdateBytes (0), m_LastBandwidthUpdateTime (0)
|
m_InBandwidth15s (0), m_OutBandwidth15s (0), m_TransitBandwidth15s (0),
|
||||||
|
m_LastInBandwidth15sUpdateBytes (0), m_LastOutBandwidth15sUpdateBytes (0), m_LastTransitBandwidth15sUpdateBytes (0),
|
||||||
|
m_LastBandwidth15sUpdateTime (0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,12 +154,13 @@ namespace transport
|
|||||||
{
|
{
|
||||||
delete m_PeerCleanupTimer; m_PeerCleanupTimer = nullptr;
|
delete m_PeerCleanupTimer; m_PeerCleanupTimer = nullptr;
|
||||||
delete m_PeerTestTimer; m_PeerTestTimer = nullptr;
|
delete m_PeerTestTimer; m_PeerTestTimer = nullptr;
|
||||||
|
delete m_UpdateBandwidthTimer; m_UpdateBandwidthTimer = nullptr;
|
||||||
delete m_Work; m_Work = nullptr;
|
delete m_Work; m_Work = nullptr;
|
||||||
delete m_Service; m_Service = nullptr;
|
delete m_Service; m_Service = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::Start (bool enableNTCP2, bool enableSSU, bool enableSSU2)
|
void Transports::Start (bool enableNTCP2, bool enableSSU2)
|
||||||
{
|
{
|
||||||
if (!m_Service)
|
if (!m_Service)
|
||||||
{
|
{
|
||||||
@@ -165,8 +168,11 @@ namespace transport
|
|||||||
m_Work = new boost::asio::io_service::work (*m_Service);
|
m_Work = new boost::asio::io_service::work (*m_Service);
|
||||||
m_PeerCleanupTimer = new boost::asio::deadline_timer (*m_Service);
|
m_PeerCleanupTimer = new boost::asio::deadline_timer (*m_Service);
|
||||||
m_PeerTestTimer = new boost::asio::deadline_timer (*m_Service);
|
m_PeerTestTimer = new boost::asio::deadline_timer (*m_Service);
|
||||||
|
m_UpdateBandwidthTimer = new boost::asio::steady_timer (*m_Service);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
|
||||||
|
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
|
||||||
i2p::config::GetOption("nat", m_IsNAT);
|
i2p::config::GetOption("nat", m_IsNAT);
|
||||||
m_X25519KeysPairSupplier.Start ();
|
m_X25519KeysPairSupplier.Start ();
|
||||||
m_IsRunning = true;
|
m_IsRunning = true;
|
||||||
@@ -190,6 +196,8 @@ namespace transport
|
|||||||
|
|
||||||
m_NTCP2Server->UseProxy(proxytype, proxyurl.host, proxyurl.port, proxyurl.user, proxyurl.pass);
|
m_NTCP2Server->UseProxy(proxytype, proxyurl.host, proxyurl.port, proxyurl.user, proxyurl.pass);
|
||||||
i2p::context.SetStatus (eRouterStatusProxy);
|
i2p::context.SetStatus (eRouterStatusProxy);
|
||||||
|
if (ipv6)
|
||||||
|
i2p::context.SetStatusV6 (eRouterStatusProxy);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint(eLogError, "Transports: Unsupported NTCP2 proxy URL ", ntcp2proxy);
|
LogPrint(eLogError, "Transports: Unsupported NTCP2 proxy URL ", ntcp2proxy);
|
||||||
@@ -201,27 +209,30 @@ namespace transport
|
|||||||
m_NTCP2Server = new NTCP2Server ();
|
m_NTCP2Server = new NTCP2Server ();
|
||||||
}
|
}
|
||||||
|
|
||||||
// create SSU server
|
|
||||||
int ssuPort = 0;
|
|
||||||
if (enableSSU)
|
|
||||||
{
|
|
||||||
auto& addresses = context.GetRouterInfo ().GetAddresses ();
|
|
||||||
for (const auto& address: addresses)
|
|
||||||
{
|
|
||||||
if (!address) continue;
|
|
||||||
if (address->transportStyle == RouterInfo::eTransportSSU)
|
|
||||||
{
|
|
||||||
ssuPort = address->port;
|
|
||||||
m_SSUServer = new SSUServer (address->port);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// create SSU2 server
|
// create SSU2 server
|
||||||
if (enableSSU2) m_SSU2Server = new SSU2Server ();
|
if (enableSSU2)
|
||||||
|
{
|
||||||
|
m_SSU2Server = new SSU2Server ();
|
||||||
|
std::string ssu2proxy; i2p::config::GetOption("ssu2.proxy", ssu2proxy);
|
||||||
|
if (!ssu2proxy.empty())
|
||||||
|
{
|
||||||
|
if (proxyurl.parse (ssu2proxy) && proxyurl.schema == "socks")
|
||||||
|
{
|
||||||
|
if (m_SSU2Server->SetProxy (proxyurl.host, proxyurl.port))
|
||||||
|
{
|
||||||
|
i2p::context.SetStatus (eRouterStatusProxy);
|
||||||
|
if (ipv6)
|
||||||
|
i2p::context.SetStatusV6 (eRouterStatusProxy);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint(eLogError, "Transports: Can't set SSU2 proxy ", ssu2proxy);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint(eLogError, "Transports: Invalid SSU2 proxy URL ", ssu2proxy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// bind to interfaces
|
// bind to interfaces
|
||||||
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
|
|
||||||
if (ipv4)
|
if (ipv4)
|
||||||
{
|
{
|
||||||
std::string address; i2p::config::GetOption("address4", address);
|
std::string address; i2p::config::GetOption("address4", address);
|
||||||
@@ -232,12 +243,22 @@ namespace transport
|
|||||||
if (!ec)
|
if (!ec)
|
||||||
{
|
{
|
||||||
if (m_NTCP2Server) m_NTCP2Server->SetLocalAddress (addr);
|
if (m_NTCP2Server) m_NTCP2Server->SetLocalAddress (addr);
|
||||||
if (m_SSUServer) m_SSUServer->SetLocalAddress (addr);
|
if (m_SSU2Server) m_SSU2Server->SetLocalAddress (addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enableSSU2)
|
||||||
|
{
|
||||||
|
uint16_t mtu; i2p::config::GetOption ("ssu2.mtu4", mtu);
|
||||||
|
if (mtu)
|
||||||
|
{
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
|
|
||||||
if (ipv6)
|
if (ipv6)
|
||||||
{
|
{
|
||||||
std::string address; i2p::config::GetOption("address6", address);
|
std::string address; i2p::config::GetOption("address6", address);
|
||||||
@@ -248,7 +269,18 @@ namespace transport
|
|||||||
if (!ec)
|
if (!ec)
|
||||||
{
|
{
|
||||||
if (m_NTCP2Server) m_NTCP2Server->SetLocalAddress (addr);
|
if (m_NTCP2Server) m_NTCP2Server->SetLocalAddress (addr);
|
||||||
if (m_SSUServer) m_SSUServer->SetLocalAddress (addr);
|
if (m_SSU2Server) m_SSU2Server->SetLocalAddress (addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enableSSU2)
|
||||||
|
{
|
||||||
|
uint16_t mtu; i2p::config::GetOption ("ssu2.mtu6", mtu);
|
||||||
|
if (mtu)
|
||||||
|
{
|
||||||
|
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, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -268,27 +300,15 @@ namespace transport
|
|||||||
|
|
||||||
// start servers
|
// start servers
|
||||||
if (m_NTCP2Server) m_NTCP2Server->Start ();
|
if (m_NTCP2Server) m_NTCP2Server->Start ();
|
||||||
if (m_SSUServer)
|
|
||||||
{
|
|
||||||
LogPrint (eLogInfo, "Transports: Start listening UDP port ", ssuPort);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
m_SSUServer->Start ();
|
|
||||||
}
|
|
||||||
catch (std::exception& ex )
|
|
||||||
{
|
|
||||||
LogPrint(eLogError, "Transports: Failed to bind to UDP port", ssuPort);
|
|
||||||
m_SSUServer->Stop ();
|
|
||||||
delete m_SSUServer;
|
|
||||||
m_SSUServer = nullptr;
|
|
||||||
}
|
|
||||||
if (m_SSUServer) DetectExternalIP ();
|
|
||||||
}
|
|
||||||
if (m_SSU2Server) m_SSU2Server->Start ();
|
if (m_SSU2Server) m_SSU2Server->Start ();
|
||||||
|
if (m_SSU2Server) DetectExternalIP ();
|
||||||
|
|
||||||
m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(5 * SESSION_CREATION_TIMEOUT));
|
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));
|
m_PeerCleanupTimer->async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1));
|
||||||
|
|
||||||
|
m_UpdateBandwidthTimer->expires_from_now (std::chrono::seconds(1));
|
||||||
|
m_UpdateBandwidthTimer->async_wait (std::bind (&Transports::HandleUpdateBandwidthTimer, this, std::placeholders::_1));
|
||||||
|
|
||||||
if (m_IsNAT)
|
if (m_IsNAT)
|
||||||
{
|
{
|
||||||
m_PeerTestTimer->expires_from_now (boost::posix_time::minutes(PEER_TEST_INTERVAL));
|
m_PeerTestTimer->expires_from_now (boost::posix_time::minutes(PEER_TEST_INTERVAL));
|
||||||
@@ -301,12 +321,6 @@ namespace transport
|
|||||||
if (m_PeerCleanupTimer) m_PeerCleanupTimer->cancel ();
|
if (m_PeerCleanupTimer) m_PeerCleanupTimer->cancel ();
|
||||||
if (m_PeerTestTimer) m_PeerTestTimer->cancel ();
|
if (m_PeerTestTimer) m_PeerTestTimer->cancel ();
|
||||||
m_Peers.clear ();
|
m_Peers.clear ();
|
||||||
if (m_SSUServer)
|
|
||||||
{
|
|
||||||
m_SSUServer->Stop ();
|
|
||||||
delete m_SSUServer;
|
|
||||||
m_SSUServer = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_SSU2Server)
|
if (m_SSU2Server)
|
||||||
{
|
{
|
||||||
@@ -350,29 +364,44 @@ namespace transport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::UpdateBandwidth ()
|
void Transports::HandleUpdateBandwidthTimer (const boost::system::error_code& ecode)
|
||||||
|
{
|
||||||
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
{
|
{
|
||||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
|
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
if (m_LastBandwidthUpdateTime > 0)
|
|
||||||
{
|
// updated every second
|
||||||
auto delta = ts - m_LastBandwidthUpdateTime;
|
m_InBandwidth = m_TotalReceivedBytes - m_LastInBandwidthUpdateBytes;
|
||||||
if (delta > 0)
|
m_OutBandwidth = m_TotalSentBytes - m_LastOutBandwidthUpdateBytes;
|
||||||
{
|
m_TransitBandwidth = m_TotalTransitTransmittedBytes - m_LastTransitBandwidthUpdateBytes;
|
||||||
m_InBandwidth = (m_TotalReceivedBytes - m_LastInBandwidthUpdateBytes)*1000/delta; // per second
|
|
||||||
m_OutBandwidth = (m_TotalSentBytes - m_LastOutBandwidthUpdateBytes)*1000/delta; // per second
|
|
||||||
m_TransitBandwidth = (m_TotalTransitTransmittedBytes - m_LastTransitBandwidthUpdateBytes)*1000/delta;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_LastBandwidthUpdateTime = ts;
|
|
||||||
m_LastInBandwidthUpdateBytes = m_TotalReceivedBytes;
|
m_LastInBandwidthUpdateBytes = m_TotalReceivedBytes;
|
||||||
m_LastOutBandwidthUpdateBytes = m_TotalSentBytes;
|
m_LastOutBandwidthUpdateBytes = m_TotalSentBytes;
|
||||||
m_LastTransitBandwidthUpdateBytes = m_TotalTransitTransmittedBytes;
|
m_LastTransitBandwidthUpdateBytes = m_TotalTransitTransmittedBytes;
|
||||||
|
|
||||||
|
// updated every 15 seconds
|
||||||
|
auto delta = ts - m_LastBandwidth15sUpdateTime;
|
||||||
|
if (delta > 15 * 1000)
|
||||||
|
{
|
||||||
|
m_InBandwidth15s = (m_TotalReceivedBytes - m_LastInBandwidth15sUpdateBytes) * 1000 / delta;
|
||||||
|
m_OutBandwidth15s = (m_TotalSentBytes - m_LastOutBandwidth15sUpdateBytes) * 1000 / delta;
|
||||||
|
m_TransitBandwidth15s = (m_TotalTransitTransmittedBytes - m_LastTransitBandwidth15sUpdateBytes) * 1000 / delta;
|
||||||
|
|
||||||
|
m_LastBandwidth15sUpdateTime = ts;
|
||||||
|
m_LastInBandwidth15sUpdateBytes = m_TotalReceivedBytes;
|
||||||
|
m_LastOutBandwidth15sUpdateBytes = m_TotalSentBytes;
|
||||||
|
m_LastTransitBandwidth15sUpdateBytes = m_TotalTransitTransmittedBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_UpdateBandwidthTimer->expires_from_now (std::chrono::seconds(1));
|
||||||
|
m_UpdateBandwidthTimer->async_wait (std::bind (&Transports::HandleUpdateBandwidthTimer, this, std::placeholders::_1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Transports::IsBandwidthExceeded () const
|
bool Transports::IsBandwidthExceeded () const
|
||||||
{
|
{
|
||||||
auto limit = i2p::context.GetBandwidthLimit() * 1024; // convert to bytes
|
auto limit = i2p::context.GetBandwidthLimit() * 1024; // convert to bytes
|
||||||
auto bw = std::max (m_InBandwidth, m_OutBandwidth);
|
auto bw = std::max (m_InBandwidth15s, m_OutBandwidth15s);
|
||||||
return bw > limit;
|
return bw > limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,9 +442,9 @@ namespace transport
|
|||||||
auto r = netdb.FindRouter (ident);
|
auto r = netdb.FindRouter (ident);
|
||||||
if (r && (r->IsUnreachable () || !r->IsReachableFrom (i2p::context.GetRouterInfo ()))) return; // router found but non-reachable
|
if (r && (r->IsUnreachable () || !r->IsReachableFrom (i2p::context.GetRouterInfo ()))) return; // router found but non-reachable
|
||||||
{
|
{
|
||||||
|
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||||
it = m_Peers.insert (std::pair<i2p::data::IdentHash, Peer>(ident, { 0, r, {},
|
it = m_Peers.insert (std::pair<i2p::data::IdentHash, Peer>(ident, {r, ts})).first;
|
||||||
i2p::util::GetSecondsSinceEpoch (), {} })).first;
|
|
||||||
}
|
}
|
||||||
connected = ConnectToPeer (ident, it->second);
|
connected = ConnectToPeer (ident, it->second);
|
||||||
}
|
}
|
||||||
@@ -450,31 +479,22 @@ namespace transport
|
|||||||
peer.router = netdb.FindRouter (ident); // try to get new one from netdb
|
peer.router = netdb.FindRouter (ident); // try to get new one from netdb
|
||||||
if (peer.router) // we have RI already
|
if (peer.router) // we have RI already
|
||||||
{
|
{
|
||||||
if (peer.numAttempts < 2) // NTCP2, 0 - ipv6, 1- ipv4
|
if (peer.priority.empty ())
|
||||||
|
SetPriority (peer);
|
||||||
|
while (peer.numAttempts < (int)peer.priority.size ())
|
||||||
{
|
{
|
||||||
if (m_NTCP2Server) // we support NTCP2
|
auto tr = peer.priority[peer.numAttempts];
|
||||||
|
peer.numAttempts++;
|
||||||
|
switch (tr)
|
||||||
{
|
{
|
||||||
std::shared_ptr<const RouterInfo::Address> address;
|
case i2p::data::RouterInfo::eNTCP2V4:
|
||||||
if (!peer.numAttempts) // NTCP2 ipv6
|
case i2p::data::RouterInfo::eNTCP2V6:
|
||||||
{
|
{
|
||||||
if (context.GetRouterInfo ().IsNTCP2V6 () && peer.router->IsReachableBy (RouterInfo::eNTCP2V6))
|
if (!m_NTCP2Server) continue;
|
||||||
{
|
std::shared_ptr<const RouterInfo::Address> address = (tr == i2p::data::RouterInfo::eNTCP2V6) ?
|
||||||
address = peer.router->GetPublishedNTCP2V6Address ();
|
peer.router->GetPublishedNTCP2V6Address () : peer.router->GetPublishedNTCP2V4Address ();
|
||||||
if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host))
|
if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host))
|
||||||
address = nullptr;
|
address = nullptr;
|
||||||
}
|
|
||||||
peer.numAttempts++;
|
|
||||||
}
|
|
||||||
if (!address && peer.numAttempts == 1) // NTCP2 ipv4
|
|
||||||
{
|
|
||||||
if (context.GetRouterInfo ().IsNTCP2 (true) && peer.router->IsReachableBy (RouterInfo::eNTCP2V4))
|
|
||||||
{
|
|
||||||
address = peer.router->GetPublishedNTCP2V4Address ();
|
|
||||||
if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host))
|
|
||||||
address = nullptr;
|
|
||||||
}
|
|
||||||
peer.numAttempts++;
|
|
||||||
}
|
|
||||||
if (address)
|
if (address)
|
||||||
{
|
{
|
||||||
auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router, address);
|
auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router, address);
|
||||||
@@ -484,49 +504,26 @@ namespace transport
|
|||||||
m_NTCP2Server->Connect (s);
|
m_NTCP2Server->Connect (s);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
case i2p::data::RouterInfo::eSSU2V4:
|
||||||
peer.numAttempts = 2; // switch to SSU
|
case i2p::data::RouterInfo::eSSU2V6:
|
||||||
}
|
|
||||||
if (peer.numAttempts == 2 || peer.numAttempts == 3) // SSU
|
|
||||||
{
|
{
|
||||||
if (m_SSUServer)
|
if (!m_SSU2Server) continue;
|
||||||
{
|
std::shared_ptr<const RouterInfo::Address> address = (tr == i2p::data::RouterInfo::eSSU2V6) ?
|
||||||
std::shared_ptr<const RouterInfo::Address> address;
|
peer.router->GetSSU2V6Address () : peer.router->GetSSU2V4Address ();
|
||||||
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))
|
if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host))
|
||||||
address = nullptr;
|
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 (address && address->IsReachableSSU ())
|
||||||
{
|
{
|
||||||
if (m_SSUServer->CreateSession (peer.router, address))
|
if (m_SSU2Server->CreateSession (peer.router, address))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
case i2p::data::RouterInfo::eNTCP2V6Mesh:
|
||||||
peer.numAttempts += 2; // switch to Mesh
|
|
||||||
}
|
|
||||||
if (peer.numAttempts == 4) // Mesh
|
|
||||||
{
|
|
||||||
peer.numAttempts++;
|
|
||||||
if (m_NTCP2Server && context.GetRouterInfo ().IsMesh () && peer.router->IsMesh ())
|
|
||||||
{
|
{
|
||||||
|
if (!m_NTCP2Server) continue;
|
||||||
auto address = peer.router->GetYggdrasilAddress ();
|
auto address = peer.router->GetYggdrasilAddress ();
|
||||||
if (address)
|
if (address)
|
||||||
{
|
{
|
||||||
@@ -534,43 +531,14 @@ namespace transport
|
|||||||
m_NTCP2Server->Connect (s);
|
m_NTCP2Server->Connect (s);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
LogPrint (eLogError, "Transports: Unknown transport ", (int)tr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (peer.numAttempts == 5 || peer.numAttempts == 6) // SSU2
|
|
||||||
{
|
LogPrint (eLogInfo, "Transports: No compatible addresses available");
|
||||||
if (m_SSU2Server)
|
|
||||||
{
|
|
||||||
std::shared_ptr<const RouterInfo::Address> address;
|
|
||||||
if (peer.numAttempts == 5) // SSU2 ipv6
|
|
||||||
{
|
|
||||||
if (context.GetRouterInfo ().IsSSU2V6 () && peer.router->IsReachableBy (RouterInfo::eSSU2V6))
|
|
||||||
{
|
|
||||||
address = peer.router->GetSSU2V6Address ();
|
|
||||||
if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host))
|
|
||||||
address = nullptr;
|
|
||||||
}
|
|
||||||
peer.numAttempts++;
|
|
||||||
}
|
|
||||||
if (!address && peer.numAttempts == 6) // SSU2 ipv4
|
|
||||||
{
|
|
||||||
if (context.GetRouterInfo ().IsSSU2V4 () && peer.router->IsReachableBy (RouterInfo::eSSU2V4))
|
|
||||||
{
|
|
||||||
address = peer.router->GetSSU2V4Address ();
|
|
||||||
if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host))
|
|
||||||
address = nullptr;
|
|
||||||
}
|
|
||||||
peer.numAttempts++;
|
|
||||||
}
|
|
||||||
if (address && address->IsReachableSSU ())
|
|
||||||
{
|
|
||||||
if (m_SSU2Server->CreateSession (peer.router, address))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
peer.numAttempts += 2;
|
|
||||||
}
|
|
||||||
LogPrint (eLogInfo, "Transports: No compatble NTCP2 or SSU addresses available");
|
|
||||||
i2p::data::netdb.SetUnreachable (ident, true); // we are here because all connection attempts failed
|
i2p::data::netdb.SetUnreachable (ident, true); // we are here because all connection attempts failed
|
||||||
peer.Done ();
|
peer.Done ();
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||||
@@ -586,6 +554,37 @@ namespace transport
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Transports::SetPriority (Peer& peer) const
|
||||||
|
{
|
||||||
|
static const std::vector<i2p::data::RouterInfo::SupportedTransports>
|
||||||
|
ntcp2Priority =
|
||||||
|
{
|
||||||
|
i2p::data::RouterInfo::eNTCP2V6,
|
||||||
|
i2p::data::RouterInfo::eNTCP2V4,
|
||||||
|
i2p::data::RouterInfo::eSSU2V6,
|
||||||
|
i2p::data::RouterInfo::eSSU2V4,
|
||||||
|
i2p::data::RouterInfo::eNTCP2V6Mesh
|
||||||
|
},
|
||||||
|
ssu2Priority =
|
||||||
|
{
|
||||||
|
i2p::data::RouterInfo::eSSU2V6,
|
||||||
|
i2p::data::RouterInfo::eSSU2V4,
|
||||||
|
i2p::data::RouterInfo::eNTCP2V6,
|
||||||
|
i2p::data::RouterInfo::eNTCP2V4,
|
||||||
|
i2p::data::RouterInfo::eNTCP2V6Mesh
|
||||||
|
};
|
||||||
|
if (!peer.router) return;
|
||||||
|
auto compatibleTransports = context.GetRouterInfo ().GetCompatibleTransports (false) &
|
||||||
|
peer.router->GetCompatibleTransports (true);
|
||||||
|
peer.numAttempts = 0;
|
||||||
|
peer.priority.clear ();
|
||||||
|
bool ssu2 = rand () & 1;
|
||||||
|
const auto& priority = ssu2 ? ssu2Priority : ntcp2Priority;
|
||||||
|
for (auto transport: priority)
|
||||||
|
if (transport & compatibleTransports)
|
||||||
|
peer.priority.push_back (transport);
|
||||||
|
}
|
||||||
|
|
||||||
void Transports::RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident)
|
void Transports::RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident)
|
||||||
{
|
{
|
||||||
m_Service->post (std::bind (&Transports::HandleRequestComplete, this, r, ident));
|
m_Service->post (std::bind (&Transports::HandleRequestComplete, this, r, ident));
|
||||||
@@ -619,40 +618,32 @@ namespace transport
|
|||||||
i2p::context.SetStatus (eRouterStatusOK);
|
i2p::context.SetStatus (eRouterStatusOK);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_SSUServer)
|
if (m_SSU2Server)
|
||||||
PeerTest ();
|
PeerTest ();
|
||||||
else
|
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)
|
void Transports::PeerTest (bool ipv4, bool ipv6)
|
||||||
{
|
{
|
||||||
if (RoutesRestricted() || !m_SSUServer) return;
|
if (RoutesRestricted() || !m_SSU2Server || m_SSU2Server->UsesProxy ()) return;
|
||||||
if (ipv4 && i2p::context.SupportsV4 ())
|
if (ipv4 && i2p::context.SupportsV4 ())
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "Transports: Started peer test IPv4");
|
LogPrint (eLogInfo, "Transports: Started peer test IPv4");
|
||||||
std::set<i2p::data::IdentHash> excluded;
|
std::set<i2p::data::IdentHash> excluded;
|
||||||
excluded.insert (i2p::context.GetIdentHash ()); // don't pick own router
|
excluded.insert (i2p::context.GetIdentHash ()); // don't pick own router
|
||||||
bool statusChanged = false;
|
|
||||||
for (int i = 0; i < 5; i++)
|
for (int i = 0; i < 5; i++)
|
||||||
{
|
{
|
||||||
auto router = i2p::data::netdb.GetRandomPeerTestRouter (true, excluded); // v4
|
auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (true, excluded); // v4
|
||||||
if (router)
|
if (router)
|
||||||
{
|
{
|
||||||
auto addr = router->GetSSUAddress (true); // ipv4
|
if (i2p::context.GetStatus () != eRouterStatusTesting)
|
||||||
if (addr && !i2p::util::net::IsInReservedRange(addr->host))
|
i2p::context.SetStatus (eRouterStatusTesting);
|
||||||
{
|
m_SSU2Server->StartPeerTest (router, true);
|
||||||
if (!statusChanged)
|
|
||||||
{
|
|
||||||
statusChanged = true;
|
|
||||||
i2p::context.SetStatus (eRouterStatusTesting); // first time only
|
|
||||||
}
|
|
||||||
m_SSUServer->CreateSession (router, addr, true); // peer test v4
|
|
||||||
}
|
|
||||||
excluded.insert (router->GetIdentHash ());
|
excluded.insert (router->GetIdentHash ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!statusChanged)
|
if (excluded.size () <= 1)
|
||||||
LogPrint (eLogWarning, "Transports: Can't find routers for peer test IPv4");
|
LogPrint (eLogWarning, "Transports: Can't find routers for peer test IPv4");
|
||||||
}
|
}
|
||||||
if (ipv6 && i2p::context.SupportsV6 ())
|
if (ipv6 && i2p::context.SupportsV6 ())
|
||||||
@@ -660,26 +651,18 @@ namespace transport
|
|||||||
LogPrint (eLogInfo, "Transports: Started peer test IPv6");
|
LogPrint (eLogInfo, "Transports: Started peer test IPv6");
|
||||||
std::set<i2p::data::IdentHash> excluded;
|
std::set<i2p::data::IdentHash> excluded;
|
||||||
excluded.insert (i2p::context.GetIdentHash ()); // don't pick own router
|
excluded.insert (i2p::context.GetIdentHash ()); // don't pick own router
|
||||||
bool statusChanged = false;
|
|
||||||
for (int i = 0; i < 5; i++)
|
for (int i = 0; i < 5; i++)
|
||||||
{
|
{
|
||||||
auto router = i2p::data::netdb.GetRandomPeerTestRouter (false, excluded); // v6
|
auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (false, excluded); // v6
|
||||||
if (router)
|
if (router)
|
||||||
{
|
{
|
||||||
auto addr = router->GetSSUV6Address ();
|
if (i2p::context.GetStatusV6 () != eRouterStatusTesting)
|
||||||
if (addr && !i2p::util::net::IsInReservedRange(addr->host))
|
i2p::context.SetStatusV6 (eRouterStatusTesting);
|
||||||
{
|
m_SSU2Server->StartPeerTest (router, false);
|
||||||
if (!statusChanged)
|
|
||||||
{
|
|
||||||
statusChanged = true;
|
|
||||||
i2p::context.SetStatusV6 (eRouterStatusTesting); // first time only
|
|
||||||
}
|
|
||||||
m_SSUServer->CreateSession (router, addr, true); // peer test v6
|
|
||||||
}
|
|
||||||
excluded.insert (router->GetIdentHash ());
|
excluded.insert (router->GetIdentHash ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!statusChanged)
|
if (excluded.size () <= 1)
|
||||||
LogPrint (eLogWarning, "Transports: Can't find routers for peer test IPv6");
|
LogPrint (eLogWarning, "Transports: Can't find routers for peer test IPv6");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -731,8 +714,9 @@ namespace transport
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
session->SendI2NPMessages ({ CreateDatabaseStoreMsg () }); // send DatabaseStore
|
session->SendI2NPMessages ({ CreateDatabaseStoreMsg () }); // send DatabaseStore
|
||||||
|
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||||
m_Peers.insert (std::make_pair (ident, Peer{ 0, nullptr, { session }, i2p::util::GetSecondsSinceEpoch (), {} }));
|
m_Peers.insert (std::make_pair (ident, Peer{ nullptr, ts }));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -781,6 +765,11 @@ namespace transport
|
|||||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
for (auto it = m_Peers.begin (); it != m_Peers.end (); )
|
for (auto it = m_Peers.begin (); it != m_Peers.end (); )
|
||||||
{
|
{
|
||||||
|
it->second.sessions.remove_if (
|
||||||
|
[](std::shared_ptr<TransportSession> session)->bool
|
||||||
|
{
|
||||||
|
return !session || !session->IsEstablished ();
|
||||||
|
});
|
||||||
if (it->second.sessions.empty () && ts > it->second.creationTime + SESSION_CREATION_TIMEOUT)
|
if (it->second.sessions.empty () && ts > it->second.creationTime + SESSION_CREATION_TIMEOUT)
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Transports: Session to peer ", it->first.ToBase64 (), " has not been created in ", SESSION_CREATION_TIMEOUT, " seconds");
|
LogPrint (eLogWarning, "Transports: Session to peer ", it->first.ToBase64 (), " has not been created in ", SESSION_CREATION_TIMEOUT, " seconds");
|
||||||
@@ -793,9 +782,18 @@ namespace transport
|
|||||||
it = m_Peers.erase (it);
|
it = m_Peers.erase (it);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
if (ts > it->second.nextRouterInfoUpdateTime)
|
||||||
|
{
|
||||||
|
auto session = it->second.sessions.front ();
|
||||||
|
if (session)
|
||||||
|
session->SendLocalRouterInfo (true);
|
||||||
|
it->second.nextRouterInfoUpdateTime = ts + PEER_ROUTER_INFO_UPDATE_INTERVAL +
|
||||||
|
rand () % PEER_ROUTER_INFO_UPDATE_INTERVAL_VARIANCE;
|
||||||
|
}
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
UpdateBandwidth (); // TODO: use separate timer(s) for it
|
}
|
||||||
bool ipv4Testing = i2p::context.GetStatus () == eRouterStatusTesting;
|
bool ipv4Testing = i2p::context.GetStatus () == eRouterStatusTesting;
|
||||||
bool ipv6Testing = i2p::context.GetStatusV6 () == eRouterStatusTesting;
|
bool ipv6Testing = i2p::context.GetStatusV6 () == eRouterStatusTesting;
|
||||||
// if still testing, repeat peer test
|
// if still testing, repeat peer test
|
||||||
@@ -919,5 +917,119 @@ namespace transport
|
|||||||
i2p::context.SetError (eRouterErrorOffline);
|
i2p::context.SetError (eRouterErrorOffline);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InitAddressFromIface ()
|
||||||
|
{
|
||||||
|
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
|
||||||
|
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
|
||||||
|
|
||||||
|
// ifname -> address
|
||||||
|
std::string ifname; i2p::config::GetOption("ifname", ifname);
|
||||||
|
if (ipv4 && i2p::config::IsDefault ("address4"))
|
||||||
|
{
|
||||||
|
std::string ifname4; i2p::config::GetOption("ifname4", ifname4);
|
||||||
|
if (!ifname4.empty ())
|
||||||
|
i2p::config::SetOption ("address4", i2p::util::net::GetInterfaceAddress(ifname4, false).to_string ()); // v4
|
||||||
|
else if (!ifname.empty ())
|
||||||
|
i2p::config::SetOption ("address4", i2p::util::net::GetInterfaceAddress(ifname, false).to_string ()); // v4
|
||||||
|
}
|
||||||
|
if (ipv6 && i2p::config::IsDefault ("address6"))
|
||||||
|
{
|
||||||
|
std::string ifname6; i2p::config::GetOption("ifname6", ifname6);
|
||||||
|
if (!ifname6.empty ())
|
||||||
|
i2p::config::SetOption ("address6", i2p::util::net::GetInterfaceAddress(ifname6, true).to_string ()); // v6
|
||||||
|
else if (!ifname.empty ())
|
||||||
|
i2p::config::SetOption ("address6", i2p::util::net::GetInterfaceAddress(ifname, true).to_string ()); // v6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitTransports ()
|
||||||
|
{
|
||||||
|
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
|
||||||
|
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
|
||||||
|
bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg);
|
||||||
|
uint16_t port; i2p::config::GetOption("port", port);
|
||||||
|
|
||||||
|
boost::asio::ip::address_v6 yggaddr;
|
||||||
|
if (ygg)
|
||||||
|
{
|
||||||
|
std::string yggaddress; i2p::config::GetOption ("meshnets.yggaddress", yggaddress);
|
||||||
|
if (!yggaddress.empty ())
|
||||||
|
{
|
||||||
|
yggaddr = boost::asio::ip::address_v6::from_string (yggaddress);
|
||||||
|
if (yggaddr.is_unspecified () || !i2p::util::net::IsYggdrasilAddress (yggaddr) ||
|
||||||
|
!i2p::util::net::IsLocalAddress (yggaddr))
|
||||||
|
{
|
||||||
|
LogPrint(eLogWarning, "Transports: Can't find Yggdrasil address ", yggaddress);
|
||||||
|
ygg = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
yggaddr = i2p::util::net::GetYggdrasilAddress ();
|
||||||
|
if (yggaddr.is_unspecified ())
|
||||||
|
{
|
||||||
|
LogPrint(eLogWarning, "Transports: Yggdrasil is not running. Disabled");
|
||||||
|
ygg = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!i2p::config::IsDefault("port"))
|
||||||
|
{
|
||||||
|
LogPrint(eLogInfo, "Transports: Accepting incoming connections at port ", port);
|
||||||
|
i2p::context.UpdatePort (port);
|
||||||
|
}
|
||||||
|
i2p::context.SetSupportsV6 (ipv6);
|
||||||
|
i2p::context.SetSupportsV4 (ipv4);
|
||||||
|
i2p::context.SetSupportsMesh (ygg, yggaddr);
|
||||||
|
|
||||||
|
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
||||||
|
if (ntcp2)
|
||||||
|
{
|
||||||
|
bool published; i2p::config::GetOption("ntcp2.published", published);
|
||||||
|
if (published)
|
||||||
|
{
|
||||||
|
std::string ntcp2proxy; i2p::config::GetOption("ntcp2.proxy", ntcp2proxy);
|
||||||
|
if (!ntcp2proxy.empty ()) published = false;
|
||||||
|
}
|
||||||
|
if (published)
|
||||||
|
{
|
||||||
|
uint16_t ntcp2port; i2p::config::GetOption("ntcp2.port", ntcp2port);
|
||||||
|
if (!ntcp2port) ntcp2port = port; // use standard port
|
||||||
|
i2p::context.PublishNTCP2Address (ntcp2port, true, ipv4, ipv6, false); // publish
|
||||||
|
if (ipv6)
|
||||||
|
{
|
||||||
|
std::string ipv6Addr; i2p::config::GetOption("ntcp2.addressv6", ipv6Addr);
|
||||||
|
auto addr = boost::asio::ip::address_v6::from_string (ipv6Addr);
|
||||||
|
if (!addr.is_unspecified () && addr != boost::asio::ip::address_v6::any ())
|
||||||
|
i2p::context.UpdateNTCP2V6Address (addr); // set ipv6 address if configured
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
i2p::context.PublishNTCP2Address (port, false, ipv4, ipv6, false); // unpublish
|
||||||
|
}
|
||||||
|
if (ygg)
|
||||||
|
{
|
||||||
|
i2p::context.PublishNTCP2Address (port, true, false, false, true);
|
||||||
|
i2p::context.UpdateNTCP2V6Address (yggaddr);
|
||||||
|
if (!ipv4 && !ipv6)
|
||||||
|
i2p::context.SetStatus (eRouterStatusMesh);
|
||||||
|
}
|
||||||
|
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
|
||||||
|
if (ssu2 && i2p::config::IsDefault ("ssu2.enabled") && !ipv4 && !ipv6)
|
||||||
|
ssu2 = false; // don't enable ssu2 for yggdrasil only router
|
||||||
|
if (ssu2)
|
||||||
|
{
|
||||||
|
uint16_t ssu2port; i2p::config::GetOption("ssu2.port", ssu2port);
|
||||||
|
if (!ssu2port && port) ssu2port = port;
|
||||||
|
bool published; i2p::config::GetOption("ssu2.published", published);
|
||||||
|
if (published)
|
||||||
|
i2p::context.PublishSSU2Address (ssu2port, true, ipv4, ipv6); // publish
|
||||||
|
else
|
||||||
|
i2p::context.PublishSSU2Address (ssu2port, false, ipv4, ipv6); // unpublish
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include "TransportSession.h"
|
#include "TransportSession.h"
|
||||||
#include "SSU.h"
|
|
||||||
#include "SSU2.h"
|
#include "SSU2.h"
|
||||||
#include "NTCP2.h"
|
#include "NTCP2.h"
|
||||||
#include "RouterInfo.h"
|
#include "RouterInfo.h"
|
||||||
@@ -62,13 +61,22 @@ namespace transport
|
|||||||
};
|
};
|
||||||
typedef EphemeralKeysSupplier<i2p::crypto::X25519Keys> X25519KeysPairSupplier;
|
typedef EphemeralKeysSupplier<i2p::crypto::X25519Keys> X25519KeysPairSupplier;
|
||||||
|
|
||||||
|
const int PEER_ROUTER_INFO_UPDATE_INTERVAL = 31*60; // in seconds
|
||||||
|
const int PEER_ROUTER_INFO_UPDATE_INTERVAL_VARIANCE = 7*60; // in seconds
|
||||||
struct Peer
|
struct Peer
|
||||||
{
|
{
|
||||||
int numAttempts;
|
int numAttempts;
|
||||||
std::shared_ptr<const i2p::data::RouterInfo> router;
|
std::shared_ptr<const i2p::data::RouterInfo> router;
|
||||||
std::list<std::shared_ptr<TransportSession> > sessions;
|
std::list<std::shared_ptr<TransportSession> > sessions;
|
||||||
uint64_t creationTime;
|
uint64_t creationTime, nextRouterInfoUpdateTime;
|
||||||
std::vector<std::shared_ptr<i2p::I2NPMessage> > delayedMessages;
|
std::vector<std::shared_ptr<i2p::I2NPMessage> > delayedMessages;
|
||||||
|
std::vector<i2p::data::RouterInfo::SupportedTransports> priority;
|
||||||
|
|
||||||
|
Peer (std::shared_ptr<const i2p::data::RouterInfo> r, uint64_t ts):
|
||||||
|
numAttempts (0), router (r), creationTime (ts),
|
||||||
|
nextRouterInfoUpdateTime (ts + PEER_ROUTER_INFO_UPDATE_INTERVAL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void Done ()
|
void Done ()
|
||||||
{
|
{
|
||||||
@@ -77,7 +85,7 @@ namespace transport
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const size_t SESSION_CREATION_TIMEOUT = 15; // in seconds
|
const uint64_t SESSION_CREATION_TIMEOUT = 15; // in seconds
|
||||||
const int PEER_TEST_INTERVAL = 71; // in minutes
|
const int PEER_TEST_INTERVAL = 71; // in minutes
|
||||||
const int MAX_NUM_DELAYED_MESSAGES = 150;
|
const int MAX_NUM_DELAYED_MESSAGES = 150;
|
||||||
class Transports
|
class Transports
|
||||||
@@ -87,10 +95,10 @@ namespace transport
|
|||||||
Transports ();
|
Transports ();
|
||||||
~Transports ();
|
~Transports ();
|
||||||
|
|
||||||
void Start (bool enableNTCP2=true, bool enableSSU=true, bool enableSSU2=false);
|
void Start (bool enableNTCP2=true, bool enableSSU2=true);
|
||||||
void Stop ();
|
void Stop ();
|
||||||
|
|
||||||
bool IsBoundSSU() const { return m_SSUServer != nullptr; }
|
bool IsBoundSSU2() const { return m_SSU2Server != nullptr; }
|
||||||
bool IsBoundNTCP2() const { return m_NTCP2Server != nullptr; }
|
bool IsBoundNTCP2() const { return m_NTCP2Server != nullptr; }
|
||||||
|
|
||||||
bool IsOnline() const { return m_IsOnline; };
|
bool IsOnline() const { return m_IsOnline; };
|
||||||
@@ -116,6 +124,9 @@ namespace transport
|
|||||||
uint32_t GetInBandwidth () const { return m_InBandwidth; };
|
uint32_t GetInBandwidth () const { return m_InBandwidth; };
|
||||||
uint32_t GetOutBandwidth () const { return m_OutBandwidth; };
|
uint32_t GetOutBandwidth () const { return m_OutBandwidth; };
|
||||||
uint32_t GetTransitBandwidth () const { return m_TransitBandwidth; };
|
uint32_t GetTransitBandwidth () const { return m_TransitBandwidth; };
|
||||||
|
uint32_t GetInBandwidth15s () const { return m_InBandwidth15s; };
|
||||||
|
uint32_t GetOutBandwidth15s () const { return m_OutBandwidth15s; };
|
||||||
|
uint32_t GetTransitBandwidth15s () const { return m_TransitBandwidth15s; };
|
||||||
bool IsBandwidthExceeded () const;
|
bool IsBandwidthExceeded () const;
|
||||||
bool IsTransitBandwidthExceeded () const;
|
bool IsTransitBandwidthExceeded () const;
|
||||||
size_t GetNumPeers () const { return m_Peers.size (); };
|
size_t GetNumPeers () const { return m_Peers.size (); };
|
||||||
@@ -144,10 +155,11 @@ namespace transport
|
|||||||
void HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, i2p::data::IdentHash ident);
|
void HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, i2p::data::IdentHash ident);
|
||||||
void PostMessages (i2p::data::IdentHash ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > msgs);
|
void PostMessages (i2p::data::IdentHash ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > msgs);
|
||||||
bool ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer);
|
bool ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer);
|
||||||
|
void SetPriority (Peer& peer) const;
|
||||||
void HandlePeerCleanupTimer (const boost::system::error_code& ecode);
|
void HandlePeerCleanupTimer (const boost::system::error_code& ecode);
|
||||||
void HandlePeerTestTimer (const boost::system::error_code& ecode);
|
void HandlePeerTestTimer (const boost::system::error_code& ecode);
|
||||||
|
void HandleUpdateBandwidthTimer (const boost::system::error_code& ecode);
|
||||||
|
|
||||||
void UpdateBandwidth ();
|
|
||||||
void DetectExternalIP ();
|
void DetectExternalIP ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -158,8 +170,8 @@ namespace transport
|
|||||||
boost::asio::io_service * m_Service;
|
boost::asio::io_service * m_Service;
|
||||||
boost::asio::io_service::work * m_Work;
|
boost::asio::io_service::work * m_Work;
|
||||||
boost::asio::deadline_timer * m_PeerCleanupTimer, * m_PeerTestTimer;
|
boost::asio::deadline_timer * m_PeerCleanupTimer, * m_PeerTestTimer;
|
||||||
|
boost::asio::steady_timer * m_UpdateBandwidthTimer;
|
||||||
|
|
||||||
SSUServer * m_SSUServer;
|
|
||||||
SSU2Server * m_SSU2Server;
|
SSU2Server * m_SSU2Server;
|
||||||
NTCP2Server * m_NTCP2Server;
|
NTCP2Server * m_NTCP2Server;
|
||||||
mutable std::mutex m_PeersMutex;
|
mutable std::mutex m_PeersMutex;
|
||||||
@@ -168,9 +180,15 @@ namespace transport
|
|||||||
X25519KeysPairSupplier m_X25519KeysPairSupplier;
|
X25519KeysPairSupplier m_X25519KeysPairSupplier;
|
||||||
|
|
||||||
std::atomic<uint64_t> m_TotalSentBytes, m_TotalReceivedBytes, m_TotalTransitTransmittedBytes;
|
std::atomic<uint64_t> m_TotalSentBytes, m_TotalReceivedBytes, m_TotalTransitTransmittedBytes;
|
||||||
uint32_t m_InBandwidth, m_OutBandwidth, m_TransitBandwidth; // bytes per second
|
|
||||||
|
// Bandwidth per second
|
||||||
|
uint32_t m_InBandwidth, m_OutBandwidth, m_TransitBandwidth;
|
||||||
uint64_t m_LastInBandwidthUpdateBytes, m_LastOutBandwidthUpdateBytes, m_LastTransitBandwidthUpdateBytes;
|
uint64_t m_LastInBandwidthUpdateBytes, m_LastOutBandwidthUpdateBytes, m_LastTransitBandwidthUpdateBytes;
|
||||||
uint64_t m_LastBandwidthUpdateTime;
|
|
||||||
|
// Bandwidth every 15 seconds
|
||||||
|
uint32_t m_InBandwidth15s, m_OutBandwidth15s, m_TransitBandwidth15s;
|
||||||
|
uint64_t m_LastInBandwidth15sUpdateBytes, m_LastOutBandwidth15sUpdateBytes, m_LastTransitBandwidth15sUpdateBytes;
|
||||||
|
uint64_t m_LastBandwidth15sUpdateTime;
|
||||||
|
|
||||||
/** which router families to trust for first hops */
|
/** which router families to trust for first hops */
|
||||||
std::vector<i2p::data::FamilyID> m_TrustedFamilies;
|
std::vector<i2p::data::FamilyID> m_TrustedFamilies;
|
||||||
@@ -185,13 +203,15 @@ namespace transport
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
// for HTTP only
|
// for HTTP only
|
||||||
const SSUServer * GetSSUServer () const { return m_SSUServer; };
|
|
||||||
const NTCP2Server * GetNTCP2Server () const { return m_NTCP2Server; };
|
const NTCP2Server * GetNTCP2Server () const { return m_NTCP2Server; };
|
||||||
const SSU2Server * GetSSU2Server () const { return m_SSU2Server; };
|
const SSU2Server * GetSSU2Server () const { return m_SSU2Server; };
|
||||||
const decltype(m_Peers)& GetPeers () const { return m_Peers; };
|
const decltype(m_Peers)& GetPeers () const { return m_Peers; };
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Transports transports;
|
extern Transports transports;
|
||||||
|
|
||||||
|
void InitAddressFromIface ();
|
||||||
|
void InitTransports ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,12 +76,12 @@ namespace tunnel
|
|||||||
if (m_NumInboundHops > size)
|
if (m_NumInboundHops > size)
|
||||||
{
|
{
|
||||||
m_NumInboundHops = size;
|
m_NumInboundHops = size;
|
||||||
LogPrint (eLogInfo, "Tunnels: Inbound tunnel length has beed adjusted to ", size, " for explicit peers");
|
LogPrint (eLogInfo, "Tunnels: Inbound tunnel length has been adjusted to ", size, " for explicit peers");
|
||||||
}
|
}
|
||||||
if (m_NumOutboundHops > size)
|
if (m_NumOutboundHops > size)
|
||||||
{
|
{
|
||||||
m_NumOutboundHops = size;
|
m_NumOutboundHops = size;
|
||||||
LogPrint (eLogInfo, "Tunnels: Outbound tunnel length has beed adjusted to ", size, " for explicit peers");
|
LogPrint (eLogInfo, "Tunnels: Outbound tunnel length has been adjusted to ", size, " for explicit peers");
|
||||||
}
|
}
|
||||||
m_NumInboundTunnels = 1;
|
m_NumInboundTunnels = 1;
|
||||||
m_NumOutboundTunnels = 1;
|
m_NumOutboundTunnels = 1;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@@ -60,6 +60,7 @@ namespace api
|
|||||||
else
|
else
|
||||||
i2p::log::Logger().SendTo (i2p::fs::DataDirPath (i2p::fs::GetAppName () + ".log"));
|
i2p::log::Logger().SendTo (i2p::fs::DataDirPath (i2p::fs::GetAppName () + ".log"));
|
||||||
i2p::log::Logger().Start ();
|
i2p::log::Logger().Start ();
|
||||||
|
i2p::transport::InitTransports ();
|
||||||
LogPrint(eLogInfo, "API: Starting NetDB");
|
LogPrint(eLogInfo, "API: Starting NetDB");
|
||||||
i2p::data::netdb.Start();
|
i2p::data::netdb.Start();
|
||||||
LogPrint(eLogInfo, "API: Starting Transports");
|
LogPrint(eLogInfo, "API: Starting Transports");
|
||||||
|
|||||||
117
libi2pd/util.cpp
117
libi2pd/util.cpp
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
#include "I2PEndian.h"
|
||||||
|
|
||||||
#if not defined (__FreeBSD__)
|
#if not defined (__FreeBSD__)
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
@@ -21,6 +22,9 @@
|
|||||||
#include <pthread_np.h>
|
#include <pthread_np.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
# include <AvailabilityMacros.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -32,14 +36,10 @@
|
|||||||
#include <iphlpapi.h>
|
#include <iphlpapi.h>
|
||||||
#include <shlobj.h>
|
#include <shlobj.h>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#pragma comment(lib, "IPHLPAPI.lib")
|
|
||||||
#endif // _MSC_VER
|
|
||||||
|
|
||||||
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
|
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
|
||||||
#define FREE(x) HeapFree(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
|
// 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)
|
int inet_pton_xp (int af, const char *src, void *dst)
|
||||||
{
|
{
|
||||||
@@ -65,6 +65,29 @@ int inet_pton_xp (int af, const char *src, void *dst)
|
|||||||
}
|
}
|
||||||
return 0;
|
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 directly use &size because of strict aliasing rules */
|
||||||
|
return (WSAAddressToString((struct sockaddr *)&ss, sizeof(ss), NULL, dst, &s) == 0)? dst : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
#else /* !_WIN32 => UNIX */
|
#else /* !_WIN32 => UNIX */
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
@@ -123,8 +146,15 @@ namespace util
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SetThreadName (const char *name) {
|
void SetThreadName (const char *name) {
|
||||||
#if defined(__APPLE__) && !defined(__powerpc__)
|
#if defined(__APPLE__)
|
||||||
|
# if (!defined(MAC_OS_X_VERSION_10_6) || \
|
||||||
|
(MAC_OS_X_VERSION_MAX_ALLOWED < 1060) || \
|
||||||
|
defined(__POWERPC__))
|
||||||
|
/* pthread_setname_np is not there on <10.6 and all PPC.
|
||||||
|
So do nothing. */
|
||||||
|
# else
|
||||||
pthread_setname_np((char*)name);
|
pthread_setname_np((char*)name);
|
||||||
|
# endif
|
||||||
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
|
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||||
pthread_set_name_np(pthread_self(), name);
|
pthread_set_name_np(pthread_self(), name);
|
||||||
#elif defined(__NetBSD__)
|
#elif defined(__NetBSD__)
|
||||||
@@ -137,27 +167,12 @@ namespace util
|
|||||||
namespace net
|
namespace net
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#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)
|
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;
|
ULONG outBufLen = 0;
|
||||||
PIP_ADAPTER_ADDRESSES pAddresses = nullptr;
|
PIP_ADAPTER_ADDRESSES pAddresses = nullptr;
|
||||||
PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr;
|
PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr;
|
||||||
@@ -176,7 +191,7 @@ namespace net
|
|||||||
|
|
||||||
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);
|
FREE(pAddresses);
|
||||||
return fallback;
|
return fallback;
|
||||||
}
|
}
|
||||||
@@ -188,7 +203,7 @@ namespace net
|
|||||||
|
|
||||||
pUnicast = pCurrAddresses->FirstUnicastAddress;
|
pUnicast = pCurrAddresses->FirstUnicastAddress;
|
||||||
if(pUnicast == nullptr)
|
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)
|
for(int i = 0; pUnicast != nullptr; ++i)
|
||||||
{
|
{
|
||||||
@@ -196,8 +211,13 @@ namespace net
|
|||||||
sockaddr_in* localInterfaceAddress = (sockaddr_in*) lpAddr;
|
sockaddr_in* localInterfaceAddress = (sockaddr_in*) lpAddr;
|
||||||
if(localInterfaceAddress->sin_addr.S_un.S_addr == inputAddress.sin_addr.S_un.S_addr)
|
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);
|
FREE(pAddresses);
|
||||||
|
pAddresses = nullptr;
|
||||||
|
LogPrint(eLogInfo, "NetIface: GetMTU: Using ", result, " bytes for IPv4 address ", addr);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
pUnicast = pUnicast->Next;
|
pUnicast = pUnicast->Next;
|
||||||
@@ -205,13 +225,17 @@ namespace net
|
|||||||
pCurrAddresses = pCurrAddresses->Next;
|
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);
|
FREE(pAddresses);
|
||||||
return fallback;
|
return fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetMTUWindowsIpv6 (sockaddr_in6 inputAddress, int 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;
|
ULONG outBufLen = 0;
|
||||||
PIP_ADAPTER_ADDRESSES pAddresses = nullptr;
|
PIP_ADAPTER_ADDRESSES pAddresses = nullptr;
|
||||||
PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr;
|
PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr;
|
||||||
@@ -230,7 +254,7 @@ namespace net
|
|||||||
|
|
||||||
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);
|
FREE(pAddresses);
|
||||||
return fallback;
|
return fallback;
|
||||||
}
|
}
|
||||||
@@ -242,7 +266,7 @@ namespace net
|
|||||||
PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress;
|
PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress;
|
||||||
pUnicast = pCurrAddresses->FirstUnicastAddress;
|
pUnicast = pCurrAddresses->FirstUnicastAddress;
|
||||||
if (pUnicast == nullptr)
|
if (pUnicast == nullptr)
|
||||||
LogPrint(eLogError, "NetIface: GetMTU(): Not a unicast IPv6 address, this is not supported");
|
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)
|
||||||
{
|
{
|
||||||
@@ -259,9 +283,13 @@ namespace net
|
|||||||
|
|
||||||
if (found_address)
|
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);
|
FREE(pAddresses);
|
||||||
pAddresses = nullptr;
|
pAddresses = nullptr;
|
||||||
|
LogPrint(eLogInfo, "NetIface: GetMTU: Using ", result, " bytes for IPv6 address ", addr);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
pUnicast = pUnicast->Next;
|
pUnicast = pUnicast->Next;
|
||||||
@@ -270,7 +298,7 @@ namespace net
|
|||||||
pCurrAddresses = pCurrAddresses->Next;
|
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);
|
FREE(pAddresses);
|
||||||
return fallback;
|
return fallback;
|
||||||
}
|
}
|
||||||
@@ -302,7 +330,7 @@ namespace net
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint(eLogError, "NetIface: GetMTU(): Address family is not supported");
|
LogPrint(eLogError, "NetIface: GetMTU: Address family is not supported");
|
||||||
return fallback;
|
return fallback;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -427,6 +455,27 @@ namespace net
|
|||||||
#endif
|
#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])
|
static bool IsYggdrasilAddress (const uint8_t addr[16])
|
||||||
{
|
{
|
||||||
return addr[0] == 0x02 || addr[0] == 0x03;
|
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
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@@ -112,7 +112,7 @@ namespace util
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
class MemoryPoolMt: public MemoryPool<T>
|
class MemoryPoolMt: private MemoryPool<T>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -218,6 +218,7 @@ namespace util
|
|||||||
namespace net
|
namespace net
|
||||||
{
|
{
|
||||||
int GetMTU (const boost::asio::ip::address& localAddress);
|
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);
|
const boost::asio::ip::address GetInterfaceAddress (const std::string & ifname, bool ipv6=false);
|
||||||
boost::asio::ip::address_v6 GetYggdrasilAddress ();
|
boost::asio::ip::address_v6 GetYggdrasilAddress ();
|
||||||
bool IsLocalAddress (const boost::asio::ip::address& addr);
|
bool IsLocalAddress (const boost::asio::ip::address& addr);
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
#define MAKE_VERSION_NUMBER(a,b,c) ((a*100+b)*100+c)
|
#define MAKE_VERSION_NUMBER(a,b,c) ((a*100+b)*100+c)
|
||||||
|
|
||||||
#define I2PD_VERSION_MAJOR 2
|
#define I2PD_VERSION_MAJOR 2
|
||||||
#define I2PD_VERSION_MINOR 41
|
#define I2PD_VERSION_MINOR 44
|
||||||
#define I2PD_VERSION_MICRO 0
|
#define I2PD_VERSION_MICRO 0
|
||||||
#define I2PD_VERSION_PATCH 0
|
#define I2PD_VERSION_PATCH 0
|
||||||
#ifdef GITVER
|
#ifdef GITVER
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
#define I2P_VERSION_MAJOR 0
|
#define I2P_VERSION_MAJOR 0
|
||||||
#define I2P_VERSION_MINOR 9
|
#define I2P_VERSION_MINOR 9
|
||||||
#define I2P_VERSION_MICRO 53
|
#define I2P_VERSION_MICRO 56
|
||||||
#define I2P_VERSION_PATCH 0
|
#define I2P_VERSION_PATCH 0
|
||||||
#define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
|
#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)
|
#define I2P_VERSION_NUMBER MAKE_VERSION_NUMBER(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@@ -299,7 +299,8 @@ namespace client
|
|||||||
}
|
}
|
||||||
|
|
||||||
AddressBook::AddressBook (): m_Storage(nullptr), m_IsLoaded (false), m_IsDownloading (false),
|
AddressBook::AddressBook (): m_Storage(nullptr), m_IsLoaded (false), m_IsDownloading (false),
|
||||||
m_NumRetries (0), m_DefaultSubscription (nullptr), m_SubscriptionsUpdateTimer (nullptr)
|
m_NumRetries (0), m_DefaultSubscription (nullptr), m_SubscriptionsUpdateTimer (nullptr),
|
||||||
|
m_IsEnabled (true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,6 +310,9 @@ namespace client
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AddressBook::Start ()
|
void AddressBook::Start ()
|
||||||
|
{
|
||||||
|
i2p::config::GetOption("addressbook.enabled", m_IsEnabled);
|
||||||
|
if (m_IsEnabled)
|
||||||
{
|
{
|
||||||
if (!m_Storage)
|
if (!m_Storage)
|
||||||
m_Storage = new AddressBookFilesystemStorage;
|
m_Storage = new AddressBookFilesystemStorage;
|
||||||
@@ -317,6 +321,7 @@ namespace client
|
|||||||
StartSubscriptions ();
|
StartSubscriptions ();
|
||||||
StartLookups ();
|
StartLookups ();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AddressBook::StartResolvers ()
|
void AddressBook::StartResolvers ()
|
||||||
{
|
{
|
||||||
@@ -370,6 +375,7 @@ namespace client
|
|||||||
pos = address.find (".i2p");
|
pos = address.find (".i2p");
|
||||||
if (pos != std::string::npos)
|
if (pos != std::string::npos)
|
||||||
{
|
{
|
||||||
|
if (!m_IsEnabled) return nullptr;
|
||||||
auto addr = FindAddress (address);
|
auto addr = FindAddress (address);
|
||||||
if (!addr)
|
if (!addr)
|
||||||
LookupAddress (address); // TODO:
|
LookupAddress (address); // TODO:
|
||||||
@@ -391,6 +397,19 @@ namespace client
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AddressBook::RecordExists (const std::string& address, const std::string& jump)
|
||||||
|
{
|
||||||
|
auto addr = FindAddress(address);
|
||||||
|
if (!addr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
i2p::data::IdentityEx ident;
|
||||||
|
if (ident.FromBase64 (jump) && ident.GetIdentHash () == addr->identHash)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void AddressBook::InsertAddress (const std::string& address, const std::string& jump)
|
void AddressBook::InsertAddress (const std::string& address, const std::string& jump)
|
||||||
{
|
{
|
||||||
auto pos = jump.find(".b32.i2p");
|
auto pos = jump.find(".b32.i2p");
|
||||||
@@ -561,6 +580,7 @@ namespace client
|
|||||||
|
|
||||||
void AddressBook::LoadLocal ()
|
void AddressBook::LoadLocal ()
|
||||||
{
|
{
|
||||||
|
if (!m_Storage) return;
|
||||||
std::map<std::string, std::shared_ptr<Address>> localAddresses;
|
std::map<std::string, std::shared_ptr<Address>> localAddresses;
|
||||||
m_Storage->LoadLocal (localAddresses);
|
m_Storage->LoadLocal (localAddresses);
|
||||||
for (const auto& it: localAddresses)
|
for (const auto& it: localAddresses)
|
||||||
@@ -813,40 +833,22 @@ namespace client
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_Ident = addr->identHash;
|
m_Ident = addr->identHash;
|
||||||
/* this code block still needs some love */
|
// save url parts for later use
|
||||||
std::condition_variable newDataReceived;
|
std::string dest_host = url.host;
|
||||||
std::mutex newDataReceivedMutex;
|
int dest_port = url.port ? url.port : 80;
|
||||||
auto leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (m_Ident);
|
// try to create stream to addressbook site
|
||||||
if (!leaseSet)
|
auto stream = i2p::client::context.GetSharedLocalDestination ()->CreateStream (m_Ident, dest_port);
|
||||||
|
if (!stream)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(newDataReceivedMutex);
|
|
||||||
i2p::client::context.GetSharedLocalDestination ()->RequestDestination (m_Ident,
|
|
||||||
[&newDataReceived, &leaseSet, &newDataReceivedMutex](std::shared_ptr<i2p::data::LeaseSet> ls)
|
|
||||||
{
|
|
||||||
leaseSet = ls;
|
|
||||||
std::unique_lock<std::mutex> l1(newDataReceivedMutex);
|
|
||||||
newDataReceived.notify_all ();
|
|
||||||
});
|
|
||||||
if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT)) == std::cv_status::timeout)
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "Addressbook: Subscription LeaseSet request timeout expired");
|
|
||||||
i2p::client::context.GetSharedLocalDestination ()->CancelDestinationRequest (m_Ident, false); // don't notify, because we know it already
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!leaseSet) {
|
|
||||||
/* still no leaseset found */
|
|
||||||
LogPrint (eLogError, "Addressbook: LeaseSet for address ", url.host, " not found");
|
LogPrint (eLogError, "Addressbook: LeaseSet for address ", url.host, " not found");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (m_Etag.empty() && m_LastModified.empty()) {
|
if (m_Etag.empty() && m_LastModified.empty())
|
||||||
|
{
|
||||||
m_Book.GetEtag (m_Ident, m_Etag, m_LastModified);
|
m_Book.GetEtag (m_Ident, m_Etag, m_LastModified);
|
||||||
LogPrint (eLogDebug, "Addressbook: Loaded for ", url.host, ": ETag: ", m_Etag, ", Last-Modified: ", m_LastModified);
|
LogPrint (eLogDebug, "Addressbook: Loaded for ", url.host, ": ETag: ", m_Etag, ", Last-Modified: ", m_LastModified);
|
||||||
}
|
}
|
||||||
/* save url parts for later use */
|
// create http request & send it
|
||||||
std::string dest_host = url.host;
|
|
||||||
int dest_port = url.port ? url.port : 80;
|
|
||||||
/* create http request & send it */
|
|
||||||
i2p::http::HTTPReq req;
|
i2p::http::HTTPReq req;
|
||||||
req.AddHeader("Host", dest_host);
|
req.AddHeader("Host", dest_host);
|
||||||
req.AddHeader("User-Agent", "Wget/1.11.4");
|
req.AddHeader("User-Agent", "Wget/1.11.4");
|
||||||
@@ -857,34 +859,29 @@ namespace client
|
|||||||
req.AddHeader("If-None-Match", m_Etag);
|
req.AddHeader("If-None-Match", m_Etag);
|
||||||
if (!m_LastModified.empty())
|
if (!m_LastModified.empty())
|
||||||
req.AddHeader("If-Modified-Since", m_LastModified);
|
req.AddHeader("If-Modified-Since", m_LastModified);
|
||||||
/* convert url to relative */
|
// convert url to relative
|
||||||
url.schema = "";
|
url.schema = "";
|
||||||
url.host = "";
|
url.host = "";
|
||||||
req.uri = url.to_string();
|
req.uri = url.to_string();
|
||||||
req.version = "HTTP/1.1";
|
req.version = "HTTP/1.1";
|
||||||
auto stream = i2p::client::context.GetSharedLocalDestination ()->CreateStream (leaseSet, dest_port);
|
|
||||||
std::string request = req.to_string();
|
std::string request = req.to_string();
|
||||||
stream->Send ((const uint8_t *) request.data(), request.length());
|
stream->Send ((const uint8_t *) request.data(), request.length());
|
||||||
/* read response */
|
// read response
|
||||||
std::string response;
|
std::string response;
|
||||||
uint8_t recv_buf[4096];
|
uint8_t recv_buf[4096];
|
||||||
bool end = false;
|
bool end = false;
|
||||||
int numAttempts = 0;
|
int numAttempts = 0;
|
||||||
while (!end)
|
while (!end)
|
||||||
{
|
{
|
||||||
stream->AsyncReceive (boost::asio::buffer (recv_buf, 4096),
|
size_t received = stream->Receive (recv_buf, 4096, SUBSCRIPTION_REQUEST_TIMEOUT);
|
||||||
[&](const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
if (received)
|
||||||
{
|
{
|
||||||
if (bytes_transferred)
|
response.append ((char *)recv_buf, received);
|
||||||
response.append ((char *)recv_buf, bytes_transferred);
|
if (!stream->IsOpen ()) end = true;
|
||||||
if (ecode == boost::asio::error::timed_out || !stream->IsOpen ())
|
}
|
||||||
|
else if (!stream->IsOpen ())
|
||||||
end = true;
|
end = true;
|
||||||
newDataReceived.notify_all ();
|
else
|
||||||
},
|
|
||||||
SUBSCRIPTION_REQUEST_TIMEOUT);
|
|
||||||
std::unique_lock<std::mutex> l(newDataReceivedMutex);
|
|
||||||
// wait 1 more second
|
|
||||||
if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT + 1)) == std::cv_status::timeout)
|
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "Addressbook: Subscriptions request timeout expired");
|
LogPrint (eLogError, "Addressbook: Subscriptions request timeout expired");
|
||||||
numAttempts++;
|
numAttempts++;
|
||||||
@@ -894,7 +891,7 @@ namespace client
|
|||||||
// process remaining buffer
|
// process remaining buffer
|
||||||
while (size_t len = stream->ReadSome (recv_buf, sizeof(recv_buf)))
|
while (size_t len = stream->ReadSome (recv_buf, sizeof(recv_buf)))
|
||||||
response.append ((char *)recv_buf, len);
|
response.append ((char *)recv_buf, len);
|
||||||
/* parse response */
|
// parse response
|
||||||
i2p::http::HTTPRes res;
|
i2p::http::HTTPRes res;
|
||||||
int res_head_len = res.parse(response);
|
int res_head_len = res.parse(response);
|
||||||
if (res_head_len < 0)
|
if (res_head_len < 0)
|
||||||
@@ -907,7 +904,7 @@ namespace client
|
|||||||
LogPrint(eLogError, "Addressbook: Incomplete http response from ", dest_host, ", interrupted by timeout");
|
LogPrint(eLogError, "Addressbook: Incomplete http response from ", dest_host, ", interrupted by timeout");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/* assert: res_head_len > 0 */
|
// assert: res_head_len > 0
|
||||||
response.erase(0, res_head_len);
|
response.erase(0, res_head_len);
|
||||||
if (res.code == 304)
|
if (res.code == 304)
|
||||||
{
|
{
|
||||||
@@ -930,7 +927,7 @@ namespace client
|
|||||||
LogPrint(eLogError, "Addressbook: Response size mismatch, expected: ", len, ", got: ", response.length(), "bytes");
|
LogPrint(eLogError, "Addressbook: Response size mismatch, expected: ", len, ", got: ", response.length(), "bytes");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/* assert: res.code == 200 */
|
// assert: res.code == 200
|
||||||
auto it = res.headers.find("ETag");
|
auto it = res.headers.find("ETag");
|
||||||
if (it != res.headers.end()) m_Etag = it->second;
|
if (it != res.headers.end()) m_Etag = it->second;
|
||||||
it = res.headers.find("Last-Modified");
|
it = res.headers.find("Last-Modified");
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@@ -90,6 +90,8 @@ namespace client
|
|||||||
void InsertAddress (const std::string& address, const std::string& jump); // for jump links
|
void InsertAddress (const std::string& address, const std::string& jump); // for jump links
|
||||||
void InsertFullAddress (std::shared_ptr<const i2p::data::IdentityEx> address);
|
void InsertFullAddress (std::shared_ptr<const i2p::data::IdentityEx> address);
|
||||||
|
|
||||||
|
bool RecordExists (const std::string& address, const std::string& jump);
|
||||||
|
|
||||||
bool LoadHostsFromStream (std::istream& f, bool is_update);
|
bool LoadHostsFromStream (std::istream& f, bool is_update);
|
||||||
void DownloadComplete (bool success, const i2p::data::IdentHash& subscription, const std::string& etag, const std::string& lastModified);
|
void DownloadComplete (bool success, const i2p::data::IdentHash& subscription, const std::string& etag, const std::string& lastModified);
|
||||||
//This method returns the ".b32.i2p" address
|
//This method returns the ".b32.i2p" address
|
||||||
@@ -126,6 +128,7 @@ namespace client
|
|||||||
std::vector<std::shared_ptr<AddressBookSubscription> > m_Subscriptions;
|
std::vector<std::shared_ptr<AddressBookSubscription> > m_Subscriptions;
|
||||||
std::shared_ptr<AddressBookSubscription> m_DefaultSubscription; // in case if we don't know any addresses yet
|
std::shared_ptr<AddressBookSubscription> m_DefaultSubscription; // in case if we don't know any addresses yet
|
||||||
boost::asio::deadline_timer * m_SubscriptionsUpdateTimer;
|
boost::asio::deadline_timer * m_SubscriptionsUpdateTimer;
|
||||||
|
bool m_IsEnabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AddressBookSubscription
|
class AddressBookSubscription
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
* See full license text in LICENSE file at top of project tree
|
* See full license text in LICENSE file at top of project tree
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef WITH_BOB
|
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "ClientContext.h"
|
#include "ClientContext.h"
|
||||||
@@ -158,7 +156,7 @@ namespace client
|
|||||||
{
|
{
|
||||||
if (stream)
|
if (stream)
|
||||||
{
|
{
|
||||||
auto conn = std::make_shared<I2PTunnelConnection> (this, stream, std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), m_Endpoint, m_IsQuiet);
|
auto conn = std::make_shared<I2PTunnelConnection> (this, stream, m_Endpoint, m_IsQuiet);
|
||||||
AddHandler (conn);
|
AddHandler (conn);
|
||||||
conn->Connect ();
|
conn->Connect ();
|
||||||
}
|
}
|
||||||
@@ -170,7 +168,7 @@ namespace client
|
|||||||
m_LocalDestination (localDestination),
|
m_LocalDestination (localDestination),
|
||||||
m_OutboundTunnel (nullptr), m_InboundTunnel (nullptr),
|
m_OutboundTunnel (nullptr), m_InboundTunnel (nullptr),
|
||||||
m_Nickname(nickname), m_InHost(inhost), m_OutHost(outhost),
|
m_Nickname(nickname), m_InHost(inhost), m_OutHost(outhost),
|
||||||
m_InPort(inport), m_OutPort(outport), m_Quiet(quiet)
|
m_InPort(inport), m_OutPort(outport), m_Quiet(quiet), m_IsRunning(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,6 +183,7 @@ namespace client
|
|||||||
{
|
{
|
||||||
if (m_OutboundTunnel) m_OutboundTunnel->Start ();
|
if (m_OutboundTunnel) m_OutboundTunnel->Start ();
|
||||||
if (m_InboundTunnel) m_InboundTunnel->Start ();
|
if (m_InboundTunnel) m_InboundTunnel->Start ();
|
||||||
|
m_IsRunning = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BOBDestination::Stop ()
|
void BOBDestination::Stop ()
|
||||||
@@ -195,6 +194,7 @@ namespace client
|
|||||||
|
|
||||||
void BOBDestination::StopTunnels ()
|
void BOBDestination::StopTunnels ()
|
||||||
{
|
{
|
||||||
|
m_IsRunning = false;
|
||||||
if (m_OutboundTunnel)
|
if (m_OutboundTunnel)
|
||||||
{
|
{
|
||||||
m_OutboundTunnel->Stop ();
|
m_OutboundTunnel->Stop ();
|
||||||
@@ -363,7 +363,7 @@ namespace client
|
|||||||
const auto issetStr = [](const std::string &str) { return str.empty() ? "not_set" : str; }; // for inhost, outhost
|
const auto issetStr = [](const std::string &str) { return str.empty() ? "not_set" : str; }; // for inhost, outhost
|
||||||
const auto issetNum = [&issetStr](const int p) { return issetStr(p == 0 ? "" : std::to_string(p)); }; // for inport, outport
|
const auto issetNum = [&issetStr](const int p) { return issetStr(p == 0 ? "" : std::to_string(p)); }; // for inport, outport
|
||||||
const auto destExists = [](const BOBDestination * const dest) { return dest != nullptr; };
|
const auto destExists = [](const BOBDestination * const dest) { return dest != nullptr; };
|
||||||
const auto destReady = [](const BOBDestination * const dest) { return dest->GetLocalDestination()->IsReady(); };
|
const auto destReady = [](const BOBDestination * const dest) { return dest->IsRunning(); };
|
||||||
const auto bool_str = [](const bool v) { return v ? "true" : "false"; }; // bool -> str
|
const auto bool_str = [](const bool v) { return v ? "true" : "false"; }; // bool -> str
|
||||||
|
|
||||||
// tunnel info
|
// tunnel info
|
||||||
@@ -481,19 +481,33 @@ namespace client
|
|||||||
void BOBCommandSession::SetNickCommandHandler (const char * operand, size_t len)
|
void BOBCommandSession::SetNickCommandHandler (const char * operand, size_t len)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "BOB: setnick ", operand);
|
LogPrint (eLogDebug, "BOB: setnick ", operand);
|
||||||
|
if(*operand)
|
||||||
|
{
|
||||||
|
auto dest = m_Owner.FindDestination (operand);
|
||||||
|
if (!dest)
|
||||||
|
{
|
||||||
m_Nickname = operand;
|
m_Nickname = operand;
|
||||||
std::string msg ("Nickname set to ");
|
std::string msg ("Nickname set to ");
|
||||||
msg += m_Nickname;
|
msg += m_Nickname;
|
||||||
SendReplyOK (msg.c_str ());
|
SendReplyOK (msg.c_str ());
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
SendReplyError ("tunnel is active");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
SendReplyError ("no nickname has been set");
|
||||||
|
}
|
||||||
|
|
||||||
void BOBCommandSession::GetNickCommandHandler (const char * operand, size_t len)
|
void BOBCommandSession::GetNickCommandHandler (const char * operand, size_t len)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "BOB: getnick ", operand);
|
LogPrint (eLogDebug, "BOB: getnick ", operand);
|
||||||
|
if(*operand)
|
||||||
|
{
|
||||||
m_CurrentDestination = m_Owner.FindDestination (operand);
|
m_CurrentDestination = m_Owner.FindDestination (operand);
|
||||||
if (m_CurrentDestination)
|
if (m_CurrentDestination)
|
||||||
{
|
{
|
||||||
m_Keys = m_CurrentDestination->GetKeys ();
|
m_Keys = m_CurrentDestination->GetKeys ();
|
||||||
|
m_IsActive = m_CurrentDestination->IsRunning ();
|
||||||
m_Nickname = operand;
|
m_Nickname = operand;
|
||||||
}
|
}
|
||||||
if (m_Nickname == operand)
|
if (m_Nickname == operand)
|
||||||
@@ -505,6 +519,9 @@ namespace client
|
|||||||
else
|
else
|
||||||
SendReplyError ("no nickname has been set");
|
SendReplyError ("no nickname has been set");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
SendReplyError ("no nickname has been set");
|
||||||
|
}
|
||||||
|
|
||||||
void BOBCommandSession::NewkeysCommandHandler (const char * operand, size_t len)
|
void BOBCommandSession::NewkeysCommandHandler (const char * operand, size_t len)
|
||||||
{
|
{
|
||||||
@@ -530,14 +547,14 @@ namespace client
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (signatureType, cryptoType);
|
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (signatureType, cryptoType, true);
|
||||||
SendReplyOK (m_Keys.GetPublic ()->ToBase64 ().c_str ());
|
SendReplyOK (m_Keys.GetPublic ()->ToBase64 ().c_str ());
|
||||||
}
|
}
|
||||||
|
|
||||||
void BOBCommandSession::SetkeysCommandHandler (const char * operand, size_t len)
|
void BOBCommandSession::SetkeysCommandHandler (const char * operand, size_t len)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "BOB: setkeys ", operand);
|
LogPrint (eLogDebug, "BOB: setkeys ", operand);
|
||||||
if (m_Keys.FromBase64 (operand))
|
if (*operand && m_Keys.FromBase64 (operand))
|
||||||
SendReplyOK (m_Keys.GetPublic ()->ToBase64 ().c_str ());
|
SendReplyOK (m_Keys.GetPublic ()->ToBase64 ().c_str ());
|
||||||
else
|
else
|
||||||
SendReplyError ("invalid keys");
|
SendReplyError ("invalid keys");
|
||||||
@@ -564,36 +581,56 @@ namespace client
|
|||||||
void BOBCommandSession::OuthostCommandHandler (const char * operand, size_t len)
|
void BOBCommandSession::OuthostCommandHandler (const char * operand, size_t len)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "BOB: outhost ", operand);
|
LogPrint (eLogDebug, "BOB: outhost ", operand);
|
||||||
|
if (*operand)
|
||||||
|
{
|
||||||
m_OutHost = operand;
|
m_OutHost = operand;
|
||||||
SendReplyOK ("outhost set");
|
SendReplyOK ("outhost set");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
SendReplyError ("empty outhost");
|
||||||
|
}
|
||||||
|
|
||||||
void BOBCommandSession::OutportCommandHandler (const char * operand, size_t len)
|
void BOBCommandSession::OutportCommandHandler (const char * operand, size_t len)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "BOB: outport ", operand);
|
LogPrint (eLogDebug, "BOB: outport ", operand);
|
||||||
|
if (*operand)
|
||||||
|
{
|
||||||
m_OutPort = std::stoi(operand);
|
m_OutPort = std::stoi(operand);
|
||||||
if (m_OutPort >= 0)
|
if (m_OutPort >= 0)
|
||||||
SendReplyOK ("outbound port set");
|
SendReplyOK ("outbound port set");
|
||||||
else
|
else
|
||||||
SendReplyError ("port out of range");
|
SendReplyError ("port out of range");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
SendReplyError ("empty outport");
|
||||||
|
}
|
||||||
|
|
||||||
void BOBCommandSession::InhostCommandHandler (const char * operand, size_t len)
|
void BOBCommandSession::InhostCommandHandler (const char * operand, size_t len)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "BOB: inhost ", operand);
|
LogPrint (eLogDebug, "BOB: inhost ", operand);
|
||||||
|
if (*operand)
|
||||||
|
{
|
||||||
m_InHost = operand;
|
m_InHost = operand;
|
||||||
SendReplyOK ("inhost set");
|
SendReplyOK ("inhost set");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
SendReplyError ("empty inhost");
|
||||||
|
}
|
||||||
|
|
||||||
void BOBCommandSession::InportCommandHandler (const char * operand, size_t len)
|
void BOBCommandSession::InportCommandHandler (const char * operand, size_t len)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "BOB: inport ", operand);
|
LogPrint (eLogDebug, "BOB: inport ", operand);
|
||||||
|
if (*operand)
|
||||||
|
{
|
||||||
m_InPort = std::stoi(operand);
|
m_InPort = std::stoi(operand);
|
||||||
if (m_InPort >= 0)
|
if (m_InPort >= 0)
|
||||||
SendReplyOK ("inbound port set");
|
SendReplyOK ("inbound port set");
|
||||||
else
|
else
|
||||||
SendReplyError ("port out of range");
|
SendReplyError ("port out of range");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
SendReplyError ("empty inport");
|
||||||
|
}
|
||||||
|
|
||||||
void BOBCommandSession::QuietCommandHandler (const char * operand, size_t len)
|
void BOBCommandSession::QuietCommandHandler (const char * operand, size_t len)
|
||||||
{
|
{
|
||||||
@@ -615,6 +652,8 @@ namespace client
|
|||||||
void BOBCommandSession::LookupCommandHandler (const char * operand, size_t len)
|
void BOBCommandSession::LookupCommandHandler (const char * operand, size_t len)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "BOB: lookup ", operand);
|
LogPrint (eLogDebug, "BOB: lookup ", operand);
|
||||||
|
if (*operand)
|
||||||
|
{
|
||||||
auto addr = context.GetAddressBook ().GetAddress (operand);
|
auto addr = context.GetAddressBook ().GetAddress (operand);
|
||||||
if (!addr)
|
if (!addr)
|
||||||
{
|
{
|
||||||
@@ -646,10 +685,15 @@ namespace client
|
|||||||
else
|
else
|
||||||
localDestination->RequestDestinationWithEncryptedLeaseSet (addr->blindedPublicKey, requstCallback);
|
localDestination->RequestDestinationWithEncryptedLeaseSet (addr->blindedPublicKey, requstCallback);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
SendReplyError ("empty lookup address");
|
||||||
|
}
|
||||||
|
|
||||||
void BOBCommandSession::LookupLocalCommandHandler (const char * operand, size_t len)
|
void BOBCommandSession::LookupLocalCommandHandler (const char * operand, size_t len)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "BOB: lookup local ", operand);
|
LogPrint (eLogDebug, "BOB: lookup local ", operand);
|
||||||
|
if (*operand)
|
||||||
|
{
|
||||||
auto addr = context.GetAddressBook ().GetAddress (operand);
|
auto addr = context.GetAddressBook ().GetAddress (operand);
|
||||||
if (!addr)
|
if (!addr)
|
||||||
{
|
{
|
||||||
@@ -662,6 +706,9 @@ namespace client
|
|||||||
else
|
else
|
||||||
SendReplyError ("Local LeaseSet Not found");
|
SendReplyError ("Local LeaseSet Not found");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
SendReplyError ("empty lookup address");
|
||||||
|
}
|
||||||
|
|
||||||
void BOBCommandSession::ClearCommandHandler (const char * operand, size_t len)
|
void BOBCommandSession::ClearCommandHandler (const char * operand, size_t len)
|
||||||
{
|
{
|
||||||
@@ -706,7 +753,7 @@ namespace client
|
|||||||
msg += operand;
|
msg += operand;
|
||||||
*(const_cast<char *>(value)) = '=';
|
*(const_cast<char *>(value)) = '=';
|
||||||
msg += " set to ";
|
msg += " set to ";
|
||||||
msg += value;
|
msg += value + 1;
|
||||||
SendReplyOK (msg.c_str ());
|
SendReplyOK (msg.c_str ());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -720,11 +767,11 @@ namespace client
|
|||||||
std::string statusLine;
|
std::string statusLine;
|
||||||
|
|
||||||
// always prefer destination
|
// always prefer destination
|
||||||
auto ptr = m_Owner.FindDestination(name);
|
auto dest = m_Owner.FindDestination(name);
|
||||||
if(ptr != nullptr)
|
if(dest)
|
||||||
{
|
{
|
||||||
// tunnel destination exists
|
// tunnel destination exists
|
||||||
BuildStatusLine(false, ptr, statusLine);
|
BuildStatusLine(false, dest, statusLine);
|
||||||
SendReplyOK(statusLine.c_str());
|
SendReplyOK(statusLine.c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -744,7 +791,7 @@ namespace client
|
|||||||
void BOBCommandSession::HelpCommandHandler (const char * operand, size_t len)
|
void BOBCommandSession::HelpCommandHandler (const char * operand, size_t len)
|
||||||
{
|
{
|
||||||
auto helpStrings = m_Owner.GetHelpStrings();
|
auto helpStrings = m_Owner.GetHelpStrings();
|
||||||
if(len == 0)
|
if(!*operand)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "COMMANDS:";
|
ss << "COMMANDS:";
|
||||||
@@ -886,4 +933,3 @@ namespace client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // WITH_BOB
|
|
||||||
|
|||||||
@@ -6,8 +6,6 @@
|
|||||||
* See full license text in LICENSE file at top of project tree
|
* See full license text in LICENSE file at top of project tree
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef WITH_BOB
|
|
||||||
|
|
||||||
#ifndef BOB_H__
|
#ifndef BOB_H__
|
||||||
#define BOB_H__
|
#define BOB_H__
|
||||||
|
|
||||||
@@ -165,6 +163,7 @@ namespace client
|
|||||||
int GetInPort() const { return m_InPort; }
|
int GetInPort() const { return m_InPort; }
|
||||||
int GetOutPort() const { return m_OutPort; }
|
int GetOutPort() const { return m_OutPort; }
|
||||||
bool GetQuiet() const { return m_Quiet; }
|
bool GetQuiet() const { return m_Quiet; }
|
||||||
|
bool IsRunning() const { return m_IsRunning; }
|
||||||
const i2p::data::PrivateKeys& GetKeys () const { return m_LocalDestination->GetPrivateKeys (); };
|
const i2p::data::PrivateKeys& GetKeys () const { return m_LocalDestination->GetPrivateKeys (); };
|
||||||
std::shared_ptr<ClientDestination> GetLocalDestination () const { return m_LocalDestination; };
|
std::shared_ptr<ClientDestination> GetLocalDestination () const { return m_LocalDestination; };
|
||||||
|
|
||||||
@@ -178,6 +177,7 @@ namespace client
|
|||||||
std::string m_InHost, m_OutHost;
|
std::string m_InHost, m_OutHost;
|
||||||
int m_InPort, m_OutPort;
|
int m_InPort, m_OutPort;
|
||||||
bool m_Quiet;
|
bool m_Quiet;
|
||||||
|
bool m_IsRunning;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BOBCommandChannel;
|
class BOBCommandChannel;
|
||||||
@@ -279,5 +279,5 @@ namespace client
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif // WITH_BOB
|
|
||||||
|
|||||||
@@ -26,16 +26,8 @@ namespace client
|
|||||||
ClientContext context;
|
ClientContext context;
|
||||||
|
|
||||||
ClientContext::ClientContext (): m_SharedLocalDestination (nullptr),
|
ClientContext::ClientContext (): m_SharedLocalDestination (nullptr),
|
||||||
m_HttpProxy (nullptr), m_SocksProxy (nullptr)
|
m_HttpProxy (nullptr), m_SocksProxy (nullptr), m_SamBridge (nullptr),
|
||||||
#ifdef WITH_SAM
|
m_BOBCommandChannel (nullptr), m_I2CPServer (nullptr)
|
||||||
, m_SamBridge (nullptr)
|
|
||||||
#endif
|
|
||||||
#ifdef WITH_BOB
|
|
||||||
, m_BOBCommandChannel (nullptr)
|
|
||||||
#endif
|
|
||||||
#ifdef WITH_I2CP
|
|
||||||
, m_I2CPServer (nullptr)
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,15 +35,9 @@ namespace client
|
|||||||
{
|
{
|
||||||
delete m_HttpProxy;
|
delete m_HttpProxy;
|
||||||
delete m_SocksProxy;
|
delete m_SocksProxy;
|
||||||
#ifdef WITH_SAM
|
|
||||||
delete m_SamBridge;
|
delete m_SamBridge;
|
||||||
#endif
|
|
||||||
#ifdef WITH_BOB
|
|
||||||
delete m_BOBCommandChannel;
|
delete m_BOBCommandChannel;
|
||||||
#endif
|
|
||||||
#ifdef WITH_I2CP
|
|
||||||
delete m_I2CPServer;
|
delete m_I2CPServer;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientContext::Start ()
|
void ClientContext::Start ()
|
||||||
@@ -72,7 +58,6 @@ namespace client
|
|||||||
// I2P tunnels
|
// I2P tunnels
|
||||||
ReadTunnels ();
|
ReadTunnels ();
|
||||||
|
|
||||||
#ifdef WITH_SAM
|
|
||||||
// SAM
|
// SAM
|
||||||
bool sam; i2p::config::GetOption("sam.enabled", sam);
|
bool sam; i2p::config::GetOption("sam.enabled", sam);
|
||||||
if (sam)
|
if (sam)
|
||||||
@@ -92,9 +77,7 @@ namespace client
|
|||||||
ThrowFatal ("Unable to start SAM bridge at ", samAddr, ":", samPort, ": ", e.what ());
|
ThrowFatal ("Unable to start SAM bridge at ", samAddr, ":", samPort, ": ", e.what ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef WITH_BOB
|
|
||||||
// BOB
|
// BOB
|
||||||
bool bob; i2p::config::GetOption("bob.enabled", bob);
|
bool bob; i2p::config::GetOption("bob.enabled", bob);
|
||||||
if (bob) {
|
if (bob) {
|
||||||
@@ -112,9 +95,7 @@ namespace client
|
|||||||
ThrowFatal ("Unable to start BOB bridge at ", bobAddr, ":", bobPort, ": ", e.what ());
|
ThrowFatal ("Unable to start BOB bridge at ", bobAddr, ":", bobPort, ": ", e.what ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef WITH_I2CP
|
|
||||||
// I2CP
|
// I2CP
|
||||||
bool i2cp; i2p::config::GetOption("i2cp.enabled", i2cp);
|
bool i2cp; i2p::config::GetOption("i2cp.enabled", i2cp);
|
||||||
if (i2cp)
|
if (i2cp)
|
||||||
@@ -134,7 +115,6 @@ namespace client
|
|||||||
ThrowFatal ("Unable to start I2CP at ", i2cpAddr, ":", i2cpPort, ": ", e.what ());
|
ThrowFatal ("Unable to start I2CP at ", i2cpAddr, ":", i2cpPort, ": ", e.what ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
m_AddressBook.StartResolvers ();
|
m_AddressBook.StartResolvers ();
|
||||||
|
|
||||||
@@ -178,7 +158,6 @@ namespace client
|
|||||||
}
|
}
|
||||||
m_ServerTunnels.clear ();
|
m_ServerTunnels.clear ();
|
||||||
|
|
||||||
#ifdef WITH_SAM
|
|
||||||
if (m_SamBridge)
|
if (m_SamBridge)
|
||||||
{
|
{
|
||||||
LogPrint(eLogInfo, "Clients: Stopping SAM bridge");
|
LogPrint(eLogInfo, "Clients: Stopping SAM bridge");
|
||||||
@@ -186,9 +165,7 @@ namespace client
|
|||||||
delete m_SamBridge;
|
delete m_SamBridge;
|
||||||
m_SamBridge = nullptr;
|
m_SamBridge = nullptr;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef WITH_BOB
|
|
||||||
if (m_BOBCommandChannel)
|
if (m_BOBCommandChannel)
|
||||||
{
|
{
|
||||||
LogPrint(eLogInfo, "Clients: Stopping BOB command channel");
|
LogPrint(eLogInfo, "Clients: Stopping BOB command channel");
|
||||||
@@ -196,9 +173,7 @@ namespace client
|
|||||||
delete m_BOBCommandChannel;
|
delete m_BOBCommandChannel;
|
||||||
m_BOBCommandChannel = nullptr;
|
m_BOBCommandChannel = nullptr;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef WITH_I2CP
|
|
||||||
if (m_I2CPServer)
|
if (m_I2CPServer)
|
||||||
{
|
{
|
||||||
LogPrint(eLogInfo, "Clients: Stopping I2CP");
|
LogPrint(eLogInfo, "Clients: Stopping I2CP");
|
||||||
@@ -206,7 +181,6 @@ namespace client
|
|||||||
delete m_I2CPServer;
|
delete m_I2CPServer;
|
||||||
m_I2CPServer = nullptr;
|
m_I2CPServer = nullptr;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
LogPrint(eLogInfo, "Clients: Stopping AddressBook");
|
LogPrint(eLogInfo, "Clients: Stopping AddressBook");
|
||||||
m_AddressBook.Stop ();
|
m_AddressBook.Stop ();
|
||||||
@@ -287,7 +261,7 @@ namespace client
|
|||||||
static const std::string transient("transient");
|
static const std::string transient("transient");
|
||||||
if (!filename.compare (0, transient.length (), transient)) // starts with transient
|
if (!filename.compare (0, transient.length (), transient)) // starts with transient
|
||||||
{
|
{
|
||||||
keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType);
|
keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType, true);
|
||||||
LogPrint (eLogInfo, "Clients: New transient keys address ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " created");
|
LogPrint (eLogInfo, "Clients: New transient keys address ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " created");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -314,7 +288,7 @@ namespace client
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "Clients: Can't open file ", fullPath, " Creating new one with signature type ", sigType, " crypto type ", cryptoType);
|
LogPrint (eLogError, "Clients: Can't open file ", fullPath, " Creating new one with signature type ", sigType, " crypto type ", cryptoType);
|
||||||
keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType);
|
keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType, true);
|
||||||
std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
|
std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
|
||||||
size_t len = keys.GetFullLen ();
|
size_t len = keys.GetFullLen ();
|
||||||
uint8_t * buf = new uint8_t[len];
|
uint8_t * buf = new uint8_t[len];
|
||||||
@@ -354,7 +328,7 @@ namespace client
|
|||||||
i2p::data::SigningKeyType sigType, i2p::data::CryptoKeyType cryptoType,
|
i2p::data::SigningKeyType sigType, i2p::data::CryptoKeyType cryptoType,
|
||||||
const std::map<std::string, std::string> * params)
|
const std::map<std::string, std::string> * params)
|
||||||
{
|
{
|
||||||
i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType);
|
i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType, true);
|
||||||
auto localDestination = std::make_shared<RunnableClientDestination> (keys, isPublic, params);
|
auto localDestination = std::make_shared<RunnableClientDestination> (keys, isPublic, params);
|
||||||
AddLocalDestination (localDestination);
|
AddLocalDestination (localDestination);
|
||||||
return localDestination;
|
return localDestination;
|
||||||
@@ -365,7 +339,7 @@ namespace client
|
|||||||
i2p::data::SigningKeyType sigType, i2p::data::CryptoKeyType cryptoType,
|
i2p::data::SigningKeyType sigType, i2p::data::CryptoKeyType cryptoType,
|
||||||
const std::map<std::string, std::string> * params)
|
const std::map<std::string, std::string> * params)
|
||||||
{
|
{
|
||||||
i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType);
|
i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType, true);
|
||||||
auto localDestination = std::make_shared<ClientDestination> (service, keys, isPublic, params);
|
auto localDestination = std::make_shared<ClientDestination> (service, keys, isPublic, params);
|
||||||
AddLocalDestination (localDestination);
|
AddLocalDestination (localDestination);
|
||||||
return localDestination;
|
return localDestination;
|
||||||
@@ -649,6 +623,14 @@ namespace client
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// TODO: update
|
||||||
|
if (ins.first->second->GetLocalDestination () != clientTunnel->GetLocalDestination ())
|
||||||
|
{
|
||||||
|
LogPrint (eLogInfo, "Clients: I2P UDP client tunnel destination updated");
|
||||||
|
ins.first->second->Stop ();
|
||||||
|
ins.first->second->SetLocalDestination (clientTunnel->GetLocalDestination ());
|
||||||
|
ins.first->second->Start ();
|
||||||
|
}
|
||||||
ins.first->second->isUpdated = true;
|
ins.first->second->isUpdated = true;
|
||||||
LogPrint(eLogError, "Clients: I2P Client forward for endpoint ", end, " already exists");
|
LogPrint(eLogError, "Clients: I2P Client forward for endpoint ", end, " already exists");
|
||||||
}
|
}
|
||||||
@@ -744,6 +726,7 @@ namespace client
|
|||||||
|
|
||||||
std::string address = section.second.get<std::string> (I2P_SERVER_TUNNEL_ADDRESS, "");
|
std::string address = section.second.get<std::string> (I2P_SERVER_TUNNEL_ADDRESS, "");
|
||||||
bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true);
|
bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true);
|
||||||
|
bool ssl = section.second.get(I2P_SERVER_TUNNEL_SSL, false);
|
||||||
|
|
||||||
// I2CP
|
// I2CP
|
||||||
std::map<std::string, std::string> options;
|
std::map<std::string, std::string> options;
|
||||||
@@ -822,6 +805,8 @@ namespace client
|
|||||||
LogPrint(eLogInfo, "Clients: Disabling loopback address mapping");
|
LogPrint(eLogInfo, "Clients: Disabling loopback address mapping");
|
||||||
serverTunnel->SetUniqueLocal(isUniqueLocal);
|
serverTunnel->SetUniqueLocal(isUniqueLocal);
|
||||||
}
|
}
|
||||||
|
if (ssl)
|
||||||
|
serverTunnel->SetSSL (true);
|
||||||
if (accessList.length () > 0)
|
if (accessList.length () > 0)
|
||||||
{
|
{
|
||||||
std::set<i2p::data::IdentHash> idents;
|
std::set<i2p::data::IdentHash> idents;
|
||||||
@@ -882,6 +867,8 @@ namespace client
|
|||||||
uint16_t httpProxyPort; i2p::config::GetOption("httpproxy.port", httpProxyPort);
|
uint16_t httpProxyPort; i2p::config::GetOption("httpproxy.port", httpProxyPort);
|
||||||
std::string httpOutProxyURL; i2p::config::GetOption("httpproxy.outproxy", httpOutProxyURL);
|
std::string httpOutProxyURL; i2p::config::GetOption("httpproxy.outproxy", httpOutProxyURL);
|
||||||
bool httpAddresshelper; i2p::config::GetOption("httpproxy.addresshelper", httpAddresshelper);
|
bool httpAddresshelper; i2p::config::GetOption("httpproxy.addresshelper", httpAddresshelper);
|
||||||
|
if (httpAddresshelper)
|
||||||
|
i2p::config::GetOption("addressbook.enabled", httpAddresshelper); // addresshelper is not supported without address book
|
||||||
i2p::data::SigningKeyType sigType; i2p::config::GetOption("httpproxy.signaturetype", sigType);
|
i2p::data::SigningKeyType sigType; i2p::config::GetOption("httpproxy.signaturetype", sigType);
|
||||||
LogPrint(eLogInfo, "Clients: Starting HTTP Proxy at ", httpProxyAddr, ":", httpProxyPort);
|
LogPrint(eLogInfo, "Clients: Starting HTTP Proxy at ", httpProxyAddr, ":", httpProxyPort);
|
||||||
if (httpProxyKeys.length () > 0)
|
if (httpProxyKeys.length () > 0)
|
||||||
@@ -1002,11 +989,11 @@ namespace client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* // TODO: Write correct UDP tunnels stop
|
// TODO: Write correct UDP tunnels stop
|
||||||
for (auto it = m_ClientForwards.begin (); it != m_ClientForwards.end ();)
|
for (auto it = m_ClientForwards.begin (); it != m_ClientForwards.end ();)
|
||||||
{
|
{
|
||||||
if(clean && !it->second->isUpdated) {
|
if(clean && !it->second->isUpdated) {
|
||||||
it->second = nullptr;
|
it->second->Stop ();
|
||||||
it = m_ClientForwards.erase(it);
|
it = m_ClientForwards.erase(it);
|
||||||
} else {
|
} else {
|
||||||
it->second->isUpdated = false;
|
it->second->isUpdated = false;
|
||||||
@@ -1017,13 +1004,13 @@ namespace client
|
|||||||
for (auto it = m_ServerForwards.begin (); it != m_ServerForwards.end ();)
|
for (auto it = m_ServerForwards.begin (); it != m_ServerForwards.end ();)
|
||||||
{
|
{
|
||||||
if(clean && !it->second->isUpdated) {
|
if(clean && !it->second->isUpdated) {
|
||||||
it->second = nullptr;
|
it->second->Stop ();
|
||||||
it = m_ServerForwards.erase(it);
|
it = m_ServerForwards.erase(it);
|
||||||
} else {
|
} else {
|
||||||
it->second->isUpdated = false;
|
it->second->isUpdated = false;
|
||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
} */
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,19 +18,10 @@
|
|||||||
#include "HTTPProxy.h"
|
#include "HTTPProxy.h"
|
||||||
#include "SOCKS.h"
|
#include "SOCKS.h"
|
||||||
#include "I2PTunnel.h"
|
#include "I2PTunnel.h"
|
||||||
|
#include "UDPTunnel.h"
|
||||||
#ifdef WITH_SAM
|
|
||||||
#include "SAM.h"
|
#include "SAM.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef WITH_BOB
|
|
||||||
#include "BOB.h"
|
#include "BOB.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef WITH_I2CP
|
|
||||||
#include "I2CP.h"
|
#include "I2CP.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "AddressBook.h"
|
#include "AddressBook.h"
|
||||||
#include "I18N_langs.h"
|
#include "I18N_langs.h"
|
||||||
|
|
||||||
@@ -71,7 +62,7 @@ namespace client
|
|||||||
const char I2P_SERVER_TUNNEL_WEBIRC_PASSWORD[] = "webircpassword";
|
const char I2P_SERVER_TUNNEL_WEBIRC_PASSWORD[] = "webircpassword";
|
||||||
const char I2P_SERVER_TUNNEL_ADDRESS[] = "address";
|
const char I2P_SERVER_TUNNEL_ADDRESS[] = "address";
|
||||||
const char I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL[] = "enableuniquelocal";
|
const char I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL[] = "enableuniquelocal";
|
||||||
|
const char I2P_SERVER_TUNNEL_SSL[] = "ssl";
|
||||||
|
|
||||||
class ClientContext
|
class ClientContext
|
||||||
{
|
{
|
||||||
@@ -86,45 +77,31 @@ namespace client
|
|||||||
void ReloadConfig ();
|
void ReloadConfig ();
|
||||||
|
|
||||||
std::shared_ptr<ClientDestination> GetSharedLocalDestination () const { return m_SharedLocalDestination; };
|
std::shared_ptr<ClientDestination> GetSharedLocalDestination () const { return m_SharedLocalDestination; };
|
||||||
|
std::shared_ptr<ClientDestination> CreateNewLocalDestination (bool isPublic = false, // transient
|
||||||
std::shared_ptr<ClientDestination> CreateNewLocalDestination (
|
|
||||||
bool isPublic = false, // transient
|
|
||||||
i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519,
|
i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519,
|
||||||
i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL,
|
i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL,
|
||||||
const std::map<std::string, std::string> * params = nullptr); // used by SAM only
|
const std::map<std::string, std::string> * params = nullptr); // used by SAM only
|
||||||
|
|
||||||
std::shared_ptr<ClientDestination> CreateNewLocalDestination (boost::asio::io_service& service,
|
std::shared_ptr<ClientDestination> CreateNewLocalDestination (boost::asio::io_service& service,
|
||||||
bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519,
|
bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519,
|
||||||
i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL,
|
i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL,
|
||||||
const std::map<std::string, std::string> * params = nullptr); // same as previous but on external io_service
|
const std::map<std::string, std::string> * params = nullptr); // same as previous but on external io_service
|
||||||
|
|
||||||
std::shared_ptr<ClientDestination> CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true,
|
std::shared_ptr<ClientDestination> CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true,
|
||||||
const std::map<std::string, std::string> * params = nullptr);
|
const std::map<std::string, std::string> * params = nullptr);
|
||||||
|
|
||||||
std::shared_ptr<ClientDestination> CreateNewLocalDestination (boost::asio::io_service& service,
|
std::shared_ptr<ClientDestination> CreateNewLocalDestination (boost::asio::io_service& service,
|
||||||
const i2p::data::PrivateKeys& keys, bool isPublic = true,
|
const i2p::data::PrivateKeys& keys, bool isPublic = true,
|
||||||
const std::map<std::string, std::string> * params = nullptr); // same as previous but on external io_service
|
const std::map<std::string, std::string> * params = nullptr); // same as previous but on external io_service
|
||||||
|
|
||||||
std::shared_ptr<ClientDestination> CreateNewMatchedTunnelDestination(const i2p::data::PrivateKeys &keys,
|
std::shared_ptr<ClientDestination> CreateNewMatchedTunnelDestination(const i2p::data::PrivateKeys &keys,
|
||||||
const std::string & name, const std::map<std::string, std::string> * params = nullptr);
|
const std::string & name, const std::map<std::string, std::string> * params = nullptr);
|
||||||
|
|
||||||
void DeleteLocalDestination (std::shared_ptr<ClientDestination> destination);
|
void DeleteLocalDestination (std::shared_ptr<ClientDestination> destination);
|
||||||
std::shared_ptr<ClientDestination> FindLocalDestination (const i2p::data::IdentHash& destination) const;
|
std::shared_ptr<ClientDestination> FindLocalDestination (const i2p::data::IdentHash& destination) const;
|
||||||
|
|
||||||
bool LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename,
|
bool LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename,
|
||||||
i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519,
|
i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519,
|
||||||
i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL);
|
i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL);
|
||||||
|
|
||||||
AddressBook& GetAddressBook () { return m_AddressBook; };
|
AddressBook& GetAddressBook () { return m_AddressBook; };
|
||||||
#ifdef WITH_BOB
|
|
||||||
const BOBCommandChannel * GetBOBCommandChannel () const { return m_BOBCommandChannel; };
|
const BOBCommandChannel * GetBOBCommandChannel () const { return m_BOBCommandChannel; };
|
||||||
#endif
|
|
||||||
#ifdef WITH_SAM
|
|
||||||
const SAMBridge * GetSAMBridge () const { return m_SamBridge; };
|
const SAMBridge * GetSAMBridge () const { return m_SamBridge; };
|
||||||
#endif
|
|
||||||
#ifdef WITH_I2CP
|
|
||||||
const I2CPServer * GetI2CPServer () const { return m_I2CPServer; };
|
const I2CPServer * GetI2CPServer () const { return m_I2CPServer; };
|
||||||
#endif
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<DatagramSessionInfo> > GetForwardInfosFor(const i2p::data::IdentHash & destination);
|
std::vector<std::shared_ptr<DatagramSessionInfo> > GetForwardInfosFor(const i2p::data::IdentHash & destination);
|
||||||
|
|
||||||
@@ -173,15 +150,9 @@ namespace client
|
|||||||
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<I2PUDPClientTunnel> > m_ClientForwards; // local endpoint -> udp tunnel
|
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<I2PUDPClientTunnel> > m_ClientForwards; // local endpoint -> udp tunnel
|
||||||
std::map<std::pair<i2p::data::IdentHash, int>, std::shared_ptr<I2PUDPServerTunnel> > m_ServerForwards; // <destination,port> -> udp tunnel
|
std::map<std::pair<i2p::data::IdentHash, int>, std::shared_ptr<I2PUDPServerTunnel> > m_ServerForwards; // <destination,port> -> udp tunnel
|
||||||
|
|
||||||
#ifdef WITH_SAM
|
|
||||||
SAMBridge * m_SamBridge;
|
SAMBridge * m_SamBridge;
|
||||||
#endif
|
|
||||||
#ifdef WITH_BOB
|
|
||||||
BOBCommandChannel * m_BOBCommandChannel;
|
BOBCommandChannel * m_BOBCommandChannel;
|
||||||
#endif
|
|
||||||
#ifdef WITH_I2CP
|
|
||||||
I2CPServer * m_I2CPServer;
|
I2CPServer * m_I2CPServer;
|
||||||
#endif
|
|
||||||
|
|
||||||
std::unique_ptr<boost::asio::deadline_timer> m_CleanupUDPTimer;
|
std::unique_ptr<boost::asio::deadline_timer> m_CleanupUDPTimer;
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@@ -32,10 +32,18 @@
|
|||||||
|
|
||||||
namespace i2p {
|
namespace i2p {
|
||||||
namespace proxy {
|
namespace proxy {
|
||||||
std::map<std::string, std::string> jumpservices = {
|
static const std::vector<std::string> jumporder = {
|
||||||
|
"reg.i2p",
|
||||||
|
"stats.i2p",
|
||||||
|
"identiguy.i2p",
|
||||||
|
"notbob.i2p"
|
||||||
|
};
|
||||||
|
|
||||||
|
static const std::map<std::string, std::string> jumpservices = {
|
||||||
{ "reg.i2p", "http://shx5vqsw7usdaunyzr2qmes2fq37oumybpudrd4jjj4e4vk4uusa.b32.i2p/jump/" },
|
{ "reg.i2p", "http://shx5vqsw7usdaunyzr2qmes2fq37oumybpudrd4jjj4e4vk4uusa.b32.i2p/jump/" },
|
||||||
{ "identiguy.i2p", "http://3mzmrus2oron5fxptw7hw2puho3bnqmw2hqy7nw64dsrrjwdilva.b32.i2p/cgi-bin/query?hostname=" },
|
{ "identiguy.i2p", "http://3mzmrus2oron5fxptw7hw2puho3bnqmw2hqy7nw64dsrrjwdilva.b32.i2p/cgi-bin/query?hostname=" },
|
||||||
{ "stats.i2p", "http://7tbay5p4kzeekxvyvbf6v7eauazemsnnl2aoyqhg5jzpr5eke7tq.b32.i2p/cgi-bin/jump.cgi?a=" },
|
{ "stats.i2p", "http://7tbay5p4kzeekxvyvbf6v7eauazemsnnl2aoyqhg5jzpr5eke7tq.b32.i2p/cgi-bin/jump.cgi?a=" },
|
||||||
|
{ "notbob.i2p", "http://nytzrhrjjfsutowojvxi7hphesskpqqr65wpistz6wa7cpajhp7a.b32.i2p/cgi-bin/jump.cgi?q=" }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *pageHead =
|
static const char *pageHead =
|
||||||
@@ -76,6 +84,7 @@ namespace proxy {
|
|||||||
void GenericProxyInfo(const std::string& title, const std::string& description);
|
void GenericProxyInfo(const std::string& title, const std::string& description);
|
||||||
void HostNotFound(std::string& host);
|
void HostNotFound(std::string& host);
|
||||||
void SendProxyError(std::string& content);
|
void SendProxyError(std::string& content);
|
||||||
|
void SendRedirect(std::string& address);
|
||||||
|
|
||||||
void ForwardToUpstreamProxy();
|
void ForwardToUpstreamProxy();
|
||||||
void HandleUpstreamHTTPProxyConnect(const boost::system::error_code & ec);
|
void HandleUpstreamHTTPProxyConnect(const boost::system::error_code & ec);
|
||||||
@@ -174,8 +183,11 @@ namespace proxy {
|
|||||||
<< "<p>" << tr("Remote host not found in router's addressbook") << "</p>\r\n"
|
<< "<p>" << tr("Remote host not found in router's addressbook") << "</p>\r\n"
|
||||||
<< "<p>" << tr("You may try to find this host on jump services below") << ":</p>\r\n"
|
<< "<p>" << tr("You may try to find this host on jump services below") << ":</p>\r\n"
|
||||||
<< "<ul>\r\n";
|
<< "<ul>\r\n";
|
||||||
for (const auto& js : jumpservices) {
|
for (const auto& jump : jumporder)
|
||||||
ss << " <li><a href=\"" << js.second << host << "\">" << js.first << "</a></li>\r\n";
|
{
|
||||||
|
auto js = jumpservices.find (jump);
|
||||||
|
if (js != jumpservices.end())
|
||||||
|
ss << " <li><a href=\"" << js->second << host << "\">" << js->first << "</a></li>\r\n";
|
||||||
}
|
}
|
||||||
ss << "</ul>\r\n";
|
ss << "</ul>\r\n";
|
||||||
std::string content = ss.str();
|
std::string content = ss.str();
|
||||||
@@ -198,6 +210,17 @@ namespace proxy {
|
|||||||
std::bind(&HTTPReqHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1));
|
std::bind(&HTTPReqHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HTTPReqHandler::SendRedirect(std::string& address)
|
||||||
|
{
|
||||||
|
i2p::http::HTTPRes res;
|
||||||
|
res.code = 302;
|
||||||
|
res.add_header("Location", address);
|
||||||
|
res.add_header("Connection", "close");
|
||||||
|
std::string response = res.to_string();
|
||||||
|
boost::asio::async_write(*m_sock, boost::asio::buffer(response), boost::asio::transfer_all(),
|
||||||
|
std::bind(&HTTPReqHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1));
|
||||||
|
}
|
||||||
|
|
||||||
bool HTTPReqHandler::ExtractAddressHelper(i2p::http::URL & url, std::string & b64, bool & confirm)
|
bool HTTPReqHandler::ExtractAddressHelper(i2p::http::URL & url, std::string & b64, bool & confirm)
|
||||||
{
|
{
|
||||||
confirm = false;
|
confirm = false;
|
||||||
@@ -228,6 +251,8 @@ namespace proxy {
|
|||||||
req.RemoveHeader("Via");
|
req.RemoveHeader("Via");
|
||||||
req.RemoveHeader("From");
|
req.RemoveHeader("From");
|
||||||
req.RemoveHeader("Forwarded");
|
req.RemoveHeader("Forwarded");
|
||||||
|
req.RemoveHeader("DNT"); // Useless DoNotTrack flag
|
||||||
|
req.RemoveHeader("X-Requested-With"); // Android Webview send this with the value set to the application ID
|
||||||
req.RemoveHeader("Accept", "Accept-Encoding"); // Accept*, but Accept-Encoding
|
req.RemoveHeader("Accept", "Accept-Encoding"); // Accept*, but Accept-Encoding
|
||||||
/* drop proxy-disclosing headers */
|
/* drop proxy-disclosing headers */
|
||||||
req.RemoveHeader("X-Forwarded");
|
req.RemoveHeader("X-Forwarded");
|
||||||
@@ -237,14 +262,14 @@ namespace proxy {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* according to i2p ticket #1862:
|
* according to i2p ticket #1862:
|
||||||
* leave Referrer if requested URL with same schema, host and port,
|
* leave Referer if requested URL with same schema, host and port,
|
||||||
* otherwise, drop it.
|
* otherwise, drop it.
|
||||||
*/
|
*/
|
||||||
if(req.GetHeader("Referrer") != "") {
|
if(req.GetHeader("Referer") != "") {
|
||||||
i2p::http::URL reqURL; reqURL.parse(req.uri);
|
i2p::http::URL reqURL; reqURL.parse(req.uri);
|
||||||
i2p::http::URL refURL; refURL.parse(req.GetHeader("Referrer"));
|
i2p::http::URL refURL; refURL.parse(req.GetHeader("Referer"));
|
||||||
if(!boost::iequals(reqURL.schema, refURL.schema) || !boost::iequals(reqURL.host, refURL.host) || reqURL.port != refURL.port)
|
if(!boost::iequals(reqURL.schema, refURL.schema) || !boost::iequals(reqURL.host, refURL.host) || reqURL.port != refURL.port)
|
||||||
req.RemoveHeader("Referrer");
|
req.RemoveHeader("Referer");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add headers */
|
/* add headers */
|
||||||
@@ -288,7 +313,14 @@ namespace proxy {
|
|||||||
GenericProxyError(tr("Invalid request"), tr("addresshelper is not supported"));
|
GenericProxyError(tr("Invalid request"), tr("addresshelper is not supported"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!i2p::client::context.GetAddressBook ().FindAddress (m_RequestURL.host) || m_Confirm)
|
|
||||||
|
if (i2p::client::context.GetAddressBook ().RecordExists (m_RequestURL.host, jump))
|
||||||
|
{
|
||||||
|
std::string full_url = m_RequestURL.to_string();
|
||||||
|
SendRedirect(full_url);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (!i2p::client::context.GetAddressBook ().FindAddress (m_RequestURL.host) || m_Confirm)
|
||||||
{
|
{
|
||||||
i2p::client::context.GetAddressBook ().InsertAddress (m_RequestURL.host, jump);
|
i2p::client::context.GetAddressBook ().InsertAddress (m_RequestURL.host, jump);
|
||||||
LogPrint (eLogInfo, "HTTPProxy: Added address from addresshelper for ", m_RequestURL.host);
|
LogPrint (eLogInfo, "HTTPProxy: Added address from addresshelper for ", m_RequestURL.host);
|
||||||
@@ -304,7 +336,8 @@ namespace proxy {
|
|||||||
std::string full_url = m_RequestURL.to_string();
|
std::string full_url = m_RequestURL.to_string();
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << tr("Host") << " " << m_RequestURL.host << " <font color=red>" << tr("already in router's addressbook") << "</font>. ";
|
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:" );
|
||||||
|
ss << " <a href=\"" << full_url << (full_url.find('?') != std::string::npos ? "&i2paddresshelper=" : "?i2paddresshelper=");
|
||||||
ss << jump << "&update=true\">" << tr("Continue") << "</a>.";
|
ss << jump << "&update=true\">" << tr("Continue") << "</a>.";
|
||||||
GenericProxyInfo(tr("Addresshelper found"), ss.str());
|
GenericProxyInfo(tr("Addresshelper found"), ss.str());
|
||||||
return true; /* request processed */
|
return true; /* request processed */
|
||||||
@@ -413,8 +446,8 @@ namespace proxy {
|
|||||||
void HTTPReqHandler::ForwardToUpstreamProxy()
|
void HTTPReqHandler::ForwardToUpstreamProxy()
|
||||||
{
|
{
|
||||||
LogPrint(eLogDebug, "HTTPProxy: Forwarded to upstream");
|
LogPrint(eLogDebug, "HTTPProxy: Forwarded to upstream");
|
||||||
// build http request
|
|
||||||
|
|
||||||
|
/* build http request */
|
||||||
m_ClientRequestURL = m_RequestURL;
|
m_ClientRequestURL = m_RequestURL;
|
||||||
LogPrint(eLogDebug, "HTTPProxy: ", m_ClientRequestURL.host);
|
LogPrint(eLogDebug, "HTTPProxy: ", m_ClientRequestURL.host);
|
||||||
m_ClientRequestURL.schema = "";
|
m_ClientRequestURL.schema = "";
|
||||||
@@ -422,17 +455,17 @@ namespace proxy {
|
|||||||
std::string origURI = m_ClientRequest.uri; // TODO: what do we need to change uri for?
|
std::string origURI = m_ClientRequest.uri; // TODO: what do we need to change uri for?
|
||||||
m_ClientRequest.uri = m_ClientRequestURL.to_string();
|
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")
|
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.UpdateHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; rv:60.0) Gecko/20100101 Firefox/60.0");
|
||||||
|
|
||||||
m_ClientRequest.write(m_ClientRequestBuffer);
|
m_ClientRequest.write(m_ClientRequestBuffer);
|
||||||
m_ClientRequestBuffer << m_recv_buf.substr(m_req_len);
|
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")
|
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.port) m_ProxyURL.port = 80;
|
||||||
if (m_ProxyURL.is_i2p())
|
if (m_ProxyURL.is_i2p())
|
||||||
{
|
{
|
||||||
@@ -440,9 +473,9 @@ namespace proxy {
|
|||||||
auto auth = i2p::http::CreateBasicAuthorizationString (m_ProxyURL.user, m_ProxyURL.pass);
|
auto auth = i2p::http::CreateBasicAuthorizationString (m_ProxyURL.user, m_ProxyURL.pass);
|
||||||
if (!auth.empty ())
|
if (!auth.empty ())
|
||||||
{
|
{
|
||||||
// remove existing authorization if any
|
/* remove existing authorization if any */
|
||||||
m_ClientRequest.RemoveHeader("Proxy-");
|
m_ClientRequest.RemoveHeader("Proxy-");
|
||||||
// add own http proxy authorization
|
/* add own http proxy authorization */
|
||||||
m_ClientRequest.AddHeader("Proxy-Authorization", auth);
|
m_ClientRequest.AddHeader("Proxy-Authorization", auth);
|
||||||
}
|
}
|
||||||
m_send_buf = m_ClientRequest.to_string();
|
m_send_buf = m_ClientRequest.to_string();
|
||||||
@@ -461,7 +494,7 @@ namespace proxy {
|
|||||||
}
|
}
|
||||||
else if (m_ProxyURL.schema == "socks")
|
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
|
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));
|
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) {
|
m_proxy_resolver.async_resolve(q, std::bind(&HTTPReqHandler::HandleUpstreamProxyResolved, this, std::placeholders::_1, std::placeholders::_2, [&](boost::asio::ip::tcp::endpoint ep) {
|
||||||
@@ -470,7 +503,7 @@ namespace proxy {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// unknown type, complain
|
/* unknown type, complain */
|
||||||
GenericProxyError(tr("unknown outproxy url"), m_ProxyURL.to_string());
|
GenericProxyError(tr("unknown outproxy url"), m_ProxyURL.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,6 @@
|
|||||||
* See full license text in LICENSE file at top of project tree
|
* See full license text in LICENSE file at top of project tree
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef WITH_I2CP
|
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
@@ -526,31 +524,21 @@ namespace client
|
|||||||
|
|
||||||
void I2CPSession::CreateSessionMessageHandler (const uint8_t * buf, size_t len)
|
void I2CPSession::CreateSessionMessageHandler (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
if (m_Destination || !m_Owner.InsertSession (shared_from_this ()))
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "I2CP: Session already exists");
|
|
||||||
SendSessionStatusMessage (eI2CPSessionStatusRefused); // refused
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
RAND_bytes ((uint8_t *)&m_SessionID, 2);
|
RAND_bytes ((uint8_t *)&m_SessionID, 2);
|
||||||
auto identity = std::make_shared<i2p::data::IdentityEx>();
|
auto identity = std::make_shared<i2p::data::IdentityEx>();
|
||||||
size_t offset = identity->FromBuffer (buf, len);
|
size_t offset = identity->FromBuffer (buf, len);
|
||||||
|
|
||||||
if (!offset)
|
if (!offset)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "I2CP: Create session malformed identity");
|
LogPrint (eLogError, "I2CP: Create session malformed identity");
|
||||||
SendSessionStatusMessage (eI2CPSessionStatusInvalid); // invalid
|
SendSessionStatusMessage (eI2CPSessionStatusInvalid); // invalid
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_Owner.FindSessionByIdentHash (identity->GetIdentHash ()))
|
if (m_Owner.FindSessionByIdentHash (identity->GetIdentHash ()))
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "I2CP: Create session duplicate address ", identity->GetIdentHash ().ToBase32 ());
|
LogPrint (eLogError, "I2CP: Create session duplicate address ", identity->GetIdentHash ().ToBase32 ());
|
||||||
SendSessionStatusMessage (eI2CPSessionStatusInvalid); // invalid
|
SendSessionStatusMessage (eI2CPSessionStatusInvalid); // invalid
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t optionsSize = bufbe16toh (buf + offset);
|
uint16_t optionsSize = bufbe16toh (buf + offset);
|
||||||
offset += 2;
|
offset += 2;
|
||||||
if (optionsSize > len - offset)
|
if (optionsSize > len - offset)
|
||||||
@@ -559,28 +547,43 @@ namespace client
|
|||||||
SendSessionStatusMessage (eI2CPSessionStatusInvalid); // invalid
|
SendSessionStatusMessage (eI2CPSessionStatusInvalid); // invalid
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, std::string> params;
|
std::map<std::string, std::string> params;
|
||||||
ExtractMapping (buf + offset, optionsSize, params);
|
ExtractMapping (buf + offset, optionsSize, params);
|
||||||
offset += optionsSize; // options
|
offset += optionsSize; // options
|
||||||
if (params[I2CP_PARAM_MESSAGE_RELIABILITY] == "none") m_IsSendAccepted = false;
|
if (params[I2CP_PARAM_MESSAGE_RELIABILITY] == "none") m_IsSendAccepted = false;
|
||||||
|
|
||||||
offset += 8; // date
|
offset += 8; // date
|
||||||
if (!identity->Verify (buf, offset, buf + offset)) // signature
|
if (identity->Verify (buf, offset, buf + offset)) // signature
|
||||||
|
{
|
||||||
|
if (!m_Destination)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "I2CP: Create session signature verification failed");
|
|
||||||
SendSessionStatusMessage (eI2CPSessionStatusInvalid); // invalid
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Destination = m_Owner.IsSingleThread () ?
|
m_Destination = m_Owner.IsSingleThread () ?
|
||||||
std::make_shared<I2CPDestination>(m_Owner.GetService (), shared_from_this (), identity, true, params):
|
std::make_shared<I2CPDestination>(m_Owner.GetService (), shared_from_this (), identity, true, params):
|
||||||
std::make_shared<RunnableI2CPDestination>(shared_from_this (), identity, true, params);
|
std::make_shared<RunnableI2CPDestination>(shared_from_this (), identity, true, params);
|
||||||
|
if (m_Owner.InsertSession (shared_from_this ()))
|
||||||
|
{
|
||||||
SendSessionStatusMessage (eI2CPSessionStatusCreated); // created
|
SendSessionStatusMessage (eI2CPSessionStatusCreated); // created
|
||||||
LogPrint (eLogDebug, "I2CP: Session ", m_SessionID, " created");
|
LogPrint (eLogDebug, "I2CP: Session ", m_SessionID, " created");
|
||||||
m_Destination->Start ();
|
m_Destination->Start ();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "I2CP: Session already exists");
|
||||||
|
SendSessionStatusMessage (eI2CPSessionStatusRefused);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "I2CP: Session already exists");
|
||||||
|
SendSessionStatusMessage (eI2CPSessionStatusRefused); // refused
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "I2CP: Create session signature verification failed");
|
||||||
|
SendSessionStatusMessage (eI2CPSessionStatusInvalid); // invalid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void I2CPSession::DestroySessionMessageHandler (const uint8_t * buf, size_t len)
|
void I2CPSession::DestroySessionMessageHandler (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
@@ -1037,4 +1040,3 @@ namespace client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // WITH_I2CP
|
|
||||||
|
|||||||
@@ -6,8 +6,6 @@
|
|||||||
* See full license text in LICENSE file at top of project tree
|
* See full license text in LICENSE file at top of project tree
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef WITH_I2CP
|
|
||||||
|
|
||||||
#ifndef I2CP_H__
|
#ifndef I2CP_H__
|
||||||
#define I2CP_H__
|
#define I2CP_H__
|
||||||
|
|
||||||
@@ -251,4 +249,3 @@ namespace client
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif // WITH_I2CP
|
|
||||||
|
|||||||
@@ -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
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
#include "Base.h"
|
#include "Base.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Destination.h"
|
#include "Destination.h"
|
||||||
@@ -45,10 +46,13 @@ namespace client
|
|||||||
}
|
}
|
||||||
|
|
||||||
I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
|
I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
|
||||||
std::shared_ptr<boost::asio::ip::tcp::socket> socket, const boost::asio::ip::tcp::endpoint& target, bool quiet):
|
const boost::asio::ip::tcp::endpoint& target, bool quiet,
|
||||||
I2PServiceHandler(owner), m_Socket (socket), m_Stream (stream),
|
std::shared_ptr<boost::asio::ssl::context> sslCtx):
|
||||||
m_RemoteEndpoint (target), m_IsQuiet (quiet)
|
I2PServiceHandler(owner), m_Stream (stream), m_RemoteEndpoint (target), m_IsQuiet (quiet)
|
||||||
{
|
{
|
||||||
|
m_Socket = std::make_shared<boost::asio::ip::tcp::socket> (owner->GetService ());
|
||||||
|
if (sslCtx)
|
||||||
|
m_SSL = std::make_shared<boost::asio::ssl::stream<boost::asio::ip::tcp::socket&> > (*m_Socket, *sslCtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
I2PTunnelConnection::~I2PTunnelConnection ()
|
I2PTunnelConnection::~I2PTunnelConnection ()
|
||||||
@@ -68,7 +72,7 @@ namespace client
|
|||||||
Receive ();
|
Receive ();
|
||||||
}
|
}
|
||||||
|
|
||||||
static boost::asio::ip::address GetLoopbackAddressFor(const i2p::data::IdentHash & addr)
|
boost::asio::ip::address GetLoopbackAddressFor(const i2p::data::IdentHash & addr)
|
||||||
{
|
{
|
||||||
boost::asio::ip::address_v4::bytes_type bytes;
|
boost::asio::ip::address_v4::bytes_type bytes;
|
||||||
const uint8_t * ident = addr;
|
const uint8_t * ident = addr;
|
||||||
@@ -79,7 +83,9 @@ namespace client
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
static void MapToLoopback(const std::shared_ptr<boost::asio::ip::tcp::socket> & sock, const i2p::data::IdentHash & addr)
|
static void MapToLoopback(std::shared_ptr<boost::asio::ip::tcp::socket> sock, const i2p::data::IdentHash & addr)
|
||||||
|
{
|
||||||
|
if (sock)
|
||||||
{
|
{
|
||||||
// bind to 127.x.x.x address
|
// bind to 127.x.x.x address
|
||||||
// where x.x.x are first three bytes from ident
|
// where x.x.x are first three bytes from ident
|
||||||
@@ -88,15 +94,15 @@ namespace client
|
|||||||
sock->bind (boost::asio::ip::tcp::endpoint (ourIP, 0), ec);
|
sock->bind (boost::asio::ip::tcp::endpoint (ourIP, 0), ec);
|
||||||
if (ec)
|
if (ec)
|
||||||
LogPrint (eLogError, "I2PTunnel: Can't bind ourIP to ", ourIP.to_string (), ": ", ec.message ());
|
LogPrint (eLogError, "I2PTunnel: Can't bind ourIP to ", ourIP.to_string (), ": ", ec.message ());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void I2PTunnelConnection::Connect (bool isUniqueLocal)
|
void I2PTunnelConnection::Connect (bool isUniqueLocal)
|
||||||
{
|
{
|
||||||
I2PTunnelSetSocketOptions(m_Socket);
|
|
||||||
if (m_Socket)
|
if (m_Socket)
|
||||||
{
|
{
|
||||||
|
I2PTunnelSetSocketOptions (m_Socket);
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
if (isUniqueLocal && m_RemoteEndpoint.address ().is_v4 () &&
|
if (isUniqueLocal && m_RemoteEndpoint.address ().is_v4 () &&
|
||||||
m_RemoteEndpoint.address ().to_v4 ().to_bytes ()[0] == 127)
|
m_RemoteEndpoint.address ().to_v4 ().to_bytes ()[0] == 127)
|
||||||
@@ -130,6 +136,7 @@ namespace client
|
|||||||
void I2PTunnelConnection::Terminate ()
|
void I2PTunnelConnection::Terminate ()
|
||||||
{
|
{
|
||||||
if (Kill()) return;
|
if (Kill()) return;
|
||||||
|
if (m_SSL) m_SSL = nullptr;
|
||||||
if (m_Stream)
|
if (m_Stream)
|
||||||
{
|
{
|
||||||
m_Stream->Close ();
|
m_Stream->Close ();
|
||||||
@@ -144,12 +151,17 @@ namespace client
|
|||||||
|
|
||||||
void I2PTunnelConnection::Receive ()
|
void I2PTunnelConnection::Receive ()
|
||||||
{
|
{
|
||||||
|
if (m_SSL)
|
||||||
|
m_SSL->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE),
|
||||||
|
std::bind(&I2PTunnelConnection::HandleReceive, shared_from_this (),
|
||||||
|
std::placeholders::_1, std::placeholders::_2));
|
||||||
|
else
|
||||||
m_Socket->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE),
|
m_Socket->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE),
|
||||||
std::bind(&I2PTunnelConnection::HandleReceived, shared_from_this (),
|
std::bind(&I2PTunnelConnection::HandleReceive, shared_from_this (),
|
||||||
std::placeholders::_1, std::placeholders::_2));
|
std::placeholders::_1, std::placeholders::_2));
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PTunnelConnection::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
void I2PTunnelConnection::HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||||
{
|
{
|
||||||
if (ecode)
|
if (ecode)
|
||||||
{
|
{
|
||||||
@@ -238,6 +250,10 @@ namespace client
|
|||||||
|
|
||||||
void I2PTunnelConnection::Write (const uint8_t * buf, size_t len)
|
void I2PTunnelConnection::Write (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
|
if (m_SSL)
|
||||||
|
boost::asio::async_write (*m_SSL, boost::asio::buffer (buf, len), boost::asio::transfer_all (),
|
||||||
|
std::bind (&I2PTunnelConnection::HandleWrite, shared_from_this (), std::placeholders::_1));
|
||||||
|
else
|
||||||
boost::asio::async_write (*m_Socket, boost::asio::buffer (buf, len), boost::asio::transfer_all (),
|
boost::asio::async_write (*m_Socket, boost::asio::buffer (buf, len), boost::asio::transfer_all (),
|
||||||
std::bind (&I2PTunnelConnection::HandleWrite, shared_from_this (), std::placeholders::_1));
|
std::bind (&I2PTunnelConnection::HandleWrite, shared_from_this (), std::placeholders::_1));
|
||||||
}
|
}
|
||||||
@@ -252,6 +268,30 @@ namespace client
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "I2PTunnel: Connected");
|
LogPrint (eLogDebug, "I2PTunnel: Connected");
|
||||||
|
if (m_SSL)
|
||||||
|
m_SSL->async_handshake (boost::asio::ssl::stream_base::client,
|
||||||
|
std::bind (&I2PTunnelConnection::HandleHandshake, shared_from_this (), std::placeholders::_1));
|
||||||
|
else
|
||||||
|
Established ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PTunnelConnection::HandleHandshake (const boost::system::error_code& ecode)
|
||||||
|
{
|
||||||
|
if (ecode)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "I2PTunnel: Handshake error: ", ecode.message ());
|
||||||
|
Terminate ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "I2PTunnel: SSL connected");
|
||||||
|
Established ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PTunnelConnection::Established ()
|
||||||
|
{
|
||||||
if (m_IsQuiet)
|
if (m_IsQuiet)
|
||||||
StreamReceive ();
|
StreamReceive ();
|
||||||
else
|
else
|
||||||
@@ -266,7 +306,6 @@ namespace client
|
|||||||
}
|
}
|
||||||
Receive ();
|
Receive ();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void I2PClientTunnelConnectionHTTP::Write (const uint8_t * buf, size_t len)
|
void I2PClientTunnelConnectionHTTP::Write (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
@@ -320,15 +359,24 @@ namespace client
|
|||||||
m_HeaderSent = true;
|
m_HeaderSent = true;
|
||||||
I2PTunnelConnection::Write ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ());
|
I2PTunnelConnection::Write ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ());
|
||||||
}
|
}
|
||||||
|
else if (m_OutHeader.tellp () < I2P_TUNNEL_HTTP_MAX_HEADER_SIZE)
|
||||||
|
StreamReceive (); // read more header
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "I2PTunnel: HTTP header exceeds max size ", I2P_TUNNEL_HTTP_MAX_HEADER_SIZE);
|
||||||
|
Terminate ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
I2PServerTunnelConnectionHTTP::I2PServerTunnelConnectionHTTP (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
|
I2PServerTunnelConnectionHTTP::I2PServerTunnelConnectionHTTP (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
|
||||||
std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
const boost::asio::ip::tcp::endpoint& target, const std::string& host,
|
||||||
const boost::asio::ip::tcp::endpoint& target, const std::string& host):
|
std::shared_ptr<boost::asio::ssl::context> sslCtx):
|
||||||
I2PTunnelConnection (owner, stream, socket, target), m_Host (host),
|
I2PTunnelConnection (owner, stream, target, true, sslCtx), m_Host (host),
|
||||||
m_HeaderSent (false), m_ResponseHeaderSent (false), m_From (stream->GetRemoteIdentity ())
|
m_HeaderSent (false), m_ResponseHeaderSent (false), m_From (stream->GetRemoteIdentity ())
|
||||||
{
|
{
|
||||||
|
if (sslCtx)
|
||||||
|
SSL_set_tlsext_host_name(GetSSL ()->native_handle(), host.c_str ());
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PServerTunnelConnectionHTTP::Write (const uint8_t * buf, size_t len)
|
void I2PServerTunnelConnectionHTTP::Write (const uint8_t * buf, size_t len)
|
||||||
@@ -340,7 +388,7 @@ namespace client
|
|||||||
m_InHeader.clear ();
|
m_InHeader.clear ();
|
||||||
m_InHeader.write ((const char *)buf, len);
|
m_InHeader.write ((const char *)buf, len);
|
||||||
std::string line;
|
std::string line;
|
||||||
bool endOfHeader = false;
|
bool endOfHeader = false, connection = false;
|
||||||
while (!endOfHeader)
|
while (!endOfHeader)
|
||||||
{
|
{
|
||||||
std::getline(m_InHeader, line);
|
std::getline(m_InHeader, line);
|
||||||
@@ -349,9 +397,33 @@ namespace client
|
|||||||
if (line == "\r") endOfHeader = true;
|
if (line == "\r") endOfHeader = true;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (m_Host.length () > 0 && !line.compare(0, 5, "Host:"))
|
// strip up some headers
|
||||||
|
static const std::vector<std::string> excluded // list of excluded headers
|
||||||
|
{
|
||||||
|
"Keep-Alive:", "X-I2P"
|
||||||
|
};
|
||||||
|
bool matched = false;
|
||||||
|
for (const auto& it: excluded)
|
||||||
|
if (boost::iequals (line.substr (0, it.length ()), it))
|
||||||
|
{
|
||||||
|
matched = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (matched) break;
|
||||||
|
|
||||||
|
// replace some headers
|
||||||
|
if (!m_Host.empty () && boost::iequals (line.substr (0, 5), "Host:"))
|
||||||
m_OutHeader << "Host: " << m_Host << "\r\n"; // override host
|
m_OutHeader << "Host: " << m_Host << "\r\n"; // override host
|
||||||
|
else if (boost::iequals (line.substr (0, 11), "Connection:"))
|
||||||
|
{
|
||||||
|
auto x = line.find("pgrade");
|
||||||
|
if (x != std::string::npos && x && std::tolower(line[x - 1]) != 'u') // upgrade or Upgrade
|
||||||
|
m_OutHeader << line << "\n";
|
||||||
else
|
else
|
||||||
|
m_OutHeader << "Connection: close\r\n";
|
||||||
|
connection = true;
|
||||||
|
}
|
||||||
|
else // forward as is
|
||||||
m_OutHeader << line << "\n";
|
m_OutHeader << line << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -361,6 +433,9 @@ namespace client
|
|||||||
|
|
||||||
if (endOfHeader)
|
if (endOfHeader)
|
||||||
{
|
{
|
||||||
|
// add Connection if not presented
|
||||||
|
if (!connection)
|
||||||
|
m_OutHeader << "Connection: close\r\n";
|
||||||
// add X-I2P fields
|
// add X-I2P fields
|
||||||
if (m_From)
|
if (m_From)
|
||||||
{
|
{
|
||||||
@@ -376,6 +451,13 @@ namespace client
|
|||||||
m_HeaderSent = true;
|
m_HeaderSent = true;
|
||||||
I2PTunnelConnection::Write ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ());
|
I2PTunnelConnection::Write ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ());
|
||||||
}
|
}
|
||||||
|
else if (m_OutHeader.tellp () < I2P_TUNNEL_HTTP_MAX_HEADER_SIZE)
|
||||||
|
StreamReceive (); // read more header
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "I2PTunnel: HTTP header exceeds max size ", I2P_TUNNEL_HTTP_MAX_HEADER_SIZE);
|
||||||
|
Terminate ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -432,9 +514,9 @@ namespace client
|
|||||||
}
|
}
|
||||||
|
|
||||||
I2PTunnelConnectionIRC::I2PTunnelConnectionIRC (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
|
I2PTunnelConnectionIRC::I2PTunnelConnectionIRC (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
|
||||||
std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
const boost::asio::ip::tcp::endpoint& target, const std::string& webircpass,
|
||||||
const boost::asio::ip::tcp::endpoint& target, const std::string& webircpass):
|
std::shared_ptr<boost::asio::ssl::context> sslCtx):
|
||||||
I2PTunnelConnection (owner, stream, socket, target), m_From (stream->GetRemoteIdentity ()),
|
I2PTunnelConnection (owner, stream, target, true, sslCtx), m_From (stream->GetRemoteIdentity ()),
|
||||||
m_NeedsWebIrc (webircpass.length() ? true : false), m_WebircPass (webircpass)
|
m_NeedsWebIrc (webircpass.length() ? true : false), m_WebircPass (webircpass)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -445,7 +527,8 @@ namespace client
|
|||||||
if (m_NeedsWebIrc)
|
if (m_NeedsWebIrc)
|
||||||
{
|
{
|
||||||
m_NeedsWebIrc = false;
|
m_NeedsWebIrc = false;
|
||||||
m_OutPacket << "WEBIRC " << m_WebircPass << " cgiirc " << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ()) << " " << GetSocket ()->local_endpoint ().address () << std::endl;
|
m_OutPacket << "WEBIRC " << m_WebircPass << " cgiirc " << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ())
|
||||||
|
<< " " << GetSocket ()->local_endpoint ().address () << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_InPacket.clear ();
|
m_InPacket.clear ();
|
||||||
@@ -632,6 +715,12 @@ namespace client
|
|||||||
|
|
||||||
void I2PServerTunnel::Stop ()
|
void I2PServerTunnel::Stop ()
|
||||||
{
|
{
|
||||||
|
if (m_PortDestination)
|
||||||
|
m_PortDestination->ResetAcceptor ();
|
||||||
|
auto localDestination = GetLocalDestination ();
|
||||||
|
if (localDestination)
|
||||||
|
localDestination->StopAcceptingStreams ();
|
||||||
|
|
||||||
ClearHandlers ();
|
ClearHandlers ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -705,6 +794,17 @@ namespace client
|
|||||||
LogPrint (eLogError, "I2PTunnel: Can't set local address ", localAddress);
|
LogPrint (eLogError, "I2PTunnel: Can't set local address ", localAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void I2PServerTunnel::SetSSL (bool ssl)
|
||||||
|
{
|
||||||
|
if (ssl)
|
||||||
|
{
|
||||||
|
m_SSLCtx = std::make_shared<boost::asio::ssl::context> (boost::asio::ssl::context::sslv23);
|
||||||
|
m_SSLCtx->set_verify_mode(boost::asio::ssl::context::verify_none);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_SSLCtx = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void I2PServerTunnel::Accept ()
|
void I2PServerTunnel::Accept ()
|
||||||
{
|
{
|
||||||
if (m_PortDestination)
|
if (m_PortDestination)
|
||||||
@@ -745,7 +845,7 @@ namespace client
|
|||||||
|
|
||||||
std::shared_ptr<I2PTunnelConnection> I2PServerTunnel::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
|
std::shared_ptr<I2PTunnelConnection> I2PServerTunnel::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
|
||||||
{
|
{
|
||||||
return std::make_shared<I2PTunnelConnection> (this, stream, std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), GetEndpoint ());
|
return std::make_shared<I2PTunnelConnection> (this, stream, GetEndpoint (), true, m_SSLCtx);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -759,8 +859,7 @@ namespace client
|
|||||||
|
|
||||||
std::shared_ptr<I2PTunnelConnection> I2PServerTunnelHTTP::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
|
std::shared_ptr<I2PTunnelConnection> I2PServerTunnelHTTP::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
|
||||||
{
|
{
|
||||||
return std::make_shared<I2PServerTunnelConnectionHTTP> (this, stream,
|
return std::make_shared<I2PServerTunnelConnectionHTTP> (this, stream, GetEndpoint (), m_Host, GetSSLCtx ());
|
||||||
std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), GetEndpoint (), m_Host);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
I2PServerTunnelIRC::I2PServerTunnelIRC (const std::string& name, const std::string& address,
|
I2PServerTunnelIRC::I2PServerTunnelIRC (const std::string& name, const std::string& address,
|
||||||
@@ -773,358 +872,8 @@ namespace client
|
|||||||
|
|
||||||
std::shared_ptr<I2PTunnelConnection> I2PServerTunnelIRC::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
|
std::shared_ptr<I2PTunnelConnection> I2PServerTunnelIRC::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
|
||||||
{
|
{
|
||||||
return std::make_shared<I2PTunnelConnectionIRC> (this, stream, std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), GetEndpoint (), this->m_WebircPass);
|
return std::make_shared<I2PTunnelConnectionIRC> (this, stream, GetEndpoint (), m_WebircPass, GetSSLCtx ());
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PUDPServerTunnel::HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
|
|
||||||
{
|
|
||||||
if (!m_LastSession || m_LastSession->Identity.GetLL()[0] != from.GetIdentHash ().GetLL()[0] || fromPort != m_LastSession->RemotePort)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(m_SessionsMutex);
|
|
||||||
m_LastSession = ObtainUDPSession(from, toPort, fromPort);
|
|
||||||
}
|
|
||||||
m_LastSession->IPSocket.send_to(boost::asio::buffer(buf, len), m_RemoteEndpoint);
|
|
||||||
m_LastSession->LastActivity = i2p::util::GetMillisecondsSinceEpoch();
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PUDPServerTunnel::HandleRecvFromI2PRaw (uint16_t, uint16_t, const uint8_t * buf, size_t len)
|
|
||||||
{
|
|
||||||
if (m_LastSession)
|
|
||||||
{
|
|
||||||
m_LastSession->IPSocket.send_to(boost::asio::buffer(buf, len), m_RemoteEndpoint);
|
|
||||||
m_LastSession->LastActivity = i2p::util::GetMillisecondsSinceEpoch();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PUDPServerTunnel::ExpireStale(const uint64_t delta) {
|
|
||||||
std::lock_guard<std::mutex> lock(m_SessionsMutex);
|
|
||||||
uint64_t now = i2p::util::GetMillisecondsSinceEpoch();
|
|
||||||
auto itr = m_Sessions.begin();
|
|
||||||
while(itr != m_Sessions.end()) {
|
|
||||||
if(now - (*itr)->LastActivity >= delta )
|
|
||||||
itr = m_Sessions.erase(itr);
|
|
||||||
else
|
|
||||||
++itr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PUDPClientTunnel::ExpireStale(const uint64_t delta) {
|
|
||||||
std::lock_guard<std::mutex> lock(m_SessionsMutex);
|
|
||||||
uint64_t now = i2p::util::GetMillisecondsSinceEpoch();
|
|
||||||
std::vector<uint16_t> removePorts;
|
|
||||||
for (const auto & s : m_Sessions) {
|
|
||||||
if (now - s.second->second >= delta)
|
|
||||||
removePorts.push_back(s.first);
|
|
||||||
}
|
|
||||||
for(auto port : removePorts) {
|
|
||||||
m_Sessions.erase(port);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UDPSessionPtr I2PUDPServerTunnel::ObtainUDPSession(const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort)
|
|
||||||
{
|
|
||||||
auto ih = from.GetIdentHash();
|
|
||||||
for (auto & s : m_Sessions )
|
|
||||||
{
|
|
||||||
if (s->Identity.GetLL()[0] == ih.GetLL()[0] && remotePort == s->RemotePort)
|
|
||||||
{
|
|
||||||
/** found existing session */
|
|
||||||
LogPrint(eLogDebug, "UDPServer: Found session ", s->IPSocket.local_endpoint(), " ", ih.ToBase32());
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
boost::asio::ip::address addr;
|
|
||||||
/** create new udp session */
|
|
||||||
if(m_IsUniqueLocal && m_LocalAddress.is_loopback())
|
|
||||||
{
|
|
||||||
auto ident = from.GetIdentHash();
|
|
||||||
addr = GetLoopbackAddressFor(ident);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
addr = m_LocalAddress;
|
|
||||||
boost::asio::ip::udp::endpoint ep(addr, 0);
|
|
||||||
m_Sessions.push_back(std::make_shared<UDPSession>(ep, m_LocalDest, m_RemoteEndpoint, &ih, localPort, remotePort));
|
|
||||||
auto & back = m_Sessions.back();
|
|
||||||
return back;
|
|
||||||
}
|
|
||||||
|
|
||||||
UDPSession::UDPSession(boost::asio::ip::udp::endpoint localEndpoint,
|
|
||||||
const std::shared_ptr<i2p::client::ClientDestination> & localDestination,
|
|
||||||
boost::asio::ip::udp::endpoint endpoint, const i2p::data::IdentHash * to,
|
|
||||||
uint16_t ourPort, uint16_t theirPort) :
|
|
||||||
m_Destination(localDestination->GetDatagramDestination()),
|
|
||||||
IPSocket(localDestination->GetService(), localEndpoint),
|
|
||||||
SendEndpoint(endpoint),
|
|
||||||
LastActivity(i2p::util::GetMillisecondsSinceEpoch()),
|
|
||||||
LocalPort(ourPort),
|
|
||||||
RemotePort(theirPort)
|
|
||||||
{
|
|
||||||
IPSocket.set_option (boost::asio::socket_base::receive_buffer_size (I2P_UDP_MAX_MTU ));
|
|
||||||
memcpy(Identity, to->data(), 32);
|
|
||||||
Receive();
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDPSession::Receive() {
|
|
||||||
LogPrint(eLogDebug, "UDPSession: Receive");
|
|
||||||
IPSocket.async_receive_from(boost::asio::buffer(m_Buffer, I2P_UDP_MAX_MTU),
|
|
||||||
FromEndpoint, std::bind(&UDPSession::HandleReceived, this, std::placeholders::_1, std::placeholders::_2));
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDPSession::HandleReceived(const boost::system::error_code & ecode, std::size_t len)
|
|
||||||
{
|
|
||||||
if(!ecode)
|
|
||||||
{
|
|
||||||
LogPrint(eLogDebug, "UDPSession: Forward ", len, "B from ", FromEndpoint);
|
|
||||||
auto ts = i2p::util::GetMillisecondsSinceEpoch();
|
|
||||||
auto session = m_Destination->GetSession (Identity);
|
|
||||||
if (ts > LastActivity + I2P_UDP_REPLIABLE_DATAGRAM_INTERVAL)
|
|
||||||
m_Destination->SendDatagram(session, m_Buffer, len, LocalPort, RemotePort);
|
|
||||||
else
|
|
||||||
m_Destination->SendRawDatagram(session, m_Buffer, len, LocalPort, RemotePort);
|
|
||||||
size_t numPackets = 0;
|
|
||||||
while (numPackets < i2p::datagram::DATAGRAM_SEND_QUEUE_MAX_SIZE)
|
|
||||||
{
|
|
||||||
boost::system::error_code ec;
|
|
||||||
size_t moreBytes = IPSocket.available(ec);
|
|
||||||
if (ec || !moreBytes) break;
|
|
||||||
len = IPSocket.receive_from (boost::asio::buffer (m_Buffer, I2P_UDP_MAX_MTU), FromEndpoint, 0, ec);
|
|
||||||
m_Destination->SendRawDatagram (session, m_Buffer, len, LocalPort, RemotePort);
|
|
||||||
numPackets++;
|
|
||||||
}
|
|
||||||
if (numPackets > 0)
|
|
||||||
LogPrint(eLogDebug, "UDPSession: Forward more ", numPackets, "packets B from ", FromEndpoint);
|
|
||||||
m_Destination->FlushSendQueue (session);
|
|
||||||
LastActivity = ts;
|
|
||||||
Receive();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
LogPrint(eLogError, "UDPSession: ", ecode.message());
|
|
||||||
}
|
|
||||||
|
|
||||||
I2PUDPServerTunnel::I2PUDPServerTunnel(const std::string & name, std::shared_ptr<i2p::client::ClientDestination> localDestination,
|
|
||||||
boost::asio::ip::address localAddress, boost::asio::ip::udp::endpoint forwardTo, uint16_t port, bool gzip) :
|
|
||||||
m_IsUniqueLocal(true),
|
|
||||||
m_Name(name),
|
|
||||||
m_LocalAddress(localAddress),
|
|
||||||
m_RemoteEndpoint(forwardTo)
|
|
||||||
{
|
|
||||||
m_LocalDest = localDestination;
|
|
||||||
m_LocalDest->Start();
|
|
||||||
auto dgram = m_LocalDest->CreateDatagramDestination(gzip);
|
|
||||||
dgram->SetReceiver(std::bind(&I2PUDPServerTunnel::HandleRecvFromI2P, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
|
|
||||||
dgram->SetRawReceiver(std::bind(&I2PUDPServerTunnel::HandleRecvFromI2PRaw, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
|
||||||
}
|
|
||||||
|
|
||||||
I2PUDPServerTunnel::~I2PUDPServerTunnel()
|
|
||||||
{
|
|
||||||
auto dgram = m_LocalDest->GetDatagramDestination();
|
|
||||||
if (dgram) dgram->ResetReceiver();
|
|
||||||
|
|
||||||
LogPrint(eLogInfo, "UDPServer: Done");
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PUDPServerTunnel::Start()
|
|
||||||
{
|
|
||||||
m_LocalDest->Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<DatagramSessionInfo> > I2PUDPServerTunnel::GetSessions()
|
|
||||||
{
|
|
||||||
std::vector<std::shared_ptr<DatagramSessionInfo> > sessions;
|
|
||||||
std::lock_guard<std::mutex> lock(m_SessionsMutex);
|
|
||||||
|
|
||||||
for ( UDPSessionPtr s : m_Sessions )
|
|
||||||
{
|
|
||||||
if (!s->m_Destination) continue;
|
|
||||||
auto info = s->m_Destination->GetInfoForRemote(s->Identity);
|
|
||||||
if(!info) continue;
|
|
||||||
|
|
||||||
auto sinfo = std::make_shared<DatagramSessionInfo>();
|
|
||||||
sinfo->Name = m_Name;
|
|
||||||
sinfo->LocalIdent = std::make_shared<i2p::data::IdentHash>(m_LocalDest->GetIdentHash().data());
|
|
||||||
sinfo->RemoteIdent = std::make_shared<i2p::data::IdentHash>(s->Identity.data());
|
|
||||||
sinfo->CurrentIBGW = info->IBGW;
|
|
||||||
sinfo->CurrentOBEP = info->OBEP;
|
|
||||||
sessions.push_back(sinfo);
|
|
||||||
}
|
|
||||||
return sessions;
|
|
||||||
}
|
|
||||||
|
|
||||||
I2PUDPClientTunnel::I2PUDPClientTunnel(const std::string & name, const std::string &remoteDest,
|
|
||||||
boost::asio::ip::udp::endpoint localEndpoint,
|
|
||||||
std::shared_ptr<i2p::client::ClientDestination> localDestination,
|
|
||||||
uint16_t remotePort, bool gzip) :
|
|
||||||
m_Name(name),
|
|
||||||
m_RemoteDest(remoteDest),
|
|
||||||
m_LocalDest(localDestination),
|
|
||||||
m_LocalEndpoint(localEndpoint),
|
|
||||||
m_RemoteIdent(nullptr),
|
|
||||||
m_ResolveThread(nullptr),
|
|
||||||
m_LocalSocket(localDestination->GetService(), localEndpoint),
|
|
||||||
RemotePort(remotePort), m_LastPort (0),
|
|
||||||
m_cancel_resolve(false)
|
|
||||||
{
|
|
||||||
m_LocalSocket.set_option (boost::asio::socket_base::receive_buffer_size (I2P_UDP_MAX_MTU));
|
|
||||||
m_LocalSocket.set_option (boost::asio::socket_base::reuse_address (true));
|
|
||||||
|
|
||||||
auto dgram = m_LocalDest->CreateDatagramDestination(gzip);
|
|
||||||
dgram->SetReceiver(std::bind(&I2PUDPClientTunnel::HandleRecvFromI2P, this,
|
|
||||||
std::placeholders::_1, std::placeholders::_2,
|
|
||||||
std::placeholders::_3, std::placeholders::_4,
|
|
||||||
std::placeholders::_5));
|
|
||||||
dgram->SetRawReceiver(std::bind(&I2PUDPClientTunnel::HandleRecvFromI2PRaw, this,
|
|
||||||
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PUDPClientTunnel::Start() {
|
|
||||||
m_LocalDest->Start();
|
|
||||||
if (m_ResolveThread == nullptr)
|
|
||||||
m_ResolveThread = new std::thread(std::bind(&I2PUDPClientTunnel::TryResolving, this));
|
|
||||||
RecvFromLocal();
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PUDPClientTunnel::RecvFromLocal()
|
|
||||||
{
|
|
||||||
m_LocalSocket.async_receive_from(boost::asio::buffer(m_RecvBuff, I2P_UDP_MAX_MTU),
|
|
||||||
m_RecvEndpoint, std::bind(&I2PUDPClientTunnel::HandleRecvFromLocal, this, std::placeholders::_1, std::placeholders::_2));
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PUDPClientTunnel::HandleRecvFromLocal(const boost::system::error_code & ec, std::size_t transferred)
|
|
||||||
{
|
|
||||||
if(m_cancel_resolve) {
|
|
||||||
LogPrint(eLogDebug, "UDP Client: Ignoring incomming data: stopping");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(ec) {
|
|
||||||
LogPrint(eLogError, "UDP Client: Reading from socket error: ", ec.message(), ". Restarting listener...");
|
|
||||||
RecvFromLocal(); // Restart listener and continue work
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(!m_RemoteIdent) {
|
|
||||||
LogPrint(eLogWarning, "UDP Client: Remote endpoint not resolved yet");
|
|
||||||
RecvFromLocal();
|
|
||||||
return; // drop, remote not resolved
|
|
||||||
}
|
|
||||||
auto remotePort = m_RecvEndpoint.port();
|
|
||||||
if (!m_LastPort || m_LastPort != remotePort)
|
|
||||||
{
|
|
||||||
auto itr = m_Sessions.find(remotePort);
|
|
||||||
if (itr != m_Sessions.end())
|
|
||||||
m_LastSession = itr->second;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_LastSession = std::make_shared<UDPConvo>(boost::asio::ip::udp::endpoint(m_RecvEndpoint), 0);
|
|
||||||
m_Sessions.emplace (remotePort, m_LastSession);
|
|
||||||
}
|
|
||||||
m_LastPort = remotePort;
|
|
||||||
}
|
|
||||||
// send off to remote i2p destination
|
|
||||||
auto ts = i2p::util::GetMillisecondsSinceEpoch();
|
|
||||||
LogPrint(eLogDebug, "UDP Client: Send ", transferred, " to ", m_RemoteIdent->ToBase32(), ":", RemotePort);
|
|
||||||
auto session = m_LocalDest->GetDatagramDestination()->GetSession (*m_RemoteIdent);
|
|
||||||
if (ts > m_LastSession->second + I2P_UDP_REPLIABLE_DATAGRAM_INTERVAL)
|
|
||||||
m_LocalDest->GetDatagramDestination()->SendDatagram (session, m_RecvBuff, transferred, remotePort, RemotePort);
|
|
||||||
else
|
|
||||||
m_LocalDest->GetDatagramDestination()->SendRawDatagram (session, m_RecvBuff, transferred, remotePort, RemotePort);
|
|
||||||
size_t numPackets = 0;
|
|
||||||
while (numPackets < i2p::datagram::DATAGRAM_SEND_QUEUE_MAX_SIZE)
|
|
||||||
{
|
|
||||||
boost::system::error_code ec;
|
|
||||||
size_t moreBytes = m_LocalSocket.available(ec);
|
|
||||||
if (ec || !moreBytes) break;
|
|
||||||
transferred = m_LocalSocket.receive_from (boost::asio::buffer (m_RecvBuff, I2P_UDP_MAX_MTU), m_RecvEndpoint, 0, ec);
|
|
||||||
remotePort = m_RecvEndpoint.port();
|
|
||||||
// TODO: check remotePort
|
|
||||||
m_LocalDest->GetDatagramDestination()->SendRawDatagram (session, m_RecvBuff, transferred, remotePort, RemotePort);
|
|
||||||
numPackets++;
|
|
||||||
}
|
|
||||||
if (numPackets)
|
|
||||||
LogPrint(eLogDebug, "UDP Client: Sent ", numPackets, " more packets to ", m_RemoteIdent->ToBase32());
|
|
||||||
m_LocalDest->GetDatagramDestination()->FlushSendQueue (session);
|
|
||||||
|
|
||||||
// mark convo as active
|
|
||||||
if (m_LastSession)
|
|
||||||
m_LastSession->second = ts;
|
|
||||||
RecvFromLocal();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<DatagramSessionInfo> > I2PUDPClientTunnel::GetSessions()
|
|
||||||
{
|
|
||||||
// TODO: implement
|
|
||||||
std::vector<std::shared_ptr<DatagramSessionInfo> > infos;
|
|
||||||
return infos;
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PUDPClientTunnel::TryResolving() {
|
|
||||||
i2p::util::SetThreadName("UDP Resolver");
|
|
||||||
LogPrint(eLogInfo, "UDP Tunnel: Trying to resolve ", m_RemoteDest);
|
|
||||||
|
|
||||||
std::shared_ptr<const Address> addr;
|
|
||||||
while(!(addr = context.GetAddressBook().GetAddress(m_RemoteDest)) && !m_cancel_resolve)
|
|
||||||
{
|
|
||||||
LogPrint(eLogWarning, "UDP Tunnel: Failed to lookup ", m_RemoteDest);
|
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
||||||
}
|
|
||||||
if(m_cancel_resolve)
|
|
||||||
{
|
|
||||||
LogPrint(eLogError, "UDP Tunnel: Lookup of ", m_RemoteDest, " was cancelled");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!addr || !addr->IsIdentHash ())
|
|
||||||
{
|
|
||||||
LogPrint(eLogError, "UDP Tunnel: ", m_RemoteDest, " not found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_RemoteIdent = new i2p::data::IdentHash;
|
|
||||||
*m_RemoteIdent = addr->identHash;
|
|
||||||
LogPrint(eLogInfo, "UDP Tunnel: Resolved ", m_RemoteDest, " to ", m_RemoteIdent->ToBase32());
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PUDPClientTunnel::HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
|
|
||||||
{
|
|
||||||
if(m_RemoteIdent && from.GetIdentHash() == *m_RemoteIdent)
|
|
||||||
HandleRecvFromI2PRaw (fromPort, toPort, buf, len);
|
|
||||||
else
|
|
||||||
LogPrint(eLogWarning, "UDP Client: Unwarranted traffic from ", from.GetIdentHash().ToBase32());
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2PUDPClientTunnel::HandleRecvFromI2PRaw(uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
|
|
||||||
{
|
|
||||||
auto itr = m_Sessions.find(toPort);
|
|
||||||
// found convo ?
|
|
||||||
if(itr != m_Sessions.end())
|
|
||||||
{
|
|
||||||
// found convo
|
|
||||||
if (len > 0)
|
|
||||||
{
|
|
||||||
LogPrint(eLogDebug, "UDP Client: Got ", len, "B from ", m_RemoteIdent ? m_RemoteIdent->ToBase32() : "");
|
|
||||||
m_LocalSocket.send_to(boost::asio::buffer(buf, len), itr->second->first);
|
|
||||||
// mark convo as active
|
|
||||||
itr->second->second = i2p::util::GetMillisecondsSinceEpoch();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
LogPrint(eLogWarning, "UDP Client: Not tracking udp session using port ", (int) toPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
I2PUDPClientTunnel::~I2PUDPClientTunnel()
|
|
||||||
{
|
|
||||||
auto dgram = m_LocalDest->GetDatagramDestination();
|
|
||||||
if (dgram) dgram->ResetReceiver();
|
|
||||||
m_cancel_resolve = true;
|
|
||||||
|
|
||||||
m_Sessions.clear();
|
|
||||||
|
|
||||||
if(m_LocalSocket.is_open())
|
|
||||||
m_LocalSocket.close();
|
|
||||||
|
|
||||||
if(m_ResolveThread)
|
|
||||||
{
|
|
||||||
m_ResolveThread->join();
|
|
||||||
delete m_ResolveThread;
|
|
||||||
m_ResolveThread = nullptr;
|
|
||||||
}
|
|
||||||
if (m_RemoteIdent) delete m_RemoteIdent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user