Add I2P support using statically configured destinations #20254

pull vasild wants to merge 5 commits into bitcoin:master from vasild:i2p_static changing 8 files +146 −26
  1. vasild commented at 12:02 pm on October 27, 2020: member

    This PR is mostly for experiments, testing and discussion. It works but see below.

    Add I2P support:

    • Outgoing connections to I2P destinations use the I2P socks5 proxy i2pd, i2p from the newly added option -i2pproxy=addr:port.
    • Incoming connections from I2P (listen) use statically configured destinations i2pd, i2p, similarly to statically configured Tor hidden services where the I2P/Tor daemon redirects incoming connections to an application listening on a normal TCP port. The user has to configure the I2P/Tor daemon separately from bitcoind.

    What’s missing:

    • -onlynet=i2p
    • -bind=127.0.0.1:8335=i2p in order to distinguish incoming I2P from incoming clearnet connections

    It is possible to accept incoming connections using the SAM I2P protocol. This would make it possible to configure the destination (hidden service) automatically (so the user does not have to extra-configure the I2P daemon). It would also resolve the problem with distinguishing incoming I2P connections. I am looking into doing that.

    If that is done, it will supersede this PR because both outgoing and incoming connections would be made via SAM. Thus this PR is a draft.


    A bitcoin node is running at yfsvsy467mt5xafaq7zaukkjyzehvmew445yaaejvrwpk53acejq.b32.i2p:31872.

  2. util: support DecodeBase32() without padding
    I2P addresses are Base32 encoded but have the padding `=` omitted.
    Extend `DecodeBase32()` to support that.
    151786fb4b
  3. init: add config option to specify I2P proxy
    Add a new config option so that users can specify a dedicated SOCKS5
    proxy for reaching I2P peers.
    
    I2P is a closed network (almost). The I2P proxy cannot be used to reach
    non-I2P peers and the other proxies (the generic one and the Tor one)
    cannot be used to reach I2P peers. Thus the new option is unrelated to
    the other options: does not default to `-proxy` and `-proxy` is not used
    to reach I2P peers.
    
    When the new option is set the I2P network will be set as reachable,
    thus making the node relay I2P addresses to its peers (see
    `RelayAddress()`).
    8f55c06127
  4. net: extend CNetAddr::SetSpecial() to support I2P
    Recognize also I2P addresses in the form `base32encodedpublickey.b32.i2p`
    from `CNetAddr::SetSpecial()`.
    
    This makes `Lookup()` support them, which in turn makes it possible to
    manually connect to an I2P node by using
    `-i2pproxy=i2p_proxy:port -addnode=i2p_address.b32.i2p:port`
    7cbc804402
  5. net: extend GetNetworkName() to recognize I2P
    With this change the output of `getpeerinfo` and `getnetworkinfo`
    contains proper `i2p` instead of an empty string:
    
    ```
    bitcoin-cli getpeerinfo 2>&1 |jq '.[].network'
    bitcoin-cli getnetworkinfo 2>&1 |jq '.networks[].name'
    ```
    ba87ca49cf
  6. test: extend feature_proxy.py to test -i2pproxy 8b4a3714b9
  7. fanquake added the label P2P on Oct 27, 2020
  8. DrahtBot commented at 12:26 pm on October 27, 2020: 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:

    • #20120 (net, rpc, test, bugfix: update GetNetworkName, GetNetworksInfo, regression tests by jonatack)
    • #18766 (Disable fee estimation in blocksonly mode (by removing the fee estimates global) by darosior)

    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. Saibato commented at 2:15 pm on October 27, 2020: contributor
    ̶p̶l̶s̶ ̶n̶o̶t̶e̶ ̶t̶h̶e̶ ̶i̶2̶p̶ ̶p̶r̶o̶x̶y̶ ̶t̶a̶k̶e̶s̶ ̶a̶d̶d̶r̶e̶s̶s̶e̶s̶ ̶i̶n̶ ̶t̶h̶e̶ ̶f̶o̶r̶m̶ ̶y̶f̶s̶v̶s̶y̶4̶6̶7̶m̶t̶5̶x̶a̶f̶a̶q̶7̶z̶a̶u̶k̶k̶j̶y̶z̶e̶h̶v̶m̶e̶w̶4̶4̶5̶y̶a̶a̶e̶j̶v̶r̶w̶p̶k̶5̶3̶a̶c̶e̶j̶q̶.̶i̶2̶p̶ ̶w̶i̶t̶h̶o̶u̶t̶ ̶.̶b̶3̶2̶.̶ ̶A̶F̶A̶I̶K̶ @vasild is ur node up? I was unable to reach from remote or is it by now just local? And by what directory is it published, AFAIK one has to import that directory and address mappings before u can use an address.
  10. vasild commented at 2:39 pm on October 27, 2020: member

    Yes, it is up. From another computer:

    02020-10-27T14:31:09Z New outbound peer connected: version: 70015, blocks=654455, peer=0, peeraddr=yfsvsy467mt5xafaq7zaukkjyzehvmew445yaaejvrwpk53acejq.b32.i2p:31872 (full-relay)
    

    The .b32 must be present. See “B32” in https://i2pplus.com/glossary/. The port seems to be irrelevant. I guess we can skip it altogether.

  11. Saibato commented at 2:51 pm on October 27, 2020: contributor

    Yes, it is up. From another computer:

    thx, maybe i must update my version i use i2pd 2.29.0 ?

    ediit@saibato @vasild Was able to connect :+1: I had forgot to create a fixed i2p client tunnel in i2pd for port 31872.

    concept tACK

    cmd line -connect=yfsvsy467mt5xafaq7zaukkjyzehvmew445yaaejvrwpk53acejq.b32.i2p:31872 then worked.

  12. vasild commented at 5:37 pm on October 27, 2020: member

    Was able to connect

    Excellent!

    However I got:

    0pid 82450 (i2pd), jid 0, uid 255: exited on signal 10
    1pid 19775 (i2pd), jid 0, uid 255: exited on signal 6
    2pid 19909 (i2pd), jid 0, uid 255: exited on signal 6
    3pid 20207 (i2pd), jid 0, uid 255: exited on signal 6
    

    I stopped it until I figure out what’s going on.

  13. Saibato commented at 5:53 pm on October 27, 2020: contributor

    I stopped it until I figure out what’s going on.

    tyi, while testing i also direct connected with netcat and connect-proxy without the bitcoin client and hammered on my keyboard, happy fuzzing! Maybe something @practicalswift might want to look in?

  14. jonatack commented at 9:55 pm on November 3, 2020: member

    @vasild Yay! My node is connected to your I2P peer and you even sent me a block.

    If you pull the last commit of https://github.com/jonatack/bitcoin/commits/netinfo-add-i2p into this draft PR, -netinfo will display I2P peers.

    0Peer connections sorted by direction and min ping
    1<-> relay   net  mping   ping send recv  txn  blk  age  asmap id address                                                        version
    2out  full   i2p   1375   1375    1    3    0    1    6        44 yfsvsy467mt5xafaq7zaukkjyzehvmew445yaaejvrwpk53acejq.b32.i2p   70015/Satoshi:0.20.1/
    3                    ms     ms  sec  sec  min  min  min
    4
    5        ipv4    ipv6   onion     i2p   total  block-relay
    6in         0       0       0       0       0       0
    7out        6       0      12       1      19       2
    8total      6       0      12       1      19       2
    
  15. in src/init.cpp:460 in 8b4a3714b9
    456@@ -457,12 +457,13 @@ void SetupServerArgs(NodeContext& node)
    457     argsman.AddArg("-maxtimeadjustment", strprintf("Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)", DEFAULT_MAX_TIME_ADJUSTMENT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
    458     argsman.AddArg("-maxuploadtarget=<n>", strprintf("Tries to keep outbound traffic under the given target (in MiB per 24h). Limit does not apply to peers with 'download' permission. 0 = no limit (default: %d)", DEFAULT_MAX_UPLOAD_TARGET), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
    459     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);
    460+    argsman.AddArg("-i2pproxy=<ip:port>", "SOCKS5 proxy to reach I2P peers (default: none, I2P peers are not reachable)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
    


    luke-jr commented at 2:51 pm on November 13, 2020:
    I wonder if -proxy=<ip:port>=i2p would make more sense

    vasild commented at 3:15 pm on November 13, 2020:
    Hmm, maybe yes. Anyway, I am working on a support for the I2P SAM protocol which would be used to accept incoming connections - it allows us to know that it is an I2P incoming connection and also to know the peer’s I2P address. That will be -i2psam=<addr:port>. Once we have that we can use it also for making outgoing connections, so -i2pproxy= will not be needed.
  16. in src/util/strencodings.h:56 in 8b4a3714b9
    49@@ -50,8 +50,26 @@ std::vector<unsigned char> DecodeBase64(const char* p, bool* pf_invalid = nullpt
    50 std::string DecodeBase64(const std::string& str, bool* pf_invalid = nullptr);
    51 std::string EncodeBase64(Span<const unsigned char> input);
    52 std::string EncodeBase64(const std::string& str);
    53-std::vector<unsigned char> DecodeBase32(const char* p, bool* pf_invalid = nullptr);
    54-std::string DecodeBase32(const std::string& str, bool* pf_invalid = nullptr);
    55+
    56+/**
    57+ * Base32 decode.
    58+ * If `allow_nopad` is true, then the input is allowed to have length that is not
    


    luke-jr commented at 2:55 pm on November 13, 2020:
    This comment is outdated?

    vasild commented at 3:08 pm on November 13, 2020:
    Indeed! I renamed the parameter so that the default behavior is with a true argument, to be in line with EncodeBase32().
  17. luke-jr changes_requested
  18. vasild commented at 3:23 pm on November 13, 2020: member

    pid 82450 (i2pd), jid 0, uid 255: exited on signal 10 I stopped it until I figure out what’s going on.

    https://github.com/PurpleI2P/i2pd/issues/1568

  19. luke-jr commented at 0:52 am on November 27, 2020: member
    Is it intentional that this (alone) ignores the bare -proxy setting?
  20. vasild commented at 9:11 am on November 27, 2020: member

    @luke-jr yes, usually an I2P socks5 proxy can be used only for connecting to I2P addresses*, so if we point -proxy to such a proxy, then one will not be able to make connections to IPv4, IPv6 or Tor addresses.

    *there could be exceptions and there may be out-routers for going out of the I2P network, but that is unreliable.

  21. in src/netaddress.cpp:226 in 8b4a3714b9
    229- * @see CNetAddr::IsTor()
    230- */
    231-bool CNetAddr::SetSpecial(const std::string& str)
    232+bool CNetAddr::SetSpecial(const std::string& name)
    233+{
    234+    if (SetTor(name)) {
    


    lontivero commented at 6:27 pm on December 15, 2020:

    Validating the string is common to both. It could be moved here maybe.

    0bool CNetAddr::SetSpecial(const std::string& name)
    1{
    2    if (!ValidAsCString(name)) {
    3         return false;
    4    }
    5    if (SetTor(name)) {
    

    vasild commented at 10:00 am on December 16, 2020:
  22. in src/netaddress.cpp:287 in 8b4a3714b9
    282+
    283+    if (!ValidAsCString(str) || str.size() <= suffix_len ||
    284+        str.substr(str.size() - suffix_len) != suffix) {
    285+        return false;
    286+    }
    287+
    


    lontivero commented at 6:32 pm on December 15, 2020:

    There are (or there will be) more than one base32 encoded addresses, or at least that’s what I found reading the i2p specs. The “traditional” one is 52 chars length while the Encrypted LS with Base 32 Addresses is 56 chars length (https://geti2p.net/spec/encryptedleaseset.txt)

    It seems we only support the 32 bytes addresses (52 chars) so, it could make sense to validate it.

    0    // base32-encoded public key hash (SHA256) length (without padding) 
    1    if ((str.size() - suffix_len) != 52)
    2    {
    3        return false;
    4    }
    

    vasild commented at 10:04 am on December 16, 2020:
    We already do that below: address_bytes.size() != ADDR_I2P_SIZE. It would be a minuscule optimization to invalidate it before Base32-decoding, but I will skip it for now (same applies when parsing Tor addresses).

    lontivero commented at 4:06 pm on December 16, 2020:
    Make sense.

    vasild commented at 1:05 pm on December 29, 2020:
    Added such a check, see #20685 (review) for details.
  23. lontivero changes_requested
  24. lontivero commented at 6:36 pm on December 15, 2020: contributor
    I was implementing a pretty similar subset of this PR. You could take the UTs from here: https://github.com/lontivero/bitcoin/blob/6b07fb122a9690f0480766fe45d4dc789dbca2e3/src/test/net_tests.cpp#L349-L367
  25. vasild commented at 10:01 am on December 16, 2020: member

    You could take the UTs from here…

    Done in https://github.com/vasild/bitcoin/commit/2f493235200a7bc3353b75379ff03a6f729e25c9 (part of the I2P SAM implementation which I am going to PR soon to supersede this PR).

    Thanks!

  26. in src/netaddress.cpp:280 in 8b4a3714b9
    274@@ -271,6 +275,30 @@ bool CNetAddr::SetSpecial(const std::string& str)
    275     return false;
    276 }
    277 
    278+bool CNetAddr::SetI2P(const std::string& str)
    279+{
    280+    static const char* suffix{".b32.i2p"};
    


    lontivero commented at 4:17 pm on December 16, 2020:
    It seems I2P software support addresses that use uppercase characters but they make sure to convert them to lowercase before processing them everywhere. Take a look at this for example: https://github.com/i2p/i2p.i2p/blob/9ba86e86aa1f320a9ddbb644e09afcdf0d1b01ba/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java#L814

    vasild commented at 1:28 pm on December 29, 2020:
    Done in #20685, thanks!
  27. vasild commented at 12:50 pm on December 17, 2020: member
    Closing this as superseded by https://github.com/bitcoin/bitcoin/pull/20685
  28. vasild closed this on Dec 17, 2020

  29. DrahtBot locked this on Feb 15, 2022

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-12-19 00:12 UTC

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