【问题标题】:connect to IPv4 mapped IPv6 address fails连接到 IPv4 映射的 IPv6 地址失败
【发布时间】:2012-04-11 04:12:15
【问题描述】:

我正在尝试使用 IPv6 套接字在 linux (debian-lenny-64 2.6.26-2-amd64) 上使用 IPv4 映射的 IPv6 地址连接到 IPv4 地址

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>

int main(int argc, void **argv)
{
    struct addrinfo *sa;
    struct addrinfo *ra;

    int err = getaddrinfo("2001:DB8::2", 0, 0, &sa);

    int fd = socket(sa->ai_family, SOCK_DGRAM, 0);

    int v6only = 0;     

    err = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&v6only, sizeof(v6only)); 

    err = bind(fd, sa->ai_addr, sa->ai_addrlen);

    err = getaddrinfo("::ffff:192.168.0.1", "9", 0, &ra);

//  err = getaddrinfo("2001:DB8::1", "9", 0, &ra);
//  err = getaddrinfo("::ffff:127.0.0.1", "9", 0, &ra);

    err = connect(fd, (struct sockaddr *)ra->ai_addr, sizeof(struct sockaddr_in6));
}

(我已经从粘贴的代码中删除了错误测试)

2001:DB8::2 和 192.168.0.2 是本地地址(都在同一个接口上)。
2001:DB8::1 和 192.168.0.1 是远程地址(都在同一个接口上)。

我更改了连接调用的远程地址并得到以下信息:

  • 连接到 ::ffff:127.0.0.1 成功(本地主机)
  • 连接到 2001:DB8::1 成功(远程 IPv6 地址)
  • 连接到 ::ffff:192.168.0.2 成功(本地 IPv4 地址)
  • 连接到 ::ffff:192.168.0.1 失败(22 无效参数 - 远程 IPv4)

如果我改为进行 IPv4 连接,那么连接也可以工作。

我认为某处的路由肯定存在问题,但我不知道我需要更改什么。 首先,理论上我应该能够做到这一点吗?
任何想法出了什么问题?

【问题讨论】:

  • 我不知道为什么本地 IPv4 地址(::ffff:127.0.0.1 和 ::ffff:192.168.0.2)有效,但远程 IPv4 地址不起作用我并不感到惊讶不工作。在连接到远程 IPv4 地址之前,您将套接字绑定到本地 IPv6 地址。那行不通...如果您忽略bind() 调用会怎样?
  • 这是一项测试,以确定我们应该在发送到远端的消息中包含哪些收听地址。我们可能会监听多宿主系统中的多个地址。我们希望确保使用适当的地址作为出站通信的来源,因为响应需要返回到我们正在收听的内容。如果它们都不合适,那么我们就不会发送(但我希望失败的案例能够奏效)。它适用于 IPv4->IPv4 和 IPv6->IPv6 情况,但是当我尝试 IPv4 映射的 IPv6 地址时,它会出错。
  • 如果你 bind() 当你 connect() 到 IPv4 地址时 bind() 到 IPv4 地址,当你 connect() 到 IPv6 地址时 bind() 到 IPv6 地址,那么我想它会工作。
  • 有趣的是,不调用 bind() 和 connect() 对远程 ::ffff:192.168.0.1 地址有效。我会看看是否可以从调用方的getsockname() 获得一些信息。谢谢。
  • 当我不绑定时,getsockname() 告诉我::ffff:192.168.0.2 是套接字的地址。所以这是有道理的。一些内部magic 意味着当您绑定到 IPv6 时,127.0.0.1 和本地 IPv4 地址将起作用。一旦您尝试使用 IPv6 套接字访问远程 IPv4 地址,您就无法绑定到本地 IPv6 地址。感谢您的帮助。

标签: c linux sockets ipv6


【解决方案1】:
  • 查看函数“getaddrinfo()”为
     ~$ man getaddrinfo 
  • 函数的“hints”参数具有属性“ai_flags”,如果您将其设置为“AI_PASSIVE”。它适用于 IPv4 和 IPv6 寻址模式。

【讨论】:

    猜你喜欢
    • 2013-09-18
    • 1970-01-01
    • 2012-12-25
    • 1970-01-01
    • 2015-01-17
    • 2015-04-01
    • 2021-11-01
    • 1970-01-01
    • 2012-06-29
    相关资源
    最近更新 更多