diff --git a/include/libp2p/multi/converters/dns_converter.hpp b/include/libp2p/multi/converters/dns_converter.hpp new file mode 100644 index 00000000..79efeeb5 --- /dev/null +++ b/include/libp2p/multi/converters/dns_converter.hpp @@ -0,0 +1,25 @@ +/** + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef LIBP2P_DNS_CONVERTER_HPP +#define LIBP2P_DNS_CONVERTER_HPP + +#include + +namespace libp2p::multi::converters { + + /** + * Converts a DNS part of a multiaddress (a hostname) + * to bytes representation as a hex string + */ + class DnsConverter { + public: + static auto addressToHex(std::string_view addr) + -> outcome::result; + }; + +} // namespace libp2p::multi::converters + +#endif // LIBP2P_DNS_CONVERTER_HPP diff --git a/include/libp2p/multi/multiaddress_protocol_list.hpp b/include/libp2p/multi/multiaddress_protocol_list.hpp index c9153079..9b5237a9 100644 --- a/include/libp2p/multi/multiaddress_protocol_list.hpp +++ b/include/libp2p/multi/multiaddress_protocol_list.hpp @@ -78,6 +78,9 @@ namespace libp2p::multi { * otherwise */ static constexpr auto get(std::string_view name) -> Protocol const * { + if(name == "ipfs") { + name = "p2p"; // IPFS is a legacy name, P2P is the preferred one + } for (Protocol const &protocol : protocols_) { if (protocol.name == name) { return &protocol; @@ -120,15 +123,15 @@ namespace libp2p::multi { {Protocol::Code::IP6, 128, "ip6"}, {Protocol::Code::IP6_ZONE, Protocol::kVarLen, "ip6zone"}, {Protocol::Code::DNS, Protocol::kVarLen, "dns"}, - {Protocol::Code::DNS4, Protocol::kVarLen, "dns64"}, + {Protocol::Code::DNS4, Protocol::kVarLen, "dns4"}, {Protocol::Code::DNS6, Protocol::kVarLen, "dns6"}, {Protocol::Code::DNS_ADDR, Protocol::kVarLen, "dnsaddr"}, {Protocol::Code::SCTP, 16, "sctp"}, {Protocol::Code::UDT, 0, "udt"}, {Protocol::Code::UTP, 0, "utp"}, {Protocol::Code::UNIX, Protocol::kVarLen, "unix"}, - // {Protocol::Code::P2P, Protocol::kVarLen, "p2p"}, - {Protocol::Code::P2P, Protocol::kVarLen, "ipfs"}, + {Protocol::Code::P2P, Protocol::kVarLen, "p2p"}, + // Also P2P protocol may have a legacy name "ipfs" {Protocol::Code::ONION, 96, "onion"}, {Protocol::Code::ONION3, 296, "onion3"}, {Protocol::Code::GARLIC64, Protocol::kVarLen, "garlic64"}, diff --git a/src/multi/converters/CMakeLists.txt b/src/multi/converters/CMakeLists.txt index cd6009b2..9944db63 100644 --- a/src/multi/converters/CMakeLists.txt +++ b/src/multi/converters/CMakeLists.txt @@ -11,6 +11,7 @@ libp2p_add_library(p2p_converters tcp_converter.cpp udp_converter.cpp ipfs_converter.cpp + dns_converter.cpp ) target_link_libraries(p2p_converters Boost::boost diff --git a/src/multi/converters/converter_utils.cpp b/src/multi/converters/converter_utils.cpp index 5a41f74a..d13b8614 100644 --- a/src/multi/converters/converter_utils.cpp +++ b/src/multi/converters/converter_utils.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -89,12 +90,14 @@ namespace libp2p::multi::converters { case Protocol::Code::P2P: return IpfsConverter::addressToHex(addr); - case Protocol::Code::IP6_ZONE: case Protocol::Code::DNS: case Protocol::Code::DNS4: case Protocol::Code::DNS6: case Protocol::Code::DNS_ADDR: case Protocol::Code::UNIX: + return DnsConverter::addressToHex(addr); + + case Protocol::Code::IP6_ZONE: case Protocol::Code::ONION3: case Protocol::Code::GARLIC64: case Protocol::Code::QUIC: @@ -127,7 +130,7 @@ namespace libp2p::multi::converters { return ConversionError::NO_SUCH_PROTOCOL; } - if (protocol->name != "ipfs") { + if (protocol->name != "ipfs" and protocol->name != "p2p") { lastpos = lastpos + UVarint::calculateSize(pid_bytes.subspan(lastpos / 2)) * 2; std::string address; diff --git a/src/multi/converters/dns_converter.cpp b/src/multi/converters/dns_converter.cpp new file mode 100644 index 00000000..535e4f8b --- /dev/null +++ b/src/multi/converters/dns_converter.cpp @@ -0,0 +1,20 @@ +/** + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include + +namespace libp2p::multi::converters { + + auto DnsConverter::addressToHex(std::string_view addr) + -> outcome::result { + std::vector bytes(addr.size()); + std::copy(addr.begin(), addr.end(), bytes.begin()); + auto hex = common::hex_lower(bytes); + return UVarint{bytes.size()}.toHex() + hex; + } +} diff --git a/src/multi/multiaddress.cpp b/src/multi/multiaddress.cpp index 730e2891..d392b022 100644 --- a/src/multi/multiaddress.cpp +++ b/src/multi/multiaddress.cpp @@ -127,6 +127,17 @@ namespace libp2p::multi { bool Multiaddress::decapsulateStringFromAddress(std::string_view proto, const ByteBuffer &bytes) { auto str_pos = stringified_address_.rfind(proto); + if (proto == "/p2p" or proto == "/ipfs") { + auto alt_pos = + stringified_address_.rfind(proto == "/ipfs" ? "/p2p" : "/ipfs"); + if (alt_pos != std::string::npos) { + if(str_pos == std::string::npos) { + str_pos = alt_pos; + } else { + str_pos = std::max(str_pos, alt_pos); + } + } + } if (str_pos == std::string::npos) { return false; } @@ -167,6 +178,12 @@ namespace libp2p::multi { auto proto_str = "/"s + std::string(protocol->name); auto proto_positions = findSubstringOccurrences(stringified_address_, proto_str); + if (proto == Protocol::Code::P2P) { // ipfs and p2p are equivalent + auto ipfs_occurences = + findSubstringOccurrences(stringified_address_, "/ipfs"s); + proto_positions.insert(proto_positions.end(), ipfs_occurences.begin(), + ipfs_occurences.end()); + } for (const auto &pos : proto_positions) { auto value_pos = stringified_address_.find_first_of('/', pos + 1) + 1; diff --git a/test/libp2p/multi/multiaddress_test.cpp b/test/libp2p/multi/multiaddress_test.cpp index 2a57aaba..ef807106 100644 --- a/test/libp2p/multi/multiaddress_test.cpp +++ b/test/libp2p/multi/multiaddress_test.cpp @@ -38,9 +38,7 @@ class MultiaddressTest : public ::testing::Test { * @then creation succeeds */ TEST_F(MultiaddressTest, CreateFromStringValid) { - auto result = Multiaddress::create(valid_ip_udp); - ASSERT_TRUE(result); - auto &&address = result.value(); + EXPECT_OUTCOME_TRUE(address, Multiaddress::create(valid_ip_udp)); ASSERT_EQ(address.getStringAddress(), valid_ip_udp); ASSERT_EQ(address.getBytesAddress(), valid_ip_udp_bytes); } @@ -245,3 +243,15 @@ TEST_F(MultiaddressTest, GetProtocolsWithValues) { std::make_pair(*ProtocolList::get("ip4"), "127.0.0.1"), std::make_pair(*ProtocolList::get("udp"), "3232"))); } + +/** + * @given a multiaddr containing DNS and P2P entries + * @when parsing it + * @then it is accepted + */ +TEST_F(MultiaddressTest, DnsAndIpfs) { + auto addr = "/dns4/kusama-bootnode-1.paritytech.net/tcp/30333/p2p/QmV32G18YzenpNFmhqg2n7TtdjYRK7oU6FhLbDL4oRgsbe"s; + EXPECT_OUTCOME_TRUE(address, Multiaddress::create(addr)); + ASSERT_EQ(address.getStringAddress(), addr); + +} diff --git a/test/libp2p/multi/utils/string_from_to_bytes_test.cpp b/test/libp2p/multi/utils/string_from_to_bytes_test.cpp index a4b517b5..e522b760 100644 --- a/test/libp2p/multi/utils/string_from_to_bytes_test.cpp +++ b/test/libp2p/multi/utils/string_from_to_bytes_test.cpp @@ -79,7 +79,7 @@ TEST(AddressConverter, BytesToString) { VALID_BYTES_TO_STR("/udp/1234", "910204D2") VALID_BYTES_TO_STR("/tcp/1234", "0604D2") VALID_BYTES_TO_STR( - "/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234", + "/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234", "A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20DB76A68911C" "0B0604D2") VALID_BYTES_TO_STR("/ip4/127.0.0.1/udp/1234", "047F000001910204D2") @@ -87,11 +87,11 @@ TEST(AddressConverter, BytesToString) { VALID_BYTES_TO_STR("/ip4/127.0.0.1/tcp/1234/udp/0/udp/1234", "047F0000010604D291020000910204D2") VALID_BYTES_TO_STR( - "/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", + "/ip4/127.0.0.1/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", "047F000001A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20D" "B76A68911C0B") VALID_BYTES_TO_STR( - "/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/" + "/ip4/127.0.0.1/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/" "1234", "047F000001A503221220D52EBB89D85B02A284948203A62FF28389C57C9F42BEEC4EC20D" "B76A68911C0B0604D2") diff --git a/test/libp2p/peer/peer_address_test.cpp b/test/libp2p/peer/peer_address_test.cpp index 7c9dc49a..03baf545 100644 --- a/test/libp2p/peer/peer_address_test.cpp +++ b/test/libp2p/peer/peer_address_test.cpp @@ -36,7 +36,7 @@ class PeerAddressTest : public ::testing::Test { Multiaddress::create("/ip4/192.168.0.1/tcp/228").value(); const std::string kaddressString = - std::string{kDefaultAddress.getStringAddress()} + "/ipfs/" + std::string{kDefaultAddress.getStringAddress()} + "/p2p/" + kEncodedDefaultPeerId; };