IPv6 多播在局域网中不起作用

IPv6 multicast not working in LAN

本文关键字:不起作用 局域网 多播 IPv6      更新时间:2023-10-16

我试图通过我的网络发送IPv6组播数据包。发送似乎有效,因为它到达目标 PC - 至少它出现在 WireShark 中记录的网络流量中。但它没有到达我的服务器程序。当我从应该接收它的同一台PC发送数据包时,它确实有效。

这是用于发送的代码(删除了错误检查以提高可读性):

UDPBroadcastSocket = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
BOOL Yes = 1;
setsockopt(UDPBroadcastSocket, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&Yes, sizeof(BOOL));
int32_t hops = 50;
setsockopt(UDPBroadcastSocket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char*)&hops, sizeof(hops));
uint32_t IF = 0;
setsockopt(UDPBroadcastSocket, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char*)&IF, sizeof(IF));
struct sockaddr_in6 sock_in;
struct addrinfo *result = NULL;
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
hints.ai_flags = AI_NUMERICHOST;
getaddrinfo("FF18::1243", "12346", &hints, &result);
unsigned char buffer[MAXBUF];
int PacketSize = 8;
int sinlen = int(result->ai_addrlen);
memcpy(&sock_in, result->ai_addr, result->ai_addrlen);
freeaddrinfo(result);
sendto(UDPBroadcastSocket, (char*)buffer, PacketSize, 0, (sockaddr *)&sock_in, sinlen);

这是接收数据包的代码(删除了错误检查以提高可读性):

std::vector<uint32_t> GetNetworkInterfaceIndices(){
std::vector<uint32_t> Result;
/* Declare and initialize variables */
DWORD dwSize = 0;
DWORD dwRetVal = 0;
unsigned int i = 0;
// Set the flags to pass to GetAdaptersAddresses
ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
// default to unspecified address family (both)
ULONG family = AF_UNSPEC;
LPVOID lpMsgBuf = NULL;
PIP_ADAPTER_ADDRESSES pAddresses = NULL;
ULONG outBufLen = 0;
ULONG Iterations = 0;
PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL;
PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL;
IP_ADAPTER_DNS_SERVER_ADDRESS *pDnServer = NULL;
IP_ADAPTER_PREFIX *pPrefix = NULL;

family = AF_INET6;

// Allocate a 15 KB buffer to start with.
outBufLen = WORKING_BUFFER_SIZE;
do {
pAddresses = (IP_ADAPTER_ADDRESSES *)MALLOC(outBufLen);
if (pAddresses == NULL) {
return{ 0 };
}
dwRetVal =
GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen);
if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
FREE(pAddresses);
pAddresses = NULL;
}
else {
break;
}
Iterations++;
} while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES));
if (dwRetVal == NO_ERROR) {
// If successful, output some information from the data we received
pCurrAddresses = pAddresses;
while (pCurrAddresses) {
Result.emplace_back(pCurrAddresses->IfIndex);
pCurrAddresses = pCurrAddresses->Next;
}
}
else {
return{ 0 };
}
if (pAddresses) {
FREE(pAddresses);
}
return Result;
}

UDPSocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
sockaddr_in6 UDP_Sock_in;
memset(&UDP_Sock_in, 0, sizeof(sockaddr_in6));
UDP_Sock_in.sin6_addr = in6addr_any;
UDP_Sock_in.sin6_port = htons(Settings::GetPort()+1);
UDP_Sock_in.sin6_family = PF_INET6;
setsockopt(UDPSocket, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&No, sizeof(BOOL));
bind(UDPSocket, (sockaddr*)&UDP_Sock_in, sizeof(UDP_Sock_in));
ipv6_mreq BroadcastGroup;
memset(&BroadcastGroup, 0, sizeof(ipv6_mreq));
const auto IfIndices = GetNetworkInterfaceIndices();
BroadcastGroup.ipv6mr_multiaddr.u.Byte[0] = 0xFF;
BroadcastGroup.ipv6mr_multiaddr.u.Byte[1] = 0x18;
BroadcastGroup.ipv6mr_multiaddr.u.Byte[14] = 0x12;
BroadcastGroup.ipv6mr_multiaddr.u.Byte[15] = 0x43;
for (const auto& Index : IfIndices) {
BroadcastGroup.ipv6mr_interface = Index;
setsockopt(UDPSocket, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char*)&BroadcastGroup, sizeof(ipv6_mreq));        
} 

socklen_t fromLength = sizeof(sockaddr_in6);
pollfd PollFd;
PollFd.events = POLLIN;
PollFd.fd = UDPSocket;
PollFd.revents = -1;
WSAPoll(&PollFd, 1, -1);
recvfrom(UDPSocket, (char*)buffer, MAXBUF, 0, (sockaddr*)&from, &fromLength);

我基本上尝试指定每个网络接口索引,但数据包仍未到达服务器。我不知道可能出了什么问题。为什么当发送方和接收方在同一台PC上时它可以工作?我不明白这一点。有人有想法吗?这不是防火墙,我把它关掉了,什么都没有改变。当我直接指定接收PC的IP地址时,它也确实有效。

我找到了一个解决方法:只需切换到IPv4,因为IPv6多播目前似乎不适用于Windows(至少在我的用例中,请参阅评论)。我的代码已经工作了,但前段时间停止工作,直到我再次测试它我才注意到。

我尝试了一堆不同的地址,显然它们都不适用于 3 种不同的设备。然后我切换到 IPv4,它只是工作 - 我只将与 IPv6 相关的东西更改为它们的 IPv4 等效物,并删除了发送器上的跃点和接口选项。

我的接收器甚至出现在组播组列表中(您可以使用命令"netsh 接口 ipv6 show joins"看到),但仍然没有收到发送到其地址的数据包,所以我得出结论这可能是一个错误,因为我找到的每个示例代码都不适合我,我找不到任何其他我可能错过的 setsockopt 选项。如果您知道可能导致此问题的原因或如何在不切换回旧IPv4标准的情况下修复它,请随时发表评论。