aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorW. J. van der Laan <laanwj@protonmail.com>2021-11-08 14:29:56 +0100
committerW. J. van der Laan <laanwj@protonmail.com>2021-11-08 14:44:37 +0100
commit8346004ac8e7504c085992836bb5221c2d0da9a8 (patch)
tree937c5faf18bf959f4d8763d96dd473e34858d1ed
parentaecc08f62eab8f4202f8730890846e5669453468 (diff)
parent420695c1933e2b9c6e594fcd8885f1c261e435cf (diff)
Merge bitcoin/bitcoin#23077: Full CJDNS support
420695c1933e2b9c6e594fcd8885f1c261e435cf contrib: recognize CJDNS seeds as such (Vasil Dimov) f9c28330a0e77ed077f342e4669e855b3e6b20a1 net: take the first 4 random bits from CJDNS addresses in GetGroup() (Vasil Dimov) 29ff79c0a2a95abf50b78dd2be6ead2abeeaec9f net: relay CJDNS addresses even if we are not connected to CJDNS (Vasil Dimov) d96f8d304c872b21070245c1b6aacc8b1f5da697 net: don't skip CJDNS from GetNetworkNames() (Vasil Dimov) c2d751abbae3811adaf856b1dd1b71b33e54d315 net: take CJDNS into account in CNetAddr::GetReachabilityFrom() (Vasil Dimov) 9b43b3b257a00f777538fcc6e2550702055a1488 test: extend feature_proxy.py to test CJDNS (Vasil Dimov) 508eb258fd569cabda6fe15699f911fd627e0c56 test: remove default argument of feature_proxy.py:node_test() (Vasil Dimov) 6387f397b323b0fb4ca303fe418550f5465147c6 net: recognize CJDNS addresses as such (Vasil Dimov) e6890fcb440245c9a24ded0b7af46267453433f1 net: don't skip CJDNS from GetNetworksInfo() (Vasil Dimov) e9d90d3c11cee8ea70056f69afaa548cee898f40 net: introduce a new config option to enable CJDNS (Vasil Dimov) 78f456c57677e6a3a839426e211078ddf0b3e194 net: recognize CJDNS from ParseNetwork() (Vasil Dimov) de01e312b333b65b09c8dc72f0cea6295ab8e43f net: use -proxy for connecting to the CJDNS network (Vasil Dimov) aedd02ef2750329019d5698b14b17d67c5a563ad net: make it possible to connect to CJDNS addresses (Vasil Dimov) Pull request description: CJDNS overview ===== 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 applications, similarly to VPN (either in the host/OS or on the network router). Motivation ===== Even without this PR it is possible to connect two Bitcoin Core nodes through CJDNS manually by using e.g. `-addnode` in environments where CJDNS is set up. However, this PR is necessary for address relay to work properly and automatic connections to be made to CJDNS peers. I.e. to make CJDNS a first class citizen network like IPv4, IPv6, Tor and I2P. Considerations ===== An address from the `fc00::/8` network, could mean two things: 1. Part of a local network, as defined in RFC 4193. Like `10.0.0.0/8`. Bitcoin Core could be running on a machine with such address and have peers with those (e.g. in a local network), but those addresses are not relayed to other peers because they are not globally routable on the internet. 2. Part of the CJDNS network. This is like Tor or I2P - if we have connectivity to that network then we could reach such peers and we do relay them to other peers. So, Bitcoin Core needs to be able to tell which one is it when it encounters a bare `fc00::/8` address, e.g. from `-externalip=` or by looking up the machine's own addresses. Thus a new config option is introduced `-cjdnsreacable`: * `-cjdnsreacable=0`: it is assumed a `fc00::/8` address is a private IPv6 (1.) * `-cjdnsreacable=1`: it is assumed a `fc00::/8` address is a CJDNS one (2.) After setting up CJDNS outside of Bitcoin Core, a node operator only needs to enable this option. Addresses from P2P relay/gossip don't need that because they are properly tagged as IPv6 or as CJDNS. For testing ===== ``` [fc32:17ea:e415:c3bf:9808:149d:b5a2:c9aa]:8333 [fc68:7026:cb27:b014:5910:e609:dcdb:22a2]:8333 [fcb3:dc50:e1ae:7998:7dc0:7fa6:4582:8e46]:8333 [fcc7:be49:ccd1:dc91:3125:f0da:457d:8ce]:8333 [fcf2:d9e:3a25:4eef:8f84:251b:1b4d:c596]:8333 ``` ACKs for top commit: dunxen: ACK 420695c jonatack: re-ACK 420695c1933e2b9c6e594fcd8885f1c261e435cf per `git range-diff 23ae793 4fbff39 420695c` laanwj: Code review ACK 420695c1933e2b9c6e594fcd8885f1c261e435cf Tree-SHA512: 21559886271aa84671d52b120fa3fa5a50fdcf0fcb26e5b32049c56fab0d606438d19dd366a9c8ce612d3894237ae6d552ead3338b326487e3534399b88a317a
-rwxr-xr-xcontrib/seeds/generate-seeds.py11
-rw-r--r--src/init.cpp10
-rw-r--r--src/net.cpp32
-rw-r--r--src/netaddress.cpp19
-rw-r--r--src/netaddress.h3
-rw-r--r--src/netbase.cpp5
-rw-r--r--src/rpc/net.cpp2
-rw-r--r--src/test/netbase_tests.cpp2
-rwxr-xr-xtest/functional/feature_proxy.py67
-rwxr-xr-xtest/functional/interface_bitcoin_cli.py2
-rwxr-xr-xtest/functional/rpc_net.py8
11 files changed, 135 insertions, 26 deletions
diff --git a/contrib/seeds/generate-seeds.py b/contrib/seeds/generate-seeds.py
index dbecba7d1d..44345e3987 100755
--- a/contrib/seeds/generate-seeds.py
+++ b/contrib/seeds/generate-seeds.py
@@ -61,7 +61,7 @@ def name_to_bip155(addr):
raise ValueError(f'Invalid I2P {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(':')
@@ -77,7 +77,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)
diff --git a/src/init.cpp b/src/init.cpp
index e554a18fbf..b0335183d6 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -422,6 +422,7 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-asmap=<file>", strprintf("Specify asn mapping used for bucketing of the peers (default: %s). Relative paths will be prefixed by the net-specific datadir location.", DEFAULT_ASMAP_FILENAME), 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, signet: 127.0.0.1:%u=onion, regtest: 127.0.0.1:%u=onion)", defaultBaseParams->OnionServiceTargetPort(), testnetBaseParams->OnionServiceTargetPort(), signetBaseParams->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) (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);
@@ -1294,6 +1295,14 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
}
}
+ 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);
@@ -1315,6 +1324,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
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
}
diff --git a/src/net.cpp b/src/net.cpp
index 8cf59f0b0d..82e55d4189 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -230,9 +230,27 @@ std::optional<CAddress> GetLocalAddrForPeer(CNode *pnode)
return std::nullopt;
}
+/**
+ * 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)
+bool AddLocal(const CService& addr_, int nScore)
{
+ CService addr{MaybeFlipIPv6toCJDNS(addr_)};
+
if (!addr.IsRoutable())
return false;
@@ -409,7 +427,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;
@@ -1092,9 +1111,11 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
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);
@@ -2460,7 +2481,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;
}
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index f9fff5a6d5..7f1dd698b0 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -663,7 +663,7 @@ bool CNetAddr::GetInAddr(struct in_addr* pipv4Addr) const
}
/**
- * Try to get our IPv6 address.
+ * Try to get our IPv6 (or CJDNS) address.
*
* @param[out] pipv6Addr The in6_addr struct to which to copy.
*
@@ -674,7 +674,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());
@@ -794,8 +794,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;
@@ -892,6 +898,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;
@@ -993,7 +1004,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);
diff --git a/src/netaddress.h b/src/netaddress.h
index 57eb8bc72f..b0b1c5ca9e 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -224,7 +224,7 @@ public:
*/
bool IsRelayable() const
{
- return IsIPv4() || IsIPv6() || IsTor() || IsI2P();
+ return IsIPv4() || IsIPv6() || IsTor() || IsI2P() || IsCJDNS();
}
/**
@@ -550,6 +550,7 @@ public:
}
friend class CServiceHash;
+ friend CService MaybeFlipIPv6toCJDNS(const CService& service);
};
class CServiceHash
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 64d17189a6..6191f25cd9 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -96,6 +96,9 @@ enum Network ParseNetwork(const std::string& net_in) {
if (net == "i2p") {
return NET_I2P;
}
+ if (net == "cjdns") {
+ return NET_CJDNS;
+ }
return NET_UNROUTABLE;
}
@@ -120,7 +123,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) {
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index a9bee33c5d..e33f1ce4a3 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -566,7 +566,7 @@ 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;
+ if (network == NET_UNROUTABLE || network == NET_INTERNAL) continue;
proxyType proxy;
UniValue obj(UniValue::VOBJ);
GetProxy(network, proxy);
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index 687d2f6747..b6d7496cc7 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -339,11 +339,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);
diff --git a/test/functional/feature_proxy.py b/test/functional/feature_proxy.py
index 2fb5e328f5..70b9e019c1 100755
--- a/test/functional/feature_proxy.py
+++ b/test/functional/feature_proxy.py
@@ -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,6 +27,7 @@ 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
"""
@@ -50,14 +52,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 +104,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 +118,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 +166,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 +199,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 +247,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())
@@ -240,6 +274,7 @@ class ProxyTest(BitcoinTestFramework):
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())
@@ -253,6 +288,22 @@ class ProxyTest(BitcoinTestFramework):
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)
if __name__ == '__main__':
diff --git a/test/functional/interface_bitcoin_cli.py b/test/functional/interface_bitcoin_cli.py
index c28186cde7..ae665958b9 100755
--- a/test/functional/interface_bitcoin_cli.py
+++ b/test/functional/interface_bitcoin_cli.py
@@ -136,7 +136,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 bitcoin-cli getwalletinfo return expected wallet info")
diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py
index 0f3bbce54c..0857f4e0ca 100755
--- a/test/functional/rpc_net.py
+++ b/test/functional/rpc_net.py
@@ -106,7 +106,7 @@ class NetTest(BitcoinTestFramework):
assert_equal(peer_info[1][1]['connection_type'], 'inbound')
# 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")
def test_getnettotals(self):
self.log.info("Test getnettotals")
@@ -157,7 +157,7 @@ class NetTest(BitcoinTestFramework):
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")
def test_getaddednodeinfo(self):
self.log.info("Test getaddednodeinfo")
@@ -228,8 +228,8 @@ class NetTest(BitcoinTestFramework):
assert_equal(res[0]["port"], 8333)
assert_equal(res[0]["services"], P2P_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.