3

Is it possible to test IP addresses for equivalence in a dual stack environment using both IPv4 and IPv6? If so, how?

My application uses websocket++ on top of Boost ASIO.

As an example, on my LAN, one application connects to another listening on 192.168.1.2, but using this answer's IP address getter

std::string s = socket.remote_endpoint().address().to_string();

gives ::ffff:192.168.1.3 as the client's address.

The problem is that .2 will have its own node list with the original v4 address for .3, so by simple string comparison of the getter above vs a v4 version held on disk, it will seek a redundant connection to .3 even though already connected.

I've further read that things can get more complicated since by this dotted quad notation, ::ffff:192.0.2.128 is also ::ffff:c000:0280.

I am building a p2p application that accepts addresses from untrusted sources, so to prevent redundant connections, I need to be able to absolutely test for equivalence.

Can my intent be implemented? If so, how? If not, should I only use v4? I'd much rather include future capabilities now rather than worrying about integration later.

Community
  • 1
  • 1

1 Answers1

5

I think you can just use the ip::tcp::address classes' operator==.

See it Live On Coliru

#include <boost/asio.hpp>

using boost::asio::ip::address;

address from_string_ip6(std::string const& ip)
{
    address a = address::from_string(ip);
    if (a.is_v4())
        return boost::asio::ip::address_v6::v4_mapped(a.to_v4());
    else
        return a;
}

int main()
{
    address a = from_string_ip6("192.0.2.111");
    address b = from_string_ip6("::ffff:192.0.2.111");
    address c = from_string_ip6("::ffff:c000:026f");

    assert(a == b);
    assert(a == c);
    assert(b == c);
}

Update If you want to include name-resolution: ipv4 and ipv6 from any valid address

Community
  • 1
  • 1
sehe
  • 374,641
  • 47
  • 450
  • 633
  • 1
    The whole trick is to simply use the class as intended (encapsulating the domain knowledge) - and not bother about the string representation at all. Live a happy life and have a beer instead (share one with the boost devs!) – sehe Jun 12 '14 at 22:14
  • I'm not a boost dev. What do you need a pubkey for? AAAAC3NzaC1lZDI1NTE5AAAAIHOn6tEWqduGI076kYoo32EwRT6oCHbJtzS34Z0x4Vi2 (by the time that took, you can tell I don't use BSD) – sehe Jun 12 '14 at 22:31
  • 1
    you'll need to normalize all addresses to IPv6 addresses to do this. Incoming addresses via Asio/WebSocket++ should already be normalized . If you need to compare *raw* IPv4 addresses you should use the from_string constructor demonstrated above then use the boost ip::address_v6::v4_mapped function to convert to the IPv4 mapped format. (http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference/ip__address_v6/v4_mapped.html) – zaphoyd Jun 13 '14 at 01:40
  • @Gracchus Good morning :) Good call there. Here's what zaphoyd meant: [Live On Coliru](http://coliru.stacked-crooked.com/a/371d8aeea6f70651) (And, you found things I do not know/realize :)) – sehe Jun 13 '14 at 07:11