merge bitcoin#23077: Full CJDNS support

This commit is contained in:
Kittywhiskers Van Gogh 2024-05-27 09:24:31 +00:00
parent 7596a7320a
commit f9d1a9a00d
No known key found for this signature in database
GPG Key ID: 30CD0C065E5C4AAD
11 changed files with 136 additions and 26 deletions

View File

@ -54,7 +54,7 @@ def name_to_bip155(addr):
raise ValueError('Invalid onion %s' % vchAddr) raise ValueError('Invalid onion %s' % vchAddr)
elif '.' in addr: # IPv4 elif '.' in addr: # IPv4
return (BIP155Network.IPV4, bytes((int(x) for x in addr.split('.')))) return (BIP155Network.IPV4, bytes((int(x) for x in addr.split('.'))))
elif ':' in addr: # IPv6 elif ':' in addr: # IPv6 or CJDNS
sub = [[], []] # prefix, suffix sub = [[], []] # prefix, suffix
x = 0 x = 0
addr = addr.split(':') addr = addr.split(':')
@ -70,7 +70,14 @@ def name_to_bip155(addr):
sub[x].append(val & 0xff) sub[x].append(val & 0xff)
nullbytes = 16 - len(sub[0]) - len(sub[1]) nullbytes = 16 - len(sub[0]) - len(sub[1])
assert((x == 0 and nullbytes == 0) or (x == 1 and nullbytes > 0)) 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: else:
raise ValueError('Could not parse address %s' % addr) raise ValueError('Could not parse address %s' % addr)

View File

@ -566,6 +566,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("-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("-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("-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) (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("-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("-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); argsman.AddArg("-dns", strprintf("Allow DNS lookups for -addnode, -seednode and -connect (default: %u)", DEFAULT_NAME_LOOKUP), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
@ -1785,6 +1786,14 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc
} }
} }
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 // Check for host lookup allowed before parsing any network related parameters
fNameLookup = args.GetBoolArg("-dns", DEFAULT_NAME_LOOKUP); fNameLookup = args.GetBoolArg("-dns", DEFAULT_NAME_LOOKUP);
@ -1806,6 +1815,7 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc
SetProxy(NET_IPV4, addrProxy); SetProxy(NET_IPV4, addrProxy);
SetProxy(NET_IPV6, addrProxy); SetProxy(NET_IPV6, addrProxy);
SetProxy(NET_ONION, addrProxy); SetProxy(NET_ONION, addrProxy);
SetProxy(NET_CJDNS, addrProxy);
SetNameProxy(addrProxy); SetNameProxy(addrProxy);
SetReachable(NET_ONION, true); // by default, -proxy sets onion as reachable, unless -noonion later SetReachable(NET_ONION, true); // by default, -proxy sets onion as reachable, unless -noonion later
} }

View File

@ -255,9 +255,27 @@ std::optional<CAddress> GetLocalAddrForPeer(CNode *pnode)
return std::nullopt; 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()) if (!addr.IsRoutable() && Params().RequireRoutableExternalIP())
return false; return false;
@ -454,7 +472,8 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
if (pszDest) { if (pszDest) {
std::vector<CService> resolved; std::vector<CService> resolved;
if (Lookup(pszDest, resolved, default_port, fNameLookup && !HaveNameProxy(), 256) && !resolved.empty()) { 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()) { if (!addrConnect.IsValid()) {
LogPrint(BCLog::NET, "Resolver returned invalid address %s for %s\n", addrConnect.ToString(), pszDest); LogPrint(BCLog::NET, "Resolver returned invalid address %s for %s\n", addrConnect.ToString(), pszDest);
return nullptr; return nullptr;
@ -1210,9 +1229,11 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket, CMasternodeSy
if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) { if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) {
LogPrintf("Warning: Unknown socket family\n"); 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; NetPermissionFlags permissionFlags = NetPermissionFlags::None;
hListenSocket.AddSocketPermissionFlags(permissionFlags); 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)) { if (!(flags & BF_EXPLICIT) && !IsReachable(addr)) {
return false; return false;
} }

View File

@ -676,7 +676,7 @@ bool CNetAddr::GetInAddr(struct in_addr* pipv4Addr) const
*/ */
bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const
{ {
if (!IsIPv6()) { if (!IsIPv6() && !IsCJDNS()) {
return false; return false;
} }
assert(sizeof(*pipv6Addr) == m_addr.size()); assert(sizeof(*pipv6Addr) == m_addr.size());
@ -796,8 +796,14 @@ std::vector<unsigned char> CNetAddr::GetGroup(const std::vector<bool> &asmap) co
vchRet.push_back((ipv4 >> 24) & 0xFF); vchRet.push_back((ipv4 >> 24) & 0xFF);
vchRet.push_back((ipv4 >> 16) & 0xFF); vchRet.push_back((ipv4 >> 16) & 0xFF);
return vchRet; return vchRet;
} else if (IsTor() || IsI2P() || IsCJDNS()) { } else if (IsTor() || IsI2P()) {
nBits = 4; 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()) { } else if (IsHeNet()) {
// for he.net, use /36 groups // for he.net, use /36 groups
nBits = 36; nBits = 36;
@ -894,6 +900,11 @@ int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const
case NET_I2P: return REACH_PRIVATE; case NET_I2P: return REACH_PRIVATE;
default: return REACH_DEFAULT; default: return REACH_DEFAULT;
} }
case NET_CJDNS:
switch (ourNet) {
case NET_CJDNS: return REACH_PRIVATE;
default: return REACH_DEFAULT;
}
case NET_TEREDO: case NET_TEREDO:
switch(ourNet) { switch(ourNet) {
default: return REACH_DEFAULT; default: return REACH_DEFAULT;
@ -995,7 +1006,7 @@ bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const
paddrin->sin_port = htons(port); paddrin->sin_port = htons(port);
return true; return true;
} }
if (IsIPv6()) { if (IsIPv6() || IsCJDNS()) {
if (*addrlen < (socklen_t)sizeof(struct sockaddr_in6)) if (*addrlen < (socklen_t)sizeof(struct sockaddr_in6))
return false; return false;
*addrlen = sizeof(struct sockaddr_in6); *addrlen = sizeof(struct sockaddr_in6);

View File

@ -232,7 +232,7 @@ public:
*/ */
bool IsRelayable() const bool IsRelayable() const
{ {
return IsIPv4() || IsIPv6() || IsTor() || IsI2P(); return IsIPv4() || IsIPv6() || IsTor() || IsI2P() || IsCJDNS();
} }
/** /**
@ -581,6 +581,8 @@ public:
READWRITEAS(CNetAddr, obj); READWRITEAS(CNetAddr, obj);
READWRITE(Using<BigEndianFormatter<2>>(obj.port)); READWRITE(Using<BigEndianFormatter<2>>(obj.port));
} }
friend CService MaybeFlipIPv6toCJDNS(const CService& service);
}; };
bool SanityCheckASMap(const std::vector<bool>& asmap); bool SanityCheckASMap(const std::vector<bool>& asmap);

View File

@ -95,6 +95,9 @@ enum Network ParseNetwork(const std::string& net_in) {
if (net == "i2p") { if (net == "i2p") {
return NET_I2P; return NET_I2P;
} }
if (net == "cjdns") {
return NET_CJDNS;
}
return NET_UNROUTABLE; return NET_UNROUTABLE;
} }
@ -119,7 +122,7 @@ std::vector<std::string> GetNetworkNames(bool append_unroutable)
std::vector<std::string> names; std::vector<std::string> names;
for (int n = 0; n < NET_MAX; ++n) { for (int n = 0; n < NET_MAX; ++n) {
const enum Network network{static_cast<Network>(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)); names.emplace_back(GetNetworkName(network));
} }
if (append_unroutable) { if (append_unroutable) {

View File

@ -585,7 +585,7 @@ static UniValue GetNetworksInfo()
UniValue networks(UniValue::VARR); UniValue networks(UniValue::VARR);
for (int n = 0; n < NET_MAX; ++n) { for (int n = 0; n < NET_MAX; ++n) {
enum Network network = static_cast<enum Network>(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; proxyType proxy;
UniValue obj(UniValue::VOBJ); UniValue obj(UniValue::VOBJ);
GetProxy(network, proxy); GetProxy(network, proxy);

View File

@ -441,11 +441,13 @@ BOOST_AUTO_TEST_CASE(netbase_parsenetwork)
BOOST_CHECK_EQUAL(ParseNetwork("ipv6"), NET_IPV6); BOOST_CHECK_EQUAL(ParseNetwork("ipv6"), NET_IPV6);
BOOST_CHECK_EQUAL(ParseNetwork("onion"), NET_ONION); BOOST_CHECK_EQUAL(ParseNetwork("onion"), NET_ONION);
BOOST_CHECK_EQUAL(ParseNetwork("tor"), 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("IPv4"), NET_IPV4);
BOOST_CHECK_EQUAL(ParseNetwork("IPv6"), NET_IPV6); BOOST_CHECK_EQUAL(ParseNetwork("IPv6"), NET_IPV6);
BOOST_CHECK_EQUAL(ParseNetwork("ONION"), NET_ONION); BOOST_CHECK_EQUAL(ParseNetwork("ONION"), NET_ONION);
BOOST_CHECK_EQUAL(ParseNetwork("TOR"), 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(":)"), NET_UNROUTABLE);
BOOST_CHECK_EQUAL(ParseNetwork("tÖr"), NET_UNROUTABLE); BOOST_CHECK_EQUAL(ParseNetwork("tÖr"), NET_UNROUTABLE);

View File

@ -12,6 +12,7 @@ Test plan:
- `-proxy` (proxy everything) - `-proxy` (proxy everything)
- `-onion` (proxy just onions) - `-onion` (proxy just onions)
- `-proxyrandomize` Circuit randomization - `-proxyrandomize` Circuit randomization
- `-cjdnsreachable`
- Proxy configurations to test on proxy side, - Proxy configurations to test on proxy side,
- support no authentication (other proxy) - support no authentication (other proxy)
- support no authentication + user/pass authentication (Tor) - support no authentication + user/pass authentication (Tor)
@ -26,6 +27,7 @@ addnode connect to IPv4
addnode connect to IPv6 addnode connect to IPv6
addnode connect to onion addnode connect to onion
addnode connect to generic DNS name addnode connect to generic DNS name
addnode connect to a CJDNS address
- Test getnetworkinfo for each node - Test getnetworkinfo for each node
""" """
@ -50,14 +52,15 @@ NET_IPV4 = "ipv4"
NET_IPV6 = "ipv6" NET_IPV6 = "ipv6"
NET_ONION = "onion" NET_ONION = "onion"
NET_I2P = "i2p" NET_I2P = "i2p"
NET_CJDNS = "cjdns"
# Networks returned by RPC getnetworkinfo, defined in src/rpc/net.cpp::GetNetworksInfo() # 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): class ProxyTest(BitcoinTestFramework):
def set_test_params(self): def set_test_params(self):
self.num_nodes = 4 self.num_nodes = 5
self.setup_clean_chain = True self.setup_clean_chain = True
def setup_nodes(self): 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]}', ['-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'], 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.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: if self.have_ipv6:
args[3] = ['-listen', f'-proxy=[{self.conf3.addr[0]}]:{self.conf3.addr[1]}','-proxyrandomize=0', '-noonion'] 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: if peer["addr"] == addr:
assert_equal(peer["network"], network) 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 = [] rv = []
addr = "15.61.23.23:1234" addr = "15.61.23.23:1234"
self.log.debug(f"Test: outgoing IPv4 connection through node for address {addr}") self.log.debug(f"Test: outgoing IPv4 connection through node for address {addr}")
@ -161,6 +166,21 @@ class ProxyTest(BitcoinTestFramework):
rv.append(cmd) rv.append(cmd)
self.network_test(node, addr, network=NET_ONION) 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" addr = "node.noumenon:8333"
self.log.debug(f"Test: outgoing DNS name connection through node for address {addr}") self.log.debug(f"Test: outgoing DNS name connection through node for address {addr}")
node.addnode(addr, "onetry") node.addnode(addr, "onetry")
@ -179,20 +199,33 @@ class ProxyTest(BitcoinTestFramework):
def run_test(self): def run_test(self):
# basic -proxy # 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 # -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 # -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 # Check that credentials as used for -proxyrandomize connections are unique
credentials = set((x.username,x.password) for x in rv) credentials = set((x.username,x.password) for x in rv)
assert_equal(len(credentials), len(rv)) assert_equal(len(credentials), len(rv))
if self.have_ipv6: if self.have_ipv6:
# proxy on IPv6 localhost # 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): def networks_dict(d):
r = {} r = {}
@ -214,6 +247,7 @@ class ProxyTest(BitcoinTestFramework):
assert_equal(n0[net]['proxy_randomize_credentials'], expected_randomize) assert_equal(n0[net]['proxy_randomize_credentials'], expected_randomize)
assert_equal(n0['onion']['reachable'], True) assert_equal(n0['onion']['reachable'], True)
assert_equal(n0['i2p']['reachable'], False) assert_equal(n0['i2p']['reachable'], False)
assert_equal(n0['cjdns']['reachable'], False)
n1 = networks_dict(self.nodes[1].getnetworkinfo()) n1 = networks_dict(self.nodes[1].getnetworkinfo())
assert_equal(NETWORKS, n1.keys()) assert_equal(NETWORKS, n1.keys())
@ -240,6 +274,7 @@ class ProxyTest(BitcoinTestFramework):
assert_equal(n2[net]['proxy_randomize_credentials'], expected_randomize) assert_equal(n2[net]['proxy_randomize_credentials'], expected_randomize)
assert_equal(n2['onion']['reachable'], True) assert_equal(n2['onion']['reachable'], True)
assert_equal(n2['i2p']['reachable'], False) assert_equal(n2['i2p']['reachable'], False)
assert_equal(n2['cjdns']['reachable'], False)
if self.have_ipv6: if self.have_ipv6:
n3 = networks_dict(self.nodes[3].getnetworkinfo()) 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[net]['proxy_randomize_credentials'], False)
assert_equal(n3['onion']['reachable'], False) assert_equal(n3['onion']['reachable'], False)
assert_equal(n3['i2p']['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__': if __name__ == '__main__':

View File

@ -141,7 +141,7 @@ class TestBitcoinCli(BitcoinTestFramework):
network_info = self.nodes[0].getnetworkinfo() network_info = self.nodes[0].getnetworkinfo()
cli_get_info_string = self.nodes[0].cli('-getinfo').send_cli() cli_get_info_string = self.nodes[0].cli('-getinfo').send_cli()
cli_get_info = cli_get_info_string_to_dict(cli_get_info_string) 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(): if self.is_wallet_compiled():
self.log.info("Test -getinfo and dash-cli getwalletinfo return expected wallet info") self.log.info("Test -getinfo and dash-cli getwalletinfo return expected wallet info")

View File

@ -99,7 +99,7 @@ class NetTest(DashTestFramework):
assert_net_servicesnames(int(info[0]["services"], 0x10), info[0]["servicesnames"]) assert_net_servicesnames(int(info[0]["services"], 0x10), info[0]["servicesnames"])
# Check dynamically generated networks list in getpeerinfo help output. # 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. # 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 # We also create more connection during the test itself to test mn specific stats
assert_equal(peer_info[0][0]['connection_type'], 'inbound') 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"]) assert_net_servicesnames(int(info["localservices"], 0x10), info["localservicesnames"])
# Check dynamically generated networks list in getnetworkinfo help output. # 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') self.log.info('Test extended connections info')
# Connect nodes both ways. # Connect nodes both ways.
@ -252,8 +252,8 @@ class NetTest(DashTestFramework):
assert_equal(res[0]["port"], 8333) assert_equal(res[0]["port"], 8333)
assert_equal(res[0]["services"], services) assert_equal(res[0]["services"], services)
# Test for the absence of onion and I2P addresses. # Test for the absence of onion, I2P and CJDNS addresses.
for network in ["onion", "i2p"]: for network in ["onion", "i2p", "cjdns"]:
assert_equal(self.nodes[0].getnodeaddresses(0, network), []) assert_equal(self.nodes[0].getnodeaddresses(0, network), [])
# Test invalid arguments. # Test invalid arguments.