Full CJDNS support #23077

pull vasild wants to merge 13 commits into bitcoin:master from vasild:cjdns changing 11 files +135 −26
  1. vasild commented at 3:18 pm on September 23, 2021: member

    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 -cjdnsreachable:

    • -cjdnsreachable=0: it is assumed a fc00::/8 address is a private IPv6 (1.)
    • -cjdnsreachable=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

    0[fc32:17ea:e415:c3bf:9808:149d:b5a2:c9aa]:8333
    1[fc68:7026:cb27:b014:5910:e609:dcdb:22a2]:8333
    2[fcb3:dc50:e1ae:7998:7dc0:7fa6:4582:8e46]:8333
    3[fcc7:be49:ccd1:dc91:3125:f0da:457d:8ce]:8333
    4[fcf2:d9e:3a25:4eef:8f84:251b:1b4d:c596]:8333
    
  2. laanwj added the label P2P on Sep 23, 2021
  3. jonatack commented at 4:00 pm on September 23, 2021: member

    Concept ACK and building to try it :smiley:

    Edit: debug build is clean and a first read through the commits looks straightforward.

  4. kristapsk commented at 4:02 pm on September 23, 2021: contributor
    Concept ACK
  5. laanwj added the label Feature on Sep 23, 2021
  6. Zero-1729 commented at 4:27 pm on September 23, 2021: contributor
    Concept ACK 🌱
  7. ghost commented at 5:58 pm on September 23, 2021: none

    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).

    Sorry but this doesn’t look good enough to add one more network to Bitcoin Core. We already have 4 options: ipv4, ipv6, Tor, i2p and 14 combinations which can be used in onlynet for outgoing connections.

    Will do more research about CJDNS and compare with other networks before ACKing the concept. Let me know if you know any links.

  8. DrahtBot commented at 10:08 pm on September 23, 2021: member

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #21879 (Wrap accept() and extend usage of Sock by vasild)
    • #21878 (Make all networking code mockable by vasild)
    • #19358 (torcontrol : avoid to set wrong outbound proxy and network settings when creating an inbound onion service. by Saibato)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

  9. amitiuttarwar commented at 10:33 pm on September 23, 2021: contributor

    @vasild

    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.

    Thanks for providing this motivation, it’s helpful to understand the aim of this PR. Could you go a bit further and share your perspective on why you think CJDNS should be a first class citizen network in bitcoin core? Does it provide different features / privacy / etc. from other networks? Or is this a case where you think optionality is good, so supporting more networks is better? Thanks in advance!

  10. sipa commented at 10:41 pm on September 23, 2021: member
    FWIW, BIP155 does already reserve a network ID for CJDNS (that’s not an argument either way of course, but perhaps the BIP’s author have opinions on this too). @laanwj?
  11. ghost commented at 5:04 am on September 24, 2021: none

    I did some research about CJDNS, GNUnet and Yggdrasil.

    Will read more about these networks and also compare with few others in next few days. Shared initial thoughts and things I did here: https://blockchaincommons.github.io/Bitcoin-Camouflage//blog/cjdns/

  12. vasild commented at 1:30 pm on September 24, 2021: member

    @prayank23, @amitiuttarwar,

    Compared to IPv4/6, CJDNS provides e2e encryption and protects nodes from the traditional traffic analysis and filtering. For example, an ISP blocks port 8333 (dumb) or analyses the traffic to/from a given node, regardless of the port (it is easy to detect that it is Bitcoin P2P protocol being talked on a TCP connection, even if the port is not 8333).

    Compared to Tor and I2P, CJDNS provides redundancy. Each of those have their own shades, which may suit different users. For example Tor is popular/widespread but is somewhat centralized, which could lead to problems. I2P connections have source address, but I2P is somewhat slow. CJDNS does not hide the sender and the recipient from intermediate routers, but it is fast. Different things may work for different people. It is good to have options.

    So, why not have support for CJDNS? It must be noted that support for X does not come for free. We have to pay the following prices:

    • Implementation cost
    • Review cost
    • Maintenance cost

    For the implementation cost, notice that CJDNS is already included in BIP155 and that there is already rudimentary support for it in master:

    0$ git grep -i cjdns origin/master |wc -l
    1      49
    

    As a result this PR is relatively small and straight-forward. Review cost should be low. From the application’s point of view, connecting to CJDNS is as easy as connecting to a normal IPv6 address. Bitcoin Core need not implement support for a specific proxy that talks a specific protocol. Tor and I2P require that. We have this maintenance cost for them:

    0$ wc -l src/torcontrol.cpp src/i2p.cpp 
    1     636 src/torcontrol.cpp
    2     418 src/i2p.cpp
    

    Support for CJDNS goes without that, so its maintenance cost is low compared to Tor and I2P.

    Notice also that OpenWRT routers support CJDNS, so from user’s perspective it would be a matter of enabling it on their routers and running Bitcoin Core with -cjdnsreachable.

    In the case of CJDNS, my personal opinion is that the benefits outweigh the cost.

  13. jonatack commented at 2:32 pm on September 24, 2021: member
    Yes, BIP155 and Tor v3 implementation were both fairly deep changes. I2P was also extensive. This change set is relatively tiny, I’ve done a first review pass, and in terms of time it was well under 10% that of any of the BIP155 impl, Tor v3, and I2P for me.
  14. benthecarman commented at 5:45 pm on September 24, 2021: contributor
    Concept ACK, awesome to see this!
  15. dunxen commented at 9:05 pm on September 25, 2021: contributor

    Concept ACK seeing as there is already basic existing support for this in master and noting that this may match some users’ needs of speed while still protecting against traffic analysis.

    Going to build and try this out

  16. vasild commented at 7:27 am on September 27, 2021: member
    A testing/experimental Bitcoin Core node is running (most of the time) at [fcc7:be49:ccd1:dc91:3125:f0da:457d:8ce]:8333.
  17. in src/netaddress.cpp:675 in 7b4005008b outdated
    673@@ -674,7 +674,7 @@ bool CNetAddr::GetInAddr(struct in_addr* pipv4Addr) const
    674  */
    675 bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const
    


    naumenkogs commented at 7:23 am on September 29, 2021:
    In commit 7b4005008bce3b2d77a4a40db7db7f6626170f87, do you want to keep this function name and parameter?

    vasild commented at 1:11 pm on September 30, 2021:
    The function semantics remain unchanged - it is still used to “get struct in6_addr”, so I think it is ok to leave it as is.
  18. in src/init.cpp:1301 in 3064e8b147 outdated
    1258@@ -1258,6 +1259,14 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
    1259         }
    1260     }
    1261 
    1262+    if (!args.IsArgSet("-cjdnsreachable")) {
    1263+        SetReachable(NET_CJDNS, false);
    1264+    }
    1265+    // Now IsReachable(NET_CJDNS) is true if:
    


    naumenkogs commented at 7:27 am on September 29, 2021:
    In commit 3064e8b1474f955c2506711c57dfbf3b7af48686, how about the regular -reachable flag? What’s the interaction here?

    vasild commented at 1:15 pm on September 30, 2021:

    By “regular -reachable flag” you mean -onlynet=cjdns? The interaction is that we can connect to CJDNS if -cjdnsreachable is given and CJDNS is not restricted by -onlynet=:

    0    // 1. -cjdnsreachable is given and
    1    // 2.1. -onlynet is not given or
    2    // 2.2. -onlynet=cjdns is given
    

    naumenkogs commented at 6:59 am on October 1, 2021:
    Dismiss this comment, I was very confused.
  19. in src/net.cpp:250 in ec2dc3915a outdated
    245+    return ret;
    246+}
    247+
    248 // learn a new local address
    249-bool AddLocal(const CService& addr, int nScore)
    250+bool AddLocal(const CService& addr_, int nScore)
    


    naumenkogs commented at 7:43 am on September 29, 2021:

    In commit ec2dc3915a8cb645afceb0a5a80b539a77e77a4b,

    Not sure I like this addr_ approach. Don’t you think a caller should be aware of the transition to CJDNS?


    vasild commented at 1:38 pm on September 30, 2021:

    I think the callers of AddLocal() do not care that a passed fc... address may be interpreted as CJDNS instead of IPv6.

    Actually, I started by doing the flip just before AddLocal() is called, but ended up with duplicated code all over the place in all callers of AddLocal() which prompted me to move that snippet inside AddLocal().

    Ideally a CJDNS object should be returned by LookupIntern() which is the function which creates the CNetAddr objects, so they will not be created as IPv6 and later flipped to CJDNS. However LookupIntern() and WrappedGetAddrInfo() (which it uses) are defined in netbase.cpp and IsReachable() (needed to tell whether IPv6 or CJDNS should be created) is in net.cpp which would create a circular dependency. Hmm… maybe I should move IsReachable() to netbase.cpp?


    naumenkogs commented at 7:13 am on October 1, 2021:

    Actually, I started by doing the flip just before AddLocal() is called, but ended up with duplicated code all over the place in all callers of AddLocal() which prompted me to move that snippet inside AddLocal().

    I think this is a good move, i was just wondering whether it’s ok to do it quietly. Imagine logging something like “finished processing IPv6 addr” after calling AddLocal, while it’s not actually IPv6.

    I think since this is not really the case now, making a comment along AddrLocal might be sufficient to prevent the confusion.

    Hmm… maybe I should move IsReachable() to netbase.cpp?

    Perhaps attempt that in a separate PR then?

  20. naumenkogs commented at 7:54 am on September 29, 2021: member

    ACK baae5be7122056cd78fd66cd2ee4b6bd54cb8620 modulo questions above. I expect it to be implemented very similarly to Tor/I2P which are already manually tested, so it seems we aren’t missing anything.

    I haven’t run the code.

  21. luke-jr commented at 3:43 am on October 3, 2021: member
    How about simply requiring a “%cjdns” suffix on CJDNS addresses?
  22. vasild commented at 8:08 am on October 4, 2021: member

    How about simply requiring a “%cjdns” suffix on CJDNS addresses?

    Internally the addresses are already distinguished in the CNetAddr class by having m_net set to either NET_IPV6 or NET_CJDNS.

    For representation purposes:

    • On output: yes, we can print CJDNS ones with %cjdns suffix
    • On input: we can recognize e.g. fc00::123 as reserved-IPv6 and fc00::123%cjdns as CJDNS, however that would not remove the need to have the config flag -cjdnsreachable because if we stumble on fc00::123%cjdns we need to know whether we can connect to it or not (e.g. whether the OS is configured to connect to the CJDNS network). I think the existence of a config flag -cjdnsreachable makes it unnecessary to require %cjdns suffix. In this sense, having a %cjdns suffix would not make it possible to remove any of the bits of this PR. It would be possible, but would add some complexity on top of this PR.

    Does that answer the question or did I misunderstand it?

  23. laanwj commented at 11:38 am on October 4, 2021: member

    FWIW, BIP155 does already reserve a network ID for CJDNS (that’s not an argument either way of course, but perhaps the BIP’s author have opinions on this too). @laanwj?

    From what I understood back then is that CJDNS is fairly pervasive in mesh networking. You can peer it over arbitrary networks and physical layers but you’ll still have a global address from the viewpoint of software. With no central authority that needs to assign that.

    What makes it different to I2P and Tor is that it is not an anonymity network. It encrypts the payload but does not hide where it comes from. This means it can be very lightweight and low-latency. This is good for initial sync and gossip, maybe not so much for transaction broadcasting. But it’s not worse than clearnet.

    Also unlike those, from the viewpoint of software it’s simply another IPv6 interface. This means it requires only little extra code to support (mostly related to gossip and reachability). No need for proxies or special negotiation (as @vasild already mentions above).

  24. jonatack commented at 3:56 pm on October 4, 2021: member

    Connected to @vasild with his help (thanks!) and the connection has been reliable and fast so far.

    Running a bitcoind cjdns service at [fc32:17ea:e415:c3bf:9808:149d:b5a2:c9aa]:8333 if anyone wants to connect.

  25. dunxen commented at 8:34 pm on October 4, 2021: contributor

    Connected to @vasild with his help (thanks!) and the connection has been reliable and fast so far.

    Running a bitcoind cjdns service at [fc32:17ea:e415:c3bf:9808:149d:b5a2:c9aa]:8333 if anyone wants to connect.

    Ah, I did try to connect to Vasil a few days ago and had trouble. Was there something specific you had to resolve before you could? I’ll try again tomorrow when I can.

  26. jonatack commented at 10:16 am on October 5, 2021: member

    Ah, I did try to connect to Vasil a few days ago and had trouble. Was there something specific you had to resolve before you could? I’ll try again tomorrow when I can.

    Nice! For Debian I followed the instructions starting from https://github.com/cjdelisle/cjdns#1-retrieve-cjdns-from-github. My rookie mistake was skipping over section 2 (https://github.com/cjdelisle/cjdns#2-find-a-friend) and going straight to the sections after that, and so I wasn’t connected to the network. @vasild diagnosed and solved this by suggesting a peer to add to connectTo in the cjdroute.conf file. See also the IRC discussion starting from https://www.erisian.com.au/bitcoin-core-dev/log-2021-10-04.html#l-417 up to line 652 yesterday, and maybe particularly line 469.

  27. jonatack commented at 11:09 am on October 5, 2021: member

    @dunxen Yay, you’re connected in my inbound cjdns peers :ice_cream:

    0        ipv4    ipv6   onion     i2p   cjdns   total   block  manual
    1in         0       0       8       5       1      14
    2out        6       0       5       6       1      18       2       8
    3total      6       0      13      11       2      32
    
  28. dunxen commented at 11:19 am on October 5, 2021: contributor

    See also the IRC discussion starting from https://www.erisian.com.au/bitcoin-core-dev/log-2021-10-04.html#l-417 up to line 652 yesterday, and maybe particularly line 469.

    [fcf2:d9e:3a25:4eef:8f84:251b:1b4d:c596]:8333 for me.

    I actually did have two public peers in connectTo but they might have been offline when I tried so probably couldn’t connect to the network. So I added around 5 more by following those instructions to find ones that were up :)

  29. in src/netbase.cpp:126 in baae5be712 outdated
    122@@ -120,7 +123,7 @@ std::vector<std::string> GetNetworkNames(bool append_unroutable)
    123     std::vector<std::string> names;
    124     for (int n = 0; n < NET_MAX; ++n) {
    125         const enum Network network{static_cast<Network>(n)};
    126-        if (network == NET_UNROUTABLE || network == NET_CJDNS || network == NET_INTERNAL) continue;
    127+        if (network == NET_UNROUTABLE || network == NET_INTERNAL) continue;
    


    jonatack commented at 1:18 pm on October 5, 2021:

    97ee077 could update the getnodeaddresses test in this commit

    0+++ b/test/functional/rpc_net.py
    1@@ -229,7 +229,7 @@ class NetTest(BitcoinTestFramework):
    2         assert_equal(res[0]["services"], P2P_SERVICES)
    3 
    4         # Test for the absence of onion and I2P addresses.
    5-        for network in ["onion", "i2p"]:
    6+        for network in ["onion", "i2p", "cjdns"]:
    

    vasild commented at 4:05 pm on October 6, 2021:
    Done.
  30. in src/init.cpp:441 in baae5be712 outdated
    437@@ -438,6 +438,7 @@ void SetupServerArgs(ArgsManager& argsman)
    438     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);
    439     argsman.AddArg("-i2psam=<ip:port>", "I2P SAM proxy to reach I2P peers and accept I2P connections (default: none)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
    440     argsman.AddArg("-i2pacceptincoming", "If set and -i2psam is also set then incoming I2P connections are accepted via the SAM proxy. If this is not set but -i2psam is set then only outgoing connections will be made to the I2P network. Ignored if -i2psam is not set. Listening for incoming I2P connections is done through the SAM proxy, not by binding to a local address and port (default: 1)", ArgsManager::ALLOW_BOOL, OptionsCategory::CONNECTION);
    441+    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_BOOL, OptionsCategory::CONNECTION);
    


    jonatack commented at 1:20 pm on October 5, 2021:
    3064e8b nit, sort (apart from this line and the i2p config options, they are in alphabetical order)

    vasild commented at 4:06 pm on October 6, 2021:
    Done.
  31. jamesob commented at 1:25 pm on October 5, 2021: member
    Concept ACK; will review this week.
  32. in src/net.cpp:240 in baae5be712 outdated
    234+ * the CJDNS network is reachable (-cjdnsreachable config is set), then change
    235+ * the type from NET_IPV6 to NET_CJDNS.
    236+ * @param[in] service Address to convert.
    237+ * @return either `addr` or `addr` with modified network.
    238+ */
    239+CService MaybeFlipIPv6toCJDNS(const CService& service)
    


    jonatack commented at 2:04 pm on October 5, 2021:

    ec2dc391

    • service isn’t necessarily converted and addr in the documentation doesn’t refer to anything. Maybe:
    0 * [@param](/bitcoin-bitcoin/contributor/param/)[in] service Address to potentially convert.
    1 * [@returns](/bitcoin-bitcoin/contributor/returns/) a copy of `service` either unmodified or changed to CJDNS.
    
    • not sure if the doxygen should be in net.h (in this friend case)

    vasild commented at 4:08 pm on October 6, 2021:
    Took the doc suggestions. Left the comment in net.cpp. This should really be static function in net.cpp (in which case the comment belongs to net.cpp). The only reason it is not is that we need to make it a friend of CService (in netaddress.h). It is not a public/exported function for everybody to use and as such does not have a declaration in net.h.
  33. vasild commented at 2:08 pm on October 5, 2021: member

    … did have two public peers in connectTo but they might have been offline when I tried …

    tools/peerStats helps to see to which nodes you are connected.

    Added the known CJDNS addresses at the bottom of the PR description.

  34. in test/functional/feature_proxy.py:202 in baae5be712 outdated
    199 
    200     def run_test(self):
    201-        # basic -proxy
    202-        self.node_test(self.nodes[0], [self.serv1, self.serv1, self.serv1, self.serv1], False)
    203+        # -proxy=unauth -proxyrandomize=1
    204+        self.node_test(self.nodes[0], [self.serv1, self.serv1, self.serv1, self.serv1],
    


    jonatack commented at 2:18 pm on October 5, 2021:

    2c700460 while converting test_node() to named args, can enforce with * and do it for the proxies arg too

     0@@ -118,7 +118,7 @@ class ProxyTest(BitcoinTestFramework):
     1             if peer["addr"] == addr:
     2                 assert_equal(peer["network"], network)
     3 
     4-    def node_test(self, node, proxies, auth, test_onion, test_cjdns):
     5+    def node_test(self, node, *, proxies, auth, test_onion, test_cjdns):
     6         rv = []
     7         addr = "15.61.23.23:1234"
     8         self.log.debug(f"Test: outgoing IPv4 connection through node for address {addr}")
     9@@ -199,15 +199,15 @@ class ProxyTest(BitcoinTestFramework):
    10 
    11     def run_test(self):
    12         # -proxy=unauth -proxyrandomize=1
    13-        self.node_test(self.nodes[0], [self.serv1, self.serv1, self.serv1, self.serv1],
    14+        self.node_test(self.nodes[0], proxies=[self.serv1, self.serv1, self.serv1, self.serv1],
    15             auth=False, test_onion=True, test_cjdns=False)
    16 
    17         # -proxy=unauth -proxyrandomize=0 -onion=auth_or_unauth
    18-        self.node_test(self.nodes[1], [self.serv1, self.serv1, self.serv2, self.serv1],
    19+        self.node_test(self.nodes[1], proxies=[self.serv1, self.serv1, self.serv2, self.serv1],
    20             auth=False, test_onion=True, test_cjdns=False)
    21 
    22         # -proxy=auth_or_unauth -proxyrandomize=1
    23-        rv = self.node_test(self.nodes[2], [self.serv2, self.serv2, self.serv2, self.serv2],
    24+        rv = self.node_test(self.nodes[2], proxies=[self.serv2, self.serv2, self.serv2, self.serv2],
    25             auth=True, test_onion=True, test_cjdns=False)
    26         # Check that credentials as used for -proxyrandomize connections are unique
    27         credentials = set((x.username,x.password) for x in rv)
    28@@ -215,11 +215,11 @@ class ProxyTest(BitcoinTestFramework):
    29 
    30         if self.have_ipv6:
    31             # -proxy=auth_or_unauth_listening_on_::1 -proxyrandomize=0 -noonion
    32-            self.node_test(self.nodes[3], [self.serv3, self.serv3, self.serv3, self.serv3],
    33+            self.node_test(self.nodes[3], proxies=[self.serv3, self.serv3, self.serv3, self.serv3],
    34                 auth=False, test_onion=False, test_cjdns=False)
    35 
    36         # -proxy=unauth -proxyrandomize=1 -cjdnsreachable
    37-        self.node_test(self.nodes[4], [self.serv1, self.serv1, self.serv1, self.serv1],
    38+        self.node_test(self.nodes[4], proxies=[self.serv1, self.serv1, self.serv1, self.serv1],
    39             auth=False, test_onion=True, test_cjdns=True)
    

    vasild commented at 4:08 pm on October 6, 2021:
    Done.
  35. in test/functional/feature_proxy.py:182 in baae5be712 outdated
    191+            assert_equal(cmd.port, 8888)
    192+            if not auth:
    193+                assert_equal(cmd.username, None)
    194+                assert_equal(cmd.password, None)
    195+            rv.append(cmd)
    196+            self.network_test(node, addr, network=NET_CJDNS)
    


    jonatack commented at 2:26 pm on October 5, 2021:
    d80faa60 nit, this test_cjdns section would be easier to read and review if placed one section earlier, after the test_onion section, where it would share the same indentation as the have_ipv6 and test_onion ones.

    vasild commented at 4:11 pm on October 6, 2021:
    Moved.
  36. in contrib/seeds/generate-seeds.py:83 in baae5be712 outdated
    76@@ -77,7 +77,14 @@ def name_to_bip155(addr):
    77                 sub[x].append(val & 0xff)
    78         nullbytes = 16 - len(sub[0]) - len(sub[1])
    79         assert((x == 0 and nullbytes == 0) or (x == 1 and nullbytes > 0))
    80-        return (BIP155Network.IPV6, bytes(sub[0] + ([0] * nullbytes) + sub[1]))
    81+        addr_bytes = bytes(sub[0] + ([0] * nullbytes) + sub[1])
    82+        if addr_bytes[0] == 0xfc:
    83+            # Assume that seeds with fc00::/8 addresses belong to CJDNS,
    84+            # not to the publicly unroutable "Unique Local Unicast" network
    


    jonatack commented at 2:50 pm on October 5, 2021:

    Maybe mention RPC4193 in this comment.

    I wondered if IsRFC4193() might cause CNetAddr::IsRoutable() and CAddrMan::Add/Add_() to fail for CJDNS addresses, but after some time one of my two CJDNS peers was added to my addrman.

    0$ ./src/bitcoin-cli getnodeaddresses 0 cjdns
    1[
    2  {
    3    "time": 1633441675,
    4    "services": 1033,
    5    "address": "fcf2:d9e:3a25:4eef:8f84:251b:1b4d:c596",
    6    "port": 8333,
    7    "network": "cjdns"
    8  }
    9]
    

    jonatack commented at 3:11 pm on October 5, 2021:

    FWIW the CJDNS peers appear to be providing addresses as logged by CAddrMan:Add():

    0$ grep "addresses from fc" ~/.bitcoin/debug.log
    1...
    22021-10-05T14:33:26Z [msghand] Added 1 addresses from fcf2:d9e:3a25:4eef:8f84:251b:1b4d:c596: 3007 tried, 64742 new
    32021-10-05T14:46:00Z [msghand] Added 308 addresses from fcc7:be49:ccd1:dc91:3125:f0da:457d:8ce: 3007 tried, 64742 new
    

    vasild commented at 4:11 pm on October 6, 2021:

    Mentioned RFC4193.

    Yeah, IsRFC4193() is false for CJDNS addresses.

  37. jonatack commented at 3:05 pm on October 5, 2021: member

    ACK baae5be7122056cd78fd66cd2ee4b6bd54cb8620 rebased to current master, debug built with clang 13 on debian, git cloned and built cjdns per https://github.com/cjdelisle/cjdns#1-retrieve-cjdns-from-github, and have been running with -cjdnsreachable and currently 2 CJDNS peers (1 in, 1 out) with IP/TorV3/I2P open too

     0$ ./src/bitcoin-cli -netinfo 
     1
     2        ipv4    ipv6   onion     i2p   cjdns   total   block  manual
     3in         0       0       9       4       1      14
     4out        6       0       6       5       1      18       2       8
     5total      6       0      15       9       2      32
     6
     7Local addresses
     8abcd:abc:123:abcd:1234:abcd:1234:abcd                              port   8333    score      1
     9abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd.onion     port   8333    score      4
    10abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd.b32.i2p       port      0    score      4
    11fc32:17ea:e415:c3bf:9808:149d:b5a2:c9aa                            port   8333    score      1
    

    Things I would like to test further:

    • launching bitcoind with the new config option passed but cjdns not up seemed to cause bitcoind to hang or take some time to respond again; only tried once so far
    • onlynet=cjdns / onlynet=cjdns onlynet=tor onlynet=i2p
  38. vasild force-pushed on Oct 6, 2021
  39. vasild commented at 4:05 pm on October 6, 2021: member

    baae5be712...a36b806169: rebase and address suggestions

    Invalidates ACKs by @naumenkogs, @jonatack

  40. jonatack commented at 4:40 pm on October 6, 2021: member

    re-ACK a36b806169f1706053800fcecaab9b678258f39e per git range-diff 66d11b1 baae5be a36b806

    Should the cjdns tests in feature_proxy.py be behind the self.have_ipv6 conditional? e.g. netutil.py#test_ipv6_local()

  41. vasild commented at 9:11 am on October 7, 2021: member

    Should the cjdns tests in feature_proxy.py be behind the self.have_ipv6 conditional?

    That’s only required if the Socks5 proxy has IPv6 address (::1). For CJDNS tests, self.serv1 is used which listens at 127.0.0.1.

  42. in src/netaddress.cpp:799 in aa9ca9bf17 outdated
    793@@ -794,8 +794,14 @@ std::vector<unsigned char> CNetAddr::GetGroup(const std::vector<bool> &asmap) co
    794         vchRet.push_back((ipv4 >> 24) & 0xFF);
    795         vchRet.push_back((ipv4 >> 16) & 0xFF);
    796         return vchRet;
    797-    } else if (IsTor() || IsI2P() || IsCJDNS()) {
    798+    } else if (IsTor() || IsI2P()) {
    799         nBits = 4;
    800+    } else if (IsCJDNS()) {
    


    naumenkogs commented at 8:50 am on October 8, 2021:

    Just making your new comment makes sense, everything ok with the endianness here?

    In master, we say this:

    0    /**
    1     * Raw representation of the network address.
    2     * In network byte order (big endian) for IPv4 and IPv6.
    3     */
    4    prevector<ADDR_IPV6_SIZE, uint8_t> m_addr{ADDR_IPV6_SIZE, 0x0};
    

    I remember thinking that all Tor addresses are placed in a limited number of buckets (and that sounded like a good idea because it’s so easy to grind them). I could be making this up though.


    vasild commented at 9:44 am on October 8, 2021:

    everything ok with the endianness here?

    Good question. I think it is:

    0$ gdb --args ./src/test/test_bitcoin --run_test="net_tests/cnetaddr_unserialize_v2"
    1(gdb) b src/test/net_tests.cpp:534
    2(gdb) r
    3(gdb) x/16xb addr.m_addr._union.indirect_contents.indirect
    40x803994ae0:	0xfc	0x00	0x00	0x01	0x00	0x02	0x00	0x03
    50x803994ae8:	0x00	0x04	0x00	0x05	0x00	0x06	0x00	0x07
    6(gdb) p/x addr.m_addr[0]
    7$7 = (unsigned char &) [@0x803994ae0](/bitcoin-bitcoin/contributor/0x803994ae0/): 0xfc
    

    all Tor addresses are placed in a limited number of buckets

    Yes, only the first 4 bits from Tor addresses are used. This PR aims to do the same with CJDNS addresses. #22563 is related.

  43. in src/net.cpp:243 in a36b806169 outdated
    238+ * @return a copy of `service` either unmodified or changed to CJDNS.
    239+ */
    240+CService MaybeFlipIPv6toCJDNS(const CService& service)
    241+{
    242+    CService ret{service};
    243+    if (ret.m_net == NET_IPV6 && ret.m_addr[0] == 0xfc && IsReachable(NET_CJDNS)) {
    


    jamesob commented at 5:32 pm on October 8, 2021:

    18b612149ba044b593087ae6678753e6a82bfa0b

    Cool, so this still allows us to peer with local ipv6 addresses under 0xfc provided we don’t pass -cjdnsreachable.


    vasild commented at 9:33 am on October 13, 2021:

    Yes. Local IPv6 fc00::/8 peers are mutually exclusive with CJDNS at the operating system level.

    Actually you will connect to a local IPv6 fc... address even if you pass -cjdnsreachable and if CJDNS is not set up in the OS. But that would be mis-configuring bitcoin, it will mistakenly think that that is somebody from the CJDNS network.

  44. in src/netaddress.cpp:804 in aa9ca9bf17 outdated
    800+    } else if (IsCJDNS()) {
    801+        // Treat in the same way as Tor and I2P because the address in all of
    802+        // them is "random" bytes (derived from a public key). However in CJDNS
    803+        // the first byte is a constant 0xfc, so the random bytes come after it.
    804+        // Thus skip the constant 8 bits at the start.
    805+        nBits = 12;
    


    jamesob commented at 10:54 pm on October 8, 2021:

    aa9ca9bf1701cf9d1241622ec2ba069c8fc40d53

    Maybe the bit math here is tripping me up, but if we’re using for /32 groups for IPv6 below, why wouldn’t we just discard the constant byte at the head of cjdns addresses (0xfc) and set nBits = 32 - 8 = 24?


    vasild commented at 9:49 am on October 13, 2021:

    The /32 logic for IPv6 is based on the assumption that it is easy to acquire addresses with same prefix. E.g. it is likely that

    0aaaa:aaaa:3:4:5:6:7:8
    1aaaa:aaaa:3:4:5:6:7:9
    2aaaa:aaaa:3:4:5:1:1:1
    

    belong to the same actor, while

    0aaaa:aaaa:3:4:5:6:7:8
    1bbbb:bbbb:3:4:5:6:7:8
    

    are unlikely to belong to the same actor.

    This assumption is not true for any of Tor, I2P or CJDNS because their addresses are just “random” hashes:

    07cgwjuwi5ehvcay4tazy7ya6463bndjk6xzrttw5t3xbpq4p22q6fyid.onion
    17pyrpvqdhmayxggpcyqn5l3m5vqkw3qubnmgwlpya2mdo6x7pih7r7id.onion
    

    This code needs big time refactor because it takes the first 4 bits from Tor addresses and if they are the same assumes it is likely that they belong to the same actor which is not true. Actually the opposite is true - while in IP it is harder to acquire addresses with different prefixes, in Tor it is harder to acquire addresses with the same prefix (brute force is needed for that).

    Anyway, for the purposes of this PR we treat CJDNS the same as Tor and I2P - take the first 4 “random” bits.

  45. jamesob approved
  46. jamesob commented at 11:14 pm on October 8, 2021: member

    ACK a36b806169f1706053800fcecaab9b678258f39e (jamesob/ackr/23077.1.vasild.full_cjdns_support)

    Looks like I code-reviewed an older version of this branch, but I verified that the range-diff is empty (git range-diff master..96083eb8c8 master..HEAD).

    I booted a cjdroute instance (fcb3:dc50:e1ae:7998:7dc0:7fa6:4582:8e46) and started bitcoind with ./src/bitcoind -cjdnsreachable -onlynet=cjdns -debug=net. I had to manually bitcoin-cli addnode ... a few of the IPs listed in the PR description to get P2P traffic going, but once I did that I was getting the usual P2P chatter. Verified the reception of a new block and a bunch of txn data.

    I don’t seem to be connecting to other cjdns-network nodes automatically (seems I need to addnode them each manually), but I’m not sure if that’s part of the expected feature set here, though I thought it was.

    In any case, the complexity of this change is low since it’s essentially just stamping out diffs along the lines of I2P and Tor. Maintenance burden seems negligible and the changes all look pretty well tested. Thanks, @vasild!

     0-----BEGIN PGP SIGNED MESSAGE-----
     1Hash: SHA512
     2
     3ACK a36b806169f1706053800fcecaab9b678258f39e ([`jamesob/ackr/23077.1.vasild.full_cjdns_support`](https://github.com/jamesob/bitcoin/tree/ackr/23077.1.vasild.full_cjdns_support))
     4
     5Looks like I code-reviewed an older version of this branch, but I verified that the range-diff is empty (`git range-diff master..96083eb8c8 master..HEAD`).
     6
     7I booted a cjdnsroute instance (`fcb3:dc50:e1ae:7998:7dc0:7fa6:4582:8e46`) and started bitcoind with `./src/bitcoind -cjdnsreachable -onlynet=cjdns -debug=net`. I had to manually `bitcoin-cli addnode ...` a few of the IPs listed in the PR description to get P2P traffic going, but once I did that I was getting the usual P2P chatter. Verified the reception of a new block and a bunch of txn data.
     8
     9I don't seem to be connecting to other cjdns-network nodes automatically (seems I need to `addnode` them each manually), but I'm not sure if that's part of the expected feature set here, though I thought it was.
    10
    11In any case, the complexity of this change is low since it's essentially just stamping out diffs along the lines of I2P and Tor. Maintenance burden seems negligible and the changes all look pretty well tested. Thanks, [@vasild](/bitcoin-bitcoin/contributor/vasild/)!
    12
    13-----BEGIN PGP SIGNATURE-----
    14
    15iQIzBAEBCgAdFiEEGNRVI1NPYuZCSIrGepNdrbLETwUFAmFg0KYACgkQepNdrbLE
    16TwVL7hAAoT5irn5aFYl3Wl8vi6bT8T+/JK+vTCB2KBR37ZxaM1IlpSyRYwXPm8+3
    17atpfPT1X9erw8Xoin4i9a1qKQu6HLnEE89vgB9/FZ6dnsagd8rGvl7cCoYoY/RzL
    18oj7Md1TeyQTZG4bGiO4fSHD0E9AGMFZkRhHiV7uh0qiHlrOUO1Brusfod1pL1iUO
    19ufYj8Ap9JRNdU0ysQEPZysgV8SZ33bPWbb7mmUTpiP6puA8DqPM2mRyk5pS1N2cP
    20C2p+QTAF5GOlevXrPJ2yO0UwfcuYj1PYZ6zNsjwYIzjzNfedOZY9OPjox8K3Lx5p
    21J5tG7iF3ScvWmMiMFMi+X7kDqzxd5DYR5LlTfsKAdsE7hWgb5ypYj9fcbRjlL6e5
    22jN2fkihRi1kvXRmeM6u09WILuKlx/wl8KW74fQVoRU2gN3Frt9tMthSCdVbKK7KB
    23/fxm2kmIzgt2XKyxodRn8YnZ6s5CqTHPuYHFjyBvgR/rHwjA9hJA1FXx1zJYYF06
    24P/MrfWLdSCwIcGwkE9hWjypdWfxAOMjFec+2w4ArSb0Hh55mt9UiF/sff5nKEF7r
    25od84EdHvS70OQogAcRtF/E+LMHH8eg0fV31WSdxkeMhL7LA51UlzXALsQrT2saoN
    26hhhsabaAlVxA//yOZMSoetowIu4MxYxvRwxacN9BHmJpFXk+3gE=
    27=ZzwN
    28-----END PGP SIGNATURE-----
    
    0Tested on Linux-4.19.0-10-amd64-x86_64-with-glibc2.28
    1
    2Configured with ./configure LDFLAGS=-L/home/james/src/bitcoin/db4/lib/ CPPFLAGS=-I/home/james/src/bitcoin/db4/include/ CXXFLAGS=-fPIE -pipe -O2 -g -Wthread-safety-analysis -Wall -Werror=sign-compare -Wsign-compare -Werror=thread-safety-analysis --enable-wallet --enable-debug --with-daemon --enable-natpmp-default
    3
    4Compiled with /usr/bin/ccache /usr/bin/clang++ -std=c++17 -mavx -mavx2 -fPIE -pipe -O2 -g -Wthread-safety-analysis -Wall -Werror=sign-compare -Wsign-compare -Werror=thread-safety-analysis -O0 -g3 -ftrapv -fdebug-prefix-map=$(abs_srcdir)=.  -Wstack-protector -fstack-protector-all -fcf-protection=full -fstack-clash-protection -msse4 -msha -msse4.1 -msse4.2  i
    5
    6Compiler version: Debian clang version 12.0.1-++20210905123925+fed41342a82f-1~exp1~20210904224639.138
    
  47. cjdelisle commented at 2:09 am on October 13, 2021: none

    I created a fake seed node with the two nodes I found from here which are working: btc-fake.cjdns.fr

     0diff --git a/src/chainparams.cpp b/src/chainparams.cpp
     1index b15574579..4ce0edc7d 100644
     2--- a/src/chainparams.cpp
     3+++ b/src/chainparams.cpp
     4@@ -127,6 +127,7 @@ public:
     5         vSeeds.emplace_back("seed.bitcoin.sprovoost.nl"); // Sjors Provoost
     6         vSeeds.emplace_back("dnsseed.emzy.de"); // Stephan Oeste
     7         vSeeds.emplace_back("seed.bitcoin.wiz.biz"); // Jason Maurice
     8+        vSeeds.emplace_back("btc-fake.cjdns.fr"); // cjd's fake cjdns-only seed for testing                                                                                                                 
     9         base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0);
    10         base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5);                                                                                                                                   
    

    I’m also running [fc68:7026:cb27:b014:5910:e609:dcdb:22a2]:8333 but it is running with -cjdnsreachable -onlynet=cjdns so it is still syncing (headers). But I can confirm the seeding seems to work.

  48. laanwj referenced this in commit ee1294f155 on Oct 21, 2021
  49. sidhujag referenced this in commit b43d231c1d on Oct 21, 2021
  50. DrahtBot added the label Needs rebase on Oct 25, 2021
  51. vasild force-pushed on Oct 27, 2021
  52. vasild commented at 8:05 am on October 27, 2021: member

    a36b806169...4fbff39e8f: rebase due to conflicts

    Invalidates ACKs from @jonatack, @jamesob

    Previously invalidated ACK from @naumenkogs

  53. DrahtBot removed the label Needs rebase on Oct 27, 2021
  54. naumenkogs commented at 8:14 am on October 29, 2021: member
    ACK 4fbff39e8fb0c110025b2c0ee6eb933b6d16182a
  55. dunxen commented at 9:22 pm on October 29, 2021: contributor

    Tested ACK 4fbff39

    Been running this for some time now without any issues.

  56. jonatack commented at 2:48 pm on October 30, 2021: member
    ACK 4fbff39e8fb0c110025b2c0ee6eb933b6d16182a have been testing this off and on since October 4, for this review verified change is rebase-only since my last review, then rebased to latest master, debug build clean, started bitcoind with ip/onion/i2p/cjdns running, connected manually to vasild’s and cjdelisle’s bitcoind cjdns services and seeing nominal operation
  57. jonatack commented at 10:24 pm on November 2, 2021: member

    Rebased this PR just now on latest master and seeing what might be a merge conflict (at first glance possibly from #22766 but haven’t looked further):

    0init.cpp:425:184: error: no member named 'ALLOW_BOOL' in 'ArgsManager'; did you mean 'ALLOW_ANY'?
    1    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_BOOL, OptionsCategory::CONNECTION);
    2                                                                                                                                                                          ~~~~~~~~~~~~~^~~~~~~~~~
    3                                                                                                                                                                                       ALLOW_ANY
    4./util/system.h:166:9: note: 'ALLOW_ANY' declared here
    5        ALLOW_ANY = 0x01,         //!< disable validation
    6        ^
    71 error generated.
    
  58. net: make it possible to connect to CJDNS addresses
    Connecting to CJDNS addresses works without a proxy, just like
    connecting to an IPv6 address. Thus adapt `CService::GetSockAddr()` to
    retrieve the `struct sockaddr*` even for `CService::IsCJDNS()` objects.
    aedd02ef27
  59. net: use -proxy for connecting to the CJDNS network
    If `-proxy` is given, then also use it for connecting to the CJDNS
    network.
    de01e312b3
  60. net: recognize CJDNS from ParseNetwork()
    This allows to use "cjdns" as an argument to the `getnodeaddresses` RPC
    and to the `-onlynet=` parameter.
    78f456c576
  61. net: introduce a new config option to enable CJDNS
    CJDNS is set up in the host OS, outside of the application. When the
    routing is configured properly then connecting to fc00::/8 results in
    connecting to the CJDNS network.
    
    Introduce an option so that Bitcoin Core knows whether this is the case.
    e9d90d3c11
  62. net: don't skip CJDNS from GetNetworksInfo() e6890fcb44
  63. net: recognize CJDNS addresses as such
    In some cases addresses come from an external source as a string or as a
    `struct sockaddr_in6`, without a tag to tell whether it is a private
    IPv6 or a CJDNS address. In those cases interpret the address as a CJDNS
    address instead of an IPv6 address if `-cjdnsreachable` is set and the
    seemingly-IPv6-address belongs to `fc00::/8`. Those external sources are:
    
    * `-externalip=`
    * `-bind=`
    * UPnP
    * `getifaddrs(3)` (called through `-discover`)
    * `addnode`
    * `connect`
    * incoming connections (returned by `accept(2)`)
    6387f397b3
  64. test: remove default argument of feature_proxy.py:node_test()
    The default bool argument makes it harder to read because the last but
    one argument is also bool. Pass all of them as named arguments to
    increase readability.
    
    Another bool argument will be added to indicate whether to test CJDNS.
    
    Co-authored-by: Jon Atack <jon@atack.com>
    508eb258fd
  65. test: extend feature_proxy.py to test CJDNS 9b43b3b257
  66. net: take CJDNS into account in CNetAddr::GetReachabilityFrom()
    This way `GetLocal()` will pick our CJDNS address for a CJDNS peer.
    c2d751abba
  67. net: don't skip CJDNS from GetNetworkNames() d96f8d304c
  68. net: relay CJDNS addresses even if we are not connected to CJDNS
    This will help with propagation, so that multi-homed nodes can learn
    CJDNS addresses outside of the CJDNS network.
    29ff79c0a2
  69. net: take the first 4 random bits from CJDNS addresses in GetGroup()
    CJDNS addresses start with constant 8 bits, so in order to account for
    the first 4 random ones, we must take the first 12. Otherwise the entire
    CJDNS network will belong to one group.
    f9c28330a0
  70. contrib: recognize CJDNS seeds as such
    An IPv6 address from fc00::/8 could be either from the CJDNS network or
    from a private-unroutable-reserved segment of IPv6. A seed node with
    such an address must be from the CJDNS network, otherwise other peers
    will not be able to connect to it.
    420695c193
  71. vasild force-pushed on Nov 3, 2021
  72. vasild commented at 2:10 pm on November 3, 2021: member

    4fbff39e8f...420695c193: rebase due to a silent merge conflict with #22766

    Thanks, @jonatack!

    Invalidates ACKs from @naumenkogs, @dunxen, @jonatack

    Previously invalidated ACK from @jamesob

  73. dunxen commented at 2:28 pm on November 3, 2021: contributor
    ACK 420695c
  74. jonatack commented at 3:17 pm on November 3, 2021: member

    re-ACK 420695c1933e2b9c6e594fcd8885f1c261e435cf per git range-diff 23ae793 4fbff39 420695c

    Have been running this patch with that change since yesterday evening.

  75. laanwj commented at 1:44 pm on November 8, 2021: member
    Code review ACK 420695c1933e2b9c6e594fcd8885f1c261e435cf
  76. laanwj merged this on Nov 8, 2021
  77. laanwj closed this on Nov 8, 2021

  78. vasild deleted the branch on Nov 8, 2021
  79. sidhujag referenced this in commit f6b094b4e5 on Nov 8, 2021
  80. laanwj referenced this in commit caf8b26b52 on Nov 15, 2021
  81. sidhujag referenced this in commit 5371b96f1e on Nov 16, 2021
  82. laanwj referenced this in commit 8b6cd42c62 on Mar 2, 2022
  83. jonatack referenced this in commit 82cebb2531 on Mar 14, 2022
  84. jonatack referenced this in commit a6596c6b48 on Mar 14, 2022
  85. jonatack referenced this in commit 5ca4787405 on Mar 14, 2022
  86. jonatack referenced this in commit 7e41745690 on Mar 17, 2022
  87. jonatack referenced this in commit 437c68ed36 on Mar 21, 2022
  88. jonatack referenced this in commit ed15848475 on Mar 22, 2022
  89. laanwj referenced this in commit 65e9ca2278 on Mar 24, 2022
  90. hebasto referenced this in commit 866b13fa53 on Mar 31, 2022
  91. jonatack referenced this in commit 4690e8af13 on Mar 31, 2022
  92. DrahtBot locked this on Mar 24, 2023

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-07-08 22:13 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me