【问题标题】:Are there C functions to convert a sockaddr_in to a sockaddr_in6 structure?是否有将 sockaddr_in 转换为 sockaddr_in6 结构的 C 函数?
【发布时间】:2015-12-30 04:58:51
【问题描述】:

我想使用规范化的 IP 地址将数据保存在数据库中。

此时,该软件可能会获得 IPv4 或 IPv6 地址。我想通过将所有地址转换为 IPv6 地址来规范化。

我知道inet_pton() 将字符串转换为二进制地址。所以我可以用 IPv6 试一次,如果失败了,用 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;

所以,我正在寻找诸如inet_convert_ipv4_to_ipv6(&sa4, &sa); 之类的函数来将sockaddr_in 转换为sockaddr_in6。我们在 C 库中有这样的吗?

如果我们没有这样的功能,解决方案是使用 '::ffff:' 介绍器,如下所示:

// 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);

我希望我们有办法将 IPv4 sockaddr_in 转换为 IPv6 sockaddr_in6 函数。我认为它会更干净......我认为最后一段代码不是 100% 安全的(我想我可以先测试 IPv4 转换,如果成功,然后使用 IPv6 转换使其安全。真是浪费不过时间!)

【问题讨论】:

  • 我认为你有更多的担心,例如cc++ 不同,而你只是用c 标记了你的问题,只有在那里有std::string。这个std::string ipv4_to_ipv6("::ffff:"); 是无效的c 语法。
  • 我不是在寻找 C++ 解决方案。只有一个 C 函数进行该转换,因此我的标记。现在只有对 C++ 感兴趣的人才会给我愚蠢的答案。也不好。
  • @ChronoKitsune,请注意,我明确表示我想将其用作数据库中的唯一键,而不是允许通过套接字进行事务的方式。话虽如此,了解 IPv6 的“缺点”是件好事。不过,据我了解,如果您正确设置了 IPv6 防火墙,则应该没问题。您只需要记住在执行该工作时阻止所有 IPv4(或大多数)。
  • 由于 IPv4 映射地址 (::ffff:0:0/96) 在 Internet 上不可路由,我不会花很多精力来阻止它们从 Internet 访问,当然也不会尝试使用他们上网。
  • 在我看来,根据您的 cmets,您不会尝试使用这些地址发送数据,仅作为索引,您应该将 96 位 0 附加到前面IPv4 地址,从而创建一个已弃用的与 IPv4 兼容的 IPv6 地址。这应该足够简单,无需查找库函数。生成的 IPv6 地址实际上不能用于任何东西,从数据库中读取它的任何东西都可以假定以 96 位 0 开头的地址是 IPv4 地址。

标签: network-programming posix ipv6 ipv4 sockaddr-in


【解决方案1】:

您可以在对inet_pton 的两次调用中继续使用sockaddr_in6。成功转换 IPv4 后,您可以转移到正确的位置。 Here 是 map4to6() 方法中的一个例子。

编辑:修复提到的错误方法名称。

【讨论】:

  • 看起来他们将 IPv4 的 4 个字节保存为 IPv6 的最后 4 个字节,我认为这是不正确的。但我更希望有一个系统功能,所以如果有什么变化(现在我想不太可能......)那么软件会继续工作。
  • 实际上看起来他们正确地将 IPv4 保存在地址中。只有您引用的特定功能并没有清楚地表明...
  • @AlexisWilke,我显示了错误的功能。正确的是map4to6。将数据从开头 (in_addr) 转移到结尾 (in6_addr)。但是单独的移位是不可能的,因为需要设置其他两个字节。我会编辑来解决这个问题。
  • @AlexisWike 另一个问题,为什么需要它?我的意思是,如果您让服务器在默认情况下使用 IPv6 侦听套接字,您将接受所有 IPv4 通信。对吗?
  • 我只想为我的数据库提供一个规范化的密钥。所以在这种情况下,它不会通过电线使用......
【解决方案2】:
unsigned char *ip = in6_addr.s6_addr;
((uint64*)ip)[0] = 0;
((uint16*)ip)[4] = 0;
ip[10] = 0xFF;
ip[11] = 0xFF;
((in_addr_t*)(ip + 12))[0] = in_addr.s_addr

【讨论】:

    猜你喜欢
    • 2017-01-15
    • 1970-01-01
    • 2016-12-19
    • 2011-04-01
    • 2013-09-07
    • 1970-01-01
    • 2013-02-28
    • 2020-11-22
    • 2012-07-25
    相关资源
    最近更新 更多