Your question is lacking a bit of context. So it is not clear what exactly you are asking for. However I have three suggestions depending on how I interpret your question.
You have a server reachable over both IPv4 and IPv6 which clients connect to. You want to tell clients about the IPv6 addresses of each other. But for a client which connected over IPv4, chances are that client has no IPv6 address. Those which have both IPv4 and IPv6 are expected to use IPv6 to connect to your server.
In this situation if the protocol only allows communicating an IPv6 address, but the only IP address you have to give out about a peer is an IPv4 address, then you can simply use the ::ffff:0:0/96
prefix. If the IPv4 address of a client was 192.0.2.3
then you can tell another client, that the address was ::ffff:192.0.2.3
. When the other client attempts to connect to ::ffff:192.0.2.3
, it will in fact make an IPv4 connection to that IP address.
This of course still doesn't solve issues introduced by NAT.
It might be that the client which connected to your server using IPv4 did so because it had no native IPv6 address, but it might still have an automatic tunnel. For example some systems automatically assign a 6to4 address if they have a public IPv4 address but no IPv6 address. If the IPv4 address was 192.0.2.3
a common approach to generating a 6to4 address would look almost like this 2002:192.0.2.3::192.0.2.3
(this is not an entirely valid notation, because embedding an IPv4 address into the IPv6 address notation is only permitted for the last 32 bits. A valid notation would be 2002:c000:203::192.0.2.3
).
But this way to derive an IPv6 address for a host from an IPv4 address would only work for a host with a public IPv4 address. And not all hosts will automatically configure 6to4, so it is not going to work in most situations.
If you have an IPv6-only application, and you want to add support for clients with no native IPv6 address by embedding tunneling directly in the application, then I think Teredo is the most suitable protocol. Teredo has the advantage that it works by tunneling IPv6 over UDP, and thus it can be embedded in an application without needing special privileges. Most OS permit any application to open a UDP port.
If your application would normally send UDP packets over IPv6 between the clients, then constructing a Teredo packet by embedding that UDPv6 packet inside a Teredo packet is quite simple. You just need to prefix two fixed size headers and compute a checksum. If your client would normally communicate by using TCP over IPv6, then this approach becomes a lot harder. By binding to a UDP port and using your own Teredo implementation over that, then you won't be using the TCP implementation within the OS, thus your application would have to contain its own TCP implementation. I would recommend aiming for a design in which that won't become necessary.
Assuming your application bind to a UDP port and as long as both sender and receiver has native IPv6, you simply send UDP packets between them, then what would this approach mean for the other cases?
Your application would have to operate in one of three different modes:
- IPv6 only. Used by instances which have a native IPv6 address and no public IPv4 address. It would assume the entire world is IPv6 and rely on third party Teredo relays for communicating with clients that have no IPv6 address.
- Teredo relay mode. Used by instances which have a native IPv6 address and a public IPv4 address. Because these instances have a public IPv4 address their UDP port can be reached by those clients, which have no native IPv6. This avoids the dependence on third party Teredo relays.
- Teredo client mode. Used by instances which have no native IPv6 address.
Any direct communication between two IPv4 only hosts behind separate NAT gateways will have to rely on some form of NAT hole punching. Teredo allows for many different kinds of NAT hole punching to be used, so if you are going to need NAT hole punching in your application, you might as well use the Teredo protocol because it simultaneously provides a bit of IPv6 transition mechanism.
I wish I could simply point to a library doing all of the above, but unfortunately, I don't know one.