【问题标题】:C socket dual stack ss_family always IPv6C 套接字双栈 ss_family 始终 IPv6
【发布时间】:2020-04-17 17:23:42
【问题描述】:

当使用accept()getpeername() 时,sockaddr_storage 总是有ss_family=AF_INET6

struct sockaddr_storage address = {0};
socklen_t sockaddrlen = sizeof(address);
int client = accept(sock, (struct sockaddr*)(&address), &sockaddrlen);
if (client < 0) {
    perror("Unable to accept");
    exit(EXIT_FAILURE);
}
if( address.ss_family==AF_INET6  ){
    std::cout << "IPv6" << std::endl;
} else {
    std::cout << "IPv4" << std::endl;
}

我觉得它与创作有关:

s = socket(AF_INET6, SOCK_STREAM, 0);

或绑定

struct sockaddr_in6 addr;
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
addr.sin6_port   = htons(port);
addr.sin6_addr   = in6addr_any;

if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) {

我怎样才能更正ss_family,或者以其他方式告诉它是什么类型的IP?

【问题讨论】:

  • 这能回答你的问题吗? How to support both IPv4 and IPv6 connections
  • 您将需要更复杂的检测来查看 IPv6 地址是否是 IPv4 映射地址,例如 ::ffff:1.2.3.4
  • 贴出的代码是C++,不是C。请更正问题标签
  • @user3629249 唯一的部分 c++ 是 cout,套接字部分是 c,这就是我一直在用谷歌搜索“c 套接字问题”如果我谷歌“c++ 套接字问题”它显示的东西不相关所以我认为 C 是正确的标签,所以其他人可以找到它。
  • 文件中的任何部分代码为 C++ 都会导致使用 C++ 编译器。都必须是 C。

标签: c sockets networking


【解决方案1】:

双栈套接字是 IPv6 套接字,仅支持 IPv4,因此其 IP 地址将始终为 AF_INET6 地址。但是,对于 IPv4 连接,这些地址将是 IPv4-mapped IPv6 addresses

混合双栈 IPv6/IPv4 实现可识别一类特殊的地址,即 IPv4 映射的 IPv6 地址。这些地址通常使用标准 IPv6 格式的 96 位前缀编写,其余 32 位使用 IPv4 的习惯点十进制表示法编写。

该组中的地址由 80 位前缀的 0 组成,接下来的 16 位是 1,其余的最低有效 32 位包含 IPv4 地址。例如, ::ffff:192.0.2.128 表示 IPv4 地址 192.0.2.128。另一种格式,称为“与 IPv4 兼容的 IPv6 地址”,是:::192.0.2.128;但是,此方法已被弃用。

您需要明确地检测到,请参阅How to resolve IPv4 address from IPv4 mapped IPv6 address?,例如:

#ifndef IN6_IS_ADDR_V4MAPPED
#define IN6_IS_ADDR_V4MAPPED(a) \
    ((((a)->s6_words[0]) == 0) && \
    (((a)->s6_words[1]) == 0) && \
    (((a)->s6_word[2]) == 0) && \
    (((a)->s6_word[3]) == 0) && \
    (((a)->s6_word[4]) == 0) && \
    (((a)->s6_word[5]) == 0xFFFF))
#endif

struct sockaddr_storage address = {0};
socklen_t sockaddrlen = sizeof(address);
int client = accept(sock, (struct sockaddr*)(&address), &sockaddrlen);
if (client < 0) {
    perror("Unable to accept");
    exit(EXIT_FAILURE);
}
if (address.ss_family == AF_INET6){
    struct sockaddr_in6 *addr = (struct sockaddr_in6*)(&address);
    if (IN6_IS_ADDR_V4MAPPED(&(addr->sin6_addr))) {
        std::cout << "IPv4 (mapped)" << std::endl;
    } else {
        std::cout << "IPv6" << std::endl;
    }
} else {
    std::cout << "IPv4" << std::endl;
}

【讨论】:

  • 这正是我需要的谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-21
  • 1970-01-01
  • 1970-01-01
  • 2012-11-05
相关资源
最近更新 更多