I want to save data in a database using a canonicalized IP address.
The software, at this point, may get IPv4 or IPv6 addresses. I want to canonicalize by converting all addresses to an IPv6 address.
I know of inet_pton()
to convert the string to a binary address. So I can try once with IPv6 and if that fails, try again with IPv4:
struct sockaddr_in6 sa;
int r = inet_pton(AF_INET6, input_addr, &sa.sin6_addr);
if(r != 1)
{
// try again with IPv4
struct sockaddr_in sa4;
int r = inet_pton(AF_INET, input_addr, &sa4.sin_addr);
// is there such a function?!
inet_convert_ipv4_to_ipv6(&sa4, &sa);
}
char output_addr[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &sa, output_addr, sizeof(output_addr));
// in C++, I can do that if function returns std::string
// in C you cannot return a pointer on the stack, watch out!
return output_addr;
So, I am looking for a function such as inet_convert_ipv4_to_ipv6(&sa4, &sa);
to convert the sockaddr_in
to a sockaddr_in6
. Do we have such in the C library?
If we do not have such a function, would a solution be to use the '::ffff:' introducer as in:
// try again with IPv4
std::string ipv4_to_ipv6("::ffff:");
ipv4_to_ipv6 += input_addr;
int r = inet_pton(AF_INET6, ipv4_to_ipv6.c_str(), &sa.sin_addr);
I would hope that we have a way to convert an IPv4 sockaddr_in
to an IPv6 sockaddr_in6
function instead. I think it would be cleaner... I think that this last piece of code is not 100% secure (I guess I can test the IPv4 conversion first and if it succeeds, then use the IPv6 conversion to make it secure. What a waste of time though!)
You could keep using sockaddr_in6 in both calls to inet_pton. When you convert the IPv4 successfully, you could do a shift to the correct place. Here is a example of that in map4to6() method.
EDIT: To fix the wrong method name mentioned.