mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 03:52:49 +01:00
Merge #6031: backport: merge bitcoin#23077, #22834, #24165, #24555, #24663, #24205, #24687, #25173, #24991, partial bitcoin#24468 (cjdns support)
32f8fda7d6
merge bitcoin#24991: allow startup with -onlynet=onion -listenonion=1 (Kittywhiskers Van Gogh)e67ed92d3d
merge bitcoin#25173: add coverage for unknown network in -onlynet (Kittywhiskers Van Gogh)77efd36112
merge bitcoin#24687: Check an invalid -i2psam will raise an init error (Kittywhiskers Van Gogh)fb1416f7cb
merge bitcoin#24205: improve network reachability test coverage and safety (Kittywhiskers Van Gogh)7cb7479829
merge bitcoin#24663: add links to doc/cjdns.md (Kittywhiskers Van Gogh)c736ebf566
merge bitcoin#24555: create initial doc/cjdns.md for CJDNS how-to documentation (Kittywhiskers Van Gogh)554bd24186
partial bitcoin#24468: improve -onlynet help and related tor/i2p documentation (Kittywhiskers Van Gogh)5436b6a82d
merge bitcoin#24165: extend inbound eviction protection by network to CJDNS peers (Kittywhiskers Van Gogh)d52724d039
merge bitcoin#22834: respect -onlynet= when making outbound connections (Kittywhiskers Van Gogh)f9d1a9a00d
merge bitcoin#23077: Full CJDNS support (Kittywhiskers Van Gogh) Pull request description: ## Additional Information * Depends on https://github.com/dashpay/dash/pull/6034 * Depends on https://github.com/dashpay/dash/pull/6035 * If `-proxy=` is given together with `-noonion` then the provided proxy will not be set as a proxy for reaching the Tor network. So it will not be possible to open manual connections to the Tor network for example with the `addnode` RPC. To mimic the old behavior use `-proxy=` together with `-onlynet=` listing all relevant networks except `onion`. * [bitcoin#24165](https://github.com/bitcoin/bitcoin/pull/24165) has been backported _before_ [bitcoin#23758](https://github.com/bitcoin/bitcoin/pull/23758) and to account for this, minor changes were made in `src/test/net_peer_eviction_tests.cpp` (using `nTimeConnected` instead of `m_connected`). When backporting [bitcoin#23758](https://github.com/bitcoin/bitcoin/pull/23758), these changes will have to be reversed as they won't be covered by the cherry-pick diff. * CJDNS support has been labelled as being introduced in Dash Core 21.0, in line with the milestone designation of the PR. Should `develop` be used for a new minor/patch release, `doc/cjdns.md` will have to be modified to reflect the correct version number. ## Breaking changes No expected protocol or consensus changes. ## Checklist: - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas **(note: N/A)** - [x] I have added or updated relevant unit/integration/functional/e2e tests - [x] I have made corresponding changes to the documentation - [x] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_ ACKs for top commit: PastaPastaPasta: utACK32f8fda7d6
Tree-SHA512: e23b22ca5edbe4c4abeab0bc07780303e68e7c4cc46b7697300b0837c5acd3a98649b6b03bd07a23c827bd85f64210173027b0b0eea31872c031fa4ed04eeb0c
This commit is contained in:
commit
825bba1312
@ -54,7 +54,7 @@ def name_to_bip155(addr):
|
||||
raise ValueError('Invalid onion %s' % vchAddr)
|
||||
elif '.' in addr: # IPv4
|
||||
return (BIP155Network.IPV4, bytes((int(x) for x in addr.split('.'))))
|
||||
elif ':' in addr: # IPv6
|
||||
elif ':' in addr: # IPv6 or CJDNS
|
||||
sub = [[], []] # prefix, suffix
|
||||
x = 0
|
||||
addr = addr.split(':')
|
||||
@ -70,7 +70,14 @@ def name_to_bip155(addr):
|
||||
sub[x].append(val & 0xff)
|
||||
nullbytes = 16 - len(sub[0]) - len(sub[1])
|
||||
assert((x == 0 and nullbytes == 0) or (x == 1 and nullbytes > 0))
|
||||
return (BIP155Network.IPV6, bytes(sub[0] + ([0] * nullbytes) + sub[1]))
|
||||
addr_bytes = bytes(sub[0] + ([0] * nullbytes) + sub[1])
|
||||
if addr_bytes[0] == 0xfc:
|
||||
# Assume that seeds with fc00::/8 addresses belong to CJDNS,
|
||||
# not to the publicly unroutable "Unique Local Unicast" network, see
|
||||
# RFC4193: https://datatracker.ietf.org/doc/html/rfc4193#section-8
|
||||
return (BIP155Network.CJDNS, addr_bytes)
|
||||
else:
|
||||
return (BIP155Network.IPV6, addr_bytes)
|
||||
else:
|
||||
raise ValueError('Could not parse address %s' % addr)
|
||||
|
||||
|
@ -69,6 +69,7 @@ The Dash Core repo's [root README](/README.md) contains relevant information on
|
||||
### Miscellaneous
|
||||
- [Assets Attribution](assets-attribution.md)
|
||||
- [dash.conf Configuration File](dash-conf.md)
|
||||
- [CJDNS Support](cjdns.md)
|
||||
- [Files](files.md)
|
||||
- [Fuzz-testing](fuzzing.md)
|
||||
- [I2P Support](i2p.md)
|
||||
|
95
doc/cjdns.md
Normal file
95
doc/cjdns.md
Normal file
@ -0,0 +1,95 @@
|
||||
# CJDNS support in Dash Core
|
||||
|
||||
It is possible to run Dash Core over CJDNS, an encrypted IPv6 network that
|
||||
uses public-key cryptography for address allocation and a distributed hash table
|
||||
for routing.
|
||||
|
||||
## What is CJDNS?
|
||||
|
||||
CJDNS is like a distributed, shared VPN with multiple entry points where every
|
||||
participant can reach any other participant. All participants use addresses from
|
||||
the `fc00::/8` network (reserved IPv6 range). Installation and configuration is
|
||||
done outside of Dash Core, similarly to a VPN (either in the host/OS or on
|
||||
the network router).
|
||||
|
||||
Compared to IPv4/IPv6, CJDNS provides end-to-end encryption and protects nodes
|
||||
from traffic analysis and filtering.
|
||||
|
||||
Used with Tor and I2P, CJDNS is a complementary option that can enhance network
|
||||
redundancy and robustness for both the Dash network and individual nodes.
|
||||
|
||||
Each network has different characteristics. For instance, Tor is widely used but
|
||||
somewhat centralized. I2P connections have a source address and I2P is slow.
|
||||
CJDNS is fast but does not hide the sender and the recipient from intermediate
|
||||
routers.
|
||||
|
||||
## Installing CJDNS and connecting to the network
|
||||
|
||||
To install and set up CJDNS, follow the instructions at
|
||||
https://github.com/cjdelisle/cjdns#cjdns.
|
||||
|
||||
Don't skip steps
|
||||
["2. Find a friend"](https://github.com/cjdelisle/cjdns#2-find-a-friend) and
|
||||
["3. Connect your node to your friend's
|
||||
node"](https://github.com/cjdelisle/cjdns#3-connect-your-node-to-your-friends-node).
|
||||
You need to be connected to the CJDNS network before it will work with your
|
||||
Dash Core node.
|
||||
|
||||
Typically, CJDNS might be launched from its directory with
|
||||
`sudo ./cjdroute < cjdroute.conf` and it sheds permissions after setting up the
|
||||
[TUN](https://en.wikipedia.org/wiki/TUN/TAP) interface. You may also [launch it as an
|
||||
unprivileged user](https://github.com/cjdelisle/cjdns/blob/master/doc/non-root-user.md)
|
||||
with some additional setup.
|
||||
|
||||
The network connection can be checked by running `./tools/peerStats` from the
|
||||
CJDNS directory.
|
||||
|
||||
## Run Dash Core with CJDNS
|
||||
|
||||
Once you are connected to the CJDNS network, the following Dash Core
|
||||
configuration option makes CJDNS peers automatically reachable:
|
||||
|
||||
```
|
||||
-cjdnsreachable
|
||||
```
|
||||
|
||||
When enabled, this option tells Dash Core that it is running in an
|
||||
environment where a connection to an `fc00::/8` address will be to the CJDNS
|
||||
network instead of to an [RFC4193](https://datatracker.ietf.org/doc/html/rfc4193)
|
||||
IPv6 local network. This helps Dash Core perform better address management:
|
||||
- Your node can consider incoming `fc00::/8` connections to be from the CJDNS
|
||||
network rather than from an IPv6 private one.
|
||||
- If one of your node's local addresses is `fc00::/8`, then it can choose to
|
||||
gossip that address to peers.
|
||||
|
||||
## Additional configuration options related to CJDNS
|
||||
|
||||
```
|
||||
-onlynet=cjdns
|
||||
```
|
||||
|
||||
Make automatic outbound connections only to CJDNS addresses. Inbound and manual
|
||||
connections are not affected by this option. It can be specified multiple times
|
||||
to allow multiple networks, e.g. onlynet=cjdns, onlynet=i2p, onlynet=onion.
|
||||
|
||||
CJDNS support was added to Dash Core in version 21.0 and there may be fewer
|
||||
CJDNS peers than Tor or IP ones. You can use `dash-cli -addrinfo` to see the
|
||||
number of CJDNS addresses known to your node.
|
||||
|
||||
In general, a node can be run with both an onion service and CJDNS (or any/all
|
||||
of IPv4/IPv6/onion/I2P/CJDNS), which can provide a potential fallback if one of
|
||||
the networks has issues. There are a number of ways to configure this; see
|
||||
[doc/tor.md](https://github.com/dashpay/dash/blob/master/doc/tor.md) for
|
||||
details.
|
||||
|
||||
## CJDNS-related information in Dash Core
|
||||
|
||||
There are several ways to see your CJDNS address in Dash Core:
|
||||
- in the "Local addresses" output of CLI `-netinfo`
|
||||
- in the "localaddresses" output of RPC `getnetworkinfo`
|
||||
|
||||
To see which CJDNS peers your node is connected to, use `dash-cli -netinfo 4`
|
||||
or the `getpeerinfo` RPC (i.e. `dash-cli getpeerinfo`).
|
||||
|
||||
To see which CJDNS addresses your node knows, use the `getnodeaddresses 0 cjdns`
|
||||
RPC.
|
20
doc/i2p.md
20
doc/i2p.md
@ -58,13 +58,9 @@ 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.
|
||||
Make automatic outbound connections only to I2P addresses. Inbound and manual
|
||||
connections are not affected by this option. It can be specified multiple times
|
||||
to allow multiple networks, e.g. onlynet=onion, onlynet=i2p.
|
||||
|
||||
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
|
||||
@ -77,8 +73,8 @@ 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.
|
||||
any/all of IPv4/IPv6/onion/I2P/CJDNS), which can provide a potential fallback if
|
||||
one of the networks has issues.
|
||||
|
||||
## Persistent vs transient I2P addresses
|
||||
|
||||
@ -106,9 +102,9 @@ listening should only be turned off if really needed.
|
||||
|
||||
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
|
||||
- in the "Local addresses" output of CLI `-netinfo`
|
||||
- in the "localaddresses" output of RPC `getnetworkinfo`
|
||||
- in the debug log (grep for `AddLocal`; the I2P address ends in `.b32.i2p`)
|
||||
|
||||
To see which I2P peers your node is connected to, use `dash-cli -netinfo 4`
|
||||
or the `getpeerinfo` RPC (e.g. `dash-cli getpeerinfo`).
|
||||
|
8
doc/release-notes-22834.md
Normal file
8
doc/release-notes-22834.md
Normal file
@ -0,0 +1,8 @@
|
||||
Updated settings
|
||||
----------------
|
||||
|
||||
- If `-proxy=` is given together with `-noonion` then the provided proxy will
|
||||
not be set as a proxy for reaching the Tor network. So it will not be
|
||||
possible to open manual connections to the Tor network for example with the
|
||||
`addnode` RPC. To mimic the old behavior use `-proxy=` together with
|
||||
`-onlynet=` listing all relevant networks except `onion`.
|
21
doc/tor.md
21
doc/tor.md
@ -11,9 +11,9 @@ for how to properly configure Tor.
|
||||
## How to see information about your Tor configuration via Dash Core
|
||||
|
||||
There are several ways to see your local onion address in Dash Core:
|
||||
- in the debug log (grep for "tor:" or "AddLocal")
|
||||
- in the output of RPC `getnetworkinfo` in the "localaddresses" section
|
||||
- in the output of the CLI `-netinfo` peer connections dashboard
|
||||
- in the "Local addresses" output of CLI `-netinfo`
|
||||
- in the "localaddresses" output of RPC `getnetworkinfo`
|
||||
- in the debug log (grep for "AddLocal"; the Tor address ends in `.onion`)
|
||||
|
||||
You may set the `-debug=tor` config logging option to have additional
|
||||
information in the debug log about your Tor configuration.
|
||||
@ -22,6 +22,9 @@ CLI `-addrinfo` returns the number of addresses known to your node per
|
||||
network. This can be useful to see how many onion peers your node knows,
|
||||
e.g. for `-onlynet=onion`.
|
||||
|
||||
To fetch a number of onion addresses that your node knows, for example seven
|
||||
addresses, use the `getnodeaddresses 7 onion` RPC.
|
||||
|
||||
## 1. Run Dash Core behind a Tor proxy
|
||||
|
||||
The first step is running Dash Core behind a Tor proxy. This will already anonymize all
|
||||
@ -50,14 +53,10 @@ outgoing connections, but more is possible.
|
||||
-seednode=X SOCKS5. In Tor mode, such addresses can also be exchanged with
|
||||
other P2P nodes.
|
||||
|
||||
-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.
|
||||
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.
|
||||
-onlynet=onion Make automatic outbound connections only to .onion addresses.
|
||||
Inbound and manual connections are not affected by this option.
|
||||
It can be specified multiple times to allow multiple networks,
|
||||
e.g. onlynet=onion, onlynet=i2p, onlynet=cjdns.
|
||||
|
||||
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:
|
||||
|
58
src/init.cpp
58
src/init.cpp
@ -567,6 +567,7 @@ void SetupServerArgs(NodeContext& node)
|
||||
argsman.AddArg("-allowprivatenet", strprintf("Allow RFC1918 addresses to be relayed and connected to (default: %u)", DEFAULT_ALLOWPRIVATENET), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||
argsman.AddArg("-bantime=<n>", strprintf("Default duration (in seconds) of manually configured bans (default: %u)", DEFAULT_MISBEHAVING_BANTIME), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||
argsman.AddArg("-bind=<addr>[:<port>][=onion]", strprintf("Bind to given address and always listen on it (default: 0.0.0.0). Use [host]:port notation for IPv6. Append =onion to tag any incoming connections to that address and port as incoming Tor connections (default: 127.0.0.1:%u=onion, testnet: 127.0.0.1:%u=onion, regtest: 127.0.0.1:%u=onion)", defaultBaseParams->OnionServiceTargetPort(), testnetBaseParams->OnionServiceTargetPort(), regtestBaseParams->OnionServiceTargetPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
|
||||
argsman.AddArg("-cjdnsreachable", "If set, then this host is configured for CJDNS (connecting to fc00::/8 addresses would lead us to the CJDNS network, see doc/cjdns.md) (default: 0)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||
argsman.AddArg("-connect=<ip>", "Connect only to the specified node; -noconnect disables automatic connections (the rules for this peer are the same as for -addnode). This option can be specified multiple times to connect to multiple nodes.", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
|
||||
argsman.AddArg("-discover", "Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||
argsman.AddArg("-dns", strprintf("Allow DNS lookups for -addnode, -seednode and -connect (default: %u)", DEFAULT_NAME_LOOKUP), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||
@ -584,7 +585,7 @@ void SetupServerArgs(NodeContext& node)
|
||||
argsman.AddArg("-onion=<ip:port>", "Use separate SOCKS5 proxy to reach peers via Tor onion services, set -noonion to disable (default: -proxy)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||
argsman.AddArg("-i2psam=<ip:port>", "I2P SAM proxy to reach I2P peers and accept I2P connections (default: none)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||
argsman.AddArg("-i2pacceptincoming", strprintf("Whether to accept inbound I2P connections (default: %i). 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.", DEFAULT_I2P_ACCEPT_INCOMING), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||
argsman.AddArg("-onlynet=<net>", "Make outgoing connections only through network <net> (" + Join(GetNetworkNames(), ", ") + "). Incoming connections are not affected by this option. This option can be specified multiple times to allow multiple networks. Warning: if it is used with non-onion networks and the -onion or -proxy option is set, then outbound onion connections will still be made; use -noonion or -onion=0 to disable outbound onion connections in this case.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||
argsman.AddArg("-onlynet=<net>", "Make automatic outbound connections only to network <net> (" + Join(GetNetworkNames(), ", ") + "). Inbound and manual connections are not affected by this option. It can be specified multiple times to allow multiple networks.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||
argsman.AddArg("-peerblockfilters", strprintf("Serve compact block filters to peers per BIP 157 (default: %u)", DEFAULT_PEERBLOCKFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||
argsman.AddArg("-peerbloomfilters", strprintf("Support filtering of blocks and transaction with bloom filters (default: %u)", DEFAULT_PEERBLOOMFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||
argsman.AddArg("-peertimeout=<n>", strprintf("Specify a p2p connection timeout delay in seconds. After connecting to a peer, wait this amount of time before considering disconnection based on inactivity (minimum: 1, default: %d)", DEFAULT_PEER_CONNECT_TIMEOUT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||
@ -1825,56 +1826,84 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc
|
||||
}
|
||||
for (int n = 0; n < NET_MAX; n++) {
|
||||
enum Network net = (enum Network)n;
|
||||
assert(IsReachable(net));
|
||||
if (!nets.count(net))
|
||||
SetReachable(net, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (!args.IsArgSet("-cjdnsreachable")) {
|
||||
SetReachable(NET_CJDNS, false);
|
||||
}
|
||||
// Now IsReachable(NET_CJDNS) is true if:
|
||||
// 1. -cjdnsreachable is given and
|
||||
// 2.1. -onlynet is not given or
|
||||
// 2.2. -onlynet=cjdns is given
|
||||
|
||||
// Check for host lookup allowed before parsing any network related parameters
|
||||
fNameLookup = args.GetBoolArg("-dns", DEFAULT_NAME_LOOKUP);
|
||||
|
||||
Proxy onion_proxy;
|
||||
|
||||
bool proxyRandomize = args.GetBoolArg("-proxyrandomize", DEFAULT_PROXYRANDOMIZE);
|
||||
// -proxy sets a proxy for all outgoing network traffic
|
||||
// -noproxy (or -proxy=0) as well as the empty string can be used to not set a proxy, this is the default
|
||||
std::string proxyArg = args.GetArg("-proxy", "");
|
||||
SetReachable(NET_ONION, false);
|
||||
if (proxyArg != "" && proxyArg != "0") {
|
||||
CService proxyAddr;
|
||||
if (!Lookup(proxyArg, proxyAddr, 9050, fNameLookup)) {
|
||||
return InitError(strprintf(_("Invalid -proxy address or hostname: '%s'"), proxyArg));
|
||||
}
|
||||
|
||||
proxyType addrProxy = proxyType(proxyAddr, proxyRandomize);
|
||||
Proxy addrProxy = Proxy(proxyAddr, proxyRandomize);
|
||||
if (!addrProxy.IsValid())
|
||||
return InitError(strprintf(_("Invalid -proxy address or hostname: '%s'"), proxyArg));
|
||||
|
||||
SetProxy(NET_IPV4, addrProxy);
|
||||
SetProxy(NET_IPV6, addrProxy);
|
||||
SetProxy(NET_ONION, addrProxy);
|
||||
SetProxy(NET_CJDNS, addrProxy);
|
||||
SetNameProxy(addrProxy);
|
||||
SetReachable(NET_ONION, true); // by default, -proxy sets onion as reachable, unless -noonion later
|
||||
onion_proxy = addrProxy;
|
||||
}
|
||||
|
||||
const bool onlynet_used_with_onion{args.IsArgSet("-onlynet") && IsReachable(NET_ONION)};
|
||||
|
||||
// -onion can be used to set only a proxy for .onion, or override normal proxy for .onion addresses
|
||||
// -noonion (or -onion=0) disables connecting to .onion entirely
|
||||
// An empty string is used to not override the onion proxy (in which case it defaults to -proxy set above, or none)
|
||||
std::string onionArg = args.GetArg("-onion", "");
|
||||
if (onionArg != "") {
|
||||
if (onionArg == "0") { // Handle -noonion/-onion=0
|
||||
SetReachable(NET_ONION, false);
|
||||
onion_proxy = Proxy{};
|
||||
if (onlynet_used_with_onion) {
|
||||
return InitError(
|
||||
_("Outbound connections restricted to Tor (-onlynet=onion) but the proxy for "
|
||||
"reaching the Tor network is explicitly forbidden: -onion=0"));
|
||||
}
|
||||
} else {
|
||||
CService onionProxy;
|
||||
if (!Lookup(onionArg, onionProxy, 9050, fNameLookup)) {
|
||||
CService addr;
|
||||
if (!Lookup(onionArg, addr, 9050, fNameLookup) || !addr.IsValid()) {
|
||||
return InitError(strprintf(_("Invalid -onion address or hostname: '%s'"), onionArg));
|
||||
}
|
||||
proxyType addrOnion = proxyType(onionProxy, proxyRandomize);
|
||||
if (!addrOnion.IsValid())
|
||||
return InitError(strprintf(_("Invalid -onion address or hostname: '%s'"), onionArg));
|
||||
SetProxy(NET_ONION, addrOnion);
|
||||
SetReachable(NET_ONION, true);
|
||||
onion_proxy = Proxy{addr, proxyRandomize};
|
||||
}
|
||||
}
|
||||
|
||||
if (onion_proxy.IsValid()) {
|
||||
SetProxy(NET_ONION, onion_proxy);
|
||||
} else {
|
||||
// If -listenonion is set, then we will (try to) connect to the Tor control port
|
||||
// later from the torcontrol thread and may retrieve the onion proxy from there.
|
||||
const bool listenonion_disabled{!args.GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)};
|
||||
if (onlynet_used_with_onion && listenonion_disabled) {
|
||||
return InitError(
|
||||
_("Outbound connections restricted to Tor (-onlynet=onion) but the proxy for "
|
||||
"reaching the Tor network is not provided: none of -proxy, -onion or "
|
||||
"-listenonion is given"));
|
||||
}
|
||||
SetReachable(NET_ONION, false);
|
||||
}
|
||||
|
||||
for (const std::string& strAddr : args.GetArgs("-externalip")) {
|
||||
CService addrLocal;
|
||||
if (Lookup(strAddr, addrLocal, GetListenPort(), fNameLookup) && addrLocal.IsValid())
|
||||
@ -2560,8 +2589,7 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc
|
||||
if (!Lookup(i2psam_arg, addr, 7656, fNameLookup) || !addr.IsValid()) {
|
||||
return InitError(strprintf(_("Invalid -i2psam address or hostname: '%s'"), i2psam_arg));
|
||||
}
|
||||
SetReachable(NET_I2P, true);
|
||||
SetProxy(NET_I2P, proxyType{addr});
|
||||
SetProxy(NET_I2P, Proxy{addr});
|
||||
} else {
|
||||
SetReachable(NET_I2P, false);
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ class CNodeStats;
|
||||
class Coin;
|
||||
class RPCTimerInterface;
|
||||
class UniValue;
|
||||
class proxyType;
|
||||
class Proxy;
|
||||
struct bilingual_str;
|
||||
enum class SynchronizationState;
|
||||
struct CNodeStateStats;
|
||||
@ -174,7 +174,7 @@ public:
|
||||
virtual void mapPort(bool use_upnp, bool use_natpmp) = 0;
|
||||
|
||||
//! Get proxy.
|
||||
virtual bool getProxy(Network net, proxyType& proxy_info) = 0;
|
||||
virtual bool getProxy(Network net, Proxy& proxy_info) = 0;
|
||||
|
||||
//! Get number of connections.
|
||||
virtual size_t getNodeCount(ConnectionDirection flags) = 0;
|
||||
|
50
src/net.cpp
50
src/net.cpp
@ -257,9 +257,27 @@ std::optional<CAddress> GetLocalAddrForPeer(CNode *pnode)
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// learn a new local address
|
||||
bool AddLocal(const CService& addr, int nScore)
|
||||
/**
|
||||
* If an IPv6 address belongs to the address range used by the CJDNS network and
|
||||
* the CJDNS network is reachable (-cjdnsreachable config is set), then change
|
||||
* the type from NET_IPV6 to NET_CJDNS.
|
||||
* @param[in] service Address to potentially convert.
|
||||
* @return a copy of `service` either unmodified or changed to CJDNS.
|
||||
*/
|
||||
CService MaybeFlipIPv6toCJDNS(const CService& service)
|
||||
{
|
||||
CService ret{service};
|
||||
if (ret.m_net == NET_IPV6 && ret.m_addr[0] == 0xfc && IsReachable(NET_CJDNS)) {
|
||||
ret.m_net = NET_CJDNS;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// learn a new local address
|
||||
bool AddLocal(const CService& addr_, int nScore)
|
||||
{
|
||||
CService addr{MaybeFlipIPv6toCJDNS(addr_)};
|
||||
|
||||
if (!addr.IsRoutable() && Params().RequireRoutableExternalIP())
|
||||
return false;
|
||||
|
||||
@ -456,7 +474,8 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
|
||||
if (pszDest) {
|
||||
std::vector<CService> resolved;
|
||||
if (Lookup(pszDest, resolved, default_port, fNameLookup && !HaveNameProxy(), 256) && !resolved.empty()) {
|
||||
addrConnect = CAddress(resolved[GetRand(resolved.size())], NODE_NONE);
|
||||
const CService rnd{resolved[GetRand(resolved.size())]};
|
||||
addrConnect = CAddress{MaybeFlipIPv6toCJDNS(rnd), NODE_NONE};
|
||||
if (!addrConnect.IsValid()) {
|
||||
LogPrint(BCLog::NET, "Resolver returned invalid address %s for %s\n", addrConnect.ToString(), pszDest);
|
||||
return nullptr;
|
||||
@ -475,7 +494,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
|
||||
// Connect
|
||||
bool connected = false;
|
||||
std::unique_ptr<Sock> sock;
|
||||
proxyType proxy;
|
||||
Proxy proxy;
|
||||
CAddress addr_bind;
|
||||
assert(!addr_bind.IsValid());
|
||||
std::unique_ptr<i2p::sam::Session> i2p_transient_session;
|
||||
@ -1008,17 +1027,17 @@ void ProtectEvictionCandidatesByRatio(std::vector<NodeEvictionCandidate>& evicti
|
||||
// Protect the half of the remaining nodes which have been connected the longest.
|
||||
// This replicates the non-eviction implicit behavior, and precludes attacks that start later.
|
||||
// To favorise the diversity of our peer connections, reserve up to half of these protected
|
||||
// spots for Tor/onion, localhost and I2P peers, even if they're not longest uptime overall.
|
||||
// This helps protect these higher-latency peers that tend to be otherwise
|
||||
// spots for Tor/onion, localhost, I2P, and CJDNS peers, even if they're not longest uptime
|
||||
// overall. This helps protect these higher-latency peers that tend to be otherwise
|
||||
// disadvantaged under our eviction criteria.
|
||||
const size_t initial_size = eviction_candidates.size();
|
||||
const size_t total_protect_size{initial_size / 2};
|
||||
|
||||
// Disadvantaged networks to protect: I2P, localhost, Tor/onion. In case of equal counts, earlier
|
||||
// array members have first opportunity to recover unused slots from the previous iteration.
|
||||
// Disadvantaged networks to protect. In the case of equal counts, earlier array members
|
||||
// have the first opportunity to recover unused slots from the previous iteration.
|
||||
struct Net { bool is_local; Network id; size_t count; };
|
||||
std::array<Net, 3> networks{
|
||||
{{false, NET_I2P, 0}, {/* localhost */ true, NET_MAX, 0}, {false, NET_ONION, 0}}};
|
||||
std::array<Net, 4> networks{
|
||||
{{false, NET_CJDNS, 0}, {false, NET_I2P, 0}, {/*localhost=*/true, NET_MAX, 0}, {false, NET_ONION, 0}}};
|
||||
|
||||
// Count and store the number of eviction candidates per network.
|
||||
for (Net& n : networks) {
|
||||
@ -1211,9 +1230,11 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket, CMasternodeSy
|
||||
|
||||
if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) {
|
||||
LogPrintf("Warning: Unknown socket family\n");
|
||||
} else {
|
||||
addr = CAddress{MaybeFlipIPv6toCJDNS(addr), NODE_NONE};
|
||||
}
|
||||
|
||||
const CAddress addr_bind = GetBindAddress(hSocket);
|
||||
const CAddress addr_bind{MaybeFlipIPv6toCJDNS(GetBindAddress(hSocket)), NODE_NONE};
|
||||
|
||||
NetPermissionFlags permissionFlags = NetPermissionFlags::None;
|
||||
hListenSocket.AddSocketPermissionFlags(permissionFlags);
|
||||
@ -3303,7 +3324,10 @@ NodeId CConnman::GetNewNodeId()
|
||||
}
|
||||
|
||||
|
||||
bool CConnman::Bind(const CService &addr, unsigned int flags, NetPermissionFlags permissions) {
|
||||
bool CConnman::Bind(const CService& addr_, unsigned int flags, NetPermissionFlags permissions)
|
||||
{
|
||||
const CService addr{MaybeFlipIPv6toCJDNS(addr_)};
|
||||
|
||||
if (!(flags & BF_EXPLICIT) && !IsReachable(addr)) {
|
||||
return false;
|
||||
}
|
||||
@ -3368,7 +3392,7 @@ bool CConnman::Start(CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_met
|
||||
return false;
|
||||
}
|
||||
|
||||
proxyType i2p_sam;
|
||||
Proxy i2p_sam;
|
||||
if (GetProxy(NET_I2P, i2p_sam) && connOptions.m_i2p_accept_incoming) {
|
||||
m_i2p_sam_session = std::make_unique<i2p::sam::Session>(GetDataDir() / "i2p_private_key",
|
||||
i2p_sam.proxy, &interruptNet);
|
||||
|
@ -1657,6 +1657,8 @@ size_t GetRequestedObjectCount(NodeId nodeId) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
*
|
||||
* - I2P peers
|
||||
*
|
||||
* - CJDNS peers
|
||||
*
|
||||
* This helps protect these privacy network peers, which tend to be otherwise
|
||||
* disadvantaged under our eviction criteria for their higher min ping times
|
||||
* relative to IPv4/IPv6 peers, and favorise the diversity of peer connections.
|
||||
|
@ -680,7 +680,7 @@ bool CNetAddr::GetInAddr(struct in_addr* pipv4Addr) const
|
||||
*/
|
||||
bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const
|
||||
{
|
||||
if (!IsIPv6()) {
|
||||
if (!IsIPv6() && !IsCJDNS()) {
|
||||
return false;
|
||||
}
|
||||
assert(sizeof(*pipv6Addr) == m_addr.size());
|
||||
@ -800,8 +800,14 @@ std::vector<unsigned char> CNetAddr::GetGroup(const std::vector<bool> &asmap) co
|
||||
vchRet.push_back((ipv4 >> 24) & 0xFF);
|
||||
vchRet.push_back((ipv4 >> 16) & 0xFF);
|
||||
return vchRet;
|
||||
} else if (IsTor() || IsI2P() || IsCJDNS()) {
|
||||
} else if (IsTor() || IsI2P()) {
|
||||
nBits = 4;
|
||||
} else if (IsCJDNS()) {
|
||||
// Treat in the same way as Tor and I2P because the address in all of
|
||||
// them is "random" bytes (derived from a public key). However in CJDNS
|
||||
// the first byte is a constant 0xfc, so the random bytes come after it.
|
||||
// Thus skip the constant 8 bits at the start.
|
||||
nBits = 12;
|
||||
} else if (IsHeNet()) {
|
||||
// for he.net, use /36 groups
|
||||
nBits = 36;
|
||||
@ -898,6 +904,11 @@ int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const
|
||||
case NET_I2P: return REACH_PRIVATE;
|
||||
default: return REACH_DEFAULT;
|
||||
}
|
||||
case NET_CJDNS:
|
||||
switch (ourNet) {
|
||||
case NET_CJDNS: return REACH_PRIVATE;
|
||||
default: return REACH_DEFAULT;
|
||||
}
|
||||
case NET_TEREDO:
|
||||
switch(ourNet) {
|
||||
default: return REACH_DEFAULT;
|
||||
@ -999,7 +1010,7 @@ bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const
|
||||
paddrin->sin_port = htons(port);
|
||||
return true;
|
||||
}
|
||||
if (IsIPv6()) {
|
||||
if (IsIPv6() || IsCJDNS()) {
|
||||
if (*addrlen < (socklen_t)sizeof(struct sockaddr_in6))
|
||||
return false;
|
||||
*addrlen = sizeof(struct sockaddr_in6);
|
||||
|
@ -232,7 +232,7 @@ public:
|
||||
*/
|
||||
bool IsRelayable() const
|
||||
{
|
||||
return IsIPv4() || IsIPv6() || IsTor() || IsI2P();
|
||||
return IsIPv4() || IsIPv6() || IsTor() || IsI2P() || IsCJDNS();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -581,6 +581,8 @@ public:
|
||||
READWRITEAS(CNetAddr, obj);
|
||||
READWRITE(Using<BigEndianFormatter<2>>(obj.port));
|
||||
}
|
||||
|
||||
friend CService MaybeFlipIPv6toCJDNS(const CService& service);
|
||||
};
|
||||
|
||||
#endif // BITCOIN_NETADDRESS_H
|
||||
|
@ -30,8 +30,8 @@
|
||||
|
||||
// Settings
|
||||
static Mutex g_proxyinfo_mutex;
|
||||
static proxyType proxyInfo[NET_MAX] GUARDED_BY(g_proxyinfo_mutex);
|
||||
static proxyType nameProxy GUARDED_BY(g_proxyinfo_mutex);
|
||||
static Proxy proxyInfo[NET_MAX] GUARDED_BY(g_proxyinfo_mutex);
|
||||
static Proxy nameProxy GUARDED_BY(g_proxyinfo_mutex);
|
||||
int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
|
||||
bool fNameLookup = DEFAULT_NAME_LOOKUP;
|
||||
|
||||
@ -95,6 +95,9 @@ enum Network ParseNetwork(const std::string& net_in) {
|
||||
if (net == "i2p") {
|
||||
return NET_I2P;
|
||||
}
|
||||
if (net == "cjdns") {
|
||||
return NET_CJDNS;
|
||||
}
|
||||
return NET_UNROUTABLE;
|
||||
}
|
||||
|
||||
@ -119,7 +122,7 @@ std::vector<std::string> GetNetworkNames(bool append_unroutable)
|
||||
std::vector<std::string> names;
|
||||
for (int n = 0; n < NET_MAX; ++n) {
|
||||
const enum Network network{static_cast<Network>(n)};
|
||||
if (network == NET_UNROUTABLE || network == NET_CJDNS || network == NET_INTERNAL) continue;
|
||||
if (network == NET_UNROUTABLE || network == NET_INTERNAL) continue;
|
||||
names.emplace_back(GetNetworkName(network));
|
||||
}
|
||||
if (append_unroutable) {
|
||||
@ -601,7 +604,7 @@ bool ConnectSocketDirectly(const CService &addrConnect, const Sock& sock, int nT
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SetProxy(enum Network net, const proxyType &addrProxy) {
|
||||
bool SetProxy(enum Network net, const Proxy &addrProxy) {
|
||||
assert(net >= 0 && net < NET_MAX);
|
||||
if (!addrProxy.IsValid())
|
||||
return false;
|
||||
@ -610,7 +613,7 @@ bool SetProxy(enum Network net, const proxyType &addrProxy) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetProxy(enum Network net, proxyType &proxyInfoOut) {
|
||||
bool GetProxy(enum Network net, Proxy &proxyInfoOut) {
|
||||
assert(net >= 0 && net < NET_MAX);
|
||||
LOCK(g_proxyinfo_mutex);
|
||||
if (!proxyInfo[net].IsValid())
|
||||
@ -619,7 +622,7 @@ bool GetProxy(enum Network net, proxyType &proxyInfoOut) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SetNameProxy(const proxyType &addrProxy) {
|
||||
bool SetNameProxy(const Proxy &addrProxy) {
|
||||
if (!addrProxy.IsValid())
|
||||
return false;
|
||||
LOCK(g_proxyinfo_mutex);
|
||||
@ -627,7 +630,7 @@ bool SetNameProxy(const proxyType &addrProxy) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetNameProxy(proxyType &nameProxyOut) {
|
||||
bool GetNameProxy(Proxy &nameProxyOut) {
|
||||
LOCK(g_proxyinfo_mutex);
|
||||
if(!nameProxy.IsValid())
|
||||
return false;
|
||||
@ -649,7 +652,7 @@ bool IsProxy(const CNetAddr &addr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ConnectThroughProxy(const proxyType& proxy, const std::string& strDest, uint16_t port, const Sock& sock, int nTimeout, bool& outProxyConnectionFailed)
|
||||
bool ConnectThroughProxy(const Proxy& proxy, const std::string& strDest, uint16_t port, const Sock& sock, int nTimeout, bool& outProxyConnectionFailed)
|
||||
{
|
||||
// first connect to proxy server
|
||||
if (!ConnectSocketDirectly(proxy.proxy, sock, nTimeout, true)) {
|
||||
|
@ -49,11 +49,11 @@ static inline bool operator&(ConnectionDirection a, ConnectionDirection b) {
|
||||
return (underlying(a) & underlying(b));
|
||||
}
|
||||
|
||||
class proxyType
|
||||
class Proxy
|
||||
{
|
||||
public:
|
||||
proxyType(): randomize_credentials(false) {}
|
||||
explicit proxyType(const CService &_proxy, bool _randomize_credentials=false): proxy(_proxy), randomize_credentials(_randomize_credentials) {}
|
||||
Proxy(): randomize_credentials(false) {}
|
||||
explicit Proxy(const CService &_proxy, bool _randomize_credentials=false): proxy(_proxy), randomize_credentials(_randomize_credentials) {}
|
||||
|
||||
bool IsValid() const { return proxy.IsValid(); }
|
||||
|
||||
@ -77,8 +77,8 @@ enum Network ParseNetwork(const std::string& net);
|
||||
std::string GetNetworkName(enum Network net);
|
||||
/** Return a vector of publicly routable Network names; optionally append NET_UNROUTABLE. */
|
||||
std::vector<std::string> GetNetworkNames(bool append_unroutable = false);
|
||||
bool SetProxy(enum Network net, const proxyType &addrProxy);
|
||||
bool GetProxy(enum Network net, proxyType &proxyInfoOut);
|
||||
bool SetProxy(enum Network net, const Proxy &addrProxy);
|
||||
bool GetProxy(enum Network net, Proxy &proxyInfoOut);
|
||||
bool IsProxy(const CNetAddr &addr);
|
||||
/**
|
||||
* Set the name proxy to use for all connections to nodes specified by a
|
||||
@ -96,9 +96,9 @@ bool IsProxy(const CNetAddr &addr);
|
||||
* server in common use (most notably Tor) actually implements UDP
|
||||
* support, and a DNS resolver is beyond the scope of this project.
|
||||
*/
|
||||
bool SetNameProxy(const proxyType &addrProxy);
|
||||
bool SetNameProxy(const Proxy &addrProxy);
|
||||
bool HaveNameProxy();
|
||||
bool GetNameProxy(proxyType &nameProxyOut);
|
||||
bool GetNameProxy(Proxy &nameProxyOut);
|
||||
|
||||
using DNSLookupFn = std::function<std::vector<CNetAddr>(const std::string&, bool)>;
|
||||
extern DNSLookupFn g_dns_lookup;
|
||||
@ -223,7 +223,7 @@ bool ConnectSocketDirectly(const CService &addrConnect, const Sock& sock, int nT
|
||||
*
|
||||
* @returns Whether or not the operation succeeded.
|
||||
*/
|
||||
bool ConnectThroughProxy(const proxyType& proxy, const std::string& strDest, uint16_t port, const Sock& sock, int nTimeout, bool& outProxyConnectionFailed);
|
||||
bool ConnectThroughProxy(const Proxy& proxy, const std::string& strDest, uint16_t port, const Sock& sock, int nTimeout, bool& outProxyConnectionFailed);
|
||||
|
||||
/** Enable non-blocking mode for a socket */
|
||||
bool SetSocketNonBlocking(const SOCKET& hSocket);
|
||||
|
@ -341,7 +341,7 @@ public:
|
||||
}
|
||||
bool shutdownRequested() override { return ShutdownRequested(); }
|
||||
void mapPort(bool use_upnp, bool use_natpmp) override { StartMapPort(use_upnp, use_natpmp); }
|
||||
bool getProxy(Network net, proxyType& proxy_info) override { return GetProxy(net, proxy_info); }
|
||||
bool getProxy(Network net, Proxy& proxy_info) override { return GetProxy(net, proxy_info); }
|
||||
size_t getNodeCount(ConnectionDirection flags) override
|
||||
{
|
||||
return m_context->connman ? m_context->connman->GetNodeCount(flags) : 0;
|
||||
|
@ -381,7 +381,7 @@ void ClientModel::unsubscribeFromCoreSignals()
|
||||
|
||||
bool ClientModel::getProxyInfo(std::string& ip_port) const
|
||||
{
|
||||
proxyType ipv4, ipv6;
|
||||
Proxy ipv4, ipv6;
|
||||
if (m_node.getProxy((Network) 1, ipv4) && m_node.getProxy((Network) 2, ipv6)) {
|
||||
ip_port = ipv4.proxy.ToStringIPPort();
|
||||
return true;
|
||||
|
@ -485,7 +485,7 @@ void OptionsDialog::updateProxyValidationState()
|
||||
|
||||
void OptionsDialog::updateDefaultProxyNets()
|
||||
{
|
||||
proxyType proxy;
|
||||
Proxy proxy;
|
||||
std::string strProxy;
|
||||
QString strDefaultProxyGUI;
|
||||
|
||||
@ -567,7 +567,7 @@ QValidator::State ProxyAddressValidator::validate(QString &input, int &pos) cons
|
||||
Q_UNUSED(pos);
|
||||
// Validate the proxy
|
||||
CService serv(LookupNumeric(input.toStdString(), DEFAULT_GUI_PROXY_PORT));
|
||||
proxyType addrProxy = proxyType(serv, true);
|
||||
Proxy addrProxy = Proxy(serv, true);
|
||||
if (addrProxy.IsValid())
|
||||
return QValidator::Acceptable;
|
||||
|
||||
|
@ -585,8 +585,8 @@ static UniValue GetNetworksInfo()
|
||||
UniValue networks(UniValue::VARR);
|
||||
for (int n = 0; n < NET_MAX; ++n) {
|
||||
enum Network network = static_cast<enum Network>(n);
|
||||
if (network == NET_UNROUTABLE || network == NET_CJDNS || network == NET_INTERNAL) continue;
|
||||
proxyType proxy;
|
||||
if (network == NET_UNROUTABLE || network == NET_INTERNAL) continue;
|
||||
Proxy proxy;
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
GetProxy(network, proxy);
|
||||
obj.pushKV("name", GetNetworkName(network));
|
||||
|
@ -112,7 +112,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
|
||||
// Test protection of onion, localhost, and I2P peers...
|
||||
|
||||
// Expect 1/4 onion peers to be protected from eviction,
|
||||
// if no localhost or I2P peers.
|
||||
// if no localhost, I2P, or CJDNS peers.
|
||||
BOOST_CHECK(IsProtected(
|
||||
num_peers, [](NodeEvictionCandidate& c) {
|
||||
c.m_is_local = false;
|
||||
@ -123,7 +123,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
|
||||
random_context));
|
||||
|
||||
// Expect 1/4 onion peers and 1/4 of the other peers to be protected,
|
||||
// sorted by longest uptime (lowest nTimeConnected), if no localhost or I2P peers.
|
||||
// sorted by longest uptime (lowest nTimeConnected), if no localhost, I2P or CJDNS peers.
|
||||
BOOST_CHECK(IsProtected(
|
||||
num_peers, [](NodeEvictionCandidate& c) {
|
||||
c.nTimeConnected = c.id;
|
||||
@ -135,7 +135,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
|
||||
random_context));
|
||||
|
||||
// Expect 1/4 localhost peers to be protected from eviction,
|
||||
// if no onion or I2P peers.
|
||||
// if no onion, I2P, or CJDNS peers.
|
||||
BOOST_CHECK(IsProtected(
|
||||
num_peers, [](NodeEvictionCandidate& c) {
|
||||
c.m_is_local = (c.id == 1 || c.id == 9 || c.id == 11);
|
||||
@ -146,7 +146,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
|
||||
random_context));
|
||||
|
||||
// Expect 1/4 localhost peers and 1/4 of the other peers to be protected,
|
||||
// sorted by longest uptime (lowest nTimeConnected), if no onion or I2P peers.
|
||||
// sorted by longest uptime (lowest nTimeConnected), if no onion, I2P, or CJDNS peers.
|
||||
BOOST_CHECK(IsProtected(
|
||||
num_peers, [](NodeEvictionCandidate& c) {
|
||||
c.nTimeConnected = c.id;
|
||||
@ -158,7 +158,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
|
||||
random_context));
|
||||
|
||||
// Expect 1/4 I2P peers to be protected from eviction,
|
||||
// if no onion or localhost peers.
|
||||
// if no onion, localhost, or CJDNS peers.
|
||||
BOOST_CHECK(IsProtected(
|
||||
num_peers, [](NodeEvictionCandidate& c) {
|
||||
c.m_is_local = false;
|
||||
@ -168,8 +168,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
|
||||
/* unprotected_peer_ids */ {},
|
||||
random_context));
|
||||
|
||||
// Expect 1/4 I2P peers and 1/4 of the other peers to be protected,
|
||||
// sorted by longest uptime (lowest nTimeConnected), if no onion or localhost peers.
|
||||
// Expect 1/4 I2P peers and 1/4 of the other peers to be protected, sorted
|
||||
// by longest uptime (lowest nTimeConnected), if no onion, localhost, or CJDNS peers.
|
||||
BOOST_CHECK(IsProtected(
|
||||
num_peers, [](NodeEvictionCandidate& c) {
|
||||
c.nTimeConnected = c.id;
|
||||
@ -180,6 +180,29 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
|
||||
/* unprotected_peer_ids */ {3, 5, 6, 7, 8, 11},
|
||||
random_context));
|
||||
|
||||
// Expect 1/4 CJDNS peers to be protected from eviction,
|
||||
// if no onion, localhost, or I2P peers.
|
||||
BOOST_CHECK(IsProtected(
|
||||
num_peers, [](NodeEvictionCandidate& c) {
|
||||
c.m_is_local = false;
|
||||
c.m_network = (c.id == 2 || c.id == 7 || c.id == 10) ? NET_CJDNS : NET_IPV4;
|
||||
},
|
||||
/*protected_peer_ids=*/{2, 7, 10},
|
||||
/*unprotected_peer_ids=*/{},
|
||||
random_context));
|
||||
|
||||
// Expect 1/4 CJDNS peers and 1/4 of the other peers to be protected, sorted
|
||||
// by longest uptime (lowest nTimeConnected), if no onion, localhost, or I2P peers.
|
||||
BOOST_CHECK(IsProtected(
|
||||
num_peers, [](NodeEvictionCandidate& c) {
|
||||
c.nTimeConnected = c.id;
|
||||
c.m_is_local = false;
|
||||
c.m_network = (c.id == 4 || c.id > 8) ? NET_CJDNS : NET_IPV6;
|
||||
},
|
||||
/*protected_peer_ids=*/{0, 1, 2, 4, 9, 10},
|
||||
/*unprotected_peer_ids=*/{3, 5, 6, 7, 8, 11},
|
||||
random_context));
|
||||
|
||||
// Tests with 2 networks...
|
||||
|
||||
// Combined test: expect having 1 localhost and 1 onion peer out of 4 to
|
||||
@ -311,16 +334,16 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
|
||||
BOOST_CHECK(IsProtected(
|
||||
4, [](NodeEvictionCandidate& c) {
|
||||
c.nTimeConnected = c.id;
|
||||
c.m_is_local = (c.id == 3);
|
||||
if (c.id == 4) {
|
||||
c.m_is_local = (c.id == 2);
|
||||
if (c.id == 3) {
|
||||
c.m_network = NET_I2P;
|
||||
} else if (c.id == 2) {
|
||||
} else if (c.id == 1) {
|
||||
c.m_network = NET_ONION;
|
||||
} else {
|
||||
c.m_network = NET_IPV6;
|
||||
}
|
||||
},
|
||||
/* protected_peer_ids */ {0, 4},
|
||||
/* protected_peer_ids */ {0, 3},
|
||||
/* unprotected_peer_ids */ {1, 2},
|
||||
random_context));
|
||||
|
||||
@ -438,15 +461,15 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
|
||||
/* unprotected_peer_ids */ {6, 7, 8, 9, 10, 11, 16, 19, 20, 21, 22, 23},
|
||||
random_context));
|
||||
|
||||
// Combined test: expect having 8 localhost, 4 I2P, and 3 onion peers out of
|
||||
// 24 to protect 2 of each (6 total), plus 6 others for 12/24 total, sorted
|
||||
// by longest uptime.
|
||||
// Combined test: expect having 8 localhost, 4 CJDNS, and 3 onion peers out
|
||||
// of 24 to protect 2 of each (6 total), plus 6 others for 12/24 total,
|
||||
// sorted by longest uptime.
|
||||
BOOST_CHECK(IsProtected(
|
||||
24, [](NodeEvictionCandidate& c) {
|
||||
c.nTimeConnected = c.id;
|
||||
c.m_is_local = (c.id > 15);
|
||||
if (c.id > 10 && c.id < 15) {
|
||||
c.m_network = NET_I2P;
|
||||
c.m_network = NET_CJDNS;
|
||||
} else if (c.id > 6 && c.id < 10) {
|
||||
c.m_network = NET_ONION;
|
||||
} else {
|
||||
@ -456,6 +479,116 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
|
||||
/* protected_peer_ids */ {0, 1, 2, 3, 4, 5, 7, 8, 11, 12, 16, 17},
|
||||
/* unprotected_peer_ids */ {6, 9, 10, 13, 14, 15, 18, 19, 20, 21, 22, 23},
|
||||
random_context));
|
||||
|
||||
// Tests with 4 networks...
|
||||
|
||||
// Combined test: expect having 1 CJDNS, 1 I2P, 1 localhost and 1 onion peer
|
||||
// out of 5 to protect 1 CJDNS, 0 I2P, 0 localhost, 0 onion and 1 other peer
|
||||
// (2 total), sorted by longest uptime; stable sort breaks tie with array
|
||||
// order of CJDNS first.
|
||||
BOOST_CHECK(IsProtected(
|
||||
5, [](NodeEvictionCandidate& c) {
|
||||
c.nTimeConnected = c.id;
|
||||
c.m_is_local = (c.id == 3);
|
||||
if (c.id == 4) {
|
||||
c.m_network = NET_CJDNS;
|
||||
} else if (c.id == 1) {
|
||||
c.m_network = NET_I2P;
|
||||
} else if (c.id == 2) {
|
||||
c.m_network = NET_ONION;
|
||||
} else {
|
||||
c.m_network = NET_IPV6;
|
||||
}
|
||||
},
|
||||
/* protected_peer_ids */ {0, 4},
|
||||
/* unprotected_peer_ids */ {1, 2, 3},
|
||||
random_context));
|
||||
|
||||
// Combined test: expect having 1 CJDNS, 1 I2P, 1 localhost and 1 onion peer
|
||||
// out of 7 to protect 1 CJDNS, 0, I2P, 0 localhost, 0 onion and 2 other
|
||||
// peers (3 total) sorted by longest uptime; stable sort breaks tie with
|
||||
// array order of CJDNS first.
|
||||
BOOST_CHECK(IsProtected(
|
||||
7, [](NodeEvictionCandidate& c) {
|
||||
c.nTimeConnected = c.id;
|
||||
c.m_is_local = (c.id == 4);
|
||||
if (c.id == 6) {
|
||||
c.m_network = NET_CJDNS;
|
||||
} else if (c.id == 5) {
|
||||
c.m_network = NET_I2P;
|
||||
} else if (c.id == 3) {
|
||||
c.m_network = NET_ONION;
|
||||
} else {
|
||||
c.m_network = NET_IPV4;
|
||||
}
|
||||
},
|
||||
/*protected_peer_ids=*/{0, 1, 6},
|
||||
/*unprotected_peer_ids=*/{2, 3, 4, 5},
|
||||
random_context));
|
||||
|
||||
// Combined test: expect having 1 CJDNS, 1 I2P, 1 localhost and 1 onion peer
|
||||
// out of 8 to protect 1 CJDNS, 1 I2P, 0 localhost, 0 onion and 2 other
|
||||
// peers (4 total) sorted by longest uptime; stable sort breaks tie with
|
||||
// array order of CJDNS first.
|
||||
BOOST_CHECK(IsProtected(
|
||||
8, [](NodeEvictionCandidate& c) {
|
||||
c.nTimeConnected = c.id;
|
||||
c.m_is_local = (c.id == 3);
|
||||
if (c.id == 5) {
|
||||
c.m_network = NET_CJDNS;
|
||||
} else if (c.id == 6) {
|
||||
c.m_network = NET_I2P;
|
||||
} else if (c.id == 3) {
|
||||
c.m_network = NET_ONION;
|
||||
} else {
|
||||
c.m_network = NET_IPV6;
|
||||
}
|
||||
},
|
||||
/*protected_peer_ids=*/{0, 1, 5, 6},
|
||||
/*unprotected_peer_ids=*/{2, 3, 4, 7},
|
||||
random_context));
|
||||
|
||||
// Combined test: expect having 2 CJDNS, 2 I2P, 4 localhost, and 2 onion
|
||||
// peers out of 16 to protect 1 CJDNS, 1 I2P, 1 localhost, 1 onion (4/16
|
||||
// total), plus 4 others for 8 total, sorted by longest uptime.
|
||||
BOOST_CHECK(IsProtected(
|
||||
16, [](NodeEvictionCandidate& c) {
|
||||
c.nTimeConnected = c.id;
|
||||
c.m_is_local = (c.id > 5);
|
||||
if (c.id == 11 || c.id == 15) {
|
||||
c.m_network = NET_CJDNS;
|
||||
} else if (c.id == 10 || c.id == 14) {
|
||||
c.m_network = NET_I2P;
|
||||
} else if (c.id == 8 || c.id == 9) {
|
||||
c.m_network = NET_ONION;
|
||||
} else {
|
||||
c.m_network = NET_IPV4;
|
||||
}
|
||||
},
|
||||
/*protected_peer_ids=*/{0, 1, 2, 3, 6, 8, 10, 11},
|
||||
/*unprotected_peer_ids=*/{4, 5, 7, 9, 12, 13, 14, 15},
|
||||
random_context));
|
||||
|
||||
// Combined test: expect having 6 CJDNS, 1 I2P, 1 localhost, and 4 onion
|
||||
// peers out of 24 to protect 2 CJDNS, 1 I2P, 1 localhost, and 2 onions (6
|
||||
// total), plus 6 others for 12/24 total, sorted by longest uptime.
|
||||
BOOST_CHECK(IsProtected(
|
||||
24, [](NodeEvictionCandidate& c) {
|
||||
c.nTimeConnected = c.id;
|
||||
c.m_is_local = (c.id == 13);
|
||||
if (c.id > 17) {
|
||||
c.m_network = NET_CJDNS;
|
||||
} else if (c.id == 17) {
|
||||
c.m_network = NET_I2P;
|
||||
} else if (c.id == 12 || c.id == 14 || c.id == 15 || c.id == 16) {
|
||||
c.m_network = NET_ONION;
|
||||
} else {
|
||||
c.m_network = NET_IPV6;
|
||||
}
|
||||
},
|
||||
/*protected_peer_ids=*/{0, 1, 2, 3, 4, 5, 12, 13, 14, 17, 18, 19},
|
||||
/*unprotected_peer_ids=*/{6, 7, 8, 9, 10, 11, 15, 16, 20, 21, 22, 23},
|
||||
random_context));
|
||||
}
|
||||
|
||||
// Returns true if any of the node ids in node_ids are selected for eviction.
|
||||
|
@ -632,26 +632,31 @@ BOOST_AUTO_TEST_CASE(LimitedAndReachable_Network)
|
||||
BOOST_CHECK(IsReachable(NET_IPV6));
|
||||
BOOST_CHECK(IsReachable(NET_ONION));
|
||||
BOOST_CHECK(IsReachable(NET_I2P));
|
||||
BOOST_CHECK(IsReachable(NET_CJDNS));
|
||||
|
||||
SetReachable(NET_IPV4, false);
|
||||
SetReachable(NET_IPV6, false);
|
||||
SetReachable(NET_ONION, false);
|
||||
SetReachable(NET_I2P, false);
|
||||
SetReachable(NET_CJDNS, false);
|
||||
|
||||
BOOST_CHECK(!IsReachable(NET_IPV4));
|
||||
BOOST_CHECK(!IsReachable(NET_IPV6));
|
||||
BOOST_CHECK(!IsReachable(NET_ONION));
|
||||
BOOST_CHECK(!IsReachable(NET_I2P));
|
||||
BOOST_CHECK(!IsReachable(NET_CJDNS));
|
||||
|
||||
SetReachable(NET_IPV4, true);
|
||||
SetReachable(NET_IPV6, true);
|
||||
SetReachable(NET_ONION, true);
|
||||
SetReachable(NET_I2P, true);
|
||||
SetReachable(NET_CJDNS, true);
|
||||
|
||||
BOOST_CHECK(IsReachable(NET_IPV4));
|
||||
BOOST_CHECK(IsReachable(NET_IPV6));
|
||||
BOOST_CHECK(IsReachable(NET_ONION));
|
||||
BOOST_CHECK(IsReachable(NET_I2P));
|
||||
BOOST_CHECK(IsReachable(NET_CJDNS));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(LimitedAndReachable_NetworkCaseUnroutableAndInternal)
|
||||
|
@ -441,11 +441,13 @@ BOOST_AUTO_TEST_CASE(netbase_parsenetwork)
|
||||
BOOST_CHECK_EQUAL(ParseNetwork("ipv6"), NET_IPV6);
|
||||
BOOST_CHECK_EQUAL(ParseNetwork("onion"), NET_ONION);
|
||||
BOOST_CHECK_EQUAL(ParseNetwork("tor"), NET_ONION);
|
||||
BOOST_CHECK_EQUAL(ParseNetwork("cjdns"), NET_CJDNS);
|
||||
|
||||
BOOST_CHECK_EQUAL(ParseNetwork("IPv4"), NET_IPV4);
|
||||
BOOST_CHECK_EQUAL(ParseNetwork("IPv6"), NET_IPV6);
|
||||
BOOST_CHECK_EQUAL(ParseNetwork("ONION"), NET_ONION);
|
||||
BOOST_CHECK_EQUAL(ParseNetwork("TOR"), NET_ONION);
|
||||
BOOST_CHECK_EQUAL(ParseNetwork("CJDNS"), NET_CJDNS);
|
||||
|
||||
BOOST_CHECK_EQUAL(ParseNetwork(":)"), NET_UNROUTABLE);
|
||||
BOOST_CHECK_EQUAL(ParseNetwork("tÖr"), NET_UNROUTABLE);
|
||||
|
@ -374,10 +374,25 @@ void TorController::auth_cb(TorControlConnection& _conn, const TorControlReply&
|
||||
// if -onion isn't set to something else.
|
||||
if (gArgs.GetArg("-onion", "") == "") {
|
||||
CService resolved(LookupNumeric("127.0.0.1", 9050));
|
||||
proxyType addrOnion = proxyType(resolved, true);
|
||||
Proxy addrOnion = Proxy(resolved, true);
|
||||
SetProxy(NET_ONION, addrOnion);
|
||||
|
||||
const auto onlynets = gArgs.GetArgs("-onlynet");
|
||||
|
||||
const bool onion_allowed_by_onlynet{
|
||||
!gArgs.IsArgSet("-onlynet") ||
|
||||
std::any_of(onlynets.begin(), onlynets.end(), [](const auto& n) {
|
||||
return ParseNetwork(n) == NET_ONION;
|
||||
})};
|
||||
|
||||
if (onion_allowed_by_onlynet) {
|
||||
// If NET_ONION is reachable, then the below is a noop.
|
||||
//
|
||||
// If NET_ONION is not reachable, then none of -proxy or -onion was given.
|
||||
// Since we are here, then -torcontrol and -torpassword were given.
|
||||
SetReachable(NET_ONION, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Finally - now create the service
|
||||
if (private_key.empty()) { // No private key, generate one
|
||||
|
@ -12,6 +12,7 @@ Test plan:
|
||||
- `-proxy` (proxy everything)
|
||||
- `-onion` (proxy just onions)
|
||||
- `-proxyrandomize` Circuit randomization
|
||||
- `-cjdnsreachable`
|
||||
- Proxy configurations to test on proxy side,
|
||||
- support no authentication (other proxy)
|
||||
- support no authentication + user/pass authentication (Tor)
|
||||
@ -26,8 +27,16 @@ addnode connect to IPv4
|
||||
addnode connect to IPv6
|
||||
addnode connect to onion
|
||||
addnode connect to generic DNS name
|
||||
addnode connect to a CJDNS address
|
||||
|
||||
- Test getnetworkinfo for each node
|
||||
|
||||
- Test passing invalid -proxy
|
||||
- Test passing invalid -onion
|
||||
- Test passing invalid -i2psam
|
||||
- Test passing -onlynet=onion without -proxy or -onion
|
||||
- Test passing -onlynet=onion with -onion=0 and with -noonion
|
||||
- Test passing unknown -onlynet
|
||||
"""
|
||||
|
||||
import socket
|
||||
@ -50,14 +59,15 @@ NET_IPV4 = "ipv4"
|
||||
NET_IPV6 = "ipv6"
|
||||
NET_ONION = "onion"
|
||||
NET_I2P = "i2p"
|
||||
NET_CJDNS = "cjdns"
|
||||
|
||||
# Networks returned by RPC getnetworkinfo, defined in src/rpc/net.cpp::GetNetworksInfo()
|
||||
NETWORKS = frozenset({NET_IPV4, NET_IPV6, NET_ONION, NET_I2P})
|
||||
NETWORKS = frozenset({NET_IPV4, NET_IPV6, NET_ONION, NET_I2P, NET_CJDNS})
|
||||
|
||||
|
||||
class ProxyTest(BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
self.num_nodes = 4
|
||||
self.num_nodes = 5
|
||||
self.setup_clean_chain = True
|
||||
|
||||
def setup_nodes(self):
|
||||
@ -101,7 +111,9 @@ class ProxyTest(BitcoinTestFramework):
|
||||
['-listen', f'-proxy={self.conf1.addr[0]}:{self.conf1.addr[1]}',f'-onion={self.conf2.addr[0]}:{self.conf2.addr[1]}',
|
||||
f'-i2psam={self.i2p_sam[0]}:{self.i2p_sam[1]}', '-i2pacceptincoming=0', '-proxyrandomize=0'],
|
||||
['-listen', f'-proxy={self.conf2.addr[0]}:{self.conf2.addr[1]}','-proxyrandomize=1'],
|
||||
[]
|
||||
[],
|
||||
['-listen', f'-proxy={self.conf1.addr[0]}:{self.conf1.addr[1]}','-proxyrandomize=1',
|
||||
'-cjdnsreachable']
|
||||
]
|
||||
if self.have_ipv6:
|
||||
args[3] = ['-listen', f'-proxy=[{self.conf3.addr[0]}]:{self.conf3.addr[1]}','-proxyrandomize=0', '-noonion']
|
||||
@ -113,7 +125,7 @@ class ProxyTest(BitcoinTestFramework):
|
||||
if peer["addr"] == addr:
|
||||
assert_equal(peer["network"], network)
|
||||
|
||||
def node_test(self, node, proxies, auth, test_onion=True):
|
||||
def node_test(self, node, *, proxies, auth, test_onion, test_cjdns):
|
||||
rv = []
|
||||
addr = "15.61.23.23:1234"
|
||||
self.log.debug(f"Test: outgoing IPv4 connection through node for address {addr}")
|
||||
@ -161,6 +173,21 @@ class ProxyTest(BitcoinTestFramework):
|
||||
rv.append(cmd)
|
||||
self.network_test(node, addr, network=NET_ONION)
|
||||
|
||||
if test_cjdns:
|
||||
addr = "[fc00:1:2:3:4:5:6:7]:8888"
|
||||
self.log.debug(f"Test: outgoing CJDNS connection through node for address {addr}")
|
||||
node.addnode(addr, "onetry")
|
||||
cmd = proxies[1].queue.get()
|
||||
assert isinstance(cmd, Socks5Command)
|
||||
assert_equal(cmd.atyp, AddressType.DOMAINNAME)
|
||||
assert_equal(cmd.addr, b"fc00:1:2:3:4:5:6:7")
|
||||
assert_equal(cmd.port, 8888)
|
||||
if not auth:
|
||||
assert_equal(cmd.username, None)
|
||||
assert_equal(cmd.password, None)
|
||||
rv.append(cmd)
|
||||
self.network_test(node, addr, network=NET_CJDNS)
|
||||
|
||||
addr = "node.noumenon:8333"
|
||||
self.log.debug(f"Test: outgoing DNS name connection through node for address {addr}")
|
||||
node.addnode(addr, "onetry")
|
||||
@ -179,20 +206,33 @@ class ProxyTest(BitcoinTestFramework):
|
||||
|
||||
def run_test(self):
|
||||
# basic -proxy
|
||||
self.node_test(self.nodes[0], [self.serv1, self.serv1, self.serv1, self.serv1], False)
|
||||
self.node_test(self.nodes[0],
|
||||
proxies=[self.serv1, self.serv1, self.serv1, self.serv1],
|
||||
auth=False, test_onion=True, test_cjdns=False)
|
||||
|
||||
# -proxy plus -onion
|
||||
self.node_test(self.nodes[1], [self.serv1, self.serv1, self.serv2, self.serv1], False)
|
||||
self.node_test(self.nodes[1],
|
||||
proxies=[self.serv1, self.serv1, self.serv2, self.serv1],
|
||||
auth=False, test_onion=True, test_cjdns=False)
|
||||
|
||||
# -proxy plus -onion, -proxyrandomize
|
||||
rv = self.node_test(self.nodes[2], [self.serv2, self.serv2, self.serv2, self.serv2], True)
|
||||
rv = self.node_test(self.nodes[2],
|
||||
proxies=[self.serv2, self.serv2, self.serv2, self.serv2],
|
||||
auth=True, test_onion=True, test_cjdns=False)
|
||||
# Check that credentials as used for -proxyrandomize connections are unique
|
||||
credentials = set((x.username,x.password) for x in rv)
|
||||
assert_equal(len(credentials), len(rv))
|
||||
|
||||
if self.have_ipv6:
|
||||
# proxy on IPv6 localhost
|
||||
self.node_test(self.nodes[3], [self.serv3, self.serv3, self.serv3, self.serv3], False, False)
|
||||
self.node_test(self.nodes[3],
|
||||
proxies=[self.serv3, self.serv3, self.serv3, self.serv3],
|
||||
auth=False, test_onion=False, test_cjdns=False)
|
||||
|
||||
# -proxy=unauth -proxyrandomize=1 -cjdnsreachable
|
||||
self.node_test(self.nodes[4],
|
||||
proxies=[self.serv1, self.serv1, self.serv1, self.serv1],
|
||||
auth=False, test_onion=True, test_cjdns=True)
|
||||
|
||||
def networks_dict(d):
|
||||
r = {}
|
||||
@ -214,6 +254,7 @@ class ProxyTest(BitcoinTestFramework):
|
||||
assert_equal(n0[net]['proxy_randomize_credentials'], expected_randomize)
|
||||
assert_equal(n0['onion']['reachable'], True)
|
||||
assert_equal(n0['i2p']['reachable'], False)
|
||||
assert_equal(n0['cjdns']['reachable'], False)
|
||||
|
||||
n1 = networks_dict(self.nodes[1].getnetworkinfo())
|
||||
assert_equal(NETWORKS, n1.keys())
|
||||
@ -229,30 +270,89 @@ class ProxyTest(BitcoinTestFramework):
|
||||
|
||||
n2 = networks_dict(self.nodes[2].getnetworkinfo())
|
||||
assert_equal(NETWORKS, n2.keys())
|
||||
proxy = f'{self.conf2.addr[0]}:{self.conf2.addr[1]}'
|
||||
for net in NETWORKS:
|
||||
if net == NET_I2P:
|
||||
expected_proxy = ''
|
||||
expected_randomize = False
|
||||
else:
|
||||
expected_proxy = f'{self.conf2.addr[0]}:{self.conf2.addr[1]}'
|
||||
expected_proxy = proxy
|
||||
expected_randomize = True
|
||||
assert_equal(n2[net]['proxy'], expected_proxy)
|
||||
assert_equal(n2[net]['proxy_randomize_credentials'], expected_randomize)
|
||||
assert_equal(n2['onion']['reachable'], True)
|
||||
assert_equal(n2['i2p']['reachable'], False)
|
||||
assert_equal(n2['cjdns']['reachable'], False)
|
||||
|
||||
if self.have_ipv6:
|
||||
n3 = networks_dict(self.nodes[3].getnetworkinfo())
|
||||
assert_equal(NETWORKS, n3.keys())
|
||||
proxy = f'[{self.conf3.addr[0]}]:{self.conf3.addr[1]}'
|
||||
for net in NETWORKS:
|
||||
if net == NET_I2P:
|
||||
expected_proxy = ''
|
||||
else:
|
||||
expected_proxy = f'[{self.conf3.addr[0]}]:{self.conf3.addr[1]}'
|
||||
expected_proxy = '' if net == NET_I2P or net == NET_ONION else proxy
|
||||
assert_equal(n3[net]['proxy'], expected_proxy)
|
||||
assert_equal(n3[net]['proxy_randomize_credentials'], False)
|
||||
assert_equal(n3['onion']['reachable'], False)
|
||||
assert_equal(n3['i2p']['reachable'], False)
|
||||
assert_equal(n3['cjdns']['reachable'], False)
|
||||
|
||||
n4 = networks_dict(self.nodes[4].getnetworkinfo())
|
||||
assert_equal(NETWORKS, n4.keys())
|
||||
for net in NETWORKS:
|
||||
if net == NET_I2P:
|
||||
expected_proxy = ''
|
||||
expected_randomize = False
|
||||
else:
|
||||
expected_proxy = '%s:%i' % (self.conf1.addr)
|
||||
expected_randomize = True
|
||||
assert_equal(n4[net]['proxy'], expected_proxy)
|
||||
assert_equal(n4[net]['proxy_randomize_credentials'], expected_randomize)
|
||||
assert_equal(n4['onion']['reachable'], True)
|
||||
assert_equal(n4['i2p']['reachable'], False)
|
||||
assert_equal(n4['cjdns']['reachable'], True)
|
||||
|
||||
self.stop_node(1)
|
||||
|
||||
self.log.info("Test passing invalid -proxy raises expected init error")
|
||||
self.nodes[1].extra_args = ["-proxy=abc:def"]
|
||||
msg = "Error: Invalid -proxy address or hostname: 'abc:def'"
|
||||
self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
|
||||
|
||||
self.log.info("Test passing invalid -onion raises expected init error")
|
||||
self.nodes[1].extra_args = ["-onion=xyz:abc"]
|
||||
msg = "Error: Invalid -onion address or hostname: 'xyz:abc'"
|
||||
self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
|
||||
|
||||
self.log.info("Test passing invalid -i2psam raises expected init error")
|
||||
self.nodes[1].extra_args = ["-i2psam=def:xyz"]
|
||||
msg = "Error: Invalid -i2psam address or hostname: 'def:xyz'"
|
||||
self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
|
||||
|
||||
self.log.info("Test passing -onlynet=onion with -onion=0/-noonion raises expected init error")
|
||||
msg = (
|
||||
"Error: Outbound connections restricted to Tor (-onlynet=onion) but "
|
||||
"the proxy for reaching the Tor network is explicitly forbidden: -onion=0"
|
||||
)
|
||||
for arg in ["-onion=0", "-noonion"]:
|
||||
self.nodes[1].extra_args = ["-onlynet=onion", arg]
|
||||
self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
|
||||
|
||||
self.log.info("Test passing -onlynet=onion without -proxy, -onion or -listenonion raises expected init error")
|
||||
self.nodes[1].extra_args = ["-onlynet=onion", "-listenonion=0"]
|
||||
msg = (
|
||||
"Error: Outbound connections restricted to Tor (-onlynet=onion) but the proxy for "
|
||||
"reaching the Tor network is not provided: none of -proxy, -onion or -listenonion is given"
|
||||
)
|
||||
self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
|
||||
|
||||
self.log.info("Test passing -onlynet=onion without -proxy or -onion but with -listenonion=1 is ok")
|
||||
self.start_node(1, extra_args=["-onlynet=onion", "-listenonion=1"])
|
||||
self.stop_node(1)
|
||||
|
||||
self.log.info("Test passing unknown network to -onlynet raises expected init error")
|
||||
self.nodes[1].extra_args = ["-onlynet=abc"]
|
||||
msg = "Error: Unknown network specified in -onlynet: 'abc'"
|
||||
self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -141,7 +141,7 @@ class TestBitcoinCli(BitcoinTestFramework):
|
||||
network_info = self.nodes[0].getnetworkinfo()
|
||||
cli_get_info_string = self.nodes[0].cli('-getinfo').send_cli()
|
||||
cli_get_info = cli_get_info_string_to_dict(cli_get_info_string)
|
||||
assert_equal(cli_get_info["Proxies"], "127.0.0.1:9050 (ipv4, ipv6, onion), 127.0.0.1:7656 (i2p)")
|
||||
assert_equal(cli_get_info["Proxies"], "127.0.0.1:9050 (ipv4, ipv6, onion, cjdns), 127.0.0.1:7656 (i2p)")
|
||||
|
||||
if self.is_wallet_compiled():
|
||||
self.log.info("Test -getinfo and dash-cli getwalletinfo return expected wallet info")
|
||||
|
@ -99,7 +99,7 @@ class NetTest(DashTestFramework):
|
||||
assert_net_servicesnames(int(info[0]["services"], 0x10), info[0]["servicesnames"])
|
||||
|
||||
# Check dynamically generated networks list in getpeerinfo help output.
|
||||
assert "(ipv4, ipv6, onion, i2p, not_publicly_routable)" in self.nodes[0].help("getpeerinfo")
|
||||
assert "(ipv4, ipv6, onion, i2p, cjdns, not_publicly_routable)" in self.nodes[0].help("getpeerinfo")
|
||||
# This part is slightly different comparing to the Bitcoin implementation. This is expected because we create connections on network setup a bit differently too.
|
||||
# We also create more connection during the test itself to test mn specific stats
|
||||
assert_equal(peer_info[0][0]['connection_type'], 'inbound')
|
||||
@ -167,7 +167,7 @@ class NetTest(DashTestFramework):
|
||||
assert_net_servicesnames(int(info["localservices"], 0x10), info["localservicesnames"])
|
||||
|
||||
# Check dynamically generated networks list in getnetworkinfo help output.
|
||||
assert "(ipv4, ipv6, onion, i2p)" in self.nodes[0].help("getnetworkinfo")
|
||||
assert "(ipv4, ipv6, onion, i2p, cjdns)" in self.nodes[0].help("getnetworkinfo")
|
||||
|
||||
self.log.info('Test extended connections info')
|
||||
# Connect nodes both ways.
|
||||
@ -252,8 +252,8 @@ class NetTest(DashTestFramework):
|
||||
assert_equal(res[0]["port"], 8333)
|
||||
assert_equal(res[0]["services"], services)
|
||||
|
||||
# Test for the absence of onion and I2P addresses.
|
||||
for network in ["onion", "i2p"]:
|
||||
# Test for the absence of onion, I2P and CJDNS addresses.
|
||||
for network in ["onion", "i2p", "cjdns"]:
|
||||
assert_equal(self.nodes[0].getnodeaddresses(0, network), [])
|
||||
|
||||
# Test invalid arguments.
|
||||
|
Loading…
Reference in New Issue
Block a user