2012-08-11 74 views
0

我正在使用BSD套接字構建不需要root權限(如跟蹤路徑)的高級traceroute程序。 使用UDP和綁定套接字,我呼籲:從帶有MSG_ERRQUEUE的recvmsg讀取ICMP有效載荷

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的交叉檢查數據)。

回答

4

您可以使用此示例代碼來檢查你有哪些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 
          */ 

         } 
        } 
       } 
      } 
     } 
    } 
} 
+0

我續明白是怎麼回事了所有的地址和指針。例如,您使用「struct sockaddr_in remote;」在堆棧中分配一些空間然後在內存中獲取它的地址並將其轉換爲空指針,然後將其分配給msg.msg_name,然後將數據接收到msg結構中。所以msg結構體得到「struct sockaddr_in remote;」的地址這是由套接字接收的數據過度寫入的。成功的返回狀態究竟是什麼,接收到的總字節數是多少? – 2015-09-08 18:06:18