【发布时间】: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 地址。感谢您的帮助。