从带有MSG_ERRQUEUE标志的recvmsg读取ICMP有效负载

我正在使用BSD套接字来构建一个不需要root权限的高级traceroute程序(如tracepath)。 使用UDP和绑定套接字,我调用:

recvmsg(socket, header, MSG_ERRQUEUE) 

我收到有关先前发送的数据包已触发的假定ICMP通知的信息。 您知道是否可以访问ICMP有效负载(应该是先前发送的数据包)?

我从recvmsg手册页中读到:

 [..] The payload of the original packet that caused the error is passed as normal data via msg_iovec. [..] 

但是我找不到任何有用的东西,它只是随机数据(我用wireshark来交叉检查数据)。

您可以使用此示例代码来检查您获得的ICMP错误并处理它(该示例包含一些注释和链接):

 #define BUFFER_MAX_SIZE 1024 int on = 1; /* Set the option, so we can receive errors */ setsockopt(socket, SOL_IP, IP_RECVERR,(char*)&on, sizeof(on)); /* Other code here */ /* .... */ /* Handle receving ICMP Errors */ int return_status; char buffer[BUFFER_MAX_SIZE]; struct iovec iov; /* Data array */ struct msghdr msg; /* Message header */ struct cmsghdr *cmsg; /* Control related data */ struct sock_extended_err *sock_err; /* Struct describing the error */ struct icmphdr icmph; /* ICMP header */ struct sockaddr_in remote; /* Our socket */ for (;;) { iov.iov_base = &icmph; iov.iov_len = sizeof(icmph); msg.msg_name = (void*)&remote; msg.msg_namelen = sizeof(remote); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_flags = 0; msg.msg_control = buffer; msg.msg_controllen = sizeof(buffer); /* Receiving errors flog is set */ return_status = recvmsg(socket, &msg, MSG_ERRQUEUE); if (return_status < 0) continue; /* Control messages are always accessed via some macros * http://www.kernel.org/doc/man-pages/online/pages/man3/cmsg.3.html */ for (cmsg = CMSG_FIRSTHDR(&msg);cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { /* Ip level */ if (cmsg->cmsg_level == SOL_IP) { /* We received an error */ if (cmsg->cmsg_type == IP_RECVERR) { fprintf(stderror, "We got IP_RECVERR message\n"); sock_err = (struct sock_extended_err*)CMSG_DATA(cmsg); if (sock_err) { /* We are intrested in ICMP errors */ if (sock_err->ee_origin == SO_EE_ORIGIN_ICMP) { /* Handle ICMP errors types */ switch (sock_err->ee_type) { case ICMP_NET_UNREACH: /* Hendle this error */ fprintf(stderror, "Network Unreachable Error\n"); break; case ICMP_HOST_UNREACH: /* Hendle this error */ fprintf(stderror, "Host Unreachable Error\n"); break; /* Handle all other cases. Find more errors : * http://lxr.linux.no/linux+v3.5/include/linux/icmp.h#L39 */ } } } } } } }