Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 114 additions & 28 deletions doc/i2p.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,33 @@ started with I2P terminology.

## Run Dash Core with an I2P router (proxy)

A running I2P router (proxy) with [SAM](https://geti2p.net/en/docs/api/samv3)
enabled is required (there is an [official one](https://geti2p.net) and
[a few alternatives](https://en.wikipedia.org/wiki/I2P#Routers)). Notice the IP
address and port the SAM proxy is listening to; usually, it is
`127.0.0.1:7656`. Once it is up and running with SAM enabled, use the following
Dash Core options:
A running I2P router (proxy) is required with the [SAM](https://geti2p.net/en/docs/api/samv3)
application bridge enabled. The following routers are recommended for use with Dash Core:

- [i2prouter (I2P Router)](https://geti2p.net), the official implementation in
Java. The SAM bridge is not enabled by default; it must be started manually,
or configured to start automatically, in the Clients page in the
router console (`http://127.0.0.1:7657/configclients`) or in the `clients.config` file.
- [i2pd (I2P Daemon)](https://github.com/PurpleI2P/i2pd)
([documentation](https://i2pd.readthedocs.io/en/latest)), a lighter
alternative in C++. It enables the SAM bridge by default.

Note the IP address and port the SAM proxy is listening to; usually, it is
`127.0.0.1:7656`.

Once an I2P router with SAM enabled is up and running, use the following Dash
Core configuration options:

```
-i2psam=<ip:port>
I2P SAM proxy to reach I2P peers and accept I2P connections (default:
none)

-i2pacceptincoming
If set and -i2psam is also set then incoming I2P connections are
accepted via the SAM proxy. If this is not set but -i2psam is set
then only outgoing connections will be made to the I2P network.
Ignored if -i2psam is not set. Listening for incoming I2P
connections is done through the SAM proxy, not by binding to a
local address and port (default: 1)
Whether to accept inbound I2P connections (default: 1). Ignored if
-i2psam is not set. Listening for inbound I2P connections is
done through the SAM proxy, not by binding to a local address and
port.
```

In a typical situation, this suffices:
Expand All @@ -36,26 +44,68 @@ In a typical situation, this suffices:
dashd -i2psam=127.0.0.1:7656
```

The first time Dash Core connects to the I2P router, its I2P address (and
corresponding private key) will be automatically generated and saved in a file
named `i2p_private_key` in the Dash Core data directory.

## Additional configuration options related to I2P

You may set the `debug=i2p` config logging option to have additional
information in the debug log about your I2P configuration and connections. Run
`dash-cli help logging` for more information.
```
-debug=i2p
```

Set the `debug=i2p` config logging option to see additional information in the
debug log about your I2P configuration and connections. Run `dash-cli help
logging` for more information.

```
-onlynet=i2p
```

Make outgoing connections only to I2P addresses. Incoming connections are not
affected by this option. It can be specified multiple times to allow multiple
network types, e.g. onlynet=ipv4, onlynet=ipv6, onlynet=onion, onlynet=i2p.

Warning: if you use -onlynet with values other than onion, and the -onion or
-proxy option is set, then outgoing onion connections will still be made; use
-noonion or -onion=0 to disable outbound onion connections in this case.

It is possible to restrict outgoing connections in the usual way with
`onlynet=i2p`. I2P support was added to Dash Core in version 20.0 (fall 2023)
and there may be fewer I2P peers than Tor or IP ones. Therefore, using
`onlynet=i2p` alone (without other `onlynet=`) may make a node more susceptible
to [Sybil attacks](https://en.dash.it/wiki/Weaknesses#Sybil_attack). Use
I2P support was added to Dash Core in version 20.0 and there may be fewer I2P
peers than Tor or IP ones. Therefore, using I2P alone without other networks may
make a node more susceptible to [Sybil
attacks](https://en.bitcoin.it/wiki/Weaknesses#Sybil_attack). You can use
`dash-cli -addrinfo` to see the number of I2P addresses known to your node.

## I2P related information in Dash Core
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

22589: I would consider this complete; we don't have a need for the other commit.

Another consideration with `onlynet=i2p` is that the initial blocks download
phase when syncing up a new node can be very slow. This phase can be sped up by
using other networks, for instance `onlynet=onion`, at the same time.

In general, a node can be run with both onion and I2P hidden services (or
any/all of IPv4/IPv6/onion/I2P), which can provide a potential fallback if one
of the networks has issues.

## Persistent vs transient I2P addresses

The first time Dash Core connects to the I2P router, it automatically
generates a persistent I2P address and its corresponding private key by default
or if `-i2pacceptincoming=1` is set. The private key is saved in a file named
`i2p_private_key` in the Dash Core data directory. The persistent I2P
address is used for making outbound connections and accepting inbound
connections.

In the I2P network, the receiver of an inbound connection sees the address of
the initiator. This is unlike the Tor network, where the recipient does not
know who is connecting to it.

There are several ways to see your I2P address in Dash Core:
If your node is configured by setting `-i2pacceptincoming=0` to not accept
inbound I2P connections, then it will use a random transient I2P address for
itself on each outbound connection to make it harder to discriminate,
fingerprint or analyze it based on its I2P address.

I2P addresses are designed to be long-lived. Waiting for tunnels to be built
for every peer connection adds delay to connection setup time. Therefore, I2P
listening should only be turned off if really needed.

## Fetching I2P-related information from Dash Core

There are several ways to see your I2P address in Dash Core if accepting
incoming I2P connections (`-i2pacceptincoming`):
- in the debug log (grep for `AddLocal`, the I2P address ends in `.b32.i2p`)
- in the output of the `getnetworkinfo` RPC in the "localaddresses" section
- in the output of `dash-cli -netinfo` peer connections dashboard
Expand All @@ -73,8 +123,7 @@ to connect to the I2P network. Any I2P router that supports it can be used.

## Ports in I2P and Dash Core

Dash Core uses the [SAM v3.1](https://geti2p.net/en/docs/api/samv3)
protocol. One particularity of SAM v3.1 is that it does not support ports,
One particularity of SAM v3.1 is that it does not support ports,
unlike newer versions of SAM (v3.2 and up) that do support them and default the
port numbers to 0. From the point of view of peers that use newer versions of
SAM or other protocols that support ports, a SAM v3.1 peer is connecting to them
Expand All @@ -85,3 +134,40 @@ listening port to 0 when listening for incoming I2P connections and advertises
its own I2P address with port 0. Furthermore, it will not attempt to connect to
I2P addresses with a non-zero port number because with SAM v3.1 the destination
port (`TO_PORT`) is always set to 0 and is not in the control of Dash Core.

## Bandwidth

By default, your node shares bandwidth and transit tunnels with the I2P network
in order to increase your anonymity with cover traffic, help the I2P router used
by your node integrate optimally with the network, and give back to the network.
It's important that the nodes of a popular application like Dash contribute
as much to the I2P network as they consume.

It is possible, though strongly discouraged, to change your I2P router
configuration to limit the amount of I2P traffic relayed by your node.

With `i2pd`, this can be done by adjusting the `bandwidth`, `share` and
`transittunnels` options in your `i2pd.conf` file. For example, to limit total
I2P traffic to 256KB/s and share 50% of this limit for a maximum of 20 transit
tunnels:

```
bandwidth = 256
share = 50

[limits]
transittunnels = 20
```

Similar bandwidth configuration options for the Java I2P router can be found in
`http://127.0.0.1:7657/config` under the "Bandwidth" tab.

Before doing this, please see the "Participating Traffic Considerations" section
in [Embedding I2P in your Application](https://geti2p.net/en/docs/applications/embedding).

In most cases, the default router settings should work fine.

## Bundling I2P in a Dash application

Please see the "General Guidance for Developers" section in https://geti2p.net/en/docs/api/samv3
if you are developing a downstream application that may be bundling I2P with Dash.
5 changes: 5 additions & 0 deletions doc/release-notes-25355.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
P2P and network changes
-----------------------

- With I2P connections, a new, transient address is used for each outbound
connection if `-i2pacceptincoming=0`.
10 changes: 5 additions & 5 deletions doc/tor.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ outgoing connections, but more is possible.
-onlynet=onion Make outgoing connections only to .onion addresses. Incoming
connections are not affected by this option. This option can be
specified multiple times to allow multiple network types, e.g.
ipv4, ipv6 or onion. If you use this option with values other
than onion you *cannot* disable onion connections; outgoing onion
connections will be enabled when you use -proxy or -onion. Use
-noonion or -onion=0 if you want to be sure there are no outbound
onion connections over the default proxy or your defined -proxy.
onlynet=ipv4, onlynet=ipv6, onlynet=onion, onlynet=i2p.
Warning: if you use -onlynet with values other than onion, and
the -onion or -proxy option is set, then outgoing onion
connections will still be made; use -noonion or -onion=0 to
disable outbound onion connections in this case.

An example how to start the client if the Tor proxy is running on local host on
port 9050 and only allows .onion nodes to connect:
Expand Down
98 changes: 0 additions & 98 deletions src/addrman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#include <addrman.h>

#include <hash.h>
#include <i2p.h>
#include <logging.h>
#include <netaddress.h>
#include <serialize.h>
Expand Down Expand Up @@ -778,100 +777,3 @@ std::vector<bool> CAddrMan::DecodeAsmap(fs::path path)
}
return bits;
}

void CAddrMan::ResetI2PPorts()
{
for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; ++bucket) {
for (int i = 0; i < ADDRMAN_BUCKET_SIZE; ++i) {
const auto id = vvNew[bucket][i];
if (id == -1) {
continue;
}
auto it = mapInfo.find(id);
if (it == mapInfo.end()) {
return;
}
auto& addr_info = it->second;
if (!addr_info.IsI2P() || addr_info.GetPort() == I2P_SAM31_PORT) {
continue;
}

auto addr_info_newport = addr_info;
// The below changes addr_info_newport.GetKey(), which is used in finding a
// bucket and a position within that bucket. So a re-bucketing may be necessary.
addr_info_newport.port = I2P_SAM31_PORT;

// Reposition entries of vvNew within the same bucket because we don't know the source
// address which led to the decision to store the entry in vvNew[bucket] so we can't
// re-evaluate that decision, but even if we could, CAddrInfo::GetNewBucket() does not
// use CAddrInfo::GetKey() so it would end up in the same bucket as before the port
// change.
const auto i_target = addr_info_newport.GetBucketPosition(nKey, true, bucket);

if (i_target == i) { // No need to re-position.
addr_info = addr_info_newport;
continue;
}

// Reposition from i to i_target, removing the entry from i_target (if any).
ClearNew(bucket, i_target);
vvNew[bucket][i_target] = id;
vvNew[bucket][i] = -1;
addr_info = addr_info_newport;
}
}

for (int bucket = 0; bucket < ADDRMAN_TRIED_BUCKET_COUNT; ++bucket) {
for (int i = 0; i < ADDRMAN_BUCKET_SIZE; ++i) {
const auto id = vvTried[bucket][i];
if (id == -1) {
continue;
}
auto it = mapInfo.find(id);
if (it == mapInfo.end()) {
return;
}
auto& addr_info = it->second;
if (!addr_info.IsI2P() || addr_info.GetPort() == I2P_SAM31_PORT) {
continue;
}

auto addr_info_newport = addr_info;
// The below changes addr_info_newport.GetKey(), which is used in finding a
// bucket and a position within that bucket. So a re-bucketing may be necessary.
addr_info_newport.port = I2P_SAM31_PORT;

const auto bucket_target = addr_info_newport.GetTriedBucket(nKey, m_asmap);
const auto i_target = addr_info_newport.GetBucketPosition(nKey, false, bucket_target);

if (bucket_target == bucket && i_target == i) { // No need to re-position.
addr_info = addr_info_newport;
continue;
}

// Reposition from (bucket, i) to (bucket_target, i_target). If the latter is
// occupied, then move the entry from there to vvNew.

const auto old_target_id = vvTried[bucket_target][i_target];
if (old_target_id != -1) {
CAddrInfo& old_target_info = mapInfo[old_target_id];

old_target_info.fInTried = false;
vvTried[bucket_target][i_target] = -1;
--nTried;

const auto new_bucket = old_target_info.GetNewBucket(nKey, m_asmap);
const auto new_bucket_i = old_target_info.GetBucketPosition(nKey, true, new_bucket);
ClearNew(new_bucket, new_bucket_i);

old_target_info.nRefCount = 1;
vvNew[new_bucket][new_bucket_i] = old_target_id;
++nNew;
}

vvTried[bucket_target][i_target] = id;
vvTried[bucket][i] = -1;
addr_info = addr_info_newport;
}
}
}
10 changes: 0 additions & 10 deletions src/addrman.h
Original file line number Diff line number Diff line change
Expand Up @@ -464,8 +464,6 @@ class CAddrMan

RemoveInvalid();

ResetI2PPorts();

Check();
}

Expand Down Expand Up @@ -800,14 +798,6 @@ class CAddrMan
//! Remove invalid addresses.
void RemoveInvalid() EXCLUSIVE_LOCKS_REQUIRED(cs);

/**
* Reset the ports of I2P peers to 0.
* This is needed as a temporary measure because now we enforce port 0 and
* only connect to I2P hosts if the port is 0, but in the early days some
* I2P addresses with port 8333 were rumoured and persisted into addrmans.
*/
void ResetI2PPorts() EXCLUSIVE_LOCKS_REQUIRED(cs);

friend class CAddrManTest;
friend class CAddrManDeterministic;
};
Expand Down
Loading