【发布时间】:2019-03-30 23:27:39
【问题描述】:
我有一个原始 ipv6 套接字,我从中得到这个 udp 数据包。 套接字(AF_INET6,SOCK_RAW,IPPROTO_UDP)
我需要在收到的数据包上验证 udp 校验和,并计算伪头,需要找到源 IP 地址。不知道如何从 ipv6 原始套接字中获取它。
对于目标地址,我们有 IPV6_RECVPKTINFO 套接字选项,但不确定如何从中获取源地址。
【问题讨论】:
我有一个原始 ipv6 套接字,我从中得到这个 udp 数据包。 套接字(AF_INET6,SOCK_RAW,IPPROTO_UDP)
我需要在收到的数据包上验证 udp 校验和,并计算伪头,需要找到源 IP 地址。不知道如何从 ipv6 原始套接字中获取它。
对于目标地址,我们有 IPV6_RECVPKTINFO 套接字选项,但不确定如何从中获取源地址。
【问题讨论】:
您正在使用套接字接口。因此,您使用recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t addrlen); 或recvmsg(int sockfd, struct msghdr *msg, int flags); 接收UDP 数据包。
请注意,对于大多数操作系统(Linux、Unix、Windows...),在您收到数据包之前已经检查了 CRC,因此您不需要检查 CRC。
使用recvfrom(),源地址存储在第5个参数指向的缓冲区的一部分中,即struct sockaddr_in6结构。要分配此缓冲区,您可能更喜欢使用sockaddr_storage 结构而不是sockaddr_in6,因为它足够大,可以容纳所有支持的特定于协议的地址结构,并且您可以重新使用此缓冲区来处理其他地址类型.
因此,您可以使用填充有 ((struct sockaddr_in6 *) src_addr)->sin6_addr 的伪缓冲区(类型为 struct in6_addr)来计算 CRC。
使用recvmsg(),您在第二个参数中提供指向struct msghdr 的指针,源地址存储在msg_name 字段指向的缓冲区的一部分中,位于struct sockaddr_in6 结构中。
因此,您可以使用填充有 ((struct sockaddr_in6 *) msg_name)->sin6_addr 的伪缓冲区(类型为 struct in6_addr)来计算 CRC。
最后,请注意,对于 OS-X 或 FreeBSD 等基于 BSD 的系统,即使范围 id 存储在 struct sockaddr_in6 结构的字段中,它也会作为第二个 16 嵌入到地址本身中位字。因此,在这种情况下,您不应该将这部分地址复制到伪头中,而是将其替换为 0。
【讨论】:
我不喜欢 RAW Sockets 和 IPv6。无需执行任何代码,我建议查看 RFC。见这里:https://www.ietf.org/rfc/rfc3542.txt。特别注意第 21 页 - 4 至 6 和 6.2。
另见 msg_control:(ssize_t recvmsg(int socket, struct msghdr *message, int flags);)
struct msghdr {
void *msg_name optional address
socklen_t msg_namelen size of address
struct iovec *msg_iov scatter/gather array
int msg_iovlen members in msg_iov
void *msg_control ancillary data, see below
socklen_t msg_controllen ancillary data buffer len
int msg_flags flags on received message`
}
【讨论】: