当前位置: 首页 > 知识库问答 >
问题:

使用本地ipv6套接字将UDP发送到本地ipv4地址

蒋无尘
2023-03-14
int fd = socket(AF_INET6, SOCK_DGRAM, 0);
int no = 0;
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&no, sizeof(no));
bind(fd, (sockaddr*)&sa, sizeof(sa));
struct sockaddr_in6 peer = create_ipv6_sockaddr(55555, "193.156.108.67", 0, 0, true);
sendto(sock,content,strlen(content),0,(struct sockaddr*)&peer,sizeof(peer));

此函数创建sockaddr_in6:

sockaddr_in6 create_ipv6_sockaddr(int port, string addr, uint32_t flowinfo, uint32_t scope_id, bool ipv4=false) {
    struct sockaddr_in6 si;
    si.sin6_family = AF_INET6;
    if (ipv4) {
        si.sin6_family = AF_INET;
    }
    si.sin6_port = htons(port);
    si.sin6_flowinfo = flowinfo; // Should be 0 or 'random' number to distinguish this flow
    if (ipv4) {
        addr = "::ffff:" + addr;
    }
    inet_pton(AF_INET6, addr.c_str(), &si.sin6_addr);
    if (!si.sin6_addr.s6_addr) {
        perror("Address is wrong..");
    }
    si.sin6_scope_id = scope_id;
    return si;
}

基本上,如果地址是IPv4地址,我会在它前面加上::ffff:,并将该族设置为af_inet。

这有可能做到。如果是,我做错了什么?

sockaddr_in6 create_ipv6_sockaddr(int port, string addr, uint32_t flowinfo, uint32_t scope_id, bool ipv4=false) {
    struct sockaddr_in6 si;
    si.sin6_family = AF_INET6;
    //  if (ipv4) {
    //      si.sin6_family = AF_INET;
    //  }
    si.sin6_port = htons(port);
    si.sin6_flowinfo = flowinfo; // Should be 0 or 'random' number to distinguish this flow
    if (ipv4) {
        addr = "::ffff:" + addr;
    }
    inet_pton(AF_INET6, addr.c_str(), &si.sin6_addr);
    if (!si.sin6_addr.s6_addr) {
        perror("Address is wrong..");
    }
    //  char s[40];
    //  inet_ntop(AF_INET6, &(si.sin6_addr), s, sizeof(s));
    //  fprintf(stderr, "Sockaddr %d %s\n", si.sin6_family, s);
    si.sin6_scope_id = scope_id;
    if (scope_id == 0 && !ipv4) {
        si.sin6_scope_id = ipv6_to_scope_id(&si); // Interface number
    }
    return si;
}

int ipv6_to_scope_id(sockaddr_in6 *find) {
    struct ifaddrs *addrs, *iap;
    struct sockaddr_in6 *sa;
    char host[NI_MAXHOST];

    getifaddrs(&addrs);
    for (iap = addrs; iap != NULL; iap = iap->ifa_next) {
        if (iap->ifa_addr && (iap->ifa_flags & IFF_UP) && iap->ifa_addr->sa_family == AF_INET6) {
            sa = (struct sockaddr_in6 *)(iap->ifa_addr);
            if (memcmp(&find->sin6_addr.s6_addr, &sa->sin6_addr.s6_addr, sizeof(sa->sin6_addr.s6_addr)) == 0) {
                getnameinfo(iap->ifa_addr, sizeof(struct sockaddr_in6), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
                fprintf(stderr, "Found interface %s with scope %d\n", host, sa->sin6_scope_id);
                return sa->sin6_scope_id;
            }
        }
    }
    freeifaddrs(addrs);
    return 0;
}
int bind_ipv6 (sockaddr_in6 sa) {
    int fd = socket(AF_INET6, SOCK_DGRAM, 0);
    if (fd < 0) {
        perror("Creating socket failed");
    }
    char str[40];
    inet_ntop(AF_INET6, &(sa.sin6_addr), str, sizeof(str));
    //  fprintf(stderr, "Bind to %s:%d\n", str, ntohs(sa.sin6_port));
    int no = 0;
    if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&no, sizeof(no)) < 0 ) { // Only works with wildcard
        perror("V6ONLY failed");
    }
    if (bind(fd, (sockaddr*)&sa, sizeof(sa)) < 0) {
        perror("Binding failed");
    }

    return fd;
}

共有1个答案

酆浩邈
2023-03-14

当您使用::ffff:映射地址时,您实际上是在通过网络发送IPv4数据包,同时在软件中使用IPv6套接字。它使支持这两种协议变得更加容易,但它不允许您混合使用不同的地址族。

网络上的数据包要么是IPv4数据包(具有IPv4源地址和目的地址),要么是IPv6数据包(具有IPv6源地址和目的地址)。::FFFF:地址永远不会在实际数据包中使用。它仅作为软件表示形式存在。

如果您使用IPv6套接字与::ffff:地址通信,那么在线路上,它们将是普通的IPv4数据包,您的本地IPv4地址将用于您的连接端。

 类似资料:
  • 我有一个python应用程序,它需要为IPv6连接选择一个特定的本地源地址,但可以为IPv4连接使用“any”0.0.0.0。但应用程序在中使用主机名,以允许从名称查找地址。 那么,如果在调用之前我不知道是IPv4地址还是IPv6地址,那么如何将特定的IPv6源地址和IPv4“any”地址绑定到本地套接字? 一定有更好的办法。我怀疑我必须自己实现地址查找和选择,并将地址而不是名称传递给。这样,在进

  • 问题内容: 我有使用地址的应用程序(它存储它们的时间很长),因此它只了解地址。 可以将地址转换为with 吗? 问题答案: 尽管IPv4地址范围具有等效的IPv6,但是您不能将所有IPv6地址都转换为IPv4-IPv6地址比IPv4地址更多。 解决此问题的唯一明智的方法是更新您的应用程序,以便能够理解和存储IPv6地址。

  • 我检查了下面的代码以获取ipv6地址,这段代码返回了全局单播地址,比如“2001:x:x…”。但我想获得链接本地地址,比如“fe80:…”。如何使用以下代码获取链接本地地址?

  • 我想广播消息本地到许多应用程序。对于这一点,我认为UDP套接字是最好的IPC,纠正我,如果我是Worwn。 并倾听: 问题是我必须像这样通过IP192.168.1.255,但在实际场景中可能没有eth0接口,只有环回。那我怎么才能做到这一点呢?

  • 所以有几个网站会为你计算你的链接本地ipv6地址,就像这里的这个。 尽管如此,它并没有给出任何有用的关于这个地址是如何计算的,也没有输入参数是什么。那么,如果一个人知道自己的ipv4地址、子网掩码和网关地址,计算链路本地ipv6地址的过程(或算法)是什么?我正在使用SCTP套接字做一个项目,该项目使用ISATAP网络隧道和LL ipv6地址用于构建ISATAP地址。

  • 所以我在写一个P2P多人游戏。服务器与每个玩家建立连接(UDP),然后让玩家直接彼此连接(使用UDP Holepunching技术)。 然后我在父母家做了测试,然后就停止了工作。 null 还是这样的设置注定要失败?