C 套接字双栈 ss_family 始终 IPv6

标签 c sockets networking

使用 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);

或绑定(bind)

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?

最佳答案

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

Hybrid dual-stack IPv6/IPv4 implementations recognize a special class of addresses, the IPv4-mapped IPv6 addresses. These addresses are typically written with a 96-bit prefix in the standard IPv6 format, and the remaining 32 bits written in the customary dot-decimal notation of IPv4.

Addresses in this group consist of an 80-bit prefix of zeros, the next 16 bits are ones, and the remaining, least-significant 32 bits contain the IPv4 address. For example, ::ffff:192.0.2.128 represents the IPv4 address 192.0.2.128. Another format, called "IPv4-compatible IPv6 address", is ::192.0.2.128; however, this method is deprecated.



您需要明确检测到,请参阅 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;
}

关于C 套接字双栈 ss_family 始终 IPv6,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59505846/

相关文章:

c - 堆栈内存是如何组织的?

c - 将字符串插值转换为 C

google-chrome - Chrome 网络计时的真正含义是什么以及影响每个计时长度的因素是什么?

java - 我可以在使用 java 的 HttpUrlConnection 类的地方覆盖 Host header 吗?

c++ - NS3 套接字混淆(需要帮助理解)

c - 显然 NULL 在包含的文件中是未知的

C: printf() 和 putchar() 问题

c++ - 如何在 Windows 中使用相同的套接字获取 ipv4 和 ipv6 数据包,它在 linux 上工作

php - 检查PHP套接字服务器中的断开连接客户端

python - 模拟 "socket.socket.connect"方法以断言它是使用给定参数调用的,同时保持功能